--- zzzz-none-000/linux-4.4.271/drivers/pinctrl/qcom/pinctrl-msm.c 2021-06-03 06:22:09.000000000 +0000 +++ dakota-7530ac-750/linux-4.4.271/drivers/pinctrl/qcom/pinctrl-msm.c 2023-01-11 09:25:42.000000000 +0000 @@ -1,4 +1,5 @@ /* + * Copyright (c) 2013, Sony Mobile Communications AB. * Copyright (c) 2013, The Linux Foundation. All rights reserved. * @@ -29,7 +30,8 @@ #include #include #include - +#include +#include #include "../core.h" #include "../pinconf.h" #include "pinctrl-msm.h" @@ -52,6 +54,8 @@ * detection. * @soc; Reference to soc_data of platform specific data. * @regs: Base address for the TLMM register map. + * @emulated_od: State of emulated open drain + * @is_output: set if pin is configured as output */ struct msm_pinctrl { struct device *dev; @@ -64,6 +68,8 @@ DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO); DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO); + DECLARE_BITMAP(emulated_od_bmp, MAX_NR_GPIO); + DECLARE_BITMAP(is_output, MAX_NR_GPIO); const struct msm_pinctrl_soc_data *soc; void __iomem *regs; @@ -190,14 +196,29 @@ *mask = 3; break; case PIN_CONFIG_DRIVE_STRENGTH: + case PIN_CONFIG_DRIVE_CAP: + case PIN_CONFIG_DRIVE_TYPE: *bit = g->drv_bit; *mask = 7; break; case PIN_CONFIG_OUTPUT: case PIN_CONFIG_INPUT_ENABLE: + case PIN_CONFIG_DRIVE_EMU_OPEN_DRAIN: *bit = g->oe_bit; *mask = 1; break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + *bit = g->od_bit; + *mask = 1; + break; + case PIN_CONFIG_VM: + *bit = g->vm_bit; + *mask = 1; + break; + case PIN_CONFIG_PULL_RES: + *bit = g->pull_res; + *mask = 3; + break; default: return -ENOTSUPP; } @@ -205,11 +226,6 @@ return 0; } -#define MSM_NO_PULL 0 -#define MSM_PULL_DOWN 1 -#define MSM_KEEPER 2 -#define MSM_PULL_UP 3 - static unsigned msm_regval_to_drive(u32 val) { return (val + 1) * 2; @@ -240,20 +256,23 @@ /* Convert register value to pinconf value */ switch (param) { case PIN_CONFIG_BIAS_DISABLE: - arg = arg == MSM_NO_PULL; + arg = arg == pctrl->soc->gpio_pull->no_pull; break; case PIN_CONFIG_BIAS_PULL_DOWN: - arg = arg == MSM_PULL_DOWN; + arg = arg == pctrl->soc->gpio_pull->pull_down; break; case PIN_CONFIG_BIAS_BUS_HOLD: - arg = arg == MSM_KEEPER; + arg = arg == pctrl->soc->gpio_pull->keeper; break; case PIN_CONFIG_BIAS_PULL_UP: - arg = arg == MSM_PULL_UP; + arg = arg == pctrl->soc->gpio_pull->pull_up; break; case PIN_CONFIG_DRIVE_STRENGTH: arg = msm_regval_to_drive(arg); break; + case PIN_CONFIG_DRIVE_TYPE: + case PIN_CONFIG_DRIVE_CAP: + break; case PIN_CONFIG_OUTPUT: /* Pin is not output */ if (!arg) @@ -268,6 +287,23 @@ return -EINVAL; arg = 1; break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + case PIN_CONFIG_VM: + arg = arg == 1; + break; + case PIN_CONFIG_DRIVE_EMU_OPEN_DRAIN: + arg = test_bit(group, pctrl->emulated_od_bmp); + break; + case PIN_CONFIG_PULL_RES: + if (arg == RES_10_KOHM) + arg = 10; + else if (arg == RES_1_5_KOHM) + arg = 1.5; + else if (arg == RES_35_KOHM) + arg = 35; + else + arg = 20; + break; default: return -ENOTSUPP; } @@ -277,6 +313,53 @@ return 0; } +static int msm_config_emulated_od_set_mode(struct msm_pinctrl *pctrl, + unsigned int group, + unsigned int param) +{ + const struct msm_pingroup *g = &pctrl->soc->groups[group]; + unsigned long flags; + int rv = 0; + u32 ctlreg, ioreg; + const u32 out_bit = BIT(g->out_bit); + const u32 oe_bit = BIT(g->oe_bit); + + /* Update emulated_od state and oe according to param and current + * hardware output state. + */ + if (param == PIN_CONFIG_DRIVE_EMU_OPEN_DRAIN) { + rv = 1; + if (!test_and_set_bit(group, pctrl->emulated_od_bmp)) + return rv; + } else if (!test_and_clear_bit(group, pctrl->emulated_od_bmp)) { + return rv; + } + + if (!test_bit(group, pctrl->is_output)) + return rv; + + if (test_bit(group, pctrl->emulated_od_bmp)) { + /* Switch on */ + spin_lock_irqsave(&pctrl->lock, flags); + ioreg = readl(pctrl->regs + g->io_reg); + if (ioreg & out_bit) { + ctlreg = readl(pctrl->regs + g->ctl_reg); + ctlreg &= ~oe_bit; + writel(ctlreg, pctrl->regs + g->ctl_reg); + } + spin_unlock_irqrestore(&pctrl->lock, flags); + } else { + /* switch off */ + spin_lock_irqsave(&pctrl->lock, flags); + ctlreg = readl(pctrl->regs + g->ctl_reg); + ctlreg |= oe_bit; + writel(ctlreg, pctrl->regs + g->ctl_reg); + spin_unlock_irqrestore(&pctrl->lock, flags); + } + + return rv; +} + static int msm_config_group_set(struct pinctrl_dev *pctldev, unsigned group, unsigned long *configs, @@ -306,16 +389,16 @@ /* Convert pinconf values to register values */ switch (param) { case PIN_CONFIG_BIAS_DISABLE: - arg = MSM_NO_PULL; + arg = pctrl->soc->gpio_pull->no_pull; break; case PIN_CONFIG_BIAS_PULL_DOWN: - arg = MSM_PULL_DOWN; + arg = pctrl->soc->gpio_pull->pull_down; break; case PIN_CONFIG_BIAS_BUS_HOLD: - arg = MSM_KEEPER; + arg = pctrl->soc->gpio_pull->keeper; break; case PIN_CONFIG_BIAS_PULL_UP: - arg = MSM_PULL_UP; + arg = pctrl->soc->gpio_pull->pull_up; break; case PIN_CONFIG_DRIVE_STRENGTH: /* Check for invalid values */ @@ -324,6 +407,12 @@ else arg = (arg / 2) - 1; break; + case PIN_CONFIG_DRIVE_TYPE: + case PIN_CONFIG_DRIVE_CAP: + case PIN_CONFIG_PULL_RES: + case PIN_CONFIG_VM: + case PIN_CONFIG_DRIVE_EMU_OPEN_DRAIN: + break; case PIN_CONFIG_OUTPUT: /* set output value */ spin_lock_irqsave(&pctrl->lock, flags); @@ -336,11 +425,16 @@ spin_unlock_irqrestore(&pctrl->lock, flags); /* enable output */ + set_bit(group, pctrl->is_output); arg = 1; break; case PIN_CONFIG_INPUT_ENABLE: /* disable output */ arg = 0; + clear_bit(group, pctrl->is_output); + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + arg = 1; break; default: dev_err(pctrl->dev, "Unsupported config parameter: %x\n", @@ -354,6 +448,9 @@ return -EINVAL; } + if (msm_config_emulated_od_set_mode(pctrl, group, param)) + continue; + spin_lock_irqsave(&pctrl->lock, flags); val = readl(pctrl->regs + g->ctl_reg); val &= ~(mask << bit); @@ -378,6 +475,25 @@ .owner = THIS_MODULE, }; +static int msm_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ + const struct msm_pingroup *g; + struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); + u32 val; + + g = &pctrl->soc->groups[offset]; + + /* This is to avoid confusion with pin direction on emulated open + * drain. + */ + if (test_bit(offset, pctrl->emulated_od_bmp)) + return test_bit(offset, pctrl->is_output) ? + GPIOF_DIR_OUT : GPIOF_DIR_IN; + + val = readl(pctrl->regs + g->ctl_reg); + return val & BIT(g->oe_bit) ? GPIOF_DIR_OUT : GPIOF_DIR_IN; +} + static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { const struct msm_pingroup *g; @@ -395,31 +511,41 @@ spin_unlock_irqrestore(&pctrl->lock, flags); + clear_bit(offset, pctrl->is_output); + return 0; } static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) { - const struct msm_pingroup *g; struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); + const struct msm_pingroup *g = &pctrl->soc->groups[offset]; unsigned long flags; - u32 val; + u32 ctlreg, ioreg; + const u32 out_bit = BIT(g->out_bit); + const u32 oe_bit = BIT(g->oe_bit); - g = &pctrl->soc->groups[offset]; + set_bit(offset, pctrl->is_output); + /* Update oe output according to emulated_od state and value. */ spin_lock_irqsave(&pctrl->lock, flags); - - val = readl(pctrl->regs + g->io_reg); - if (value) - val |= BIT(g->out_bit); - else - val &= ~BIT(g->out_bit); - writel(val, pctrl->regs + g->io_reg); - - val = readl(pctrl->regs + g->ctl_reg); - val |= BIT(g->oe_bit); - writel(val, pctrl->regs + g->ctl_reg); - + ctlreg = readl(pctrl->regs + g->ctl_reg); + ioreg = readl(pctrl->regs + g->io_reg); + if (test_bit(offset, pctrl->emulated_od_bmp)) { + ioreg &= ~out_bit; + if (value) + ctlreg &= ~oe_bit; + else + ctlreg |= oe_bit; + } else { + ctlreg |= oe_bit; + if (value) + ioreg |= out_bit; + else + ioreg &= ~out_bit; + } + writel(ioreg, pctrl->regs + g->io_reg); + writel(ctlreg, pctrl->regs + g->ctl_reg); spin_unlock_irqrestore(&pctrl->lock, flags); return 0; @@ -439,23 +565,32 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - const struct msm_pingroup *g; struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); + const struct msm_pingroup *g = &pctrl->soc->groups[offset]; unsigned long flags; - u32 val; - - g = &pctrl->soc->groups[offset]; + u32 ctl_reg, io_reg; + const u32 out_bit = BIT(g->out_bit); + const u32 oe_bit = BIT(g->oe_bit); spin_lock_irqsave(&pctrl->lock, flags); - - val = readl(pctrl->regs + g->io_reg); - if (value) - val |= BIT(g->out_bit); - else - val &= ~BIT(g->out_bit); - writel(val, pctrl->regs + g->io_reg); - + io_reg = readl(pctrl->regs + g->io_reg); + if (test_bit(offset, pctrl->emulated_od_bmp)) { + io_reg &= ~out_bit; + ctl_reg = readl(pctrl->regs + g->ctl_reg); + if (value) + ctl_reg &= ~oe_bit; + else + ctl_reg |= oe_bit; + writel(ctl_reg, pctrl->regs + g->ctl_reg); + } else { + if (value) + io_reg |= out_bit; + else + io_reg &= ~out_bit; + } + writel(io_reg, pctrl->regs + g->io_reg); spin_unlock_irqrestore(&pctrl->lock, flags); + } #ifdef CONFIG_DEBUG_FS @@ -493,6 +628,8 @@ seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func); seq_printf(s, " %dmA", msm_regval_to_drive(drive)); seq_printf(s, " %s", pulls[pull]); + if (test_bit(offset, pctrl->emulated_od_bmp)) + seq_puts(s, " emulated_od"); } static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) @@ -511,6 +648,7 @@ #endif static struct gpio_chip msm_gpio_template = { + .get_direction = msm_gpio_get_direction, .direction_input = msm_gpio_direction_input, .direction_output = msm_gpio_direction_output, .get = msm_gpio_get, @@ -638,6 +776,9 @@ const struct msm_pingroup *g; unsigned long flags; u32 val; + u32 addr; + int ret; + const __be32 *reg; g = &pctrl->soc->groups[d->hwirq]; @@ -651,11 +792,30 @@ else clear_bit(d->hwirq, pctrl->dual_edge_irqs); + ret = of_device_is_compatible(pctrl->dev->of_node, + "qcom,ipq8064-pinctrl"); /* Route interrupts to application cpu */ - val = readl(pctrl->regs + g->intr_target_reg); - val &= ~(7 << g->intr_target_bit); - val |= g->intr_target_kpss_val << g->intr_target_bit; - writel(val, pctrl->regs + g->intr_target_reg); + if (!ret) { + val = readl(pctrl->regs + g->intr_target_reg); + val &= ~(7 << g->intr_target_bit); + val |= g->intr_target_kpss_val << g->intr_target_bit; + writel(val, pctrl->regs + g->intr_target_reg); + } else { + reg = of_get_property(pctrl->dev->of_node, "reg", NULL); + if (reg) { + addr = be32_to_cpup(reg) + g->intr_target_reg; + val = qcom_scm_pinmux_read(addr); + __iormb(); + + val &= ~(7 << g->intr_target_bit); + val |= g->intr_target_kpss_val << g->intr_target_bit; + + __iowmb(); + ret = qcom_scm_pinmux_write(addr, val); + if (ret) + pr_err("\n Routing interrupts to Apps proc failed"); + } + } /* Update configuration for gpio. * RAW_STATUS_EN is left on for all gpio irqs. Due to the @@ -796,7 +956,7 @@ chip->base = 0; chip->ngpio = ngpio; chip->label = dev_name(pctrl->dev); - chip->dev = pctrl->dev; + chip->parent = pctrl->dev; chip->owner = THIS_MODULE; chip->of_node = pctrl->dev->of_node; @@ -884,6 +1044,7 @@ struct msm_pinctrl *pctrl; struct resource *res; int ret; + void avmgpio_register_msm_pinctrl(struct msm_pinctrl *pctrl); pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); if (!pctrl) { @@ -928,6 +1089,7 @@ dev_dbg(&pdev->dev, "Probed Qualcomm pinctrl driver\n"); + avmgpio_register_msm_pinctrl(pctrl->regs); return 0; } EXPORT_SYMBOL(msm_pinctrl_probe); @@ -944,4 +1106,3 @@ return 0; } EXPORT_SYMBOL(msm_pinctrl_remove); -