These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / pinctrl / mediatek / pinctrl-mtk-common.c
index 474812e..5c71727 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/mfd/syscon.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/pm.h>
 #include <dt-bindings/pinctrl/mt65xx.h>
 
 #include "../core.h"
@@ -107,28 +108,38 @@ static void mtk_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        regmap_write(mtk_get_regmap(pctl, offset), reg_addr, bit);
 }
 
-static void mtk_pconf_set_ies_smt(struct mtk_pinctrl *pctl, unsigned pin,
-               int value, enum pin_config_param param)
+static int mtk_pconf_set_ies_smt(struct mtk_pinctrl *pctl, unsigned pin,
+               int value, enum pin_config_param arg)
 {
        unsigned int reg_addr, offset;
        unsigned int bit;
-       int ret;
+
+       /**
+        * Due to some soc are not support ies/smt config, add this special
+        * control to handle it.
+        */
+       if (!pctl->devdata->spec_ies_smt_set &&
+               pctl->devdata->ies_offset == MTK_PINCTRL_NOT_SUPPORT &&
+                       arg == PIN_CONFIG_INPUT_ENABLE)
+               return -EINVAL;
+
+       if (!pctl->devdata->spec_ies_smt_set &&
+               pctl->devdata->smt_offset == MTK_PINCTRL_NOT_SUPPORT &&
+                       arg == PIN_CONFIG_INPUT_SCHMITT_ENABLE)
+               return -EINVAL;
 
        /*
         * Due to some pins are irregular, their input enable and smt
-        * control register are discontinuous, but they are mapping together.
-        * So we need this special handle.
+        * control register are discontinuous, so we need this special handle.
         */
        if (pctl->devdata->spec_ies_smt_set) {
-               ret = pctl->devdata->spec_ies_smt_set(mtk_get_regmap(pctl, pin),
-                       pin, pctl->devdata->port_align, value);
-               if (!ret)
-                       return;
+               return pctl->devdata->spec_ies_smt_set(mtk_get_regmap(pctl, pin),
+                       pin, pctl->devdata->port_align, value, arg);
        }
 
        bit = BIT(pin & 0xf);
 
-       if (param == PIN_CONFIG_INPUT_ENABLE)
+       if (arg == PIN_CONFIG_INPUT_ENABLE)
                offset = pctl->devdata->ies_offset;
        else
                offset = pctl->devdata->smt_offset;
@@ -139,6 +150,33 @@ static void mtk_pconf_set_ies_smt(struct mtk_pinctrl *pctl, unsigned pin,
                reg_addr = CLR_ADDR(mtk_get_port(pctl, pin) + offset, pctl);
 
        regmap_write(mtk_get_regmap(pctl, pin), reg_addr, bit);
+       return 0;
+}
+
+int mtk_pconf_spec_set_ies_smt_range(struct regmap *regmap,
+               const struct mtk_pin_ies_smt_set *ies_smt_infos, unsigned int info_num,
+               unsigned int pin, unsigned char align, int value)
+{
+       unsigned int i, reg_addr, bit;
+
+       for (i = 0; i < info_num; i++) {
+               if (pin >= ies_smt_infos[i].start &&
+                               pin <= ies_smt_infos[i].end) {
+                       break;
+               }
+       }
+
+       if (i == info_num)
+               return -EINVAL;
+
+       if (value)
+               reg_addr = ies_smt_infos[i].offset + align;
+       else
+               reg_addr = ies_smt_infos[i].offset + (align << 1);
+
+       bit = BIT(ies_smt_infos[i].bit);
+       regmap_write(regmap, reg_addr, bit);
+       return 0;
 }
 
 static const struct mtk_pin_drv_grp *mtk_find_pin_drv_grp_by_pin(
@@ -186,6 +224,66 @@ static int mtk_pconf_set_driving(struct mtk_pinctrl *pctl,
        return -EINVAL;
 }
 
+int mtk_pctrl_spec_pull_set_samereg(struct regmap *regmap,
+               const struct mtk_pin_spec_pupd_set_samereg *pupd_infos,
+               unsigned int info_num, unsigned int pin,
+               unsigned char align, bool isup, unsigned int r1r0)
+{
+       unsigned int i;
+       unsigned int reg_pupd, reg_set, reg_rst;
+       unsigned int bit_pupd, bit_r0, bit_r1;
+       const struct mtk_pin_spec_pupd_set_samereg *spec_pupd_pin;
+       bool find = false;
+
+       for (i = 0; i < info_num; i++) {
+               if (pin == pupd_infos[i].pin) {
+                       find = true;
+                       break;
+               }
+       }
+
+       if (!find)
+               return -EINVAL;
+
+       spec_pupd_pin = pupd_infos + i;
+       reg_set = spec_pupd_pin->offset + align;
+       reg_rst = spec_pupd_pin->offset + (align << 1);
+
+       if (isup)
+               reg_pupd = reg_rst;
+       else
+               reg_pupd = reg_set;
+
+       bit_pupd = BIT(spec_pupd_pin->pupd_bit);
+       regmap_write(regmap, reg_pupd, bit_pupd);
+
+       bit_r0 = BIT(spec_pupd_pin->r0_bit);
+       bit_r1 = BIT(spec_pupd_pin->r1_bit);
+
+       switch (r1r0) {
+       case MTK_PUPD_SET_R1R0_00:
+               regmap_write(regmap, reg_rst, bit_r0);
+               regmap_write(regmap, reg_rst, bit_r1);
+               break;
+       case MTK_PUPD_SET_R1R0_01:
+               regmap_write(regmap, reg_set, bit_r0);
+               regmap_write(regmap, reg_rst, bit_r1);
+               break;
+       case MTK_PUPD_SET_R1R0_10:
+               regmap_write(regmap, reg_rst, bit_r0);
+               regmap_write(regmap, reg_set, bit_r1);
+               break;
+       case MTK_PUPD_SET_R1R0_11:
+               regmap_write(regmap, reg_set, bit_r0);
+               regmap_write(regmap, reg_set, bit_r1);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int mtk_pconf_set_pull_select(struct mtk_pinctrl *pctl,
                unsigned int pin, bool enable, bool isup, unsigned int arg)
 {
@@ -235,36 +333,37 @@ static int mtk_pconf_parse_conf(struct pinctrl_dev *pctldev,
                unsigned int pin, enum pin_config_param param,
                enum pin_config_param arg)
 {
+       int ret = 0;
        struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
 
        switch (param) {
        case PIN_CONFIG_BIAS_DISABLE:
-               mtk_pconf_set_pull_select(pctl, pin, false, false, arg);
+               ret = mtk_pconf_set_pull_select(pctl, pin, false, false, arg);
                break;
        case PIN_CONFIG_BIAS_PULL_UP:
-               mtk_pconf_set_pull_select(pctl, pin, true, true, arg);
+               ret = mtk_pconf_set_pull_select(pctl, pin, true, true, arg);
                break;
        case PIN_CONFIG_BIAS_PULL_DOWN:
-               mtk_pconf_set_pull_select(pctl, pin, true, false, arg);
+               ret = mtk_pconf_set_pull_select(pctl, pin, true, false, arg);
                break;
        case PIN_CONFIG_INPUT_ENABLE:
-               mtk_pconf_set_ies_smt(pctl, pin, arg, param);
+               ret = mtk_pconf_set_ies_smt(pctl, pin, arg, param);
                break;
        case PIN_CONFIG_OUTPUT:
                mtk_gpio_set(pctl->chip, pin, arg);
-               mtk_pmx_gpio_set_direction(pctldev, NULL, pin, false);
+               ret = mtk_pmx_gpio_set_direction(pctldev, NULL, pin, false);
                break;
        case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
-               mtk_pconf_set_ies_smt(pctl, pin, arg, param);
+               ret = mtk_pconf_set_ies_smt(pctl, pin, arg, param);
                break;
        case PIN_CONFIG_DRIVE_STRENGTH:
-               mtk_pconf_set_driving(pctl, pin, arg);
+               ret = mtk_pconf_set_driving(pctl, pin, arg);
                break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
        }
 
-       return 0;
+       return ret;
 }
 
 static int mtk_pconf_group_get(struct pinctrl_dev *pctldev,
@@ -283,12 +382,14 @@ static int mtk_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group,
 {
        struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
        struct mtk_pinctrl_group *g = &pctl->groups[group];
-       int i;
+       int i, ret;
 
        for (i = 0; i < num_configs; i++) {
-               mtk_pconf_parse_conf(pctldev, g->pin,
+               ret = mtk_pconf_parse_conf(pctldev, g->pin,
                        pinconf_to_config_param(configs[i]),
                        pinconf_to_config_argument(configs[i]));
+               if (ret < 0)
+                       return ret;
 
                g->config = configs[i];
        }
@@ -602,7 +703,7 @@ static int mtk_pmx_set_mux(struct pinctrl_dev *pctldev,
 
        ret = mtk_pctrl_is_function_valid(pctl, g->pin, function);
        if (!ret) {
-               dev_err(pctl->dev, "invaild function %d on group %d .\n",
+               dev_err(pctl->dev, "invalid function %d on group %d .\n",
                                function, group);
                return -EINVAL;
        }
@@ -622,16 +723,6 @@ static const struct pinmux_ops mtk_pmx_ops = {
        .gpio_set_direction     = mtk_pmx_gpio_set_direction,
 };
 
-static int mtk_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
-       return pinctrl_request_gpio(chip->base + offset);
-}
-
-static void mtk_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
-       pinctrl_free_gpio(chip->base + offset);
-}
-
 static int mtk_gpio_direction_input(struct gpio_chip *chip,
                                        unsigned offset)
 {
@@ -656,7 +747,7 @@ static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
        reg_addr =  mtk_get_port(pctl, offset) + pctl->devdata->dir_offset;
        bit = BIT(offset & 0xf);
        regmap_read(pctl->regmap1, reg_addr, &read_val);
-       return !!(read_val & bit);
+       return !(read_val & bit);
 }
 
 static int mtk_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -666,12 +757,8 @@ static int mtk_gpio_get(struct gpio_chip *chip, unsigned offset)
        unsigned int read_val = 0;
        struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
 
-       if (mtk_gpio_get_direction(chip, offset))
-               reg_addr = mtk_get_port(pctl, offset) +
-                       pctl->devdata->dout_offset;
-       else
-               reg_addr = mtk_get_port(pctl, offset) +
-                       pctl->devdata->din_offset;
+       reg_addr = mtk_get_port(pctl, offset) +
+               pctl->devdata->din_offset;
 
        bit = BIT(offset & 0xf);
        regmap_read(pctl->regmap1, reg_addr, &read_val);
@@ -798,7 +885,7 @@ static int mtk_eint_flip_edge(struct mtk_pinctrl *pctl, int hwirq)
        int start_level, curr_level;
        unsigned int reg_offset;
        const struct mtk_eint_offsets *eint_offsets = &(pctl->devdata->eint_offsets);
-       u32 mask = 1 << (hwirq & 0x1f);
+       u32 mask = BIT(hwirq & 0x1f);
        u32 port = (hwirq >> 5) & eint_offsets->port_mask;
        void __iomem *reg = pctl->eint_reg_base + (port << 2);
        const struct mtk_desc_pin *pin;
@@ -904,8 +991,9 @@ static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
 
 static struct gpio_chip mtk_gpio_chip = {
        .owner                  = THIS_MODULE,
-       .request                = mtk_gpio_request,
-       .free                   = mtk_gpio_free,
+       .request                = gpiochip_generic_request,
+       .free                   = gpiochip_generic_free,
+       .get_direction          = mtk_gpio_get_direction,
        .direction_input        = mtk_gpio_direction_input,
        .direction_output       = mtk_gpio_direction_output,
        .get                    = mtk_gpio_get,
@@ -962,6 +1050,77 @@ static int mtk_eint_set_type(struct irq_data *d,
        return 0;
 }
 
+static int mtk_eint_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+       struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
+       int shift = d->hwirq & 0x1f;
+       int reg = d->hwirq >> 5;
+
+       if (on)
+               pctl->wake_mask[reg] |= BIT(shift);
+       else
+               pctl->wake_mask[reg] &= ~BIT(shift);
+
+       return 0;
+}
+
+static void mtk_eint_chip_write_mask(const struct mtk_eint_offsets *chip,
+               void __iomem *eint_reg_base, u32 *buf)
+{
+       int port;
+       void __iomem *reg;
+
+       for (port = 0; port < chip->ports; port++) {
+               reg = eint_reg_base + (port << 2);
+               writel_relaxed(~buf[port], reg + chip->mask_set);
+               writel_relaxed(buf[port], reg + chip->mask_clr);
+       }
+}
+
+static void mtk_eint_chip_read_mask(const struct mtk_eint_offsets *chip,
+               void __iomem *eint_reg_base, u32 *buf)
+{
+       int port;
+       void __iomem *reg;
+
+       for (port = 0; port < chip->ports; port++) {
+               reg = eint_reg_base + chip->mask + (port << 2);
+               buf[port] = ~readl_relaxed(reg);
+               /* Mask is 0 when irq is enabled, and 1 when disabled. */
+       }
+}
+
+static int mtk_eint_suspend(struct device *device)
+{
+       void __iomem *reg;
+       struct mtk_pinctrl *pctl = dev_get_drvdata(device);
+       const struct mtk_eint_offsets *eint_offsets =
+                       &pctl->devdata->eint_offsets;
+
+       reg = pctl->eint_reg_base;
+       mtk_eint_chip_read_mask(eint_offsets, reg, pctl->cur_mask);
+       mtk_eint_chip_write_mask(eint_offsets, reg, pctl->wake_mask);
+
+       return 0;
+}
+
+static int mtk_eint_resume(struct device *device)
+{
+       struct mtk_pinctrl *pctl = dev_get_drvdata(device);
+       const struct mtk_eint_offsets *eint_offsets =
+                       &pctl->devdata->eint_offsets;
+
+       mtk_eint_chip_write_mask(eint_offsets,
+                       pctl->eint_reg_base, pctl->cur_mask);
+
+       return 0;
+}
+
+const struct dev_pm_ops mtk_eint_pm_ops = {
+       .suspend = mtk_eint_suspend,
+       .resume = mtk_eint_resume,
+};
+
 static void mtk_eint_ack(struct irq_data *d)
 {
        struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
@@ -976,10 +1135,12 @@ static void mtk_eint_ack(struct irq_data *d)
 
 static struct irq_chip mtk_pinctrl_irq_chip = {
        .name = "mt-eint",
+       .irq_disable = mtk_eint_mask,
        .irq_mask = mtk_eint_mask,
        .irq_unmask = mtk_eint_unmask,
        .irq_ack = mtk_eint_ack,
        .irq_set_type = mtk_eint_set_type,
+       .irq_set_wake = mtk_eint_irq_set_wake,
        .irq_request_resources = mtk_pinctrl_irq_request_resources,
        .irq_release_resources = mtk_pinctrl_irq_release_resources,
 };
@@ -1016,10 +1177,10 @@ mtk_eint_debounce_process(struct mtk_pinctrl *pctl, int index)
        }
 }
 
-static void mtk_eint_irq_handler(unsigned irq, struct irq_desc *desc)
+static void mtk_eint_irq_handler(struct irq_desc *desc)
 {
-       struct irq_chip *chip = irq_get_chip(irq);
-       struct mtk_pinctrl *pctl = irq_get_handler_data(irq);
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct mtk_pinctrl *pctl = irq_desc_get_handler_data(desc);
        unsigned int status, eint_num;
        int offset, index, virq;
        const struct mtk_eint_offsets *eint_offsets =
@@ -1102,21 +1263,16 @@ static int mtk_pctrl_build_state(struct platform_device *pdev)
        return 0;
 }
 
-static struct pinctrl_desc mtk_pctrl_desc = {
-       .confops        = &mtk_pconf_ops,
-       .pctlops        = &mtk_pctrl_ops,
-       .pmxops         = &mtk_pmx_ops,
-};
-
 int mtk_pctrl_init(struct platform_device *pdev,
-               const struct mtk_pinctrl_devdata *data)
+               const struct mtk_pinctrl_devdata *data,
+               struct regmap *regmap)
 {
        struct pinctrl_pin_desc *pins;
        struct mtk_pinctrl *pctl;
        struct device_node *np = pdev->dev.of_node, *node;
        struct property *prop;
        struct resource *res;
-       int i, ret, irq;
+       int i, ret, irq, ports_buf;
 
        pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
        if (!pctl)
@@ -1135,6 +1291,11 @@ int mtk_pctrl_init(struct platform_device *pdev,
                pctl->regmap1 = syscon_node_to_regmap(node);
                if (IS_ERR(pctl->regmap1))
                        return PTR_ERR(pctl->regmap1);
+       } else if (regmap) {
+               pctl->regmap1  = regmap;
+       } else {
+               dev_err(&pdev->dev, "Pinctrl node has not register regmap.\n");
+               return -EINVAL;
        }
 
        /* Only 8135 has two base addr, other SoCs have only one. */
@@ -1159,15 +1320,20 @@ int mtk_pctrl_init(struct platform_device *pdev,
 
        for (i = 0; i < pctl->devdata->npins; i++)
                pins[i] = pctl->devdata->pins[i].pin;
-       mtk_pctrl_desc.name = dev_name(&pdev->dev);
-       mtk_pctrl_desc.owner = THIS_MODULE;
-       mtk_pctrl_desc.pins = pins;
-       mtk_pctrl_desc.npins = pctl->devdata->npins;
+
+       pctl->pctl_desc.name = dev_name(&pdev->dev);
+       pctl->pctl_desc.owner = THIS_MODULE;
+       pctl->pctl_desc.pins = pins;
+       pctl->pctl_desc.npins = pctl->devdata->npins;
+       pctl->pctl_desc.confops = &mtk_pconf_ops;
+       pctl->pctl_desc.pctlops = &mtk_pctrl_ops;
+       pctl->pctl_desc.pmxops = &mtk_pmx_ops;
        pctl->dev = &pdev->dev;
-       pctl->pctl_dev = pinctrl_register(&mtk_pctrl_desc, &pdev->dev, pctl);
-       if (!pctl->pctl_dev) {
+
+       pctl->pctl_dev = pinctrl_register(&pctl->pctl_desc, &pdev->dev, pctl);
+       if (IS_ERR(pctl->pctl_dev)) {
                dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
-               return -EINVAL;
+               return PTR_ERR(pctl->pctl_dev);
        }
 
        pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL);
@@ -1176,11 +1342,11 @@ int mtk_pctrl_init(struct platform_device *pdev,
                goto pctrl_error;
        }
 
-       pctl->chip = &mtk_gpio_chip;
+       *pctl->chip = mtk_gpio_chip;
        pctl->chip->ngpio = pctl->devdata->npins;
        pctl->chip->label = dev_name(&pdev->dev);
        pctl->chip->dev = &pdev->dev;
-       pctl->chip->base = 0;
+       pctl->chip->base = -1;
 
        ret = gpiochip_add(pctl->chip);
        if (ret) {
@@ -1196,6 +1362,9 @@ int mtk_pctrl_init(struct platform_device *pdev,
                goto chip_error;
        }
 
+       if (!of_property_read_bool(np, "interrupt-controller"))
+               return 0;
+
        /* Get EINT register base from dts. */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
@@ -1210,6 +1379,21 @@ int mtk_pctrl_init(struct platform_device *pdev,
                goto chip_error;
        }
 
+       ports_buf = pctl->devdata->eint_offsets.ports;
+       pctl->wake_mask = devm_kcalloc(&pdev->dev, ports_buf,
+                                       sizeof(*pctl->wake_mask), GFP_KERNEL);
+       if (!pctl->wake_mask) {
+               ret = -ENOMEM;
+               goto chip_error;
+       }
+
+       pctl->cur_mask = devm_kcalloc(&pdev->dev, ports_buf,
+                                       sizeof(*pctl->cur_mask), GFP_KERNEL);
+       if (!pctl->cur_mask) {
+               ret = -ENOMEM;
+               goto chip_error;
+       }
+
        pctl->eint_dual_edges = devm_kcalloc(&pdev->dev, pctl->devdata->ap_num,
                                             sizeof(int), GFP_KERNEL);
        if (!pctl->eint_dual_edges) {
@@ -1239,12 +1423,9 @@ int mtk_pctrl_init(struct platform_device *pdev,
                irq_set_chip_and_handler(virq, &mtk_pinctrl_irq_chip,
                        handle_level_irq);
                irq_set_chip_data(virq, pctl);
-               set_irq_flags(virq, IRQF_VALID);
-       };
+       }
 
-       irq_set_chained_handler(irq, mtk_eint_irq_handler);
-       irq_set_handler_data(irq, pctl);
-       set_irq_flags(irq, IRQF_VALID);
+       irq_set_chained_handler_and_data(irq, mtk_eint_irq_handler, pctl);
        return 0;
 
 chip_error: