X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=kernel%2Fdrivers%2Fpinctrl%2Fmediatek%2Fpinctrl-mtk-common.c;h=181b35879ebd7d3f755d942cba18a1def04eb751;hb=52f993b8e89487ec9ee15a7fb4979e0f09a45b27;hp=474812e2b0cb97c806402fda486ab2e883398c06;hpb=9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00;p=kvmfornfv.git diff --git a/kernel/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/kernel/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index 474812e2b..181b35879 100644 --- a/kernel/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/kernel/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #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; @@ -852,7 +939,8 @@ static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset, struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev); int eint_num, virq, eint_offset; unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask, dbnc; - static const unsigned int dbnc_arr[] = {0 , 1, 16, 32, 64, 128, 256}; + static const unsigned int debounce_time[] = {500, 1000, 16000, 32000, 64000, + 128000, 256000}; const struct mtk_desc_pin *pin; struct irq_data *d; @@ -870,9 +958,9 @@ static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset, if (!mtk_eint_can_en_debounce(pctl, eint_num)) return -ENOSYS; - dbnc = ARRAY_SIZE(dbnc_arr); - for (i = 0; i < ARRAY_SIZE(dbnc_arr); i++) { - if (debounce <= dbnc_arr[i]) { + dbnc = ARRAY_SIZE(debounce_time); + for (i = 0; i < ARRAY_SIZE(debounce_time); i++) { + if (debounce <= debounce_time[i]) { dbnc = i; break; } @@ -904,8 +992,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 +1051,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 +1136,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 +1178,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 = @@ -1029,9 +1191,10 @@ static void mtk_eint_irq_handler(unsigned irq, struct irq_desc *desc) const struct mtk_desc_pin *pin; chained_irq_enter(chip, desc); - for (eint_num = 0; eint_num < pctl->devdata->ap_num; eint_num += 32) { + for (eint_num = 0; + eint_num < pctl->devdata->ap_num; + eint_num += 32, reg += 4) { status = readl(reg); - reg += 4; while (status) { offset = __ffs(status); index = eint_num + offset; @@ -1102,21 +1265,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 +1293,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 +1322,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 +1344,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 +1364,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 +1381,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 +1425,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: