Merge tag 'backlight-for-linus-3.19' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / drivers / pinctrl / pinctrl-rockchip.c
index 016f4578e49432926eb2f17966d1c098ffae905f..40970c305dd0aa7947fe63cff952284eb88db9a2 100644 (file)
@@ -856,27 +856,22 @@ static int rockchip_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
  * leads to this function call (via the pinctrl_gpio_direction_{input|output}()
  * function called from the gpiolib interface).
  */
-static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
-                                             struct pinctrl_gpio_range *range,
-                                             unsigned offset, bool input)
+static int _rockchip_pmx_gpio_set_direction(struct gpio_chip *chip,
+                                           int pin, bool input)
 {
-       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
        struct rockchip_pin_bank *bank;
-       struct gpio_chip *chip;
-       int pin, ret;
+       int ret;
+       unsigned long flags;
        u32 data;
 
-       chip = range->gc;
        bank = gc_to_pin_bank(chip);
-       pin = offset - chip->base;
-
-       dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n",
-                offset, range->name, pin, input ? "input" : "output");
 
        ret = rockchip_set_mux(bank, pin, RK_FUNC_GPIO);
        if (ret < 0)
                return ret;
 
+       spin_lock_irqsave(&bank->slock, flags);
+
        data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
        /* set bit to 1 for output, 0 for input */
        if (!input)
@@ -885,9 +880,28 @@ static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
                data &= ~BIT(pin);
        writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR);
 
+       spin_unlock_irqrestore(&bank->slock, flags);
+
        return 0;
 }
 
+static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+                                             struct pinctrl_gpio_range *range,
+                                             unsigned offset, bool input)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       struct gpio_chip *chip;
+       int pin;
+
+       chip = range->gc;
+       pin = offset - chip->base;
+       dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n",
+                offset, range->name, pin, input ? "input" : "output");
+
+       return _rockchip_pmx_gpio_set_direction(chip, offset - chip->base,
+                                               input);
+}
+
 static const struct pinmux_ops rockchip_pmx_ops = {
        .get_functions_count    = rockchip_pmx_get_funcs_count,
        .get_function_name      = rockchip_pmx_get_func_name,
@@ -917,8 +931,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
        return false;
 }
 
-static int rockchip_gpio_direction_output(struct gpio_chip *gc,
-                                         unsigned offset, int value);
+static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value);
 static int rockchip_gpio_get(struct gpio_chip *gc, unsigned offset);
 
 /* set the pin config settings for a specified pin */
@@ -959,9 +972,10 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
                                return rc;
                        break;
                case PIN_CONFIG_OUTPUT:
-                       rc = rockchip_gpio_direction_output(&bank->gpio_chip,
-                                                           pin - bank->pin_base,
-                                                           arg);
+                       rockchip_gpio_set(&bank->gpio_chip,
+                                         pin - bank->pin_base, arg);
+                       rc = _rockchip_pmx_gpio_set_direction(&bank->gpio_chip,
+                                         pin - bank->pin_base, false);
                        if (rc)
                                return rc;
                        break;
@@ -1253,6 +1267,10 @@ static int rockchip_pinctrl_register(struct platform_device *pdev,
                }
        }
 
+       ret = rockchip_pinctrl_parse_dt(pdev, info);
+       if (ret)
+               return ret;
+
        info->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, info);
        if (!info->pctl_dev) {
                dev_err(&pdev->dev, "could not register pinctrl driver\n");
@@ -1270,12 +1288,6 @@ static int rockchip_pinctrl_register(struct platform_device *pdev,
                pinctrl_add_gpio_range(info->pctl_dev, &pin_bank->grange);
        }
 
-       ret = rockchip_pinctrl_parse_dt(pdev, info);
-       if (ret) {
-               pinctrl_unregister(info->pctl_dev);
-               return ret;
-       }
-
        return 0;
 }
 
@@ -1387,6 +1399,7 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc)
        u32 polarity = 0, data = 0;
        u32 pend;
        bool edge_changed = false;
+       unsigned long flags;
 
        dev_dbg(bank->drvdata->dev, "got irq for bank %s\n", bank->name);
 
@@ -1432,10 +1445,14 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc)
 
        if (bank->toggle_edge_mode && edge_changed) {
                /* Interrupt params should only be set with ints disabled */
+               spin_lock_irqsave(&bank->slock, flags);
+
                data = readl_relaxed(bank->reg_base + GPIO_INTEN);
                writel_relaxed(0, bank->reg_base + GPIO_INTEN);
                writel(polarity, bank->reg_base + GPIO_INT_POLARITY);
                writel(data, bank->reg_base + GPIO_INTEN);
+
+               spin_unlock_irqrestore(&bank->slock, flags);
        }
 
        chained_irq_exit(chip, desc);
@@ -1449,6 +1466,7 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
        u32 polarity;
        u32 level;
        u32 data;
+       unsigned long flags;
        int ret;
 
        /* make sure the pin is configured as gpio input */
@@ -1456,15 +1474,20 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
        if (ret < 0)
                return ret;
 
+       spin_lock_irqsave(&bank->slock, flags);
+
        data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
        data &= ~mask;
        writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR);
 
+       spin_unlock_irqrestore(&bank->slock, flags);
+
        if (type & IRQ_TYPE_EDGE_BOTH)
                __irq_set_handler_locked(d->irq, handle_edge_irq);
        else
                __irq_set_handler_locked(d->irq, handle_level_irq);
 
+       spin_lock_irqsave(&bank->slock, flags);
        irq_gc_lock(gc);
 
        level = readl_relaxed(gc->reg_base + GPIO_INTTYPE_LEVEL);
@@ -1507,6 +1530,7 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
                break;
        default:
                irq_gc_unlock(gc);
+               spin_unlock_irqrestore(&bank->slock, flags);
                return -EINVAL;
        }
 
@@ -1514,6 +1538,7 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
        writel_relaxed(polarity, gc->reg_base + GPIO_INT_POLARITY);
 
        irq_gc_unlock(gc);
+       spin_unlock_irqrestore(&bank->slock, flags);
 
        return 0;
 }
@@ -1563,6 +1588,7 @@ static int rockchip_interrupts_register(struct platform_device *pdev,
                gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
                gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake;
                gc->chip_types[0].chip.irq_set_type = rockchip_irq_set_type;
+               gc->wake_enabled = IRQ_MSK(bank->nr_pins);
 
                irq_set_handler_data(bank->irq, bank);
                irq_set_chained_handler(bank->irq, rockchip_irq_demux);
@@ -1770,6 +1796,51 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
        return ctrl;
 }
 
+#define RK3288_GRF_GPIO6C_IOMUX                0x64
+#define GPIO6C6_SEL_WRITE_ENABLE       BIT(28)
+
+static u32 rk3288_grf_gpio6c_iomux;
+
+static int __maybe_unused rockchip_pinctrl_suspend(struct device *dev)
+{
+       struct rockchip_pinctrl *info = dev_get_drvdata(dev);
+       int ret = pinctrl_force_sleep(info->pctl_dev);
+
+       if (ret)
+               return ret;
+
+       /*
+        * RK3288 GPIO6_C6 mux would be modified by Maskrom when resume, so save
+        * the setting here, and restore it at resume.
+        */
+       if (info->ctrl->type == RK3288) {
+               ret = regmap_read(info->regmap_base, RK3288_GRF_GPIO6C_IOMUX,
+                                 &rk3288_grf_gpio6c_iomux);
+               if (ret) {
+                       pinctrl_force_default(info->pctl_dev);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int __maybe_unused rockchip_pinctrl_resume(struct device *dev)
+{
+       struct rockchip_pinctrl *info = dev_get_drvdata(dev);
+       int ret = regmap_write(info->regmap_base, RK3288_GRF_GPIO6C_IOMUX,
+                              rk3288_grf_gpio6c_iomux |
+                              GPIO6C6_SEL_WRITE_ENABLE);
+
+       if (ret)
+               return ret;
+
+       return pinctrl_force_default(info->pctl_dev);
+}
+
+static SIMPLE_DEV_PM_OPS(rockchip_pinctrl_dev_pm_ops, rockchip_pinctrl_suspend,
+                        rockchip_pinctrl_resume);
+
 static int rockchip_pinctrl_probe(struct platform_device *pdev)
 {
        struct rockchip_pinctrl *info;
@@ -1983,6 +2054,7 @@ static struct platform_driver rockchip_pinctrl_driver = {
        .driver = {
                .name   = "rockchip-pinctrl",
                .owner  = THIS_MODULE,
+               .pm = &rockchip_pinctrl_dev_pm_ops,
                .of_match_table = rockchip_pinctrl_dt_match,
        },
 };