From 8e54033b4250cecadd653817e7d3497e98af9a09 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 29 Jan 2025 16:49:39 +0200 Subject: pinctrl: baytrail: Use dedicated helpers for chained IRQ handlers Instead of relying on the fact that the parent IRQ chip supports fasteoi mode and calling the respective callback at the end of the interrupt handler, surround it with enter and exit helpers for chained IRQ handlers which will consider all possible cases. This in particular unifies how GPIO drivers handle IRQ. Reviewed-by: Hans de Goede Acked-by: Mika Westerberg Signed-off-by: Andy Shevchenko --- drivers/pinctrl/intel/pinctrl-baytrail.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 7340dc20349c..c4458ac539ff 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -1355,6 +1355,8 @@ static void byt_gpio_irq_handler(struct irq_desc *desc) void __iomem *reg; unsigned long pending; + chained_irq_enter(chip, desc); + /* check from GPIO controller which pin triggered the interrupt */ for (base = 0; base < vg->chip.ngpio; base += 32) { reg = byt_gpio_reg(vg, base, BYT_INT_STAT_REG); @@ -1369,7 +1371,8 @@ static void byt_gpio_irq_handler(struct irq_desc *desc) for_each_set_bit(pin, &pending, 32) generic_handle_domain_irq(vg->chip.irq.domain, base + pin); } - chip->irq_eoi(data); + + chained_irq_exit(chip, desc); } static bool byt_direct_irq_sanity_check(struct intel_pinctrl *vg, int pin, u32 conf0) -- cgit v1.2.3-59-g8ed1b From 5feac4d72d9f0aa80ff76690d56522e6106b3c7b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 29 Jan 2025 16:49:40 +0200 Subject: pinctrl: lynxpoint: Use dedicated helpers for chained IRQ handlers Instead of relying on the fact that the parent IRQ chip supports fasteoi mode and calling the respective callback at the end of the interrupt handler, surround it with enter and exit helpers for chained IRQ handlers which will consider all possible cases. This in particular unifies how GPIO drivers handle IRQ. Reviewed-by: Hans de Goede Acked-by: Mika Westerberg Signed-off-by: Andy Shevchenko --- drivers/pinctrl/intel/pinctrl-lynxpoint.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-lynxpoint.c b/drivers/pinctrl/intel/pinctrl-lynxpoint.c index cc5ede17c383..ac5459a4c63e 100644 --- a/drivers/pinctrl/intel/pinctrl-lynxpoint.c +++ b/drivers/pinctrl/intel/pinctrl-lynxpoint.c @@ -549,6 +549,8 @@ static void lp_gpio_irq_handler(struct irq_desc *desc) unsigned long pending; u32 base, pin; + chained_irq_enter(chip, desc); + /* check from GPIO controller which pin triggered the interrupt */ for (base = 0; base < lg->chip.ngpio; base += 32) { reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); @@ -560,7 +562,8 @@ static void lp_gpio_irq_handler(struct irq_desc *desc) for_each_set_bit(pin, &pending, 32) generic_handle_domain_irq(lg->chip.irq.domain, base + pin); } - chip->irq_eoi(data); + + chained_irq_exit(chip, desc); } static void lp_irq_ack(struct irq_data *d) -- cgit v1.2.3-59-g8ed1b From c42a407beeb91dd5e8cf1d537a7291a5d6415192 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 23 Jan 2025 11:11:10 +0100 Subject: pinctrl: intel: Import PWM_LPSS namespace for devm_pwm_lpss_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Intel pinctrl driver can provide a PWM device and for that needs to call the function devm_pwm_lpss_probe(). That function is provided by the pwm-lpss driver which intends to export it in the "PWM_LPSS" namespace. To prepare fixing the pwm-lpss driver to indeed use the "PWM_LPSS" namespace, import that namespace when used. Signed-off-by: Uwe Kleine-König Signed-off-by: Andy Shevchenko --- drivers/pinctrl/intel/pinctrl-intel.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 527e4b87ae52..d593ad03f949 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -1941,3 +1941,4 @@ MODULE_AUTHOR("Mathias Nyman "); MODULE_AUTHOR("Mika Westerberg "); MODULE_DESCRIPTION("Intel pinctrl/GPIO core driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("PWM_LPSS"); -- cgit v1.2.3-59-g8ed1b From 112f5e0917cff2af35ada29e7db0b4d05bca7941 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 23 Jan 2025 11:11:11 +0100 Subject: pwm: lpss: Actually use a module namespace by defining the namespace earlier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DEFAULT_SYMBOL_NAMESPACE must be already defined when is included. So move the define above the include block. With the DEFAULT_SYMBOL_NAMESPACE being defined too late, the exported symbols end up in the default namespace. So the respective modules can use the symbols defined in pwm-lpss.c just fine and up to now just imported the PWM_LPSS namespace without any gain. Signed-off-by: Uwe Kleine-König Signed-off-by: Andy Shevchenko --- drivers/pwm/pwm-lpss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 3b99feb3bb49..e3c72ed7fff1 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -10,6 +10,8 @@ * Author: Alan Cox */ +#define DEFAULT_SYMBOL_NAMESPACE "PWM_LPSS" + #include #include #include @@ -19,8 +21,6 @@ #include #include -#define DEFAULT_SYMBOL_NAMESPACE "PWM_LPSS" - #include "pwm-lpss.h" #define PWM 0x00000000 -- cgit v1.2.3-59-g8ed1b From 0eee258cdf172763502f142d85e967f27a573be0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 Feb 2025 21:44:51 +0200 Subject: pinctrl: intel: Fix wrong bypass assignment in intel_pinctrl_probe_pwm() When instantiating PWM, the bypass should be set to false. The field is used for the selected Intel SoCs that do not have PWM feature enabled in their pin control IPs. Fixes: eb78d3604d6b ("pinctrl: intel: Enumerate PWM device when community has a capability") Reported-by: Alexis GUILLEMET Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Tested-by: Alexis GUILLEMET --- drivers/pinctrl/intel/pinctrl-intel.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index d593ad03f949..e4de88e10d68 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -1543,7 +1543,6 @@ static int intel_pinctrl_probe_pwm(struct intel_pinctrl *pctrl, .clk_rate = 19200000, .npwm = 1, .base_unit_bits = 22, - .bypass = true, }; struct pwm_chip *chip; -- cgit v1.2.3-59-g8ed1b From b2bd65fbb617353e3c46ba5206b3b030fa0f260c Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 5 Feb 2025 12:01:16 +0200 Subject: pinctrl: renesas: rzg2l: Add suspend/resume support for pull up/down The Renesas RZ/G3S supports a power-saving mode where power to most of the SoC components is lost, including the PIN controller. Save and restore the pull-up/pull-down register contents to ensure the functionality is preserved after a suspend/resume cycle. Signed-off-by: Claudiu Beznea Reviewed-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250205100116.2032765-1-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/renesas/pinctrl-rzg2l.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index ce4a07a3df49..298e1aa89c8f 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -318,6 +318,7 @@ struct rzg2l_pinctrl_pin_settings { * @pmc: PMC registers cache * @pfc: PFC registers cache * @iolh: IOLH registers cache + * @pupd: PUPD registers cache * @ien: IEN registers cache * @sd_ch: SD_CH registers cache * @eth_poc: ET_POC registers cache @@ -331,6 +332,7 @@ struct rzg2l_pinctrl_reg_cache { u32 *pfc; u32 *iolh[2]; u32 *ien[2]; + u32 *pupd[2]; u8 sd_ch[2]; u8 eth_poc[2]; u8 eth_mode; @@ -2712,6 +2714,11 @@ static int rzg2l_pinctrl_reg_cache_alloc(struct rzg2l_pinctrl *pctrl) if (!cache->ien[i]) return -ENOMEM; + cache->pupd[i] = devm_kcalloc(pctrl->dev, nports, sizeof(*cache->pupd[i]), + GFP_KERNEL); + if (!cache->pupd[i]) + return -ENOMEM; + /* Allocate dedicated cache. */ dedicated_cache->iolh[i] = devm_kcalloc(pctrl->dev, n_dedicated_pins, sizeof(*dedicated_cache->iolh[i]), @@ -2953,7 +2960,7 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen struct rzg2l_pinctrl_reg_cache *cache = pctrl->cache; for (u32 port = 0; port < nports; port++) { - bool has_iolh, has_ien; + bool has_iolh, has_ien, has_pupd; u32 off, caps; u8 pincnt; u64 cfg; @@ -2965,6 +2972,7 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen caps = FIELD_GET(PIN_CFG_MASK, cfg); has_iolh = !!(caps & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B | PIN_CFG_IOLH_C)); has_ien = !!(caps & PIN_CFG_IEN); + has_pupd = !!(caps & PIN_CFG_PUPD); if (suspend) RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + PFC(off), cache->pfc[port]); @@ -2983,6 +2991,15 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen } } + if (has_pupd) { + RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + PUPD(off), + cache->pupd[0][port]); + if (pincnt >= 4) { + RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + PUPD(off), + cache->pupd[1][port]); + } + } + RZG2L_PCTRL_REG_ACCESS16(suspend, pctrl->base + PM(off), cache->pm[port]); RZG2L_PCTRL_REG_ACCESS8(suspend, pctrl->base + P(off), cache->p[port]); -- cgit v1.2.3-59-g8ed1b From f752ee5b5b86b5f88a5687c9eb0ef9b39859b908 Mon Sep 17 00:00:00 2001 From: Chenyuan Yang Date: Mon, 10 Feb 2025 17:25:52 -0600 Subject: pinctrl: renesas: rza2: Fix potential NULL pointer dereference `chip.label` in rza2_gpio_register() could be NULL. Add the missing check. Signed-off-by: Chenyuan Yang Reviewed-by: Geert Uytterhoeven Reviewed-by: Matthias Brugger Link: https://lore.kernel.org/20250210232552.1545887-1-chenyuan0y@gmail.com Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/renesas/pinctrl-rza2.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/renesas/pinctrl-rza2.c b/drivers/pinctrl/renesas/pinctrl-rza2.c index dd1f8c29d3e7..a654ede01f70 100644 --- a/drivers/pinctrl/renesas/pinctrl-rza2.c +++ b/drivers/pinctrl/renesas/pinctrl-rza2.c @@ -246,6 +246,9 @@ static int rza2_gpio_register(struct rza2_pinctrl_priv *priv) int ret; chip.label = devm_kasprintf(priv->dev, GFP_KERNEL, "%pOFn", np); + if (!chip.label) + return -ENOMEM; + chip.parent = priv->dev; chip.ngpio = priv->npins; -- cgit v1.2.3-59-g8ed1b From c98868e816209e568c9d72023ba0bc1e4d96e611 Mon Sep 17 00:00:00 2001 From: Valentin Caron Date: Thu, 16 Jan 2025 18:00:09 +0100 Subject: pinctrl: devicetree: do not goto err when probing hogs in pinctrl_dt_to_map Cross case in pinctrl framework make impossible to an hogged pin and another, not hogged, used within the same device-tree node. For example with this simplified device-tree : &pinctrl { pinctrl_pin_1: pinctrl-pin-1 { pins = "dummy-pinctrl-pin"; }; }; &rtc { pinctrl-names = "default" pinctrl-0 = <&pinctrl_pin_1 &rtc_pin_1> rtc_pin_1: rtc-pin-1 { pins = "dummy-rtc-pin"; }; }; "pinctrl_pin_1" configuration is never set. This produces this path in the code: really_probe() pinctrl_bind_pins() | devm_pinctrl_get() | pinctrl_get() | create_pinctrl() | pinctrl_dt_to_map() | // Hog pin create an abort for all pins of the node | ret = dt_to_map_one_config() | | /* Do not defer probing of hogs (circular loop) */ | | if (np_pctldev == p->dev->of_node) | | return -ENODEV; | if (ret) | goto err | call_driver_probe() stm32_rtc_probe() pinctrl_enable() pinctrl_claim_hogs() create_pinctrl() for_each_maps(maps_node, i, map) // Not hog pin is skipped if (pctldev && strcmp(dev_name(pctldev->dev), map->ctrl_dev_name)) continue; At the first call of create_pinctrl() the hogged pin produces an abort to avoid a defer of hogged pins. All other pin configurations are trashed. At the second call, create_pinctrl is now called with pctldev parameter to get hogs, but in this context only hogs are set. And other pins are skipped. To handle this, do not produce an abort in the first call of create_pinctrl(). Classic pin configuration will be set in pinctrl_bind_pins() context. And the hogged pin configuration will be set in pinctrl_claim_hogs() context. Signed-off-by: Valentin Caron Link: https://lore.kernel.org/20250116170009.2075544-1-valentin.caron@foss.st.com Signed-off-by: Linus Walleij --- drivers/pinctrl/devicetree.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index 6a94ecd6a8de..0b7f74beb6a6 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -143,10 +143,14 @@ static int dt_to_map_one_config(struct pinctrl *p, pctldev = get_pinctrl_dev_from_of_node(np_pctldev); if (pctldev) break; - /* Do not defer probing of hogs (circular loop) */ + /* + * Do not defer probing of hogs (circular loop) + * + * Return 1 to let the caller catch the case. + */ if (np_pctldev == p->dev->of_node) { of_node_put(np_pctldev); - return -ENODEV; + return 1; } } of_node_put(np_pctldev); @@ -265,6 +269,8 @@ int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev) ret = dt_to_map_one_config(p, pctldev, statename, np_config); of_node_put(np_config); + if (ret == 1) + continue; if (ret < 0) goto err; } -- cgit v1.2.3-59-g8ed1b From 75b456278ee3fa6af6cc165ce46a601a5ee34026 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Sat, 18 Jan 2025 11:11:45 +0800 Subject: pinctrl: pistachio: Remove dead code in pistachio_gpio_register() fwnode_irq_get() was changed to not return 0, so this check is dead code now. Signed-off-by: Yue Haibing Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/20250118031145.243104-1-yuehaibing@huawei.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-pistachio.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-pistachio.c b/drivers/pinctrl/pinctrl-pistachio.c index 53408344927a..8c50e0091b32 100644 --- a/drivers/pinctrl/pinctrl-pistachio.c +++ b/drivers/pinctrl/pinctrl-pistachio.c @@ -1393,12 +1393,6 @@ static int pistachio_gpio_register(struct pistachio_pinctrl *pctl) dev_err(pctl->dev, "Failed to retrieve IRQ for bank %u\n", i); goto err; } - if (!ret) { - fwnode_handle_put(child); - dev_err(pctl->dev, "No IRQ for bank %u\n", i); - ret = -EINVAL; - goto err; - } irq = ret; bank = &pctl->gpio_banks[i]; -- cgit v1.2.3-59-g8ed1b From d6c6fd77e5816e3f6689a2767cdd777797506f24 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Sat, 18 Jan 2025 11:13:34 +0800 Subject: pinctrl: nuvoton: npcm8xx: Fix error handling in npcm8xx_gpio_fw() fwnode_irq_get() was changed to not return 0, fix this by checking for negative error, also update the error log. Fixes: acf4884a5717 ("pinctrl: nuvoton: add NPCM8XX pinctrl and GPIO driver") Signed-off-by: Yue Haibing Link: https://lore.kernel.org/20250118031334.243324-1-yuehaibing@huawei.com Signed-off-by: Linus Walleij --- drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c index 471f644c5eef..70e6966049e4 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c @@ -2361,8 +2361,8 @@ static int npcm8xx_gpio_fw(struct npcm8xx_pinctrl *pctrl) return dev_err_probe(dev, ret, "gpio-ranges fail for GPIO bank %u\n", id); ret = fwnode_irq_get(child, 0); - if (!ret) - return dev_err_probe(dev, ret, "No IRQ for GPIO bank %u\n", id); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to retrieve IRQ for bank %u\n", id); pctrl->gpio_bank[id].irq = ret; pctrl->gpio_bank[id].irq_chip = npcmgpio_irqchip; -- cgit v1.2.3-59-g8ed1b From 7b0671b97f0872d6950ccc925e210cb3f67721bf Mon Sep 17 00:00:00 2001 From: Dmitry Mastykin Date: Wed, 22 Jan 2025 15:05:04 +0300 Subject: pinctrl: mcp23s08: Get rid of spurious level interrupts irq_mask()/irq_unmask() are not called for nested interrupts. So level interrupts are never masked, chip's interrupt output is not cleared on INTCAP or GPIO read, the irq handler is uselessly called again. Nested irq handler is not called again, because interrupt reason is cleared by its first call. /proc/interrupts shows that number of chip's irqs is greater than number of nested irqs. This patch adds masking and unmasking level interrupts inside irq handler. Signed-off-by: Dmitry Mastykin Link: https://lore.kernel.org/20250122120504.1279790-1-mastichi@gmail.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-mcp23s08.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c index b96e6368a956..4d1f41488017 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08.c +++ b/drivers/pinctrl/pinctrl-mcp23s08.c @@ -382,6 +382,7 @@ static irqreturn_t mcp23s08_irq(int irq, void *data) { struct mcp23s08 *mcp = data; int intcap, intcon, intf, i, gpio, gpio_orig, intcap_mask, defval, gpinten; + bool need_unmask = false; unsigned long int enabled_interrupts; unsigned int child_irq; bool intf_set, intcap_changed, gpio_bit_changed, @@ -396,9 +397,6 @@ static irqreturn_t mcp23s08_irq(int irq, void *data) goto unlock; } - if (mcp_read(mcp, MCP_INTCAP, &intcap)) - goto unlock; - if (mcp_read(mcp, MCP_INTCON, &intcon)) goto unlock; @@ -408,6 +406,16 @@ static irqreturn_t mcp23s08_irq(int irq, void *data) if (mcp_read(mcp, MCP_DEFVAL, &defval)) goto unlock; + /* Mask level interrupts to avoid their immediate reactivation after clearing */ + if (intcon) { + need_unmask = true; + if (mcp_write(mcp, MCP_GPINTEN, gpinten & ~intcon)) + goto unlock; + } + + if (mcp_read(mcp, MCP_INTCAP, &intcap)) + goto unlock; + /* This clears the interrupt(configurable on S18) */ if (mcp_read(mcp, MCP_GPIO, &gpio)) goto unlock; @@ -470,9 +478,18 @@ static irqreturn_t mcp23s08_irq(int irq, void *data) } } + if (need_unmask) { + mutex_lock(&mcp->lock); + goto unlock; + } + return IRQ_HANDLED; unlock: + if (need_unmask) + if (mcp_write(mcp, MCP_GPINTEN, gpinten)) + dev_err(mcp->chip.parent, "can't unmask GPINTEN\n"); + mutex_unlock(&mcp->lock); return IRQ_HANDLED; } -- cgit v1.2.3-59-g8ed1b From e9330dc9b3aa4b1405dc806397662f428fd07ba0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Feb 2025 11:51:11 +0200 Subject: pinctrl: cy8c95x0: Use better bitmap APIs where appropriate There are bitmap_gather() and bitmap_scatter() that are factually reimplemented in the driver. Use better bitmap APIs where appropriate. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/20250205095243.512292-2-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-cy8c95x0.c | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c index d73004b4a45e..f53dbcaf9a32 100644 --- a/drivers/pinctrl/pinctrl-cy8c95x0.c +++ b/drivers/pinctrl/pinctrl-cy8c95x0.c @@ -137,7 +137,7 @@ static const struct dmi_system_id cy8c95x0_dmi_acpi_irq_info[] = { * @irq_trig_low: I/O bits affected by a low voltage level * @irq_trig_high: I/O bits affected by a high voltage level * @push_pull: I/O bits configured as push pull driver - * @shiftmask: Mask used to compensate for Gport2 width + * @map: Mask used to compensate for Gport2 width * @nport: Number of Gports in this chip * @gpio_chip: gpiolib chip * @driver_data: private driver data @@ -158,7 +158,7 @@ struct cy8c95x0_pinctrl { DECLARE_BITMAP(irq_trig_low, MAX_LINE); DECLARE_BITMAP(irq_trig_high, MAX_LINE); DECLARE_BITMAP(push_pull, MAX_LINE); - DECLARE_BITMAP(shiftmask, MAX_LINE); + DECLARE_BITMAP(map, MAX_LINE); unsigned int nport; struct gpio_chip gpio_chip; unsigned long driver_data; @@ -622,13 +622,8 @@ static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, int ret; /* Add the 4 bit gap of Gport2 */ - bitmap_andnot(tmask, mask, chip->shiftmask, MAX_LINE); - bitmap_shift_left(tmask, tmask, 4, MAX_LINE); - bitmap_replace(tmask, tmask, mask, chip->shiftmask, BANK_SZ * 3); - - bitmap_andnot(tval, val, chip->shiftmask, MAX_LINE); - bitmap_shift_left(tval, tval, 4, MAX_LINE); - bitmap_replace(tval, tval, val, chip->shiftmask, BANK_SZ * 3); + bitmap_scatter(tmask, mask, chip->map, MAX_LINE); + bitmap_scatter(tval, val, chip->map, MAX_LINE); for (unsigned int i = 0; i < chip->nport; i++) { /* Skip over unused banks */ @@ -653,19 +648,13 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, { DECLARE_BITMAP(tmask, MAX_LINE); DECLARE_BITMAP(tval, MAX_LINE); - DECLARE_BITMAP(tmp, MAX_LINE); int read_val; u8 bits; int ret; /* Add the 4 bit gap of Gport2 */ - bitmap_andnot(tmask, mask, chip->shiftmask, MAX_LINE); - bitmap_shift_left(tmask, tmask, 4, MAX_LINE); - bitmap_replace(tmask, tmask, mask, chip->shiftmask, BANK_SZ * 3); - - bitmap_andnot(tval, val, chip->shiftmask, MAX_LINE); - bitmap_shift_left(tval, tval, 4, MAX_LINE); - bitmap_replace(tval, tval, val, chip->shiftmask, BANK_SZ * 3); + bitmap_scatter(tmask, mask, chip->map, MAX_LINE); + bitmap_scatter(tval, val, chip->map, MAX_LINE); for (unsigned int i = 0; i < chip->nport; i++) { /* Skip over unused banks */ @@ -685,8 +674,7 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, } /* Fill the 4 bit gap of Gport2 */ - bitmap_shift_right(tmp, tval, 4, MAX_LINE); - bitmap_replace(val, tmp, tval, chip->shiftmask, MAX_LINE); + bitmap_gather(val, tval, chip->map, MAX_LINE); return 0; } @@ -1486,8 +1474,11 @@ static int cy8c95x0_probe(struct i2c_client *client) return PTR_ERR(chip->regmap); bitmap_zero(chip->push_pull, MAX_LINE); - bitmap_zero(chip->shiftmask, MAX_LINE); - bitmap_set(chip->shiftmask, 0, 20); + + /* Setup HW pins mapping */ + bitmap_fill(chip->map, MAX_LINE); + bitmap_clear(chip->map, 20, 4); + mutex_init(&chip->i2c_lock); if (dmi_first_match(cy8c95x0_dmi_acpi_irq_info)) { -- cgit v1.2.3-59-g8ed1b From 83e29a7a1fdfd9e8a503934b5a0a17e6967dbe1b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Feb 2025 11:51:12 +0200 Subject: pinctrl: cy8c95x0; Switch to use for_each_set_clump8() for_each_set_clump8() has embedded check for unset clump to skip. Switch driver to use for_each_set_clump8(). Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/20250205095243.512292-3-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-cy8c95x0.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c index f53dbcaf9a32..0eb570952f3f 100644 --- a/drivers/pinctrl/pinctrl-cy8c95x0.c +++ b/drivers/pinctrl/pinctrl-cy8c95x0.c @@ -617,21 +617,18 @@ static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, { DECLARE_BITMAP(tmask, MAX_LINE); DECLARE_BITMAP(tval, MAX_LINE); + unsigned long bits, offset; int write_val; - u8 bits; int ret; /* Add the 4 bit gap of Gport2 */ bitmap_scatter(tmask, mask, chip->map, MAX_LINE); bitmap_scatter(tval, val, chip->map, MAX_LINE); - for (unsigned int i = 0; i < chip->nport; i++) { - /* Skip over unused banks */ - bits = bitmap_get_value8(tmask, i * BANK_SZ); - if (!bits) - continue; + for_each_set_clump8(offset, bits, tmask, chip->tpin) { + unsigned int i = offset / 8; - write_val = bitmap_get_value8(tval, i * BANK_SZ); + write_val = bitmap_get_value8(tval, offset); ret = cy8c95x0_regmap_update_bits(chip, reg, i, bits, write_val); if (ret < 0) { @@ -648,19 +645,16 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, { DECLARE_BITMAP(tmask, MAX_LINE); DECLARE_BITMAP(tval, MAX_LINE); + unsigned long bits, offset; int read_val; - u8 bits; int ret; /* Add the 4 bit gap of Gport2 */ bitmap_scatter(tmask, mask, chip->map, MAX_LINE); bitmap_scatter(tval, val, chip->map, MAX_LINE); - for (unsigned int i = 0; i < chip->nport; i++) { - /* Skip over unused banks */ - bits = bitmap_get_value8(tmask, i * BANK_SZ); - if (!bits) - continue; + for_each_set_clump8(offset, bits, tmask, chip->tpin) { + unsigned int i = offset / 8; ret = cy8c95x0_regmap_read(chip, reg, i, &read_val); if (ret < 0) { @@ -669,8 +663,8 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, } read_val &= bits; - read_val |= bitmap_get_value8(tval, i * BANK_SZ) & ~bits; - bitmap_set_value8(tval, read_val, i * BANK_SZ); + read_val |= bitmap_get_value8(tval, offset) & ~bits; + bitmap_set_value8(tval, read_val, offset); } /* Fill the 4 bit gap of Gport2 */ -- cgit v1.2.3-59-g8ed1b From 4f7a59abf956d71f4c79c55a2404193f151613f4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Feb 2025 11:51:13 +0200 Subject: pinctrl: cy8c95x0: Transform to cy8c95x0_regmap_read_bits() The returned value of cy8c95x0_regmap_read() is used always with a bitmask being applied. Move that bitmasking code into the function. At the same time transform it to cy8c95x0_regmap_read_bits() which will be in align with the write and update counterparts. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/20250205095243.512292-4-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-cy8c95x0.c | 45 +++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c index 0eb570952f3f..0d732e7a0868 100644 --- a/drivers/pinctrl/pinctrl-cy8c95x0.c +++ b/drivers/pinctrl/pinctrl-cy8c95x0.c @@ -575,12 +575,13 @@ static int cy8c95x0_regmap_update_bits(struct cy8c95x0_pinctrl *chip, unsigned i } /** - * cy8c95x0_regmap_read() - reads a register using the regmap cache + * cy8c95x0_regmap_read_bits() - reads a register using the regmap cache * @chip: The pinctrl to work on * @reg: The register to read from. Can be direct access or muxed register. * @port: The port to be used for muxed registers or quick path direct access * registers. Otherwise unused. - * @read_val: Value read from hardware or cache + * @mask: Bitmask to apply + * @val: Value read from hardware or cache * * This function handles the register reads from the direct access registers and * the muxed registers while caching all register accesses, internally handling @@ -590,10 +591,12 @@ static int cy8c95x0_regmap_update_bits(struct cy8c95x0_pinctrl *chip, unsigned i * * Return: 0 for successful request, else a corresponding error value */ -static int cy8c95x0_regmap_read(struct cy8c95x0_pinctrl *chip, unsigned int reg, - unsigned int port, unsigned int *read_val) +static int cy8c95x0_regmap_read_bits(struct cy8c95x0_pinctrl *chip, unsigned int reg, + unsigned int port, unsigned int mask, unsigned int *val) { - int off, ret; + unsigned int off; + unsigned int tmp; + int ret; /* Registers behind the PORTSEL mux have their own range in regmap */ if (cy8c95x0_muxed_register(reg)) { @@ -605,11 +608,14 @@ static int cy8c95x0_regmap_read(struct cy8c95x0_pinctrl *chip, unsigned int reg, else off = reg; } - guard(mutex)(&chip->i2c_lock); - ret = regmap_read(chip->regmap, off, read_val); + scoped_guard(mutex, &chip->i2c_lock) + ret = regmap_read(chip->regmap, off, &tmp); + if (ret) + return ret; - return ret; + *val = tmp & mask; + return 0; } static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, @@ -646,7 +652,7 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, DECLARE_BITMAP(tmask, MAX_LINE); DECLARE_BITMAP(tval, MAX_LINE); unsigned long bits, offset; - int read_val; + unsigned int read_val; int ret; /* Add the 4 bit gap of Gport2 */ @@ -656,13 +662,12 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, for_each_set_clump8(offset, bits, tmask, chip->tpin) { unsigned int i = offset / 8; - ret = cy8c95x0_regmap_read(chip, reg, i, &read_val); + ret = cy8c95x0_regmap_read_bits(chip, reg, i, bits, &read_val); if (ret < 0) { dev_err(chip->dev, "failed reading register %d, port %u: err %d\n", reg, i, ret); return ret; } - read_val &= bits; read_val |= bitmap_get_value8(tval, offset) & ~bits; bitmap_set_value8(tval, read_val, offset); } @@ -699,10 +704,10 @@ static int cy8c95x0_gpio_get_value(struct gpio_chip *gc, unsigned int off) struct cy8c95x0_pinctrl *chip = gpiochip_get_data(gc); u8 port = cypress_get_port(chip, off); u8 bit = cypress_get_pin_mask(chip, off); - u32 reg_val; + unsigned int reg_val; int ret; - ret = cy8c95x0_regmap_read(chip, CY8C95X0_INPUT, port, ®_val); + ret = cy8c95x0_regmap_read_bits(chip, CY8C95X0_INPUT, port, bit, ®_val); if (ret < 0) { /* * NOTE: @@ -713,7 +718,7 @@ static int cy8c95x0_gpio_get_value(struct gpio_chip *gc, unsigned int off) return 0; } - return !!(reg_val & bit); + return reg_val ? 1 : 0; } static void cy8c95x0_gpio_set_value(struct gpio_chip *gc, unsigned int off, @@ -731,14 +736,14 @@ static int cy8c95x0_gpio_get_direction(struct gpio_chip *gc, unsigned int off) struct cy8c95x0_pinctrl *chip = gpiochip_get_data(gc); u8 port = cypress_get_port(chip, off); u8 bit = cypress_get_pin_mask(chip, off); - u32 reg_val; + unsigned int reg_val; int ret; - ret = cy8c95x0_regmap_read(chip, CY8C95X0_DIRECTION, port, ®_val); + ret = cy8c95x0_regmap_read_bits(chip, CY8C95X0_DIRECTION, port, bit, ®_val); if (ret < 0) return ret; - if (reg_val & bit) + if (reg_val) return GPIO_LINE_DIRECTION_IN; return GPIO_LINE_DIRECTION_OUT; @@ -751,8 +756,8 @@ static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip, enum pin_config_param param = pinconf_to_config_param(*config); u8 port = cypress_get_port(chip, off); u8 bit = cypress_get_pin_mask(chip, off); + unsigned int reg_val; unsigned int reg; - u32 reg_val; u16 arg = 0; int ret; @@ -809,11 +814,11 @@ static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip, * Writing 1 to one of the drive mode registers will automatically * clear conflicting set bits in the other drive mode registers. */ - ret = cy8c95x0_regmap_read(chip, reg, port, ®_val); + ret = cy8c95x0_regmap_read_bits(chip, reg, port, bit, ®_val); if (ret < 0) return ret; - if (reg_val & bit) + if (reg_val) arg = 1; if (param == PIN_CONFIG_OUTPUT_ENABLE) arg = !arg; -- cgit v1.2.3-59-g8ed1b From 009ba0eafecf50d1d1c5e6cf1cfe22c6cf55360e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Feb 2025 11:51:14 +0200 Subject: pinctrl: cy8c95x0: Remove redundant check in cy8c95x0_regmap_update_bits_base() The function is never called with the PORTSEL register in the argument. Drop unneeded check, but rescue a comment. While at it, drop inline and allow any compiler to choose better stragy (note, that inline in C code is only a recomendation to most of the modern compilers anyway). Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/20250205095243.512292-5-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-cy8c95x0.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c index 0d732e7a0868..04b534b950d0 100644 --- a/drivers/pinctrl/pinctrl-cy8c95x0.c +++ b/drivers/pinctrl/pinctrl-cy8c95x0.c @@ -477,20 +477,14 @@ static const struct regmap_config cy8c9520_i2c_regmap = { #endif }; -static inline int cy8c95x0_regmap_update_bits_base(struct cy8c95x0_pinctrl *chip, - unsigned int reg, - unsigned int port, - unsigned int mask, - unsigned int val, - bool *change, bool async, - bool force) +/* Caller should never modify PORTSEL directly */ +static int cy8c95x0_regmap_update_bits_base(struct cy8c95x0_pinctrl *chip, + unsigned int reg, unsigned int port, + unsigned int mask, unsigned int val, + bool *change, bool async, bool force) { int ret, off, i; - /* Caller should never modify PORTSEL directly */ - if (reg == CY8C95X0_PORTSEL) - return -EINVAL; - /* Registers behind the PORTSEL mux have their own range in regmap */ if (cy8c95x0_muxed_register(reg)) { off = CY8C95X0_MUX_REGMAP_TO_OFFSET(reg, port); -- cgit v1.2.3-59-g8ed1b From c0fc4039832262cf615f7be47f53cd54984bb091 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Feb 2025 11:51:15 +0200 Subject: pinctrl: cy8c95x0: Replace 'return ret' by 'return 0' in some cases When it's known that the returned value can't be non-zero, use 'return 0' explicitly. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/20250205095243.512292-6-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-cy8c95x0.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c index 04b534b950d0..19f92ec83871 100644 --- a/drivers/pinctrl/pinctrl-cy8c95x0.c +++ b/drivers/pinctrl/pinctrl-cy8c95x0.c @@ -517,7 +517,7 @@ static int cy8c95x0_regmap_update_bits_base(struct cy8c95x0_pinctrl *chip, regcache_cache_only(chip->regmap, false); } - return ret; + return 0; } /** @@ -1286,7 +1286,7 @@ static int cy8c95x0_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, unsigned long *configs, unsigned int num_configs) { struct cy8c95x0_pinctrl *chip = pinctrl_dev_get_drvdata(pctldev); - int ret = 0; + int ret; int i; for (i = 0; i < num_configs; i++) { @@ -1295,7 +1295,7 @@ static int cy8c95x0_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, return ret; } - return ret; + return 0; } static const struct pinconf_ops cy8c95x0_pinconf_ops = { -- cgit v1.2.3-59-g8ed1b From 682d385aca63d53470313b98b4e9ff1a7a11f1c1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Feb 2025 11:51:16 +0200 Subject: pinctrl: cy8c95x0: Initialise boolean variable with boolean values The 'ret' variable in cy8c95x0_irq_handler() is defined as bool, but is intialised with integers. Avoid implicit castings and initialise boolean variable with boolean values. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/20250205095243.512292-7-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-cy8c95x0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c index 19f92ec83871..7e79f20f4d78 100644 --- a/drivers/pinctrl/pinctrl-cy8c95x0.c +++ b/drivers/pinctrl/pinctrl-cy8c95x0.c @@ -1076,7 +1076,7 @@ static irqreturn_t cy8c95x0_irq_handler(int irq, void *devid) if (!ret) return IRQ_RETVAL(0); - ret = 0; + ret = false; for_each_set_bit(level, pending, MAX_LINE) { /* Already accounted for 4bit gap in GPort2 */ nested_irq = irq_find_mapping(gc->irq.domain, level); @@ -1095,7 +1095,7 @@ static irqreturn_t cy8c95x0_irq_handler(int irq, void *devid) else handle_nested_irq(nested_irq); - ret = 1; + ret = true; } return IRQ_RETVAL(ret); -- cgit v1.2.3-59-g8ed1b From 145c39050e7d875b34b0dc86fba065bd22418fd2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Feb 2025 11:51:17 +0200 Subject: pinctrl: cy8c95x0: Get rid of cy8c95x0_pinmux_direction() forward declaration The function is used before being defined. Just move it up enough to get rid of forward declaration. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/20250205095243.512292-8-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-cy8c95x0.c | 54 ++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c index 7e79f20f4d78..3f2bdaea58b4 100644 --- a/drivers/pinctrl/pinctrl-cy8c95x0.c +++ b/drivers/pinctrl/pinctrl-cy8c95x0.c @@ -310,9 +310,6 @@ static const char * const cy8c95x0_groups[] = { "gp77", }; -static int cy8c95x0_pinmux_direction(struct cy8c95x0_pinctrl *chip, - unsigned int pin, bool input); - static inline u8 cypress_get_port(struct cy8c95x0_pinctrl *chip, unsigned int pin) { /* Account for GPORT2 which only has 4 bits */ @@ -672,6 +669,31 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, return 0; } +static int cy8c95x0_pinmux_direction(struct cy8c95x0_pinctrl *chip, unsigned int pin, bool input) +{ + u8 port = cypress_get_port(chip, pin); + u8 bit = cypress_get_pin_mask(chip, pin); + int ret; + + ret = cy8c95x0_regmap_write_bits(chip, CY8C95X0_DIRECTION, port, bit, input ? bit : 0); + if (ret) + return ret; + + /* + * Disable driving the pin by forcing it to HighZ. Only setting + * the direction register isn't sufficient in Push-Pull mode. + */ + if (input && test_bit(pin, chip->push_pull)) { + ret = cy8c95x0_regmap_write_bits(chip, CY8C95X0_DRV_HIZ, port, bit, bit); + if (ret) + return ret; + + __clear_bit(pin, chip->push_pull); + } + + return 0; +} + static int cy8c95x0_gpio_direction_input(struct gpio_chip *gc, unsigned int off) { return pinctrl_gpio_direction_input(gc, off); @@ -1229,32 +1251,6 @@ static int cy8c95x0_gpio_request_enable(struct pinctrl_dev *pctldev, return cy8c95x0_set_mode(chip, pin, false); } -static int cy8c95x0_pinmux_direction(struct cy8c95x0_pinctrl *chip, - unsigned int pin, bool input) -{ - u8 port = cypress_get_port(chip, pin); - u8 bit = cypress_get_pin_mask(chip, pin); - int ret; - - ret = cy8c95x0_regmap_write_bits(chip, CY8C95X0_DIRECTION, port, bit, input ? bit : 0); - if (ret) - return ret; - - /* - * Disable driving the pin by forcing it to HighZ. Only setting - * the direction register isn't sufficient in Push-Pull mode. - */ - if (input && test_bit(pin, chip->push_pull)) { - ret = cy8c95x0_regmap_write_bits(chip, CY8C95X0_DRV_HIZ, port, bit, bit); - if (ret) - return ret; - - __clear_bit(pin, chip->push_pull); - } - - return 0; -} - static int cy8c95x0_gpio_set_direction(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned int pin, bool input) -- cgit v1.2.3-59-g8ed1b From 6a6cab49f07f59b2f3bf60c97fbd2461cd210fa4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Feb 2025 11:51:18 +0200 Subject: pinctrl: cy8c95x0: Drop unneeded casting The 'arg' variable in cy8c95x0_gpio_get_pincfg() is already type of u16. No need to cast it, so drop unneeded casting. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/20250205095243.512292-9-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-cy8c95x0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c index 3f2bdaea58b4..4b683401cae1 100644 --- a/drivers/pinctrl/pinctrl-cy8c95x0.c +++ b/drivers/pinctrl/pinctrl-cy8c95x0.c @@ -839,7 +839,7 @@ static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip, if (param == PIN_CONFIG_OUTPUT_ENABLE) arg = !arg; - *config = pinconf_to_config_packed(param, (u16)arg); + *config = pinconf_to_config_packed(param, arg); return 0; } -- cgit v1.2.3-59-g8ed1b From b5bad465ac109a810d202156d82d76cc22bd8dd1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Feb 2025 11:51:19 +0200 Subject: pinctrl: cy8c95x0: Separate EEPROM related register definitios Currently it's not easy to see at a glance the group of the registers that are per port. Add a blank line and a comment to make it better. Also add a missing definition for one of the EEPROM related registers. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/20250205095243.512292-10-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-cy8c95x0.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c index 4b683401cae1..6a2c7343bf55 100644 --- a/drivers/pinctrl/pinctrl-cy8c95x0.c +++ b/drivers/pinctrl/pinctrl-cy8c95x0.c @@ -40,6 +40,7 @@ /* Port Select configures the port */ #define CY8C95X0_PORTSEL 0x18 + /* Port settings, write PORTSEL first */ #define CY8C95X0_INTMASK 0x19 #define CY8C95X0_SELPWM 0x1A @@ -53,6 +54,9 @@ #define CY8C95X0_DRV_PP_FAST 0x21 #define CY8C95X0_DRV_PP_SLOW 0x22 #define CY8C95X0_DRV_HIZ 0x23 + +/* Internal device configuration */ +#define CY8C95X0_ENABLE_WDE 0x2D #define CY8C95X0_DEVID 0x2E #define CY8C95X0_WATCHDOG 0x2F #define CY8C95X0_COMMAND 0x30 -- cgit v1.2.3-59-g8ed1b From ba1d9787f890eea908b3c9e680c0055e44af21ee Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Feb 2025 11:51:20 +0200 Subject: pinctrl: cy8c95x0: Fix comment style One comment style is not aligned with the rest. Fix that. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/20250205095243.512292-11-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-cy8c95x0.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c index 6a2c7343bf55..3cfbcaee9e65 100644 --- a/drivers/pinctrl/pinctrl-cy8c95x0.c +++ b/drivers/pinctrl/pinctrl-cy8c95x0.c @@ -502,7 +502,8 @@ static int cy8c95x0_regmap_update_bits_base(struct cy8c95x0_pinctrl *chip, if (ret < 0) return ret; - /* Mimic what hardware does and update the cache when a WC bit is written. + /* + * Mimic what hardware does and update the cache when a WC bit is written. * Allows to mark the registers as non-volatile and reduces I/O cycles. */ if (cy8c95x0_wc_register(reg) && (mask & val)) { -- cgit v1.2.3-59-g8ed1b From 574d0f2120b8e7e6a218d81267f4b543d586df11 Mon Sep 17 00:00:00 2001 From: Ivaylo Ivanov Date: Sat, 15 Feb 2025 13:32:48 +0200 Subject: pinctrl: samsung: add exynos2200 SoC pinctrl configuration Add support for the pin-controller found on the Exynos2200 SoC used in Samsung Galaxy S22, S22 Plus and S22 Ultra phones. Signed-off-by: Ivaylo Ivanov Link: https://lore.kernel.org/r/20250215113248.159386-4-ivo.ivanov.ivanov1@gmail.com Signed-off-by: Krzysztof Kozlowski --- drivers/pinctrl/samsung/pinctrl-exynos-arm64.c | 168 +++++++++++++++++++++++++ drivers/pinctrl/samsung/pinctrl-samsung.c | 2 + drivers/pinctrl/samsung/pinctrl-samsung.h | 1 + 3 files changed, 171 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c index 3ea7106ce5ea..0e310c095e99 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c @@ -70,6 +70,174 @@ static const struct samsung_pin_bank_type exynos8895_bank_type_off = { /* Pad retention control code for accessing PMU regmap */ static atomic_t exynos_shared_retention_refcnt; +/* pin banks of exynos2200 pin-controller - ALIVE */ +static const struct samsung_pin_bank_data exynos2200_pin_banks0[] __initconst = { + EXYNOS850_PIN_BANK_EINTW(8, 0x0, "gpa0", 0x00), + EXYNOS850_PIN_BANK_EINTW(8, 0x20, "gpa1", 0x04), + EXYNOS850_PIN_BANK_EINTW(8, 0x40, "gpa2", 0x08), + EXYNOS850_PIN_BANK_EINTW(8, 0x60, "gpa3", 0x0c), + EXYNOS850_PIN_BANK_EINTW(2, 0x80, "gpa4", 0x10), + EXYNOS_PIN_BANK_EINTN(4, 0xa0, "gpq0"), + EXYNOS_PIN_BANK_EINTN(2, 0xc0, "gpq1"), + EXYNOS_PIN_BANK_EINTN(2, 0xe0, "gpq2"), +}; + +/* pin banks of exynos2200 pin-controller - CMGP */ +static const struct samsung_pin_bank_data exynos2200_pin_banks1[] __initconst = { + EXYNOS850_PIN_BANK_EINTW(2, 0x0, "gpm0", 0x00), + EXYNOS850_PIN_BANK_EINTW(2, 0x20, "gpm1", 0x04), + EXYNOS850_PIN_BANK_EINTW(2, 0x40, "gpm2", 0x08), + EXYNOS850_PIN_BANK_EINTW(2, 0x60, "gpm3", 0x0c), + EXYNOS850_PIN_BANK_EINTW(2, 0x80, "gpm4", 0x10), + EXYNOS850_PIN_BANK_EINTW(2, 0xa0, "gpm5", 0x14), + EXYNOS850_PIN_BANK_EINTW(2, 0xc0, "gpm6", 0x18), + EXYNOS850_PIN_BANK_EINTW(2, 0xe0, "gpm7", 0x1c), + EXYNOS850_PIN_BANK_EINTW(2, 0x100, "gpm8", 0x20), + EXYNOS850_PIN_BANK_EINTW(2, 0x120, "gpm9", 0x24), + EXYNOS850_PIN_BANK_EINTW(2, 0x140, "gpm10", 0x28), + EXYNOS850_PIN_BANK_EINTW(2, 0x160, "gpm11", 0x2c), + EXYNOS850_PIN_BANK_EINTW(2, 0x180, "gpm12", 0x30), + EXYNOS850_PIN_BANK_EINTW(2, 0x1a0, "gpm13", 0x34), + EXYNOS850_PIN_BANK_EINTW(1, 0x1c0, "gpm14", 0x38), + EXYNOS850_PIN_BANK_EINTW(1, 0x1e0, "gpm15", 0x3c), + EXYNOS850_PIN_BANK_EINTW(1, 0x200, "gpm16", 0x40), + EXYNOS850_PIN_BANK_EINTW(1, 0x220, "gpm17", 0x44), + EXYNOS850_PIN_BANK_EINTW(1, 0x240, "gpm20", 0x48), + EXYNOS850_PIN_BANK_EINTW(1, 0x260, "gpm21", 0x4c), + EXYNOS850_PIN_BANK_EINTW(1, 0x280, "gpm22", 0x50), + EXYNOS850_PIN_BANK_EINTW(1, 0x2a0, "gpm23", 0x54), + EXYNOS850_PIN_BANK_EINTW(1, 0x2c0, "gpm24", 0x58), +}; + +/* pin banks of exynos2200 pin-controller - HSI1 */ +static const struct samsung_pin_bank_data exynos2200_pin_banks2[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(4, 0x0, "gpf0", 0x00), +}; + +/* pin banks of exynos2200 pin-controller - UFS */ +static const struct samsung_pin_bank_data exynos2200_pin_banks3[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(7, 0x0, "gpf1", 0x00), +}; + +/* pin banks of exynos2200 pin-controller - HSI1UFS */ +static const struct samsung_pin_bank_data exynos2200_pin_banks4[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(2, 0x0, "gpf2", 0x00), +}; + +/* pin banks of exynos2200 pin-controller - PERIC0 */ +static const struct samsung_pin_bank_data exynos2200_pin_banks5[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(4, 0x0, "gpb0", 0x00), + EXYNOS850_PIN_BANK_EINTG(4, 0x20, "gpb1", 0x04), + EXYNOS850_PIN_BANK_EINTG(4, 0x40, "gpb2", 0x08), + EXYNOS850_PIN_BANK_EINTG(4, 0x60, "gpb3", 0x0c), + EXYNOS850_PIN_BANK_EINTG(4, 0x80, "gpp4", 0x10), + EXYNOS850_PIN_BANK_EINTG(2, 0xa0, "gpc0", 0x14), + EXYNOS850_PIN_BANK_EINTG(2, 0xc0, "gpc1", 0x18), + EXYNOS850_PIN_BANK_EINTG(2, 0xe0, "gpc2", 0x1c), + EXYNOS850_PIN_BANK_EINTG(7, 0x100, "gpg1", 0x20), + EXYNOS850_PIN_BANK_EINTG(2, 0x120, "gpg2", 0x24), +}; + +/* pin banks of exynos2200 pin-controller - PERIC1 */ +static const struct samsung_pin_bank_data exynos2200_pin_banks6[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(4, 0x0, "gpp7", 0x00), + EXYNOS850_PIN_BANK_EINTG(4, 0x20, "gpp8", 0x04), + EXYNOS850_PIN_BANK_EINTG(4, 0x40, "gpp9", 0x08), + EXYNOS850_PIN_BANK_EINTG(4, 0x60, "gpp10", 0x0c), +}; + +/* pin banks of exynos2200 pin-controller - PERIC2 */ +static const struct samsung_pin_bank_data exynos2200_pin_banks7[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(4, 0x0, "gpp0", 0x00), + EXYNOS850_PIN_BANK_EINTG(4, 0x20, "gpp1", 0x04), + EXYNOS850_PIN_BANK_EINTG(4, 0x40, "gpp2", 0x08), + EXYNOS850_PIN_BANK_EINTG(4, 0x60, "gpp3", 0x0c), + EXYNOS850_PIN_BANK_EINTG(4, 0x80, "gpp5", 0x10), + EXYNOS850_PIN_BANK_EINTG(4, 0xa0, "gpp6", 0x14), + EXYNOS850_PIN_BANK_EINTG(4, 0xc0, "gpp11", 0x18), + EXYNOS850_PIN_BANK_EINTG(2, 0xe0, "gpc3", 0x1c), + EXYNOS850_PIN_BANK_EINTG(2, 0x100, "gpc4", 0x20), + EXYNOS850_PIN_BANK_EINTG(2, 0x120, "gpc5", 0x24), + EXYNOS850_PIN_BANK_EINTG(2, 0x140, "gpc6", 0x28), + EXYNOS850_PIN_BANK_EINTG(2, 0x160, "gpc7", 0x2c), + EXYNOS850_PIN_BANK_EINTG(2, 0x180, "gpc8", 0x30), + EXYNOS850_PIN_BANK_EINTG(2, 0x1a0, "gpc9", 0x34), + EXYNOS850_PIN_BANK_EINTG(5, 0x1c0, "gpg0", 0x38), +}; + +/* pin banks of exynos2200 pin-controller - VTS */ +static const struct samsung_pin_bank_data exynos2200_pin_banks8[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(7, 0x0, "gpv0", 0x00), +}; + +static const struct samsung_pin_ctrl exynos2200_pin_ctrl[] = { + { + /* pin-controller instance 0 ALIVE data */ + .pin_banks = exynos2200_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks0), + .eint_gpio_init = exynos_eint_gpio_init, + .eint_wkup_init = exynos_eint_wkup_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 1 CMGP data */ + .pin_banks = exynos2200_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks1), + .eint_gpio_init = exynos_eint_gpio_init, + .eint_wkup_init = exynos_eint_wkup_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 2 HSI1 data */ + .pin_banks = exynos2200_pin_banks2, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks2), + }, { + /* pin-controller instance 3 UFS data */ + .pin_banks = exynos2200_pin_banks3, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks3), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 4 HSI1UFS data */ + .pin_banks = exynos2200_pin_banks4, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks4), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 5 PERIC0 data */ + .pin_banks = exynos2200_pin_banks5, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks5), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 6 PERIC1 data */ + .pin_banks = exynos2200_pin_banks6, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks6), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 7 PERIC2 data */ + .pin_banks = exynos2200_pin_banks7, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks7), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 8 VTS data */ + .pin_banks = exynos2200_pin_banks8, + .nr_banks = ARRAY_SIZE(exynos2200_pin_banks8), + }, +}; + +const struct samsung_pinctrl_of_match_data exynos2200_of_data __initconst = { + .ctrl = exynos2200_pin_ctrl, + .num_ctrl = ARRAY_SIZE(exynos2200_pin_ctrl), +}; + /* pin banks of exynos5433 pin-controller - ALIVE */ static const struct samsung_pin_bank_data exynos5433_pin_banks0[] __initconst = { /* Must start with EINTG banks, ordered by EINT group number. */ diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index cfced7afd4ca..04a8a23f4bf1 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -1469,6 +1469,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { #ifdef CONFIG_PINCTRL_EXYNOS_ARM64 { .compatible = "google,gs101-pinctrl", .data = &gs101_of_data }, + { .compatible = "samsung,exynos2200-pinctrl", + .data = &exynos2200_of_data }, { .compatible = "samsung,exynos5433-pinctrl", .data = &exynos5433_of_data }, { .compatible = "samsung,exynos7-pinctrl", diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index bb0689d52ea0..a43803027aa8 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -373,6 +373,7 @@ struct samsung_pmx_func { }; /* list of all exported SoC specific data */ +extern const struct samsung_pinctrl_of_match_data exynos2200_of_data; extern const struct samsung_pinctrl_of_match_data exynos3250_of_data; extern const struct samsung_pinctrl_of_match_data exynos4210_of_data; extern const struct samsung_pinctrl_of_match_data exynos4x12_of_data; -- cgit v1.2.3-59-g8ed1b From ea4065345643f3163e812e58ed8add2c75c3ee46 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Sat, 15 Feb 2025 15:12:35 +0200 Subject: pinctrl: renesas: rzg2l: Suppress binding attributes Suppress binding attributes for the rzg2l pinctrl driver, as it is an essential block for Renesas SoCs. Unbinding the driver leads to warnings from __device_links_no_driver() and can eventually render the system inaccessible. Fixes: c4c4637eb57f ("pinctrl: renesas: Add RZ/G2L pin and gpio controller driver") Signed-off-by: Claudiu Beznea Reviewed-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250215131235.228274-1-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/renesas/pinctrl-rzg2l.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index 298e1aa89c8f..9280bc37a623 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -3403,6 +3403,7 @@ static struct platform_driver rzg2l_pinctrl_driver = { .name = DRV_NAME, .of_match_table = of_match_ptr(rzg2l_pinctrl_of_table), .pm = pm_sleep_ptr(&rzg2l_pinctrl_pm_ops), + .suppress_bind_attrs = true, }, .probe = rzg2l_pinctrl_probe, }; -- cgit v1.2.3-59-g8ed1b From 753764aa8eb52f54d8d1f42158595bfc16f0e748 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:06 +0530 Subject: pinctrl: intel: copy communities using devm_kmemdup_array() Copy communities using devm_kmemdup_array() instead of doing it manually. Signed-off-by: Raag Jadav Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Andy Shevchenko --- drivers/pinctrl/intel/pinctrl-intel.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 527e4b87ae52..33cb918ed806 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -1577,8 +1577,8 @@ int intel_pinctrl_probe(struct platform_device *pdev, * to the registers. */ pctrl->ncommunities = pctrl->soc->ncommunities; - pctrl->communities = devm_kcalloc(dev, pctrl->ncommunities, - sizeof(*pctrl->communities), GFP_KERNEL); + pctrl->communities = devm_kmemdup_array(dev, pctrl->soc->communities, pctrl->ncommunities, + sizeof(*pctrl->soc->communities), GFP_KERNEL); if (!pctrl->communities) return -ENOMEM; @@ -1588,8 +1588,6 @@ int intel_pinctrl_probe(struct platform_device *pdev, u32 offset; u32 value; - *community = pctrl->soc->communities[i]; - regs = devm_platform_ioremap_resource(pdev, community->barno); if (IS_ERR(regs)) return PTR_ERR(regs); -- cgit v1.2.3-59-g8ed1b From f192c8447f4ea0d6d35e17c599348f24ab264372 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:07 +0530 Subject: pinctrl: baytrail: copy communities using devm_kmemdup_array() Copy communities using devm_kmemdup_array() instead of doing it manually. Signed-off-by: Raag Jadav Reviewed-by: Linus Walleij Signed-off-by: Andy Shevchenko --- drivers/pinctrl/intel/pinctrl-baytrail.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 7340dc20349c..c856a2065a1f 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -1557,16 +1557,14 @@ static int byt_set_soc_data(struct intel_pinctrl *vg, vg->soc = soc; vg->ncommunities = vg->soc->ncommunities; - vg->communities = devm_kcalloc(vg->dev, vg->ncommunities, - sizeof(*vg->communities), GFP_KERNEL); + vg->communities = devm_kmemdup_array(vg->dev, vg->soc->communities, vg->ncommunities, + sizeof(*vg->soc->communities), GFP_KERNEL); if (!vg->communities) return -ENOMEM; for (i = 0; i < vg->soc->ncommunities; i++) { struct intel_community *comm = vg->communities + i; - *comm = vg->soc->communities[i]; - comm->pad_regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(comm->pad_regs)) return PTR_ERR(comm->pad_regs); -- cgit v1.2.3-59-g8ed1b From d795fb90d6c63ef3182b49c766a6fef75b4f790d Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:08 +0530 Subject: pinctrl: cherryview: use devm_kmemdup_array() Convert to use devm_kmemdup_array() and while at it, use source size instead of destination. Signed-off-by: Raag Jadav Reviewed-by: Linus Walleij Signed-off-by: Andy Shevchenko --- drivers/pinctrl/intel/pinctrl-cherryview.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index c673e262e1db..69b18ce0f685 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -1631,9 +1631,8 @@ static int chv_pinctrl_probe(struct platform_device *pdev) pctrl->soc = soc_data; pctrl->ncommunities = pctrl->soc->ncommunities; - pctrl->communities = devm_kmemdup(dev, pctrl->soc->communities, - pctrl->ncommunities * sizeof(*pctrl->communities), - GFP_KERNEL); + pctrl->communities = devm_kmemdup_array(dev, pctrl->soc->communities, pctrl->ncommunities, + sizeof(*pctrl->soc->communities), GFP_KERNEL); if (!pctrl->communities) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From 91bfcc7a2fdb5f7833fa8f2a1919eaef0e6a98dd Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:09 +0530 Subject: pinctrl: tangier: use devm_kmemdup_array() Convert to use devm_kmemdup_array() and while at it, use source size instead of destination. Signed-off-by: Raag Jadav Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Andy Shevchenko --- drivers/pinctrl/intel/pinctrl-tangier.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-tangier.c b/drivers/pinctrl/intel/pinctrl-tangier.c index d3baf0f4eea0..ac61e632b487 100644 --- a/drivers/pinctrl/intel/pinctrl-tangier.c +++ b/drivers/pinctrl/intel/pinctrl-tangier.c @@ -524,7 +524,6 @@ static int tng_pinctrl_probe(struct platform_device *pdev, struct device *dev = &pdev->dev; struct tng_family *families; struct tng_pinctrl *tp; - size_t families_len; void __iomem *regs; unsigned int i; @@ -543,8 +542,8 @@ static int tng_pinctrl_probe(struct platform_device *pdev, * Make a copy of the families which we can use to hold pointers * to the registers. */ - families_len = size_mul(sizeof(*families), tp->nfamilies); - families = devm_kmemdup(dev, tp->families, families_len, GFP_KERNEL); + families = devm_kmemdup_array(dev, tp->families, tp->nfamilies, + sizeof(*tp->families), GFP_KERNEL); if (!families) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From 86068aca754880715960a218410749b929c037bd Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:10 +0530 Subject: pinctrl: pxa2xx: use devm_kmemdup_array() Convert to use devm_kmemdup_array() which is more robust. Signed-off-by: Raag Jadav Reviewed-by: Linus Walleij Signed-off-by: Andy Shevchenko --- drivers/pinctrl/pxa/pinctrl-pxa2xx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c index 9e34b92ff5f2..9fd7a8fb2bc4 100644 --- a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c +++ b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c @@ -281,9 +281,8 @@ static int pxa2xx_build_functions(struct pxa_pinctrl *pctl) for (df = pctl->ppins[i].functions; df->name; df++) if (!pxa2xx_find_function(pctl, df->name, functions)) (functions + pctl->nfuncs++)->name = df->name; - pctl->functions = devm_kmemdup(pctl->dev, functions, - pctl->nfuncs * sizeof(*functions), - GFP_KERNEL); + pctl->functions = devm_kmemdup_array(pctl->dev, functions, pctl->nfuncs, + sizeof(*functions), GFP_KERNEL); if (!pctl->functions) return -ENOMEM; @@ -314,7 +313,8 @@ static int pxa2xx_build_groups(struct pxa_pinctrl *pctl) pctl->ppins[j].pin.name; func = pctl->functions + i; func->ngroups = ngroups; - func->groups = devm_kmemdup(pctl->dev, gtmp, ngroups * sizeof(*gtmp), GFP_KERNEL); + func->groups = devm_kmemdup_array(pctl->dev, gtmp, ngroups, + sizeof(*gtmp), GFP_KERNEL); if (!func->groups) return -ENOMEM; } -- cgit v1.2.3-59-g8ed1b From a0d78eec88395e67117a3453f55a4fc3c7265cf2 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:11 +0530 Subject: iio: adc: xilinx-xadc-core: use devm_kmemdup_array() Convert to use devm_kmemdup_array() and while at it, use source size instead of destination. Signed-off-by: Raag Jadav Acked-by: Jonathan Cameron Signed-off-by: Andy Shevchenko --- drivers/iio/adc/xilinx-xadc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index cfbfcaefec0f..e1f8740ae688 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -1245,8 +1245,8 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, unsigned int *conf, int irq) channel_templates = xadc_us_channels; max_channels = ARRAY_SIZE(xadc_us_channels); } - channels = devm_kmemdup(dev, channel_templates, - sizeof(channels[0]) * max_channels, GFP_KERNEL); + channels = devm_kmemdup_array(dev, channel_templates, max_channels, + sizeof(*channel_templates), GFP_KERNEL); if (!channels) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From cdcc09a495a4fa60f1c612db207d78b82b6c4531 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:12 +0530 Subject: input: sparse-keymap: use devm_kmemdup_array() Convert to use devm_kmemdup_array() and while at it, use source size instead of destination. Signed-off-by: Raag Jadav Acked-by: Dmitry Torokhov Reviewed-by: Linus Walleij Signed-off-by: Andy Shevchenko --- drivers/input/sparse-keymap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index 25bf8be6e711..96f23ae57d5a 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -176,8 +176,7 @@ int sparse_keymap_setup(struct input_dev *dev, for (e = keymap; e->type != KE_END; e++) map_size++; - map = devm_kmemdup(&dev->dev, keymap, map_size * sizeof(*map), - GFP_KERNEL); + map = devm_kmemdup_array(&dev->dev, keymap, map_size, sizeof(*keymap), GFP_KERNEL); if (!map) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From b8c38ccb2ca52b9a38cfeb9f89abab5d6e713221 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 12 Feb 2025 11:55:13 +0530 Subject: input: ipaq-micro-keys: use devm_kmemdup_array() Convert to use devm_kmemdup_array() which is more robust. Signed-off-by: Raag Jadav Reviewed-by: Linus Walleij Signed-off-by: Andy Shevchenko --- drivers/input/keyboard/ipaq-micro-keys.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/ipaq-micro-keys.c b/drivers/input/keyboard/ipaq-micro-keys.c index 58631bf7ce55..ca7ec054b1ce 100644 --- a/drivers/input/keyboard/ipaq-micro-keys.c +++ b/drivers/input/keyboard/ipaq-micro-keys.c @@ -102,9 +102,8 @@ static int micro_key_probe(struct platform_device *pdev) keys->input->keycodesize = sizeof(micro_keycodes[0]); keys->input->keycodemax = ARRAY_SIZE(micro_keycodes); - keys->codes = devm_kmemdup(&pdev->dev, micro_keycodes, - keys->input->keycodesize * keys->input->keycodemax, - GFP_KERNEL); + keys->codes = devm_kmemdup_array(&pdev->dev, micro_keycodes, keys->input->keycodemax, + keys->input->keycodesize, GFP_KERNEL); if (!keys->codes) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From 3dd3ab690172b11758e17775cfbf98986ec0cb71 Mon Sep 17 00:00:00 2001 From: Dang Huynh Date: Tue, 11 Feb 2025 23:37:48 +0100 Subject: pinctrl: qcom: msm8917: Add MSM8937 wsa_reset pin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It looks like both 8917 and 8937 are the same except for one pin "wsa_reset". Signed-off-by: Dang Huynh Signed-off-by: Barnabás Czémán Link: https://lore.kernel.org/20250211-msm8937-v1-4-7d27ed67f708@mainlining.org Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/Kconfig.msm | 4 ++-- drivers/pinctrl/qcom/pinctrl-msm8917.c | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/Kconfig.msm b/drivers/pinctrl/qcom/Kconfig.msm index 35f47660a56b..a0d63a672539 100644 --- a/drivers/pinctrl/qcom/Kconfig.msm +++ b/drivers/pinctrl/qcom/Kconfig.msm @@ -138,10 +138,10 @@ config PINCTRL_MSM8916 Qualcomm TLMM block found on the Qualcomm 8916 platform. config PINCTRL_MSM8917 - tristate "Qualcomm 8917 pin controller driver" + tristate "Qualcomm 8917/8937 pin controller driver" help This is the pinctrl, pinmux, pinconf and gpiolib driver for the - Qualcomm TLMM block found on the Qualcomm MSM8917 platform. + Qualcomm TLMM block found on the Qualcomm MSM8917, MSM8937 platform. config PINCTRL_MSM8953 tristate "Qualcomm 8953 pin controller driver" diff --git a/drivers/pinctrl/qcom/pinctrl-msm8917.c b/drivers/pinctrl/qcom/pinctrl-msm8917.c index cff137bb3b23..350636807b07 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8917.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8917.c @@ -539,6 +539,7 @@ enum msm8917_functions { msm_mux_webcam_standby, msm_mux_wsa_io, msm_mux_wsa_irq, + msm_mux_wsa_reset, msm_mux__, }; @@ -1123,6 +1124,10 @@ static const char * const wsa_io_groups[] = { "gpio94", "gpio95", }; +static const char * const wsa_reset_groups[] = { + "gpio96", +}; + static const char * const blsp_spi8_groups[] = { "gpio96", "gpio97", "gpio98", "gpio99", }; @@ -1378,6 +1383,7 @@ static const struct pinfunction msm8917_functions[] = { MSM_PIN_FUNCTION(webcam_standby), MSM_PIN_FUNCTION(wsa_io), MSM_PIN_FUNCTION(wsa_irq), + MSM_PIN_FUNCTION(wsa_reset), }; static const struct msm_pingroup msm8917_groups[] = { @@ -1616,5 +1622,5 @@ static void __exit msm8917_pinctrl_exit(void) } module_exit(msm8917_pinctrl_exit); -MODULE_DESCRIPTION("Qualcomm msm8917 pinctrl driver"); +MODULE_DESCRIPTION("Qualcomm msm8917/msm8937 pinctrl driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From ef1a5121ae3da02372fcb66d9632ed3d47ad5637 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Tue, 11 Feb 2025 13:17:49 +0800 Subject: pinctrl: sophgo: avoid to modify untouched bit when setting cv1800 pinconf When setting pinconf configuration for cv1800 SoC, the driver just writes the value. It may zero some bits of the pinconf register and cause some unexpected error. Add a mask to avoid this. Signed-off-by: Inochi Amaoto Link: https://lore.kernel.org/20250211051801.470800-2-inochiama@gmail.com Signed-off-by: Linus Walleij --- drivers/pinctrl/sophgo/pinctrl-cv18xx.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sophgo/pinctrl-cv18xx.c b/drivers/pinctrl/sophgo/pinctrl-cv18xx.c index 57f2674e75d6..84b4850771ce 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv18xx.c +++ b/drivers/pinctrl/sophgo/pinctrl-cv18xx.c @@ -574,10 +574,10 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, struct cv1800_pin *pin, unsigned long *configs, unsigned int num_configs, - u32 *value) + u32 *value, u32 *mask) { int i; - u32 v = 0; + u32 v = 0, m = 0; enum cv1800_pin_io_type type; int ret; @@ -596,10 +596,12 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, case PIN_CONFIG_BIAS_PULL_DOWN: v &= ~PIN_IO_PULLDOWN; v |= FIELD_PREP(PIN_IO_PULLDOWN, arg); + m |= PIN_IO_PULLDOWN; break; case PIN_CONFIG_BIAS_PULL_UP: v &= ~PIN_IO_PULLUP; v |= FIELD_PREP(PIN_IO_PULLUP, arg); + m |= PIN_IO_PULLUP; break; case PIN_CONFIG_DRIVE_STRENGTH_UA: ret = cv1800_pinctrl_oc2reg(pctrl, pin, arg); @@ -607,6 +609,7 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, return ret; v &= ~PIN_IO_DRIVE; v |= FIELD_PREP(PIN_IO_DRIVE, ret); + m |= PIN_IO_DRIVE; break; case PIN_CONFIG_INPUT_SCHMITT_UV: ret = cv1800_pinctrl_schmitt2reg(pctrl, pin, arg); @@ -614,6 +617,7 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, return ret; v &= ~PIN_IO_SCHMITT; v |= FIELD_PREP(PIN_IO_SCHMITT, ret); + m |= PIN_IO_SCHMITT; break; case PIN_CONFIG_POWER_SOURCE: /* Ignore power source as it is always fixed */ @@ -621,10 +625,12 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, case PIN_CONFIG_SLEW_RATE: v &= ~PIN_IO_OUT_FAST_SLEW; v |= FIELD_PREP(PIN_IO_OUT_FAST_SLEW, arg); + m |= PIN_IO_OUT_FAST_SLEW; break; case PIN_CONFIG_BIAS_BUS_HOLD: v &= ~PIN_IO_BUS_HOLD; v |= FIELD_PREP(PIN_IO_BUS_HOLD, arg); + m |= PIN_IO_BUS_HOLD; break; default: return -ENOTSUPP; @@ -632,17 +638,19 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, } *value = v; + *mask = m; return 0; } static int cv1800_pin_set_config(struct cv1800_pinctrl *pctrl, unsigned int pin_id, - u32 value) + u32 value, u32 mask) { struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id); unsigned long flags; void __iomem *addr; + u32 reg; if (!pin) return -EINVAL; @@ -650,7 +658,10 @@ static int cv1800_pin_set_config(struct cv1800_pinctrl *pctrl, addr = cv1800_pinctrl_get_component_addr(pctrl, &pin->conf); raw_spin_lock_irqsave(&pctrl->lock, flags); - writel(value, addr); + reg = readl(addr); + reg &= ~mask; + reg |= value; + writel(reg, addr); raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; @@ -662,16 +673,17 @@ static int cv1800_pconf_set(struct pinctrl_dev *pctldev, { struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id); - u32 value; + u32 value, mask; if (!pin) return -ENODEV; if (cv1800_pinconf_compute_config(pctrl, pin, - configs, num_configs, &value)) + configs, num_configs, + &value, &mask)) return -ENOTSUPP; - return cv1800_pin_set_config(pctrl, pin_id, value); + return cv1800_pin_set_config(pctrl, pin_id, value, mask); } static int cv1800_pconf_group_set(struct pinctrl_dev *pctldev, @@ -682,7 +694,7 @@ static int cv1800_pconf_group_set(struct pinctrl_dev *pctldev, struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); const struct group_desc *group; const struct cv1800_pin_mux_config *pinmuxs; - u32 value; + u32 value, mask; int i; group = pinctrl_generic_get_group(pctldev, gsel); @@ -692,11 +704,12 @@ static int cv1800_pconf_group_set(struct pinctrl_dev *pctldev, pinmuxs = group->data; if (cv1800_pinconf_compute_config(pctrl, pinmuxs[0].pin, - configs, num_configs, &value)) + configs, num_configs, + &value, &mask)) return -ENOTSUPP; for (i = 0; i < group->grp.npins; i++) - cv1800_pin_set_config(pctrl, group->grp.pins[i], value); + cv1800_pin_set_config(pctrl, group->grp.pins[i], value, mask); return 0; } -- cgit v1.2.3-59-g8ed1b From e096d3ada758b77d9df83b2ee084528cfa2833e3 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Tue, 11 Feb 2025 13:17:50 +0800 Subject: pinctrl: sophgo: introduce generic data structure for cv18xx pinctrl driver To share DT parsing and vddio code, it is necessary to introduce some generic data structure to abstract the different cv18xx series and the incoming sg2042 series. Signed-off-by: Inochi Amaoto Link: https://lore.kernel.org/20250211051801.470800-3-inochiama@gmail.com Signed-off-by: Linus Walleij --- drivers/pinctrl/sophgo/pinctrl-cv1800b.c | 21 ++- drivers/pinctrl/sophgo/pinctrl-cv1812h.c | 21 ++- drivers/pinctrl/sophgo/pinctrl-cv18xx.c | 243 +++++++++++++++++-------------- drivers/pinctrl/sophgo/pinctrl-cv18xx.h | 61 +++----- drivers/pinctrl/sophgo/pinctrl-sg2000.c | 21 ++- drivers/pinctrl/sophgo/pinctrl-sg2002.c | 21 ++- drivers/pinctrl/sophgo/pinctrl-sophgo.h | 66 +++++++++ 7 files changed, 270 insertions(+), 184 deletions(-) create mode 100644 drivers/pinctrl/sophgo/pinctrl-sophgo.h (limited to 'drivers') diff --git a/drivers/pinctrl/sophgo/pinctrl-cv1800b.c b/drivers/pinctrl/sophgo/pinctrl-cv1800b.c index 3322906689e7..45529e2ed23a 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv1800b.c +++ b/drivers/pinctrl/sophgo/pinctrl-cv1800b.c @@ -34,8 +34,9 @@ static const char *const cv1800b_power_domain_desc[] = { [VDDIO_SD0_SPI] = "VDDIO_SD0_SPI", }; -static int cv1800b_get_pull_up(struct cv1800_pin *pin, const u32 *psmap) +static int cv1800b_get_pull_up(const struct sophgo_pin *sp, const u32 *psmap) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); u32 pstate = psmap[pin->power_domain]; enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); @@ -54,8 +55,9 @@ static int cv1800b_get_pull_up(struct cv1800_pin *pin, const u32 *psmap) return -ENOTSUPP; } -static int cv1800b_get_pull_down(struct cv1800_pin *pin, const u32 *psmap) +static int cv1800b_get_pull_down(const struct sophgo_pin *sp, const u32 *psmap) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); u32 pstate = psmap[pin->power_domain]; enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); @@ -108,9 +110,10 @@ static const u32 cv1800b_eth_oc_map[] = { 17800 }; -static int cv1800b_get_oc_map(struct cv1800_pin *pin, const u32 *psmap, +static int cv1800b_get_oc_map(const struct sophgo_pin *sp, const u32 *psmap, const u32 **map) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pstate = psmap[pin->power_domain]; @@ -153,9 +156,10 @@ static const u32 cv1800b_18od33_3v3_schmitt_map[] = { 1100000 }; -static int cv1800b_get_schmitt_map(struct cv1800_pin *pin, const u32 *psmap, +static int cv1800b_get_schmitt_map(const struct sophgo_pin *sp, const u32 *psmap, const u32 **map) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pstate = psmap[pin->power_domain]; @@ -177,11 +181,11 @@ static int cv1800b_get_schmitt_map(struct cv1800_pin *pin, const u32 *psmap, return -ENOTSUPP; } -static const struct cv1800_vddio_cfg_ops cv1800b_vddio_cfg_ops = { +static const struct sophgo_vddio_cfg_ops cv1800b_vddio_cfg_ops = { .get_pull_up = cv1800b_get_pull_up, .get_pull_down = cv1800b_get_pull_down, .get_oc_map = cv1800b_get_oc_map, - .get_schmitt_map = cv1800b_get_schmitt_map, + .get_schmitt_map = cv1800b_get_schmitt_map, }; static const struct pinctrl_pin_desc cv1800b_pins[] = { @@ -433,13 +437,14 @@ static const struct cv1800_pin cv1800b_pin_data[ARRAY_SIZE(cv1800b_pins)] = { CV1800_PINCONF_AREA_SYS, 0x120, 5), }; -static const struct cv1800_pinctrl_data cv1800b_pindata = { +static const struct sophgo_pinctrl_data cv1800b_pindata = { .pins = cv1800b_pins, .pindata = cv1800b_pin_data, .pdnames = cv1800b_power_domain_desc, .vddio_ops = &cv1800b_vddio_cfg_ops, .npins = ARRAY_SIZE(cv1800b_pins), - .npd = ARRAY_SIZE(cv1800b_power_domain_desc), + .npds = ARRAY_SIZE(cv1800b_power_domain_desc), + .pinsize = sizeof(struct cv1800_pin), }; static const struct of_device_id cv1800b_pinctrl_ids[] = { diff --git a/drivers/pinctrl/sophgo/pinctrl-cv1812h.c b/drivers/pinctrl/sophgo/pinctrl-cv1812h.c index 5632290b46fa..4e30a1cc9d7d 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv1812h.c +++ b/drivers/pinctrl/sophgo/pinctrl-cv1812h.c @@ -40,8 +40,9 @@ static const char *const cv1812h_power_domain_desc[] = { [VDDIO_VIVO] = "VDDIO_VIVO", }; -static int cv1812h_get_pull_up(struct cv1800_pin *pin, const u32 *psmap) +static int cv1812h_get_pull_up(const struct sophgo_pin *sp, const u32 *psmap) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); u32 pstate = psmap[pin->power_domain]; enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); @@ -60,8 +61,9 @@ static int cv1812h_get_pull_up(struct cv1800_pin *pin, const u32 *psmap) return -ENOTSUPP; } -static int cv1812h_get_pull_down(struct cv1800_pin *pin, const u32 *psmap) +static int cv1812h_get_pull_down(const struct sophgo_pin *sp, const u32 *psmap) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); u32 pstate = psmap[pin->power_domain]; enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); @@ -114,9 +116,10 @@ static const u32 cv1812h_eth_oc_map[] = { 17800 }; -static int cv1812h_get_oc_map(struct cv1800_pin *pin, const u32 *psmap, +static int cv1812h_get_oc_map(const struct sophgo_pin *sp, const u32 *psmap, const u32 **map) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pstate = psmap[pin->power_domain]; @@ -159,9 +162,10 @@ static const u32 cv1812h_18od33_3v3_schmitt_map[] = { 1100000 }; -static int cv1812h_get_schmitt_map(struct cv1800_pin *pin, const u32 *psmap, +static int cv1812h_get_schmitt_map(const struct sophgo_pin *sp, const u32 *psmap, const u32 **map) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pstate = psmap[pin->power_domain]; @@ -183,11 +187,11 @@ static int cv1812h_get_schmitt_map(struct cv1800_pin *pin, const u32 *psmap, return -ENOTSUPP; } -static const struct cv1800_vddio_cfg_ops cv1812h_vddio_cfg_ops = { +static const struct sophgo_vddio_cfg_ops cv1812h_vddio_cfg_ops = { .get_pull_up = cv1812h_get_pull_up, .get_pull_down = cv1812h_get_pull_down, .get_oc_map = cv1812h_get_oc_map, - .get_schmitt_map = cv1812h_get_schmitt_map, + .get_schmitt_map = cv1812h_get_schmitt_map, }; static const struct pinctrl_pin_desc cv1812h_pins[] = { @@ -742,13 +746,14 @@ static const struct cv1800_pin cv1812h_pin_data[ARRAY_SIZE(cv1812h_pins)] = { CV1800_PINCONF_AREA_RTC, 0x028), }; -static const struct cv1800_pinctrl_data cv1812h_pindata = { +static const struct sophgo_pinctrl_data cv1812h_pindata = { .pins = cv1812h_pins, .pindata = cv1812h_pin_data, .pdnames = cv1812h_power_domain_desc, .vddio_ops = &cv1812h_vddio_cfg_ops, .npins = ARRAY_SIZE(cv1812h_pins), - .npd = ARRAY_SIZE(cv1812h_power_domain_desc), + .npds = ARRAY_SIZE(cv1812h_power_domain_desc), + .pinsize = sizeof(struct cv1800_pin), }; static const struct of_device_id cv1812h_pinctrl_ids[] = { diff --git a/drivers/pinctrl/sophgo/pinctrl-cv18xx.c b/drivers/pinctrl/sophgo/pinctrl-cv18xx.c index 84b4850771ce..573e00d2c752 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv18xx.c +++ b/drivers/pinctrl/sophgo/pinctrl-cv18xx.c @@ -24,30 +24,16 @@ #include -#include "../core.h" #include "../pinctrl-utils.h" #include "../pinconf.h" #include "../pinmux.h" #include "pinctrl-cv18xx.h" -struct cv1800_pinctrl { - struct device *dev; - struct pinctrl_dev *pctl_dev; - const struct cv1800_pinctrl_data *data; - struct pinctrl_desc pdesc; +struct cv1800_priv { u32 *power_cfg; - - struct mutex mutex; - raw_spinlock_t lock; - void __iomem *regs[2]; }; -struct cv1800_pin_mux_config { - struct cv1800_pin *pin; - u32 config; -}; - static unsigned int cv1800_dt_get_pin(u32 value) { return value & GENMASK(15, 0); @@ -68,38 +54,42 @@ static unsigned int cv1800_dt_get_pin_mux2(u32 value) static int cv1800_cmp_pin(const void *key, const void *pivot) { - const struct cv1800_pin *pin = pivot; + const struct sophgo_pin *pin = pivot; int pin_id = (long)key; - int pivid = pin->pin; + int pivid = pin->id; return pin_id - pivid; } -static int cv1800_set_power_cfg(struct cv1800_pinctrl *pctrl, +static int cv1800_set_power_cfg(struct sophgo_pinctrl *pctrl, u8 domain, u32 cfg) { - if (domain >= pctrl->data->npd) + struct cv1800_priv *priv = pctrl->priv_ctrl; + + if (domain >= pctrl->data->npds) return -ENOTSUPP; - if (pctrl->power_cfg[domain] && pctrl->power_cfg[domain] != cfg) + if (priv->power_cfg[domain] && priv->power_cfg[domain] != cfg) return -EINVAL; - pctrl->power_cfg[domain] = cfg; + priv->power_cfg[domain] = cfg; return 0; } -static int cv1800_get_power_cfg(struct cv1800_pinctrl *pctrl, +static int cv1800_get_power_cfg(struct sophgo_pinctrl *pctrl, u8 domain) { - return pctrl->power_cfg[domain]; + struct cv1800_priv *priv = pctrl->priv_ctrl; + + return priv->power_cfg[domain]; } -static struct cv1800_pin *cv1800_get_pin(struct cv1800_pinctrl *pctrl, - unsigned long pin) +static const struct sophgo_pin *cv1800_get_pin(struct sophgo_pinctrl *pctrl, + unsigned long pin) { return bsearch((void *)pin, pctrl->data->pindata, pctrl->data->npins, - sizeof(struct cv1800_pin), cv1800_cmp_pin); + pctrl->data->pinsize, cv1800_cmp_pin); } #define PIN_BGA_ID_OFFSET 8 @@ -112,7 +102,7 @@ static const char *const io_type_desc[] = { "ETH" }; -static const char *cv1800_get_power_cfg_desc(struct cv1800_pinctrl *pctrl, +static const char *cv1800_get_power_cfg_desc(struct sophgo_pinctrl *pctrl, u8 domain) { return pctrl->data->pdnames[domain]; @@ -121,53 +111,57 @@ static const char *cv1800_get_power_cfg_desc(struct cv1800_pinctrl *pctrl, static void cv1800_pctrl_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *seq, unsigned int pin_id) { - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id); + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct cv1800_priv *priv = pctrl->priv_ctrl; + const struct sophgo_pin *sp = cv1800_get_pin(pctrl, pin_id); + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); + u32 pin_hwid = pin->pin.id; u32 value; void __iomem *reg; - if (pin->pin >> PIN_BGA_ID_OFFSET) + if (pin_hwid >> PIN_BGA_ID_OFFSET) seq_printf(seq, "pos: %c%u ", - 'A' + (pin->pin >> PIN_BGA_ID_OFFSET) - 1, - pin->pin & PIN_BGA_ID_MASK); + 'A' + (pin_hwid >> PIN_BGA_ID_OFFSET) - 1, + pin_hwid & PIN_BGA_ID_MASK); else - seq_printf(seq, "pos: %u ", pin->pin); + seq_printf(seq, "pos: %u ", pin_hwid); seq_printf(seq, "power-domain: %s ", cv1800_get_power_cfg_desc(pctrl, pin->power_domain)); seq_printf(seq, "type: %s ", io_type_desc[type]); - reg = cv1800_pinctrl_get_component_addr(pctrl, &pin->mux); + reg = cv1800_pinctrl_get_component_addr(priv, &pin->mux); value = readl(reg); seq_printf(seq, "mux: 0x%08x ", value); - if (pin->flags & CV1800_PIN_HAVE_MUX2) { - reg = cv1800_pinctrl_get_component_addr(pctrl, &pin->mux2); + if (pin->pin.flags & CV1800_PIN_HAVE_MUX2) { + reg = cv1800_pinctrl_get_component_addr(priv, &pin->mux2); value = readl(reg); seq_printf(seq, "mux2: 0x%08x ", value); } if (type == IO_TYPE_1V8_ONLY || type == IO_TYPE_1V8_OR_3V3) { - reg = cv1800_pinctrl_get_component_addr(pctrl, &pin->conf); + reg = cv1800_pinctrl_get_component_addr(priv, &pin->conf); value = readl(reg); seq_printf(seq, "conf: 0x%08x ", value); } } -static int cv1800_verify_pinmux_config(const struct cv1800_pin_mux_config *config) +static int cv1800_verify_pinmux_config(const struct sophgo_pin_mux_config *config) { + struct cv1800_pin *pin = sophgo_to_cv1800_pin(config->pin); unsigned int mux = cv1800_dt_get_pin_mux(config->config); unsigned int mux2 = cv1800_dt_get_pin_mux2(config->config); - if (mux > config->pin->mux.max) + if (mux > pin->mux.max) return -EINVAL; - if (config->pin->flags & CV1800_PIN_HAVE_MUX2) { - if (mux != config->pin->mux2.pfunc) + if (pin->pin.flags & CV1800_PIN_HAVE_MUX2) { + if (mux != pin->mux2.pfunc) return -EINVAL; - if (mux2 > config->pin->mux2.max) + if (mux2 > pin->mux2.max) return -EINVAL; } else { if (mux2 != PIN_MUX_INVALD) @@ -177,9 +171,10 @@ static int cv1800_verify_pinmux_config(const struct cv1800_pin_mux_config *confi return 0; } -static int cv1800_verify_pin_group(const struct cv1800_pin_mux_config *mux, +static int cv1800_verify_pin_group(const struct sophgo_pin_mux_config *mux, unsigned long npins) { + struct cv1800_pin *pin; enum cv1800_pin_io_type type; u8 power_domain; int i; @@ -187,12 +182,15 @@ static int cv1800_verify_pin_group(const struct cv1800_pin_mux_config *mux, if (npins == 1) return 0; - type = cv1800_pin_io_type(mux[0].pin); - power_domain = mux[0].pin->power_domain; + pin = sophgo_to_cv1800_pin(mux[0].pin); + type = cv1800_pin_io_type(pin); + power_domain = pin->power_domain; for (i = 0; i < npins; i++) { - if (type != cv1800_pin_io_type(mux[i].pin) || - power_domain != mux[i].pin->power_domain) + pin = sophgo_to_cv1800_pin(mux[i].pin); + + if (type != cv1800_pin_io_type(pin) || + power_domain != pin->power_domain) return -ENOTSUPP; } @@ -204,7 +202,7 @@ static int cv1800_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, struct pinctrl_map **maps, unsigned int *num_maps) { - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); struct device *dev = pctrl->dev; struct device_node *child; struct pinctrl_map *map; @@ -230,7 +228,8 @@ static int cv1800_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, for_each_available_child_of_node(np, child) { int npins = of_property_count_u32_elems(child, "pinmux"); unsigned int *pins; - struct cv1800_pin_mux_config *pinmuxs; + struct sophgo_pin_mux_config *pinmuxs; + struct cv1800_pin *pin; u32 config, power; int i; @@ -303,8 +302,8 @@ static int cv1800_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, goto dt_failed; } - ret = cv1800_set_power_cfg(pctrl, pinmuxs[0].pin->power_domain, - power); + pin = sophgo_to_cv1800_pin(pinmuxs[0].pin); + ret = cv1800_set_power_cfg(pctrl, pin->power_domain, power); if (ret) goto dt_failed; @@ -371,9 +370,10 @@ static const struct pinctrl_ops cv1800_pctrl_ops = { static int cv1800_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned int fsel, unsigned int gsel) { - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct cv1800_priv *priv = pctrl->priv_ctrl; const struct group_desc *group; - const struct cv1800_pin_mux_config *configs; + const struct sophgo_pin_mux_config *configs; unsigned int i; group = pinctrl_generic_get_group(pctldev, gsel); @@ -383,7 +383,7 @@ static int cv1800_pmx_set_mux(struct pinctrl_dev *pctldev, configs = group->data; for (i = 0; i < group->grp.npins; i++) { - const struct cv1800_pin *pin = configs[i].pin; + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(configs[i].pin); u32 value = configs[i].config; void __iomem *reg_mux; void __iomem *reg_mux2; @@ -391,8 +391,8 @@ static int cv1800_pmx_set_mux(struct pinctrl_dev *pctldev, u32 mux; u32 mux2; - reg_mux = cv1800_pinctrl_get_component_addr(pctrl, &pin->mux); - reg_mux2 = cv1800_pinctrl_get_component_addr(pctrl, &pin->mux2); + reg_mux = cv1800_pinctrl_get_component_addr(priv, &pin->mux); + reg_mux2 = cv1800_pinctrl_get_component_addr(priv, &pin->mux2); mux = cv1800_dt_get_pin_mux(value); mux2 = cv1800_dt_get_pin_mux2(value); @@ -421,25 +421,28 @@ static const struct pinmux_ops cv1800_pmx_ops = { #define PIN_IO_BUS_HOLD BIT(10) #define PIN_IO_OUT_FAST_SLEW BIT(11) -static u32 cv1800_pull_down_typical_resistor(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin) +static u32 cv1800_pull_down_typical_resistor(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg) { - return pctrl->data->vddio_ops->get_pull_down(pin, pctrl->power_cfg); + return pctrl->data->vddio_ops->get_pull_down(pin, power_cfg); } -static u32 cv1800_pull_up_typical_resistor(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin) +static u32 cv1800_pull_up_typical_resistor(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg) { - return pctrl->data->vddio_ops->get_pull_up(pin, pctrl->power_cfg); + return pctrl->data->vddio_ops->get_pull_up(pin, power_cfg); } -static int cv1800_pinctrl_oc2reg(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin, u32 target) +static int cv1800_pinctrl_oc2reg(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 target) { const u32 *map; int i, len; - len = pctrl->data->vddio_ops->get_oc_map(pin, pctrl->power_cfg, &map); + len = pctrl->data->vddio_ops->get_oc_map(pin, power_cfg, &map); if (len < 0) return len; @@ -451,13 +454,14 @@ static int cv1800_pinctrl_oc2reg(struct cv1800_pinctrl *pctrl, return -EINVAL; } -static int cv1800_pinctrl_reg2oc(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin, u32 reg) +static int cv1800_pinctrl_reg2oc(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 reg) { const u32 *map; int len; - len = pctrl->data->vddio_ops->get_oc_map(pin, pctrl->power_cfg, &map); + len = pctrl->data->vddio_ops->get_oc_map(pin, power_cfg, &map); if (len < 0) return len; @@ -467,14 +471,14 @@ static int cv1800_pinctrl_reg2oc(struct cv1800_pinctrl *pctrl, return map[reg]; } -static int cv1800_pinctrl_schmitt2reg(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin, u32 target) +static int cv1800_pinctrl_schmitt2reg(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 target) { const u32 *map; int i, len; - len = pctrl->data->vddio_ops->get_schmitt_map(pin, pctrl->power_cfg, - &map); + len = pctrl->data->vddio_ops->get_schmitt_map(pin, power_cfg, &map); if (len < 0) return len; @@ -486,14 +490,14 @@ static int cv1800_pinctrl_schmitt2reg(struct cv1800_pinctrl *pctrl, return -EINVAL; } -static int cv1800_pinctrl_reg2schmitt(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin, u32 reg) +static int cv1800_pinctrl_reg2schmitt(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 reg) { const u32 *map; int len; - len = pctrl->data->vddio_ops->get_schmitt_map(pin, pctrl->power_cfg, - &map); + len = pctrl->data->vddio_ops->get_schmitt_map(pin, power_cfg, &map); if (len < 0) return len; @@ -506,9 +510,11 @@ static int cv1800_pinctrl_reg2schmitt(struct cv1800_pinctrl *pctrl, static int cv1800_pconf_get(struct pinctrl_dev *pctldev, unsigned int pin_id, unsigned long *config) { - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct cv1800_priv *priv = pctrl->priv_ctrl; int param = pinconf_to_config_param(*config); - struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id); + const struct sophgo_pin *sp = cv1800_get_pin(pctrl, pin_id); + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type; u32 value; u32 arg; @@ -522,28 +528,28 @@ static int cv1800_pconf_get(struct pinctrl_dev *pctldev, if (type == IO_TYPE_ETH || type == IO_TYPE_AUDIO) return -ENOTSUPP; - value = readl(cv1800_pinctrl_get_component_addr(pctrl, &pin->conf)); + value = readl(cv1800_pinctrl_get_component_addr(priv, &pin->conf)); switch (param) { case PIN_CONFIG_BIAS_PULL_DOWN: enabled = FIELD_GET(PIN_IO_PULLDOWN, value); - arg = cv1800_pull_down_typical_resistor(pctrl, pin); + arg = cv1800_pull_down_typical_resistor(pctrl, sp, priv->power_cfg); break; case PIN_CONFIG_BIAS_PULL_UP: enabled = FIELD_GET(PIN_IO_PULLUP, value); - arg = cv1800_pull_up_typical_resistor(pctrl, pin); + arg = cv1800_pull_up_typical_resistor(pctrl, sp, priv->power_cfg); break; case PIN_CONFIG_DRIVE_STRENGTH_UA: enabled = true; arg = FIELD_GET(PIN_IO_DRIVE, value); - ret = cv1800_pinctrl_reg2oc(pctrl, pin, arg); + ret = cv1800_pinctrl_reg2oc(pctrl, sp, priv->power_cfg, arg); if (ret < 0) return ret; arg = ret; break; case PIN_CONFIG_INPUT_SCHMITT_UV: arg = FIELD_GET(PIN_IO_SCHMITT, value); - ret = cv1800_pinctrl_reg2schmitt(pctrl, pin, arg); + ret = cv1800_pinctrl_reg2schmitt(pctrl, sp, priv->power_cfg, arg); if (ret < 0) return ret; arg = ret; @@ -570,12 +576,14 @@ static int cv1800_pconf_get(struct pinctrl_dev *pctldev, return enabled ? 0 : -EINVAL; } -static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin, +static int cv1800_pinconf_compute_config(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, unsigned long *configs, unsigned int num_configs, u32 *value, u32 *mask) { + struct cv1800_priv *priv = pctrl->priv_ctrl; + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); int i; u32 v = 0, m = 0; enum cv1800_pin_io_type type; @@ -604,7 +612,8 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, m |= PIN_IO_PULLUP; break; case PIN_CONFIG_DRIVE_STRENGTH_UA: - ret = cv1800_pinctrl_oc2reg(pctrl, pin, arg); + ret = cv1800_pinctrl_oc2reg(pctrl, sp, + priv->power_cfg, arg); if (ret < 0) return ret; v &= ~PIN_IO_DRIVE; @@ -612,7 +621,8 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, m |= PIN_IO_DRIVE; break; case PIN_CONFIG_INPUT_SCHMITT_UV: - ret = cv1800_pinctrl_schmitt2reg(pctrl, pin, arg); + ret = cv1800_pinctrl_schmitt2reg(pctrl, sp, + priv->power_cfg, arg); if (ret < 0) return ret; v &= ~PIN_IO_SCHMITT; @@ -643,19 +653,22 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, return 0; } -static int cv1800_pin_set_config(struct cv1800_pinctrl *pctrl, +static int cv1800_pin_set_config(struct sophgo_pinctrl *pctrl, unsigned int pin_id, u32 value, u32 mask) { - struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id); + struct cv1800_priv *priv = pctrl->priv_ctrl; + const struct sophgo_pin *sp = cv1800_get_pin(pctrl, pin_id); + struct cv1800_pin *pin; unsigned long flags; void __iomem *addr; u32 reg; - if (!pin) + if (!sp) return -EINVAL; + pin = sophgo_to_cv1800_pin(sp); - addr = cv1800_pinctrl_get_component_addr(pctrl, &pin->conf); + addr = cv1800_pinctrl_get_component_addr(priv, &pin->conf); raw_spin_lock_irqsave(&pctrl->lock, flags); reg = readl(addr); @@ -671,14 +684,14 @@ static int cv1800_pconf_set(struct pinctrl_dev *pctldev, unsigned int pin_id, unsigned long *configs, unsigned int num_configs) { - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id); + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct sophgo_pin *sp = cv1800_get_pin(pctrl, pin_id); u32 value, mask; - if (!pin) - return -ENODEV; + if (!sp) + return -EINVAL; - if (cv1800_pinconf_compute_config(pctrl, pin, + if (cv1800_pinconf_compute_config(pctrl, sp, configs, num_configs, &value, &mask)) return -ENOTSUPP; @@ -691,9 +704,9 @@ static int cv1800_pconf_group_set(struct pinctrl_dev *pctldev, unsigned long *configs, unsigned int num_configs) { - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); const struct group_desc *group; - const struct cv1800_pin_mux_config *pinmuxs; + const struct sophgo_pin_mux_config *pinmuxs; u32 value, mask; int i; @@ -724,33 +737,38 @@ static const struct pinconf_ops cv1800_pconf_ops = { int cv1800_pinctrl_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct cv1800_pinctrl *pctrl; - const struct cv1800_pinctrl_data *pctrl_data; + struct sophgo_pinctrl *pctrl; + struct cv1800_priv *priv; + const struct sophgo_pinctrl_data *pctrl_data; int ret; pctrl_data = device_get_match_data(dev); if (!pctrl_data) return -ENODEV; - if (pctrl_data->npins == 0 || pctrl_data->npd == 0) + if (pctrl_data->npins == 0 || pctrl_data->npds == 0) return dev_err_probe(dev, -EINVAL, "invalid pin data\n"); pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); if (!pctrl) return -ENOMEM; - pctrl->power_cfg = devm_kcalloc(dev, pctrl_data->npd, - sizeof(u32), GFP_KERNEL); - if (!pctrl->power_cfg) + priv = devm_kzalloc(dev, sizeof(struct cv1800_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->power_cfg = devm_kcalloc(dev, pctrl_data->npds, + sizeof(u32), GFP_KERNEL); + if (!priv->power_cfg) return -ENOMEM; - pctrl->regs[0] = devm_platform_ioremap_resource_byname(pdev, "sys"); - if (IS_ERR(pctrl->regs[0])) - return PTR_ERR(pctrl->regs[0]); + priv->regs[0] = devm_platform_ioremap_resource_byname(pdev, "sys"); + if (IS_ERR(priv->regs[0])) + return PTR_ERR(priv->regs[0]); - pctrl->regs[1] = devm_platform_ioremap_resource_byname(pdev, "rtc"); - if (IS_ERR(pctrl->regs[1])) - return PTR_ERR(pctrl->regs[1]); + priv->regs[1] = devm_platform_ioremap_resource_byname(pdev, "rtc"); + if (IS_ERR(priv->regs[1])) + return PTR_ERR(priv->regs[1]); pctrl->pdesc.name = dev_name(dev); pctrl->pdesc.pins = pctrl_data->pins; @@ -761,6 +779,7 @@ int cv1800_pinctrl_probe(struct platform_device *pdev) pctrl->pdesc.owner = THIS_MODULE; pctrl->data = pctrl_data; + pctrl->priv_ctrl = priv; pctrl->dev = dev; raw_spin_lock_init(&pctrl->lock); mutex_init(&pctrl->mutex); @@ -768,11 +787,11 @@ int cv1800_pinctrl_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pctrl); ret = devm_pinctrl_register_and_init(dev, &pctrl->pdesc, - pctrl, &pctrl->pctl_dev); + pctrl, &pctrl->pctrl_dev); if (ret) return dev_err_probe(dev, ret, "fail to register pinctrl driver\n"); - return pinctrl_enable(pctrl->pctl_dev); + return pinctrl_enable(pctrl->pctrl_dev); } EXPORT_SYMBOL_GPL(cv1800_pinctrl_probe); diff --git a/drivers/pinctrl/sophgo/pinctrl-cv18xx.h b/drivers/pinctrl/sophgo/pinctrl-cv18xx.h index 1a9998abb3b7..f095a6e85e52 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv18xx.h +++ b/drivers/pinctrl/sophgo/pinctrl-cv18xx.h @@ -8,13 +8,14 @@ #include #include -#include #include #include #include #include #include +#include "pinctrl-sophgo.h" + enum cv1800_pin_io_type { IO_TYPE_1V8_ONLY = 0, IO_TYPE_1V8_OR_3V3 = 1, @@ -49,48 +50,22 @@ struct cv1800_pinconf { #define CV1800_PIN_FLAG_IO_TYPE(type) \ FIELD_PREP_CONST(CV1800_PIN_IO_TYPE, type) struct cv1800_pin { - u16 pin; - u16 flags; + struct sophgo_pin pin; u8 power_domain; struct cv1800_pinmux mux; struct cv1800_pinmux2 mux2; struct cv1800_pinconf conf; }; +#define sophgo_to_cv1800_pin(_pin) \ + container_of((_pin), struct cv1800_pin, pin) + #define PIN_POWER_STATE_1V8 1800 #define PIN_POWER_STATE_3V3 3300 -/** - * struct cv1800_vddio_cfg_ops - pin vddio operations - * - * @get_pull_up: get resistor for pull up; - * @get_pull_down: get resistor for pull down. - * @get_oc_map: get mapping for typical low level output current value to - * register value map. - * @get_schmitt_map: get mapping for register value to typical schmitt - * threshold. - */ -struct cv1800_vddio_cfg_ops { - int (*get_pull_up)(struct cv1800_pin *pin, const u32 *psmap); - int (*get_pull_down)(struct cv1800_pin *pin, const u32 *psmap); - int (*get_oc_map)(struct cv1800_pin *pin, const u32 *psmap, - const u32 **map); - int (*get_schmitt_map)(struct cv1800_pin *pin, const u32 *psmap, - const u32 **map); -}; - -struct cv1800_pinctrl_data { - const struct pinctrl_pin_desc *pins; - const struct cv1800_pin *pindata; - const char * const *pdnames; - const struct cv1800_vddio_cfg_ops *vddio_ops; - u16 npins; - u16 npd; -}; - -static inline enum cv1800_pin_io_type cv1800_pin_io_type(struct cv1800_pin *pin) +static inline enum cv1800_pin_io_type cv1800_pin_io_type(const struct cv1800_pin *pin) { - return FIELD_GET(CV1800_PIN_IO_TYPE, pin->flags); + return FIELD_GET(CV1800_PIN_IO_TYPE, pin->pin.flags); }; int cv1800_pinctrl_probe(struct platform_device *pdev); @@ -98,9 +73,11 @@ int cv1800_pinctrl_probe(struct platform_device *pdev); #define CV1800_FUNC_PIN(_id, _power_domain, _type, \ _mux_area, _mux_offset, _mux_func_max) \ { \ - .pin = (_id), \ + .pin = { \ + .id = (_id), \ + .flags = CV1800_PIN_FLAG_IO_TYPE(_type), \ + }, \ .power_domain = (_power_domain), \ - .flags = CV1800_PIN_FLAG_IO_TYPE(_type), \ .mux = { \ .area = (_mux_area), \ .offset = (_mux_offset), \ @@ -112,9 +89,11 @@ int cv1800_pinctrl_probe(struct platform_device *pdev); _mux_area, _mux_offset, _mux_func_max, \ _conf_area, _conf_offset) \ { \ - .pin = (_id), \ + .pin = { \ + .id = (_id), \ + .flags = CV1800_PIN_FLAG_IO_TYPE(_type), \ + }, \ .power_domain = (_power_domain), \ - .flags = CV1800_PIN_FLAG_IO_TYPE(_type), \ .mux = { \ .area = (_mux_area), \ .offset = (_mux_offset), \ @@ -132,10 +111,12 @@ int cv1800_pinctrl_probe(struct platform_device *pdev); _mux2_func_max, \ _conf_area, _conf_offset) \ { \ - .pin = (_id), \ + .pin = { \ + .id = (_id), \ + .flags = CV1800_PIN_FLAG_IO_TYPE(_type) | \ + CV1800_PIN_HAVE_MUX2, \ + }, \ .power_domain = (_power_domain), \ - .flags = CV1800_PIN_FLAG_IO_TYPE(_type) | \ - CV1800_PIN_HAVE_MUX2, \ .mux = { \ .area = (_mux_area), \ .offset = (_mux_offset), \ diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2000.c b/drivers/pinctrl/sophgo/pinctrl-sg2000.c index 63c05b4dd68f..a83dae233cdf 100644 --- a/drivers/pinctrl/sophgo/pinctrl-sg2000.c +++ b/drivers/pinctrl/sophgo/pinctrl-sg2000.c @@ -40,8 +40,9 @@ static const char *const sg2000_power_domain_desc[] = { [VDDIO_VIVO] = "VDDIO_VIVO", }; -static int sg2000_get_pull_up(struct cv1800_pin *pin, const u32 *psmap) +static int sg2000_get_pull_up(const struct sophgo_pin *sp, const u32 *psmap) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); u32 pstate = psmap[pin->power_domain]; enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); @@ -60,8 +61,9 @@ static int sg2000_get_pull_up(struct cv1800_pin *pin, const u32 *psmap) return -ENOTSUPP; } -static int sg2000_get_pull_down(struct cv1800_pin *pin, const u32 *psmap) +static int sg2000_get_pull_down(const struct sophgo_pin *sp, const u32 *psmap) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); u32 pstate = psmap[pin->power_domain]; enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); @@ -114,9 +116,10 @@ static const u32 sg2000_eth_oc_map[] = { 17800 }; -static int sg2000_get_oc_map(struct cv1800_pin *pin, const u32 *psmap, +static int sg2000_get_oc_map(const struct sophgo_pin *sp, const u32 *psmap, const u32 **map) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pstate = psmap[pin->power_domain]; @@ -159,9 +162,10 @@ static const u32 sg2000_18od33_3v3_schmitt_map[] = { 1100000 }; -static int sg2000_get_schmitt_map(struct cv1800_pin *pin, const u32 *psmap, +static int sg2000_get_schmitt_map(const struct sophgo_pin *sp, const u32 *psmap, const u32 **map) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pstate = psmap[pin->power_domain]; @@ -183,11 +187,11 @@ static int sg2000_get_schmitt_map(struct cv1800_pin *pin, const u32 *psmap, return -ENOTSUPP; } -static const struct cv1800_vddio_cfg_ops sg2000_vddio_cfg_ops = { +static const struct sophgo_vddio_cfg_ops sg2000_vddio_cfg_ops = { .get_pull_up = sg2000_get_pull_up, .get_pull_down = sg2000_get_pull_down, .get_oc_map = sg2000_get_oc_map, - .get_schmitt_map = sg2000_get_schmitt_map, + .get_schmitt_map = sg2000_get_schmitt_map, }; static const struct pinctrl_pin_desc sg2000_pins[] = { @@ -742,13 +746,14 @@ static const struct cv1800_pin sg2000_pin_data[ARRAY_SIZE(sg2000_pins)] = { CV1800_PINCONF_AREA_RTC, 0x028), }; -static const struct cv1800_pinctrl_data sg2000_pindata = { +static const struct sophgo_pinctrl_data sg2000_pindata = { .pins = sg2000_pins, .pindata = sg2000_pin_data, .pdnames = sg2000_power_domain_desc, .vddio_ops = &sg2000_vddio_cfg_ops, .npins = ARRAY_SIZE(sg2000_pins), - .npd = ARRAY_SIZE(sg2000_power_domain_desc), + .npds = ARRAY_SIZE(sg2000_power_domain_desc), + .pinsize = sizeof(struct cv1800_pin), }; static const struct of_device_id sg2000_pinctrl_ids[] = { diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2002.c b/drivers/pinctrl/sophgo/pinctrl-sg2002.c index 5c49208dcb59..4366486d8b7f 100644 --- a/drivers/pinctrl/sophgo/pinctrl-sg2002.c +++ b/drivers/pinctrl/sophgo/pinctrl-sg2002.c @@ -34,8 +34,9 @@ static const char *const sg2002_power_domain_desc[] = { [VDDIO_SD1] = "VDDIO_SD1", }; -static int sg2002_get_pull_up(struct cv1800_pin *pin, const u32 *psmap) +static int sg2002_get_pull_up(const struct sophgo_pin *sp, const u32 *psmap) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); u32 pstate = psmap[pin->power_domain]; enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); @@ -54,8 +55,9 @@ static int sg2002_get_pull_up(struct cv1800_pin *pin, const u32 *psmap) return -ENOTSUPP; } -static int sg2002_get_pull_down(struct cv1800_pin *pin, const u32 *psmap) +static int sg2002_get_pull_down(const struct sophgo_pin *sp, const u32 *psmap) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); u32 pstate = psmap[pin->power_domain]; enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); @@ -108,9 +110,10 @@ static const u32 sg2002_eth_oc_map[] = { 17800 }; -static int sg2002_get_oc_map(struct cv1800_pin *pin, const u32 *psmap, +static int sg2002_get_oc_map(const struct sophgo_pin *sp, const u32 *psmap, const u32 **map) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pstate = psmap[pin->power_domain]; @@ -153,9 +156,10 @@ static const u32 sg2002_18od33_3v3_schmitt_map[] = { 1100000 }; -static int sg2002_get_schmitt_map(struct cv1800_pin *pin, const u32 *psmap, +static int sg2002_get_schmitt_map(const struct sophgo_pin *sp, const u32 *psmap, const u32 **map) { + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pstate = psmap[pin->power_domain]; @@ -177,11 +181,11 @@ static int sg2002_get_schmitt_map(struct cv1800_pin *pin, const u32 *psmap, return -ENOTSUPP; } -static const struct cv1800_vddio_cfg_ops sg2002_vddio_cfg_ops = { +static const struct sophgo_vddio_cfg_ops sg2002_vddio_cfg_ops = { .get_pull_up = sg2002_get_pull_up, .get_pull_down = sg2002_get_pull_down, .get_oc_map = sg2002_get_oc_map, - .get_schmitt_map = sg2002_get_schmitt_map, + .get_schmitt_map = sg2002_get_schmitt_map, }; static const struct pinctrl_pin_desc sg2002_pins[] = { @@ -513,13 +517,14 @@ static const struct cv1800_pin sg2002_pin_data[ARRAY_SIZE(sg2002_pins)] = { CV1800_PINCONF_AREA_SYS, 0xc84), }; -static const struct cv1800_pinctrl_data sg2002_pindata = { +static const struct sophgo_pinctrl_data sg2002_pindata = { .pins = sg2002_pins, .pindata = sg2002_pin_data, .pdnames = sg2002_power_domain_desc, .vddio_ops = &sg2002_vddio_cfg_ops, .npins = ARRAY_SIZE(sg2002_pins), - .npd = ARRAY_SIZE(sg2002_power_domain_desc), + .npds = ARRAY_SIZE(sg2002_power_domain_desc), + .pinsize = sizeof(struct cv1800_pin), }; static const struct of_device_id sg2002_pinctrl_ids[] = { diff --git a/drivers/pinctrl/sophgo/pinctrl-sophgo.h b/drivers/pinctrl/sophgo/pinctrl-sophgo.h new file mode 100644 index 000000000000..e43b4f30f18a --- /dev/null +++ b/drivers/pinctrl/sophgo/pinctrl-sophgo.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2024 Inochi Amaoto + */ + +#ifndef _PINCTRL_SOPHGO_H +#define _PINCTRL_SOPHGO_H + +#include +#include +#include +#include + +#include "../core.h" + +struct sophgo_pin { + u16 id; + u16 flags; +}; + +struct sophgo_pin_mux_config { + const struct sophgo_pin *pin; + u32 config; +}; + +/** + * struct sophgo_vddio_cfg_ops - pin vddio operations + * + * @get_pull_up: get resistor for pull up; + * @get_pull_down: get resistor for pull down. + * @get_oc_map: get mapping for typical low level output current value to + * register value map. + * @get_schmitt_map: get mapping for register value to typical schmitt + * threshold. + */ +struct sophgo_vddio_cfg_ops { + int (*get_pull_up)(const struct sophgo_pin *pin, const u32 *psmap); + int (*get_pull_down)(const struct sophgo_pin *pin, const u32 *psmap); + int (*get_oc_map)(const struct sophgo_pin *pin, const u32 *psmap, + const u32 **map); + int (*get_schmitt_map)(const struct sophgo_pin *pin, const u32 *psmap, + const u32 **map); +}; + +struct sophgo_pinctrl_data { + const struct pinctrl_pin_desc *pins; + const void *pindata; + const char * const *pdnames; + const struct sophgo_vddio_cfg_ops *vddio_ops; + u16 npins; + u16 npds; + u16 pinsize; +}; + +struct sophgo_pinctrl { + struct device *dev; + struct pinctrl_dev *pctrl_dev; + const struct sophgo_pinctrl_data *data; + struct pinctrl_desc pdesc; + + struct mutex mutex; + raw_spinlock_t lock; + void *priv_ctrl; +}; + +#endif /* _PINCTRL_SOPHGO_H */ -- cgit v1.2.3-59-g8ed1b From 96406fa941e2ed3e0efdceb7918ceba9e591bbb5 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Tue, 11 Feb 2025 13:17:51 +0800 Subject: pinctrl: sophgo: generalize shareable code of cv18xx pinctrl driver With generic data structure, it is possible to generalize vddio operators and DT parsing code of cv18xx pinctrl driver. Introduce sophgo_cfg_ops callback to allow the driver to adjust the soc logic and share common code. Signed-off-by: Inochi Amaoto Link: https://lore.kernel.org/20250211051801.470800-4-inochiama@gmail.com Signed-off-by: Linus Walleij --- drivers/pinctrl/sophgo/Kconfig | 19 +- drivers/pinctrl/sophgo/Makefile | 5 +- drivers/pinctrl/sophgo/pinctrl-cv1800b.c | 1 + drivers/pinctrl/sophgo/pinctrl-cv1812h.c | 1 + drivers/pinctrl/sophgo/pinctrl-cv18xx.c | 423 ++++--------------------- drivers/pinctrl/sophgo/pinctrl-cv18xx.h | 2 + drivers/pinctrl/sophgo/pinctrl-sg2000.c | 1 + drivers/pinctrl/sophgo/pinctrl-sg2002.c | 1 + drivers/pinctrl/sophgo/pinctrl-sophgo-common.c | 404 +++++++++++++++++++++++ drivers/pinctrl/sophgo/pinctrl-sophgo.h | 63 ++++ 10 files changed, 545 insertions(+), 375 deletions(-) create mode 100644 drivers/pinctrl/sophgo/pinctrl-sophgo-common.c (limited to 'drivers') diff --git a/drivers/pinctrl/sophgo/Kconfig b/drivers/pinctrl/sophgo/Kconfig index c05f909a8838..f473ece940ab 100644 --- a/drivers/pinctrl/sophgo/Kconfig +++ b/drivers/pinctrl/sophgo/Kconfig @@ -3,17 +3,21 @@ # Sophgo SoC PINCTRL drivers # -config PINCTRL_SOPHGO_CV18XX - bool +config PINCTRL_SOPHGO_COMMON + tristate select GENERIC_PINCTRL_GROUPS select GENERIC_PINMUX_FUNCTIONS select GENERIC_PINCONF +config PINCTRL_SOPHGO_CV18XX_OPS + bool + config PINCTRL_SOPHGO_CV1800B tristate "Sophgo CV1800B SoC Pinctrl driver" depends on ARCH_SOPHGO || COMPILE_TEST depends on OF - select PINCTRL_SOPHGO_CV18XX + select PINCTRL_SOPHGO_COMMON + select PINCTRL_SOPHGO_CV18XX_OPS help Say Y to select the pinctrl driver for CV1800B SoC. This pin controller allows selecting the mux function for @@ -24,7 +28,8 @@ config PINCTRL_SOPHGO_CV1812H tristate "Sophgo CV1812H SoC Pinctrl driver" depends on ARCH_SOPHGO || COMPILE_TEST depends on OF - select PINCTRL_SOPHGO_CV18XX + select PINCTRL_SOPHGO_COMMON + select PINCTRL_SOPHGO_CV18XX_OPS help Say Y to select the pinctrl driver for CV1812H SoC. This pin controller allows selecting the mux function for @@ -35,7 +40,8 @@ config PINCTRL_SOPHGO_SG2000 tristate "Sophgo SG2000 SoC Pinctrl driver" depends on ARCH_SOPHGO || COMPILE_TEST depends on OF - select PINCTRL_SOPHGO_CV18XX + select PINCTRL_SOPHGO_COMMON + select PINCTRL_SOPHGO_CV18XX_OPS help Say Y to select the pinctrl driver for SG2000 SoC. This pin controller allows selecting the mux function for @@ -46,7 +52,8 @@ config PINCTRL_SOPHGO_SG2002 tristate "Sophgo SG2002 SoC Pinctrl driver" depends on ARCH_SOPHGO || COMPILE_TEST depends on OF - select PINCTRL_SOPHGO_CV18XX + select PINCTRL_SOPHGO_COMMON + select PINCTRL_SOPHGO_CV18XX_OPS help Say Y to select the pinctrl driver for SG2002 SoC. This pin controller allows selecting the mux function for diff --git a/drivers/pinctrl/sophgo/Makefile b/drivers/pinctrl/sophgo/Makefile index 4113a5c9191b..5f24550750d6 100644 --- a/drivers/pinctrl/sophgo/Makefile +++ b/drivers/pinctrl/sophgo/Makefile @@ -1,6 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_PINCTRL_SOPHGO_CV18XX) += pinctrl-cv18xx.o +obj-$(CONFIG_PINCTRL_SOPHGO_COMMON) += pinctrl-sophgo.o +pinctrl-sophgo-objs += pinctrl-sophgo-common.o +pinctrl-sophgo-$(CONFIG_PINCTRL_SOPHGO_CV18XX_OPS) += pinctrl-cv18xx.o + obj-$(CONFIG_PINCTRL_SOPHGO_CV1800B) += pinctrl-cv1800b.o obj-$(CONFIG_PINCTRL_SOPHGO_CV1812H) += pinctrl-cv1812h.o obj-$(CONFIG_PINCTRL_SOPHGO_SG2000) += pinctrl-sg2000.o diff --git a/drivers/pinctrl/sophgo/pinctrl-cv1800b.c b/drivers/pinctrl/sophgo/pinctrl-cv1800b.c index 45529e2ed23a..ca6fb374ee15 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv1800b.c +++ b/drivers/pinctrl/sophgo/pinctrl-cv1800b.c @@ -442,6 +442,7 @@ static const struct sophgo_pinctrl_data cv1800b_pindata = { .pindata = cv1800b_pin_data, .pdnames = cv1800b_power_domain_desc, .vddio_ops = &cv1800b_vddio_cfg_ops, + .cfg_ops = &cv1800_cfg_ops, .npins = ARRAY_SIZE(cv1800b_pins), .npds = ARRAY_SIZE(cv1800b_power_domain_desc), .pinsize = sizeof(struct cv1800_pin), diff --git a/drivers/pinctrl/sophgo/pinctrl-cv1812h.c b/drivers/pinctrl/sophgo/pinctrl-cv1812h.c index 4e30a1cc9d7d..df2c2697a1fd 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv1812h.c +++ b/drivers/pinctrl/sophgo/pinctrl-cv1812h.c @@ -751,6 +751,7 @@ static const struct sophgo_pinctrl_data cv1812h_pindata = { .pindata = cv1812h_pin_data, .pdnames = cv1812h_power_domain_desc, .vddio_ops = &cv1812h_vddio_cfg_ops, + .cfg_ops = &cv1800_cfg_ops, .npins = ARRAY_SIZE(cv1812h_pins), .npds = ARRAY_SIZE(cv1812h_power_domain_desc), .pinsize = sizeof(struct cv1800_pin), diff --git a/drivers/pinctrl/sophgo/pinctrl-cv18xx.c b/drivers/pinctrl/sophgo/pinctrl-cv18xx.c index 573e00d2c752..66111110c4b3 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv18xx.c +++ b/drivers/pinctrl/sophgo/pinctrl-cv18xx.c @@ -34,11 +34,6 @@ struct cv1800_priv { void __iomem *regs[2]; }; -static unsigned int cv1800_dt_get_pin(u32 value) -{ - return value & GENMASK(15, 0); -} - static unsigned int cv1800_dt_get_pin_mux(u32 value) { return (value >> 16) & GENMASK(7, 0); @@ -52,15 +47,6 @@ static unsigned int cv1800_dt_get_pin_mux2(u32 value) #define cv1800_pinctrl_get_component_addr(pctrl, _comp) \ ((pctrl)->regs[(_comp)->area] + (_comp)->offset) -static int cv1800_cmp_pin(const void *key, const void *pivot) -{ - const struct sophgo_pin *pin = pivot; - int pin_id = (long)key; - int pivid = pin->id; - - return pin_id - pivid; -} - static int cv1800_set_power_cfg(struct sophgo_pinctrl *pctrl, u8 domain, u32 cfg) { @@ -85,13 +71,6 @@ static int cv1800_get_power_cfg(struct sophgo_pinctrl *pctrl, return priv->power_cfg[domain]; } -static const struct sophgo_pin *cv1800_get_pin(struct sophgo_pinctrl *pctrl, - unsigned long pin) -{ - return bsearch((void *)pin, pctrl->data->pindata, pctrl->data->npins, - pctrl->data->pinsize, cv1800_cmp_pin); -} - #define PIN_BGA_ID_OFFSET 8 #define PIN_BGA_ID_MASK 0xff @@ -113,7 +92,7 @@ static void cv1800_pctrl_dbg_show(struct pinctrl_dev *pctldev, { struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); struct cv1800_priv *priv = pctrl->priv_ctrl; - const struct sophgo_pin *sp = cv1800_get_pin(pctrl, pin_id); + const struct sophgo_pin *sp = sophgo_get_pin(pctrl, pin_id); const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); u32 pin_hwid = pin->pin.id; @@ -172,7 +151,7 @@ static int cv1800_verify_pinmux_config(const struct sophgo_pin_mux_config *confi } static int cv1800_verify_pin_group(const struct sophgo_pin_mux_config *mux, - unsigned long npins) + unsigned int npins) { struct cv1800_pin *pin; enum cv1800_pin_io_type type; @@ -197,165 +176,23 @@ static int cv1800_verify_pin_group(const struct sophgo_pin_mux_config *mux, return 0; } -static int cv1800_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, - struct device_node *np, - struct pinctrl_map **maps, - unsigned int *num_maps) +static int cv1800_dt_node_to_map_post(struct device_node *cur, + struct sophgo_pinctrl *pctrl, + struct sophgo_pin_mux_config *pinmuxs, + unsigned int npins) { - struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - struct device *dev = pctrl->dev; - struct device_node *child; - struct pinctrl_map *map; - const char **grpnames; - const char *grpname; - int ngroups = 0; - int nmaps = 0; + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(pinmuxs[0].pin); + u32 power; int ret; - for_each_available_child_of_node(np, child) - ngroups += 1; - - grpnames = devm_kcalloc(dev, ngroups, sizeof(*grpnames), GFP_KERNEL); - if (!grpnames) - return -ENOMEM; - - map = kcalloc(ngroups * 2, sizeof(*map), GFP_KERNEL); - if (!map) - return -ENOMEM; - - ngroups = 0; - mutex_lock(&pctrl->mutex); - for_each_available_child_of_node(np, child) { - int npins = of_property_count_u32_elems(child, "pinmux"); - unsigned int *pins; - struct sophgo_pin_mux_config *pinmuxs; - struct cv1800_pin *pin; - u32 config, power; - int i; - - if (npins < 1) { - dev_err(dev, "invalid pinctrl group %pOFn.%pOFn\n", - np, child); - ret = -EINVAL; - goto dt_failed; - } - - grpname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", - np, child); - if (!grpname) { - ret = -ENOMEM; - goto dt_failed; - } - - grpnames[ngroups++] = grpname; - - pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); - if (!pins) { - ret = -ENOMEM; - goto dt_failed; - } - - pinmuxs = devm_kcalloc(dev, npins, sizeof(*pinmuxs), GFP_KERNEL); - if (!pinmuxs) { - ret = -ENOMEM; - goto dt_failed; - } - - for (i = 0; i < npins; i++) { - ret = of_property_read_u32_index(child, "pinmux", - i, &config); - if (ret) - goto dt_failed; - - pins[i] = cv1800_dt_get_pin(config); - pinmuxs[i].config = config; - pinmuxs[i].pin = cv1800_get_pin(pctrl, pins[i]); - - if (!pinmuxs[i].pin) { - dev_err(dev, "failed to get pin %d\n", pins[i]); - ret = -ENODEV; - goto dt_failed; - } - - ret = cv1800_verify_pinmux_config(&pinmuxs[i]); - if (ret) { - dev_err(dev, "group %s pin %d is invalid\n", - grpname, i); - goto dt_failed; - } - } - - ret = cv1800_verify_pin_group(pinmuxs, npins); - if (ret) { - dev_err(dev, "group %s is invalid\n", grpname); - goto dt_failed; - } - - ret = of_property_read_u32(child, "power-source", &power); - if (ret) - goto dt_failed; - - if (!(power == PIN_POWER_STATE_3V3 || power == PIN_POWER_STATE_1V8)) { - dev_err(dev, "group %s have unsupported power: %u\n", - grpname, power); - ret = -ENOTSUPP; - goto dt_failed; - } - - pin = sophgo_to_cv1800_pin(pinmuxs[0].pin); - ret = cv1800_set_power_cfg(pctrl, pin->power_domain, power); - if (ret) - goto dt_failed; - - map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP; - map[nmaps].data.mux.function = np->name; - map[nmaps].data.mux.group = grpname; - nmaps += 1; - - ret = pinconf_generic_parse_dt_config(child, pctldev, - &map[nmaps].data.configs.configs, - &map[nmaps].data.configs.num_configs); - if (ret) { - dev_err(dev, "failed to parse pin config of group %s: %d\n", - grpname, ret); - goto dt_failed; - } - - ret = pinctrl_generic_add_group(pctldev, grpname, - pins, npins, pinmuxs); - if (ret < 0) { - dev_err(dev, "failed to add group %s: %d\n", grpname, ret); - goto dt_failed; - } - - /* don't create a map if there are no pinconf settings */ - if (map[nmaps].data.configs.num_configs == 0) - continue; - - map[nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; - map[nmaps].data.configs.group_or_pin = grpname; - nmaps += 1; - } - - ret = pinmux_generic_add_function(pctldev, np->name, - grpnames, ngroups, NULL); - if (ret < 0) { - dev_err(dev, "error adding function %s: %d\n", np->name, ret); - goto function_failed; - } - - *maps = map; - *num_maps = nmaps; - mutex_unlock(&pctrl->mutex); + ret = of_property_read_u32(cur, "power-source", &power); + if (ret) + return ret; - return 0; + if (!(power == PIN_POWER_STATE_3V3 || power == PIN_POWER_STATE_1V8)) + return -ENOTSUPP; -dt_failed: - of_node_put(child); -function_failed: - pinctrl_utils_free_map(pctldev, map, nmaps); - mutex_unlock(&pctrl->mutex); - return ret; + return cv1800_set_power_cfg(pctrl, pin->power_domain, power); } static const struct pinctrl_ops cv1800_pctrl_ops = { @@ -363,54 +200,35 @@ static const struct pinctrl_ops cv1800_pctrl_ops = { .get_group_name = pinctrl_generic_get_group_name, .get_group_pins = pinctrl_generic_get_group_pins, .pin_dbg_show = cv1800_pctrl_dbg_show, - .dt_node_to_map = cv1800_pctrl_dt_node_to_map, + .dt_node_to_map = sophgo_pctrl_dt_node_to_map, .dt_free_map = pinctrl_utils_free_map, }; -static int cv1800_pmx_set_mux(struct pinctrl_dev *pctldev, - unsigned int fsel, unsigned int gsel) +static void cv1800_set_pinmux_config(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, u32 config) { - struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); struct cv1800_priv *priv = pctrl->priv_ctrl; - const struct group_desc *group; - const struct sophgo_pin_mux_config *configs; - unsigned int i; - - group = pinctrl_generic_get_group(pctldev, gsel); - if (!group) - return -EINVAL; - - configs = group->data; - - for (i = 0; i < group->grp.npins; i++) { - const struct cv1800_pin *pin = sophgo_to_cv1800_pin(configs[i].pin); - u32 value = configs[i].config; - void __iomem *reg_mux; - void __iomem *reg_mux2; - unsigned long flags; - u32 mux; - u32 mux2; - - reg_mux = cv1800_pinctrl_get_component_addr(priv, &pin->mux); - reg_mux2 = cv1800_pinctrl_get_component_addr(priv, &pin->mux2); - mux = cv1800_dt_get_pin_mux(value); - mux2 = cv1800_dt_get_pin_mux2(value); - - raw_spin_lock_irqsave(&pctrl->lock, flags); - writel_relaxed(mux, reg_mux); - if (mux2 != PIN_MUX_INVALD) - writel_relaxed(mux2, reg_mux2); - raw_spin_unlock_irqrestore(&pctrl->lock, flags); - } - - return 0; + void __iomem *reg_mux; + void __iomem *reg_mux2; + u32 mux; + u32 mux2; + + reg_mux = cv1800_pinctrl_get_component_addr(priv, &pin->mux); + reg_mux2 = cv1800_pinctrl_get_component_addr(priv, &pin->mux2); + mux = cv1800_dt_get_pin_mux(config); + mux2 = cv1800_dt_get_pin_mux2(config); + + writel_relaxed(mux, reg_mux); + if (mux2 != PIN_MUX_INVALD) + writel_relaxed(mux2, reg_mux2); } static const struct pinmux_ops cv1800_pmx_ops = { .get_functions_count = pinmux_generic_get_function_count, .get_function_name = pinmux_generic_get_function_name, .get_function_groups = pinmux_generic_get_function_groups, - .set_mux = cv1800_pmx_set_mux, + .set_mux = sophgo_pmx_set_mux, .strict = true, }; @@ -421,99 +239,13 @@ static const struct pinmux_ops cv1800_pmx_ops = { #define PIN_IO_BUS_HOLD BIT(10) #define PIN_IO_OUT_FAST_SLEW BIT(11) -static u32 cv1800_pull_down_typical_resistor(struct sophgo_pinctrl *pctrl, - const struct sophgo_pin *pin, - const u32 *power_cfg) -{ - return pctrl->data->vddio_ops->get_pull_down(pin, power_cfg); -} - -static u32 cv1800_pull_up_typical_resistor(struct sophgo_pinctrl *pctrl, - const struct sophgo_pin *pin, - const u32 *power_cfg) -{ - return pctrl->data->vddio_ops->get_pull_up(pin, power_cfg); -} - -static int cv1800_pinctrl_oc2reg(struct sophgo_pinctrl *pctrl, - const struct sophgo_pin *pin, - const u32 *power_cfg, u32 target) -{ - const u32 *map; - int i, len; - - len = pctrl->data->vddio_ops->get_oc_map(pin, power_cfg, &map); - if (len < 0) - return len; - - for (i = 0; i < len; i++) { - if (map[i] >= target) - return i; - } - - return -EINVAL; -} - -static int cv1800_pinctrl_reg2oc(struct sophgo_pinctrl *pctrl, - const struct sophgo_pin *pin, - const u32 *power_cfg, u32 reg) -{ - const u32 *map; - int len; - - len = pctrl->data->vddio_ops->get_oc_map(pin, power_cfg, &map); - if (len < 0) - return len; - - if (reg >= len) - return -EINVAL; - - return map[reg]; -} - -static int cv1800_pinctrl_schmitt2reg(struct sophgo_pinctrl *pctrl, - const struct sophgo_pin *pin, - const u32 *power_cfg, u32 target) -{ - const u32 *map; - int i, len; - - len = pctrl->data->vddio_ops->get_schmitt_map(pin, power_cfg, &map); - if (len < 0) - return len; - - for (i = 0; i < len; i++) { - if (map[i] == target) - return i; - } - - return -EINVAL; -} - -static int cv1800_pinctrl_reg2schmitt(struct sophgo_pinctrl *pctrl, - const struct sophgo_pin *pin, - const u32 *power_cfg, u32 reg) -{ - const u32 *map; - int len; - - len = pctrl->data->vddio_ops->get_schmitt_map(pin, power_cfg, &map); - if (len < 0) - return len; - - if (reg >= len) - return -EINVAL; - - return map[reg]; -} - static int cv1800_pconf_get(struct pinctrl_dev *pctldev, unsigned int pin_id, unsigned long *config) { struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); struct cv1800_priv *priv = pctrl->priv_ctrl; int param = pinconf_to_config_param(*config); - const struct sophgo_pin *sp = cv1800_get_pin(pctrl, pin_id); + const struct sophgo_pin *sp = sophgo_get_pin(pctrl, pin_id); const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type; u32 value; @@ -533,23 +265,23 @@ static int cv1800_pconf_get(struct pinctrl_dev *pctldev, switch (param) { case PIN_CONFIG_BIAS_PULL_DOWN: enabled = FIELD_GET(PIN_IO_PULLDOWN, value); - arg = cv1800_pull_down_typical_resistor(pctrl, sp, priv->power_cfg); + arg = sophgo_pinctrl_typical_pull_down(pctrl, sp, priv->power_cfg); break; case PIN_CONFIG_BIAS_PULL_UP: enabled = FIELD_GET(PIN_IO_PULLUP, value); - arg = cv1800_pull_up_typical_resistor(pctrl, sp, priv->power_cfg); + arg = sophgo_pinctrl_typical_pull_up(pctrl, sp, priv->power_cfg); break; case PIN_CONFIG_DRIVE_STRENGTH_UA: enabled = true; arg = FIELD_GET(PIN_IO_DRIVE, value); - ret = cv1800_pinctrl_reg2oc(pctrl, sp, priv->power_cfg, arg); + ret = sophgo_pinctrl_reg2oc(pctrl, sp, priv->power_cfg, arg); if (ret < 0) return ret; arg = ret; break; case PIN_CONFIG_INPUT_SCHMITT_UV: arg = FIELD_GET(PIN_IO_SCHMITT, value); - ret = cv1800_pinctrl_reg2schmitt(pctrl, sp, priv->power_cfg, arg); + ret = sophgo_pinctrl_reg2schmitt(pctrl, sp, priv->power_cfg, arg); if (ret < 0) return ret; arg = ret; @@ -612,7 +344,7 @@ static int cv1800_pinconf_compute_config(struct sophgo_pinctrl *pctrl, m |= PIN_IO_PULLUP; break; case PIN_CONFIG_DRIVE_STRENGTH_UA: - ret = cv1800_pinctrl_oc2reg(pctrl, sp, + ret = sophgo_pinctrl_oc2reg(pctrl, sp, priv->power_cfg, arg); if (ret < 0) return ret; @@ -621,7 +353,7 @@ static int cv1800_pinconf_compute_config(struct sophgo_pinctrl *pctrl, m |= PIN_IO_DRIVE; break; case PIN_CONFIG_INPUT_SCHMITT_UV: - ret = cv1800_pinctrl_schmitt2reg(pctrl, sp, + ret = sophgo_pinctrl_schmitt2reg(pctrl, sp, priv->power_cfg, arg); if (ret < 0) return ret; @@ -653,84 +385,29 @@ static int cv1800_pinconf_compute_config(struct sophgo_pinctrl *pctrl, return 0; } -static int cv1800_pin_set_config(struct sophgo_pinctrl *pctrl, - unsigned int pin_id, - u32 value, u32 mask) +static int cv1800_set_pinconf_config(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, + u32 value, u32 mask) { struct cv1800_priv *priv = pctrl->priv_ctrl; - const struct sophgo_pin *sp = cv1800_get_pin(pctrl, pin_id); - struct cv1800_pin *pin; - unsigned long flags; + struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); void __iomem *addr; u32 reg; - if (!sp) - return -EINVAL; - pin = sophgo_to_cv1800_pin(sp); - addr = cv1800_pinctrl_get_component_addr(priv, &pin->conf); - raw_spin_lock_irqsave(&pctrl->lock, flags); reg = readl(addr); reg &= ~mask; reg |= value; writel(reg, addr); - raw_spin_unlock_irqrestore(&pctrl->lock, flags); - - return 0; -} - -static int cv1800_pconf_set(struct pinctrl_dev *pctldev, - unsigned int pin_id, unsigned long *configs, - unsigned int num_configs) -{ - struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - const struct sophgo_pin *sp = cv1800_get_pin(pctrl, pin_id); - u32 value, mask; - - if (!sp) - return -EINVAL; - - if (cv1800_pinconf_compute_config(pctrl, sp, - configs, num_configs, - &value, &mask)) - return -ENOTSUPP; - - return cv1800_pin_set_config(pctrl, pin_id, value, mask); -} - -static int cv1800_pconf_group_set(struct pinctrl_dev *pctldev, - unsigned int gsel, - unsigned long *configs, - unsigned int num_configs) -{ - struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - const struct group_desc *group; - const struct sophgo_pin_mux_config *pinmuxs; - u32 value, mask; - int i; - - group = pinctrl_generic_get_group(pctldev, gsel); - if (!group) - return -EINVAL; - - pinmuxs = group->data; - - if (cv1800_pinconf_compute_config(pctrl, pinmuxs[0].pin, - configs, num_configs, - &value, &mask)) - return -ENOTSUPP; - - for (i = 0; i < group->grp.npins; i++) - cv1800_pin_set_config(pctrl, group->grp.pins[i], value, mask); return 0; } static const struct pinconf_ops cv1800_pconf_ops = { .pin_config_get = cv1800_pconf_get, - .pin_config_set = cv1800_pconf_set, - .pin_config_group_set = cv1800_pconf_group_set, + .pin_config_set = sophgo_pconf_set, + .pin_config_group_set = sophgo_pconf_group_set, .is_generic = true, }; @@ -795,3 +472,13 @@ int cv1800_pinctrl_probe(struct platform_device *pdev) return pinctrl_enable(pctrl->pctrl_dev); } EXPORT_SYMBOL_GPL(cv1800_pinctrl_probe); + +const struct sophgo_cfg_ops cv1800_cfg_ops = { + .verify_pinmux_config = cv1800_verify_pinmux_config, + .verify_pin_group = cv1800_verify_pin_group, + .dt_node_to_map_post = cv1800_dt_node_to_map_post, + .compute_pinconf_config = cv1800_pinconf_compute_config, + .set_pinconf_config = cv1800_set_pinconf_config, + .set_pinmux_config = cv1800_set_pinmux_config, +}; +EXPORT_SYMBOL_GPL(cv1800_cfg_ops); diff --git a/drivers/pinctrl/sophgo/pinctrl-cv18xx.h b/drivers/pinctrl/sophgo/pinctrl-cv18xx.h index f095a6e85e52..821e554e550b 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv18xx.h +++ b/drivers/pinctrl/sophgo/pinctrl-cv18xx.h @@ -68,6 +68,8 @@ static inline enum cv1800_pin_io_type cv1800_pin_io_type(const struct cv1800_pin return FIELD_GET(CV1800_PIN_IO_TYPE, pin->pin.flags); }; +extern const struct sophgo_cfg_ops cv1800_cfg_ops; + int cv1800_pinctrl_probe(struct platform_device *pdev); #define CV1800_FUNC_PIN(_id, _power_domain, _type, \ diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2000.c b/drivers/pinctrl/sophgo/pinctrl-sg2000.c index a83dae233cdf..9580bd285699 100644 --- a/drivers/pinctrl/sophgo/pinctrl-sg2000.c +++ b/drivers/pinctrl/sophgo/pinctrl-sg2000.c @@ -751,6 +751,7 @@ static const struct sophgo_pinctrl_data sg2000_pindata = { .pindata = sg2000_pin_data, .pdnames = sg2000_power_domain_desc, .vddio_ops = &sg2000_vddio_cfg_ops, + .cfg_ops = &cv1800_cfg_ops, .npins = ARRAY_SIZE(sg2000_pins), .npds = ARRAY_SIZE(sg2000_power_domain_desc), .pinsize = sizeof(struct cv1800_pin), diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2002.c b/drivers/pinctrl/sophgo/pinctrl-sg2002.c index 4366486d8b7f..e3041a8b8ba6 100644 --- a/drivers/pinctrl/sophgo/pinctrl-sg2002.c +++ b/drivers/pinctrl/sophgo/pinctrl-sg2002.c @@ -522,6 +522,7 @@ static const struct sophgo_pinctrl_data sg2002_pindata = { .pindata = sg2002_pin_data, .pdnames = sg2002_power_domain_desc, .vddio_ops = &sg2002_vddio_cfg_ops, + .cfg_ops = &cv1800_cfg_ops, .npins = ARRAY_SIZE(sg2002_pins), .npds = ARRAY_SIZE(sg2002_power_domain_desc), .pinsize = sizeof(struct cv1800_pin), diff --git a/drivers/pinctrl/sophgo/pinctrl-sophgo-common.c b/drivers/pinctrl/sophgo/pinctrl-sophgo-common.c new file mode 100644 index 000000000000..957d84e75643 --- /dev/null +++ b/drivers/pinctrl/sophgo/pinctrl-sophgo-common.c @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sophgo SoCs pinctrl common ops. + * + * Copyright (C) 2024 Inochi Amaoto + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../pinctrl-utils.h" +#include "../pinconf.h" +#include "../pinmux.h" + +#include "pinctrl-sophgo.h" + +static u16 sophgo_dt_get_pin(u32 value) +{ + return value; +} + +static int sophgo_cmp_pin(const void *key, const void *pivot) +{ + const struct sophgo_pin *pin = pivot; + int pin_id = (long)key; + int pivid = pin->id; + + return pin_id - pivid; +} + +const struct sophgo_pin *sophgo_get_pin(struct sophgo_pinctrl *pctrl, + unsigned long pin_id) +{ + return bsearch((void *)pin_id, pctrl->data->pindata, pctrl->data->npins, + pctrl->data->pinsize, sophgo_cmp_pin); +} + +static int sophgo_verify_pinmux_config(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin_mux_config *config) +{ + if (pctrl->data->cfg_ops->verify_pinmux_config) + return pctrl->data->cfg_ops->verify_pinmux_config(config); + return 0; +} + +static int sophgo_verify_pin_group(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin_mux_config *config, + unsigned int npins) +{ + if (pctrl->data->cfg_ops->verify_pin_group) + return pctrl->data->cfg_ops->verify_pin_group(config, npins); + return 0; +} + +static int sophgo_dt_node_to_map_post(struct device_node *cur, + struct sophgo_pinctrl *pctrl, + struct sophgo_pin_mux_config *config, + unsigned int npins) +{ + if (pctrl->data->cfg_ops->dt_node_to_map_post) + return pctrl->data->cfg_ops->dt_node_to_map_post(cur, pctrl, + config, npins); + return 0; +} + +int sophgo_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np, + struct pinctrl_map **maps, unsigned int *num_maps) +{ + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct device *dev = pctrl->dev; + struct device_node *child; + struct pinctrl_map *map; + const char **grpnames; + const char *grpname; + int ngroups = 0; + int nmaps = 0; + int ret; + + for_each_available_child_of_node(np, child) + ngroups += 1; + + grpnames = devm_kcalloc(dev, ngroups, sizeof(*grpnames), GFP_KERNEL); + if (!grpnames) + return -ENOMEM; + + map = kcalloc(ngroups * 2, sizeof(*map), GFP_KERNEL); + if (!map) + return -ENOMEM; + + ngroups = 0; + guard(mutex)(&pctrl->mutex); + for_each_available_child_of_node(np, child) { + int npins = of_property_count_u32_elems(child, "pinmux"); + unsigned int *pins; + struct sophgo_pin_mux_config *pinmuxs; + u32 config; + int i; + + if (npins < 1) { + dev_err(dev, "invalid pinctrl group %pOFn.%pOFn\n", + np, child); + ret = -EINVAL; + goto dt_failed; + } + + grpname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", + np, child); + if (!grpname) { + ret = -ENOMEM; + goto dt_failed; + } + + grpnames[ngroups++] = grpname; + + pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); + if (!pins) { + ret = -ENOMEM; + goto dt_failed; + } + + pinmuxs = devm_kcalloc(dev, npins, sizeof(*pinmuxs), GFP_KERNEL); + if (!pinmuxs) { + ret = -ENOMEM; + goto dt_failed; + } + + for (i = 0; i < npins; i++) { + ret = of_property_read_u32_index(child, "pinmux", + i, &config); + if (ret) + goto dt_failed; + + pins[i] = sophgo_dt_get_pin(config); + pinmuxs[i].config = config; + pinmuxs[i].pin = sophgo_get_pin(pctrl, pins[i]); + + if (!pinmuxs[i].pin) { + dev_err(dev, "failed to get pin %d\n", pins[i]); + ret = -ENODEV; + goto dt_failed; + } + + ret = sophgo_verify_pinmux_config(pctrl, &pinmuxs[i]); + if (ret) { + dev_err(dev, "group %s pin %d is invalid\n", + grpname, i); + goto dt_failed; + } + } + + ret = sophgo_verify_pin_group(pctrl, pinmuxs, npins); + if (ret) { + dev_err(dev, "group %s is invalid\n", grpname); + goto dt_failed; + } + + ret = sophgo_dt_node_to_map_post(child, pctrl, pinmuxs, npins); + if (ret) + goto dt_failed; + + map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP; + map[nmaps].data.mux.function = np->name; + map[nmaps].data.mux.group = grpname; + nmaps += 1; + + ret = pinconf_generic_parse_dt_config(child, pctldev, + &map[nmaps].data.configs.configs, + &map[nmaps].data.configs.num_configs); + if (ret) { + dev_err(dev, "failed to parse pin config of group %s: %d\n", + grpname, ret); + goto dt_failed; + } + + ret = pinctrl_generic_add_group(pctldev, grpname, + pins, npins, pinmuxs); + if (ret < 0) { + dev_err(dev, "failed to add group %s: %d\n", grpname, ret); + goto dt_failed; + } + + /* don't create a map if there are no pinconf settings */ + if (map[nmaps].data.configs.num_configs == 0) + continue; + + map[nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; + map[nmaps].data.configs.group_or_pin = grpname; + nmaps += 1; + } + + ret = pinmux_generic_add_function(pctldev, np->name, + grpnames, ngroups, NULL); + if (ret < 0) { + dev_err(dev, "error adding function %s: %d\n", np->name, ret); + goto function_failed; + } + + *maps = map; + *num_maps = nmaps; + + return 0; + +dt_failed: + of_node_put(child); +function_failed: + pinctrl_utils_free_map(pctldev, map, nmaps); + return ret; +} + +int sophgo_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned int fsel, unsigned int gsel) +{ + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct group_desc *group; + const struct sophgo_pin_mux_config *configs; + unsigned int i; + + group = pinctrl_generic_get_group(pctldev, gsel); + if (!group) + return -EINVAL; + + configs = group->data; + + for (i = 0; i < group->grp.npins; i++) { + const struct sophgo_pin *pin = configs[i].pin; + u32 value = configs[i].config; + + guard(raw_spinlock_irqsave)(&pctrl->lock); + + pctrl->data->cfg_ops->set_pinmux_config(pctrl, pin, value); + } + + return 0; +} + +static int sophgo_pin_set_config(struct sophgo_pinctrl *pctrl, + unsigned int pin_id, + u32 value, u32 mask) +{ + const struct sophgo_pin *pin = sophgo_get_pin(pctrl, pin_id); + + if (!pin) + return -EINVAL; + + guard(raw_spinlock_irqsave)(&pctrl->lock); + + return pctrl->data->cfg_ops->set_pinconf_config(pctrl, pin, value, mask); +} + +int sophgo_pconf_set(struct pinctrl_dev *pctldev, unsigned int pin_id, + unsigned long *configs, unsigned int num_configs) +{ + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct sophgo_pin *pin = sophgo_get_pin(pctrl, pin_id); + u32 value, mask; + + if (!pin) + return -ENODEV; + + if (pctrl->data->cfg_ops->compute_pinconf_config(pctrl, pin, + configs, num_configs, + &value, &mask)) + return -ENOTSUPP; + + return sophgo_pin_set_config(pctrl, pin_id, value, mask); +} + +int sophgo_pconf_group_set(struct pinctrl_dev *pctldev, unsigned int gsel, + unsigned long *configs, unsigned int num_configs) +{ + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct group_desc *group; + const struct sophgo_pin_mux_config *pinmuxs; + u32 value, mask; + int i; + + group = pinctrl_generic_get_group(pctldev, gsel); + if (!group) + return -EINVAL; + + pinmuxs = group->data; + + if (pctrl->data->cfg_ops->compute_pinconf_config(pctrl, pinmuxs[0].pin, + configs, num_configs, + &value, &mask)) + return -ENOTSUPP; + + for (i = 0; i < group->grp.npins; i++) + sophgo_pin_set_config(pctrl, group->grp.pins[i], value, mask); + + return 0; +} + +u32 sophgo_pinctrl_typical_pull_down(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg) +{ + return pctrl->data->vddio_ops->get_pull_down(pin, power_cfg); +} + +u32 sophgo_pinctrl_typical_pull_up(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg) +{ + return pctrl->data->vddio_ops->get_pull_up(pin, power_cfg); +} + +int sophgo_pinctrl_oc2reg(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 target) +{ + const u32 *map; + int i, len; + + if (!pctrl->data->vddio_ops->get_oc_map) + return -ENOTSUPP; + + len = pctrl->data->vddio_ops->get_oc_map(pin, power_cfg, &map); + if (len < 0) + return len; + + for (i = 0; i < len; i++) { + if (map[i] >= target) + return i; + } + + return -EINVAL; +} + +int sophgo_pinctrl_reg2oc(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 reg) +{ + const u32 *map; + int len; + + if (!pctrl->data->vddio_ops->get_oc_map) + return -ENOTSUPP; + + len = pctrl->data->vddio_ops->get_oc_map(pin, power_cfg, &map); + if (len < 0) + return len; + + if (reg >= len) + return -EINVAL; + + return map[reg]; +} + +int sophgo_pinctrl_schmitt2reg(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 target) +{ + const u32 *map; + int i, len; + + if (!pctrl->data->vddio_ops->get_schmitt_map) + return -ENOTSUPP; + + len = pctrl->data->vddio_ops->get_schmitt_map(pin, power_cfg, &map); + if (len < 0) + return len; + + for (i = 0; i < len; i++) { + if (map[i] == target) + return i; + } + + return -EINVAL; +} + +int sophgo_pinctrl_reg2schmitt(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 reg) +{ + const u32 *map; + int len; + + if (!pctrl->data->vddio_ops->get_schmitt_map) + return -ENOTSUPP; + + len = pctrl->data->vddio_ops->get_schmitt_map(pin, power_cfg, &map); + if (len < 0) + return len; + + if (reg >= len) + return -EINVAL; + + return map[reg]; +} + +MODULE_DESCRIPTION("Common pinctrl helper function for the Sophgo SoC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/sophgo/pinctrl-sophgo.h b/drivers/pinctrl/sophgo/pinctrl-sophgo.h index e43b4f30f18a..f8b094a09f7c 100644 --- a/drivers/pinctrl/sophgo/pinctrl-sophgo.h +++ b/drivers/pinctrl/sophgo/pinctrl-sophgo.h @@ -9,10 +9,13 @@ #include #include #include +#include #include #include "../core.h" +struct sophgo_pinctrl; + struct sophgo_pin { u16 id; u16 flags; @@ -23,6 +26,36 @@ struct sophgo_pin_mux_config { u32 config; }; +/** + * struct sophgo_cfg_ops - pin configuration operations + * + * @verify_pinmux_config: verify the pinmux config for a pin + * @verify_pin_group: verify the whole pinmux group + * @dt_node_to_map_post: post init for the pinmux config map + * @compute_pinconf_config: compute pinconf config + * @set_pinconf_config: set pinconf config (the caller holds lock) + * @set_pinmux_config: set mux config (the caller holds lock) + */ +struct sophgo_cfg_ops { + int (*verify_pinmux_config)(const struct sophgo_pin_mux_config *config); + int (*verify_pin_group)(const struct sophgo_pin_mux_config *pinmuxs, + unsigned int npins); + int (*dt_node_to_map_post)(struct device_node *cur, + struct sophgo_pinctrl *pctrl, + struct sophgo_pin_mux_config *pinmuxs, + unsigned int npins); + int (*compute_pinconf_config)(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, + unsigned long *configs, + unsigned int num_configs, + u32 *value, u32 *mask); + int (*set_pinconf_config)(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, + u32 value, u32 mask); + void (*set_pinmux_config)(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, u32 config); +}; + /** * struct sophgo_vddio_cfg_ops - pin vddio operations * @@ -47,6 +80,7 @@ struct sophgo_pinctrl_data { const void *pindata; const char * const *pdnames; const struct sophgo_vddio_cfg_ops *vddio_ops; + const struct sophgo_cfg_ops *cfg_ops; u16 npins; u16 npds; u16 pinsize; @@ -63,4 +97,33 @@ struct sophgo_pinctrl { void *priv_ctrl; }; +const struct sophgo_pin *sophgo_get_pin(struct sophgo_pinctrl *pctrl, + unsigned long pin_id); +int sophgo_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np, + struct pinctrl_map **maps, unsigned int *num_maps); +int sophgo_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned int fsel, unsigned int gsel); +int sophgo_pconf_set(struct pinctrl_dev *pctldev, unsigned int pin_id, + unsigned long *configs, unsigned int num_configs); +int sophgo_pconf_group_set(struct pinctrl_dev *pctldev, unsigned int gsel, + unsigned long *configs, unsigned int num_configs); +u32 sophgo_pinctrl_typical_pull_down(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg); +u32 sophgo_pinctrl_typical_pull_up(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg); +int sophgo_pinctrl_oc2reg(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 target); +int sophgo_pinctrl_reg2oc(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 reg); +int sophgo_pinctrl_schmitt2reg(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 target); +int sophgo_pinctrl_reg2schmitt(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *pin, + const u32 *power_cfg, u32 reg); + #endif /* _PINCTRL_SOPHGO_H */ -- cgit v1.2.3-59-g8ed1b From 2a85188c2f7a8176e328e86445c6c77613a2fa63 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Tue, 11 Feb 2025 13:17:52 +0800 Subject: pinctrl: sophgo: introduce generic probe function Since different series of the Sophgo chip share a common pinctrl data structure. It is necessary to add a common probe function to alloc the this data structure. Add pctrl_init callback to allow soc to perform its own initialization. Signed-off-by: Inochi Amaoto Link: https://lore.kernel.org/20250211051801.470800-5-inochiama@gmail.com Signed-off-by: Linus Walleij --- drivers/pinctrl/sophgo/pinctrl-cv1800b.c | 5 ++- drivers/pinctrl/sophgo/pinctrl-cv1812h.c | 5 ++- drivers/pinctrl/sophgo/pinctrl-cv18xx.c | 59 ++++++-------------------- drivers/pinctrl/sophgo/pinctrl-cv18xx.h | 5 ++- drivers/pinctrl/sophgo/pinctrl-sg2000.c | 5 ++- drivers/pinctrl/sophgo/pinctrl-sg2002.c | 5 ++- drivers/pinctrl/sophgo/pinctrl-sophgo-common.c | 47 ++++++++++++++++++++ drivers/pinctrl/sophgo/pinctrl-sophgo.h | 7 +++ 8 files changed, 86 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sophgo/pinctrl-cv1800b.c b/drivers/pinctrl/sophgo/pinctrl-cv1800b.c index ca6fb374ee15..82db60212477 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv1800b.c +++ b/drivers/pinctrl/sophgo/pinctrl-cv1800b.c @@ -443,6 +443,9 @@ static const struct sophgo_pinctrl_data cv1800b_pindata = { .pdnames = cv1800b_power_domain_desc, .vddio_ops = &cv1800b_vddio_cfg_ops, .cfg_ops = &cv1800_cfg_ops, + .pctl_ops = &cv1800_pctrl_ops, + .pmx_ops = &cv1800_pmx_ops, + .pconf_ops = &cv1800_pconf_ops, .npins = ARRAY_SIZE(cv1800b_pins), .npds = ARRAY_SIZE(cv1800b_power_domain_desc), .pinsize = sizeof(struct cv1800_pin), @@ -455,7 +458,7 @@ static const struct of_device_id cv1800b_pinctrl_ids[] = { MODULE_DEVICE_TABLE(of, cv1800b_pinctrl_ids); static struct platform_driver cv1800b_pinctrl_driver = { - .probe = cv1800_pinctrl_probe, + .probe = sophgo_pinctrl_probe, .driver = { .name = "cv1800b-pinctrl", .suppress_bind_attrs = true, diff --git a/drivers/pinctrl/sophgo/pinctrl-cv1812h.c b/drivers/pinctrl/sophgo/pinctrl-cv1812h.c index df2c2697a1fd..881a4d7ef589 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv1812h.c +++ b/drivers/pinctrl/sophgo/pinctrl-cv1812h.c @@ -752,6 +752,9 @@ static const struct sophgo_pinctrl_data cv1812h_pindata = { .pdnames = cv1812h_power_domain_desc, .vddio_ops = &cv1812h_vddio_cfg_ops, .cfg_ops = &cv1800_cfg_ops, + .pctl_ops = &cv1800_pctrl_ops, + .pmx_ops = &cv1800_pmx_ops, + .pconf_ops = &cv1800_pconf_ops, .npins = ARRAY_SIZE(cv1812h_pins), .npds = ARRAY_SIZE(cv1812h_power_domain_desc), .pinsize = sizeof(struct cv1800_pin), @@ -764,7 +767,7 @@ static const struct of_device_id cv1812h_pinctrl_ids[] = { MODULE_DEVICE_TABLE(of, cv1812h_pinctrl_ids); static struct platform_driver cv1812h_pinctrl_driver = { - .probe = cv1800_pinctrl_probe, + .probe = sophgo_pinctrl_probe, .driver = { .name = "cv1812h-pinctrl", .suppress_bind_attrs = true, diff --git a/drivers/pinctrl/sophgo/pinctrl-cv18xx.c b/drivers/pinctrl/sophgo/pinctrl-cv18xx.c index 66111110c4b3..c3a2dcf71f2a 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv18xx.c +++ b/drivers/pinctrl/sophgo/pinctrl-cv18xx.c @@ -15,8 +15,6 @@ #include #include -#include -#include #include #include #include @@ -25,7 +23,6 @@ #include #include "../pinctrl-utils.h" -#include "../pinconf.h" #include "../pinmux.h" #include "pinctrl-cv18xx.h" @@ -195,7 +192,7 @@ static int cv1800_dt_node_to_map_post(struct device_node *cur, return cv1800_set_power_cfg(pctrl, pin->power_domain, power); } -static const struct pinctrl_ops cv1800_pctrl_ops = { +const struct pinctrl_ops cv1800_pctrl_ops = { .get_groups_count = pinctrl_generic_get_group_count, .get_group_name = pinctrl_generic_get_group_name, .get_group_pins = pinctrl_generic_get_group_pins, @@ -203,6 +200,7 @@ static const struct pinctrl_ops cv1800_pctrl_ops = { .dt_node_to_map = sophgo_pctrl_dt_node_to_map, .dt_free_map = pinctrl_utils_free_map, }; +EXPORT_SYMBOL_GPL(cv1800_pctrl_ops); static void cv1800_set_pinmux_config(struct sophgo_pinctrl *pctrl, const struct sophgo_pin *sp, u32 config) @@ -224,13 +222,14 @@ static void cv1800_set_pinmux_config(struct sophgo_pinctrl *pctrl, writel_relaxed(mux2, reg_mux2); } -static const struct pinmux_ops cv1800_pmx_ops = { +const struct pinmux_ops cv1800_pmx_ops = { .get_functions_count = pinmux_generic_get_function_count, .get_function_name = pinmux_generic_get_function_name, .get_function_groups = pinmux_generic_get_function_groups, .set_mux = sophgo_pmx_set_mux, .strict = true, }; +EXPORT_SYMBOL_GPL(cv1800_pmx_ops); #define PIN_IO_PULLUP BIT(2) #define PIN_IO_PULLDOWN BIT(3) @@ -404,37 +403,25 @@ static int cv1800_set_pinconf_config(struct sophgo_pinctrl *pctrl, return 0; } -static const struct pinconf_ops cv1800_pconf_ops = { +const struct pinconf_ops cv1800_pconf_ops = { .pin_config_get = cv1800_pconf_get, .pin_config_set = sophgo_pconf_set, .pin_config_group_set = sophgo_pconf_group_set, .is_generic = true, }; +EXPORT_SYMBOL_GPL(cv1800_pconf_ops); -int cv1800_pinctrl_probe(struct platform_device *pdev) +static int cv1800_pinctrl_init(struct platform_device *pdev, + struct sophgo_pinctrl *pctrl) { - struct device *dev = &pdev->dev; - struct sophgo_pinctrl *pctrl; + const struct sophgo_pinctrl_data *pctrl_data = pctrl->data; struct cv1800_priv *priv; - const struct sophgo_pinctrl_data *pctrl_data; - int ret; - - pctrl_data = device_get_match_data(dev); - if (!pctrl_data) - return -ENODEV; - - if (pctrl_data->npins == 0 || pctrl_data->npds == 0) - return dev_err_probe(dev, -EINVAL, "invalid pin data\n"); - - pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); - if (!pctrl) - return -ENOMEM; - priv = devm_kzalloc(dev, sizeof(struct cv1800_priv), GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, sizeof(struct cv1800_priv), GFP_KERNEL); if (!priv) return -ENOMEM; - priv->power_cfg = devm_kcalloc(dev, pctrl_data->npds, + priv->power_cfg = devm_kcalloc(&pdev->dev, pctrl_data->npds, sizeof(u32), GFP_KERNEL); if (!priv->power_cfg) return -ENOMEM; @@ -447,33 +434,13 @@ int cv1800_pinctrl_probe(struct platform_device *pdev) if (IS_ERR(priv->regs[1])) return PTR_ERR(priv->regs[1]); - pctrl->pdesc.name = dev_name(dev); - pctrl->pdesc.pins = pctrl_data->pins; - pctrl->pdesc.npins = pctrl_data->npins; - pctrl->pdesc.pctlops = &cv1800_pctrl_ops; - pctrl->pdesc.pmxops = &cv1800_pmx_ops; - pctrl->pdesc.confops = &cv1800_pconf_ops; - pctrl->pdesc.owner = THIS_MODULE; - - pctrl->data = pctrl_data; pctrl->priv_ctrl = priv; - pctrl->dev = dev; - raw_spin_lock_init(&pctrl->lock); - mutex_init(&pctrl->mutex); - - platform_set_drvdata(pdev, pctrl); - ret = devm_pinctrl_register_and_init(dev, &pctrl->pdesc, - pctrl, &pctrl->pctrl_dev); - if (ret) - return dev_err_probe(dev, ret, - "fail to register pinctrl driver\n"); - - return pinctrl_enable(pctrl->pctrl_dev); + return 0; } -EXPORT_SYMBOL_GPL(cv1800_pinctrl_probe); const struct sophgo_cfg_ops cv1800_cfg_ops = { + .pctrl_init = cv1800_pinctrl_init, .verify_pinmux_config = cv1800_verify_pinmux_config, .verify_pin_group = cv1800_verify_pin_group, .dt_node_to_map_post = cv1800_dt_node_to_map_post, diff --git a/drivers/pinctrl/sophgo/pinctrl-cv18xx.h b/drivers/pinctrl/sophgo/pinctrl-cv18xx.h index 821e554e550b..759c0e604acf 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv18xx.h +++ b/drivers/pinctrl/sophgo/pinctrl-cv18xx.h @@ -68,10 +68,11 @@ static inline enum cv1800_pin_io_type cv1800_pin_io_type(const struct cv1800_pin return FIELD_GET(CV1800_PIN_IO_TYPE, pin->pin.flags); }; +extern const struct pinctrl_ops cv1800_pctrl_ops; +extern const struct pinmux_ops cv1800_pmx_ops; +extern const struct pinconf_ops cv1800_pconf_ops; extern const struct sophgo_cfg_ops cv1800_cfg_ops; -int cv1800_pinctrl_probe(struct platform_device *pdev); - #define CV1800_FUNC_PIN(_id, _power_domain, _type, \ _mux_area, _mux_offset, _mux_func_max) \ { \ diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2000.c b/drivers/pinctrl/sophgo/pinctrl-sg2000.c index 9580bd285699..0e303d2fa104 100644 --- a/drivers/pinctrl/sophgo/pinctrl-sg2000.c +++ b/drivers/pinctrl/sophgo/pinctrl-sg2000.c @@ -752,6 +752,9 @@ static const struct sophgo_pinctrl_data sg2000_pindata = { .pdnames = sg2000_power_domain_desc, .vddio_ops = &sg2000_vddio_cfg_ops, .cfg_ops = &cv1800_cfg_ops, + .pctl_ops = &cv1800_pctrl_ops, + .pmx_ops = &cv1800_pmx_ops, + .pconf_ops = &cv1800_pconf_ops, .npins = ARRAY_SIZE(sg2000_pins), .npds = ARRAY_SIZE(sg2000_power_domain_desc), .pinsize = sizeof(struct cv1800_pin), @@ -764,7 +767,7 @@ static const struct of_device_id sg2000_pinctrl_ids[] = { MODULE_DEVICE_TABLE(of, sg2000_pinctrl_ids); static struct platform_driver sg2000_pinctrl_driver = { - .probe = cv1800_pinctrl_probe, + .probe = sophgo_pinctrl_probe, .driver = { .name = "sg2000-pinctrl", .suppress_bind_attrs = true, diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2002.c b/drivers/pinctrl/sophgo/pinctrl-sg2002.c index e3041a8b8ba6..2443fff1bc00 100644 --- a/drivers/pinctrl/sophgo/pinctrl-sg2002.c +++ b/drivers/pinctrl/sophgo/pinctrl-sg2002.c @@ -523,6 +523,9 @@ static const struct sophgo_pinctrl_data sg2002_pindata = { .pdnames = sg2002_power_domain_desc, .vddio_ops = &sg2002_vddio_cfg_ops, .cfg_ops = &cv1800_cfg_ops, + .pctl_ops = &cv1800_pctrl_ops, + .pmx_ops = &cv1800_pmx_ops, + .pconf_ops = &cv1800_pconf_ops, .npins = ARRAY_SIZE(sg2002_pins), .npds = ARRAY_SIZE(sg2002_power_domain_desc), .pinsize = sizeof(struct cv1800_pin), @@ -535,7 +538,7 @@ static const struct of_device_id sg2002_pinctrl_ids[] = { MODULE_DEVICE_TABLE(of, sg2002_pinctrl_ids); static struct platform_driver sg2002_pinctrl_driver = { - .probe = cv1800_pinctrl_probe, + .probe = sophgo_pinctrl_probe, .driver = { .name = "sg2002-pinctrl", .suppress_bind_attrs = true, diff --git a/drivers/pinctrl/sophgo/pinctrl-sophgo-common.c b/drivers/pinctrl/sophgo/pinctrl-sophgo-common.c index 957d84e75643..7f1fd68db19e 100644 --- a/drivers/pinctrl/sophgo/pinctrl-sophgo-common.c +++ b/drivers/pinctrl/sophgo/pinctrl-sophgo-common.c @@ -400,5 +400,52 @@ int sophgo_pinctrl_reg2schmitt(struct sophgo_pinctrl *pctrl, return map[reg]; } +int sophgo_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sophgo_pinctrl *pctrl; + const struct sophgo_pinctrl_data *pctrl_data; + int ret; + + pctrl_data = device_get_match_data(dev); + if (!pctrl_data) + return -ENODEV; + + if (pctrl_data->npins == 0) + return dev_err_probe(dev, -EINVAL, "invalid pin data\n"); + + pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pctrl->pdesc.name = dev_name(dev); + pctrl->pdesc.pins = pctrl_data->pins; + pctrl->pdesc.npins = pctrl_data->npins; + pctrl->pdesc.pctlops = pctrl_data->pctl_ops; + pctrl->pdesc.pmxops = pctrl_data->pmx_ops; + pctrl->pdesc.confops = pctrl_data->pconf_ops; + pctrl->pdesc.owner = THIS_MODULE; + + pctrl->data = pctrl_data; + pctrl->dev = dev; + raw_spin_lock_init(&pctrl->lock); + mutex_init(&pctrl->mutex); + + ret = pctrl->data->cfg_ops->pctrl_init(pdev, pctrl); + if (ret) + return ret; + + platform_set_drvdata(pdev, pctrl); + + ret = devm_pinctrl_register_and_init(dev, &pctrl->pdesc, + pctrl, &pctrl->pctrl_dev); + if (ret) + return dev_err_probe(dev, ret, + "fail to register pinctrl driver\n"); + + return pinctrl_enable(pctrl->pctrl_dev); +} +EXPORT_SYMBOL_GPL(sophgo_pinctrl_probe); + MODULE_DESCRIPTION("Common pinctrl helper function for the Sophgo SoC"); MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/sophgo/pinctrl-sophgo.h b/drivers/pinctrl/sophgo/pinctrl-sophgo.h index f8b094a09f7c..4cd9b5484894 100644 --- a/drivers/pinctrl/sophgo/pinctrl-sophgo.h +++ b/drivers/pinctrl/sophgo/pinctrl-sophgo.h @@ -29,6 +29,7 @@ struct sophgo_pin_mux_config { /** * struct sophgo_cfg_ops - pin configuration operations * + * @pctrl_init: soc specific init callback * @verify_pinmux_config: verify the pinmux config for a pin * @verify_pin_group: verify the whole pinmux group * @dt_node_to_map_post: post init for the pinmux config map @@ -37,6 +38,8 @@ struct sophgo_pin_mux_config { * @set_pinmux_config: set mux config (the caller holds lock) */ struct sophgo_cfg_ops { + int (*pctrl_init)(struct platform_device *pdev, + struct sophgo_pinctrl *pctrl); int (*verify_pinmux_config)(const struct sophgo_pin_mux_config *config); int (*verify_pin_group)(const struct sophgo_pin_mux_config *pinmuxs, unsigned int npins); @@ -81,6 +84,9 @@ struct sophgo_pinctrl_data { const char * const *pdnames; const struct sophgo_vddio_cfg_ops *vddio_ops; const struct sophgo_cfg_ops *cfg_ops; + const struct pinctrl_ops *pctl_ops; + const struct pinmux_ops *pmx_ops; + const struct pinconf_ops *pconf_ops; u16 npins; u16 npds; u16 pinsize; @@ -125,5 +131,6 @@ int sophgo_pinctrl_schmitt2reg(struct sophgo_pinctrl *pctrl, int sophgo_pinctrl_reg2schmitt(struct sophgo_pinctrl *pctrl, const struct sophgo_pin *pin, const u32 *power_cfg, u32 reg); +int sophgo_pinctrl_probe(struct platform_device *pdev); #endif /* _PINCTRL_SOPHGO_H */ -- cgit v1.2.3-59-g8ed1b From 1e67465d3b74b87c05bfee292f3ff0887808d0e7 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Tue, 11 Feb 2025 13:17:54 +0800 Subject: pinctrl: sophgo: add support for SG2042 SoC Add base driver for SG2042 SoC and pin definition. Signed-off-by: Inochi Amaoto Link: https://lore.kernel.org/20250211051801.470800-7-inochiama@gmail.com Signed-off-by: Linus Walleij --- drivers/pinctrl/sophgo/Kconfig | 15 + drivers/pinctrl/sophgo/Makefile | 2 + drivers/pinctrl/sophgo/pinctrl-sg2042-ops.c | 296 +++++++++++++ drivers/pinctrl/sophgo/pinctrl-sg2042.c | 655 ++++++++++++++++++++++++++++ drivers/pinctrl/sophgo/pinctrl-sg2042.h | 49 +++ 5 files changed, 1017 insertions(+) create mode 100644 drivers/pinctrl/sophgo/pinctrl-sg2042-ops.c create mode 100644 drivers/pinctrl/sophgo/pinctrl-sg2042.c create mode 100644 drivers/pinctrl/sophgo/pinctrl-sg2042.h (limited to 'drivers') diff --git a/drivers/pinctrl/sophgo/Kconfig b/drivers/pinctrl/sophgo/Kconfig index f473ece940ab..94f3646c5d5b 100644 --- a/drivers/pinctrl/sophgo/Kconfig +++ b/drivers/pinctrl/sophgo/Kconfig @@ -59,3 +59,18 @@ config PINCTRL_SOPHGO_SG2002 This pin controller allows selecting the mux function for each pin. This driver can also be built as a module called pinctrl-sg2002. + +config PINCTRL_SOPHGO_SG2042_OPS + bool + +config PINCTRL_SOPHGO_SG2042 + tristate "Sophgo SG2042 SoC Pinctrl driver" + depends on ARCH_SOPHGO || COMPILE_TEST + depends on OF + select PINCTRL_SOPHGO_COMMON + select PINCTRL_SOPHGO_SG2042_OPS + help + Say Y to select the pinctrl driver for SG2042 SoC. + This pin controller allows selecting the mux function for + each pin. This driver can also be built as a module called + pinctrl-sg2042. diff --git a/drivers/pinctrl/sophgo/Makefile b/drivers/pinctrl/sophgo/Makefile index 5f24550750d6..7be7a1006e09 100644 --- a/drivers/pinctrl/sophgo/Makefile +++ b/drivers/pinctrl/sophgo/Makefile @@ -3,8 +3,10 @@ obj-$(CONFIG_PINCTRL_SOPHGO_COMMON) += pinctrl-sophgo.o pinctrl-sophgo-objs += pinctrl-sophgo-common.o pinctrl-sophgo-$(CONFIG_PINCTRL_SOPHGO_CV18XX_OPS) += pinctrl-cv18xx.o +pinctrl-sophgo-$(CONFIG_PINCTRL_SOPHGO_SG2042_OPS) += pinctrl-sg2042-ops.o obj-$(CONFIG_PINCTRL_SOPHGO_CV1800B) += pinctrl-cv1800b.o obj-$(CONFIG_PINCTRL_SOPHGO_CV1812H) += pinctrl-cv1812h.o obj-$(CONFIG_PINCTRL_SOPHGO_SG2000) += pinctrl-sg2000.o obj-$(CONFIG_PINCTRL_SOPHGO_SG2002) += pinctrl-sg2002.o +obj-$(CONFIG_PINCTRL_SOPHGO_SG2042) += pinctrl-sg2042.o diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2042-ops.c b/drivers/pinctrl/sophgo/pinctrl-sg2042-ops.c new file mode 100644 index 000000000000..0526aa3f8438 --- /dev/null +++ b/drivers/pinctrl/sophgo/pinctrl-sg2042-ops.c @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sophgo sg2042 SoCs pinctrl driver. + * + * Copyright (C) 2024 Inochi Amaoto + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../pinctrl-utils.h" +#include "../pinmux.h" + +#include "pinctrl-sg2042.h" + +#define PIN_IO_PULL_ONE_ENABLE BIT(0) +#define PIN_IO_PULL_DIR_UP (BIT(1) | PIN_IO_PULL_ONE_ENABLE) +#define PIN_IO_PULL_DIR_DOWN (0 | PIN_IO_PULL_ONE_ENABLE) +#define PIN_IO_PULL_ONE_MASK GENMASK(1, 0) + +#define PIN_IO_PULL_UP BIT(2) +#define PIN_IO_PULL_UP_DONW BIT(3) +#define PIN_IO_PULL_UP_MASK GENMASK(3, 2) + +#define PIN_IO_MUX GENMASK(5, 4) +#define PIN_IO_DRIVE GENMASK(9, 6) +#define PIN_IO_SCHMITT_ENABLE BIT(10) +#define PIN_IO_OUTPUT_ENABLE BIT(11) + +struct sg2042_priv { + void __iomem *regs; +}; + +static u8 sg2042_dt_get_pin_mux(u32 value) +{ + return value >> 16; +} + +static inline u32 sg2042_get_pin_reg(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp) +{ + struct sg2042_priv *priv = pctrl->priv_ctrl; + const struct sg2042_pin *pin = sophgo_to_sg2042_pin(sp); + void __iomem *reg = priv->regs + pin->offset; + + if (sp->flags & PIN_FLAG_WRITE_HIGH) + return readl(reg) >> 16; + else + return readl(reg) & 0xffff; +} + +static int sg2042_set_pin_reg(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, + u32 value, u32 mask) +{ + struct sg2042_priv *priv = pctrl->priv_ctrl; + const struct sg2042_pin *pin = sophgo_to_sg2042_pin(sp); + void __iomem *reg = priv->regs + pin->offset; + u32 v = readl(reg); + + if (sp->flags & PIN_FLAG_WRITE_HIGH) { + v &= ~(mask << 16); + v |= value << 16; + } else { + v &= ~mask; + v |= value; + } + + writel(v, reg); + + return 0; +} + +static void sg2042_pctrl_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *seq, unsigned int pin_id) +{ + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct sophgo_pin *sp = sophgo_get_pin(pctrl, pin_id); + u32 value, mux; + + value = sg2042_get_pin_reg(pctrl, sp); + mux = FIELD_GET(PIN_IO_MUX, value); + seq_printf(seq, "mux:%u reg:0x%04x ", mux, value); +} + +const struct pinctrl_ops sg2042_pctrl_ops = { + .get_groups_count = pinctrl_generic_get_group_count, + .get_group_name = pinctrl_generic_get_group_name, + .get_group_pins = pinctrl_generic_get_group_pins, + .pin_dbg_show = sg2042_pctrl_dbg_show, + .dt_node_to_map = sophgo_pctrl_dt_node_to_map, + .dt_free_map = pinctrl_utils_free_map, +}; +EXPORT_SYMBOL_GPL(sg2042_pctrl_ops); + +static void sg2042_set_pinmux_config(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, u32 config) +{ + u32 mux = sg2042_dt_get_pin_mux(config); + + if (!(sp->flags & PIN_FLAG_NO_PINMUX)) + sg2042_set_pin_reg(pctrl, sp, mux, PIN_IO_MUX); +} + +const struct pinmux_ops sg2042_pmx_ops = { + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, + .set_mux = sophgo_pmx_set_mux, + .strict = true, +}; +EXPORT_SYMBOL_GPL(sg2042_pmx_ops); + +static int sg2042_pconf_get(struct pinctrl_dev *pctldev, + unsigned int pin_id, unsigned long *config) +{ + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + int param = pinconf_to_config_param(*config); + const struct sophgo_pin *sp = sophgo_get_pin(pctrl, pin_id); + u32 value; + u32 arg; + bool enabled; + int ret; + + if (!sp) + return -EINVAL; + + value = sg2042_get_pin_reg(pctrl, sp); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + if (sp->flags & PIN_FLAG_ONLY_ONE_PULL) + arg = FIELD_GET(PIN_IO_PULL_ONE_ENABLE, value); + else + arg = FIELD_GET(PIN_IO_PULL_UP_MASK, value); + enabled = arg == 0; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (sp->flags & PIN_FLAG_ONLY_ONE_PULL) { + arg = FIELD_GET(PIN_IO_PULL_ONE_MASK, value); + enabled = arg == PIN_IO_PULL_DIR_DOWN; + } else { + enabled = FIELD_GET(PIN_IO_PULL_UP_DONW, value) != 0; + } + arg = sophgo_pinctrl_typical_pull_down(pctrl, sp, NULL); + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (sp->flags & PIN_FLAG_ONLY_ONE_PULL) { + arg = FIELD_GET(PIN_IO_PULL_ONE_MASK, value); + enabled = arg == PIN_IO_PULL_DIR_UP; + } else { + enabled = FIELD_GET(PIN_IO_PULL_UP, value) != 0; + } + arg = sophgo_pinctrl_typical_pull_up(pctrl, sp, NULL); + break; + case PIN_CONFIG_DRIVE_STRENGTH_UA: + enabled = FIELD_GET(PIN_IO_OUTPUT_ENABLE, value) != 0; + arg = FIELD_GET(PIN_IO_DRIVE, value); + ret = sophgo_pinctrl_reg2oc(pctrl, sp, NULL, arg); + if (ret < 0) + return ret; + arg = ret; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + arg = FIELD_GET(PIN_IO_SCHMITT_ENABLE, value); + enabled = arg != 0; + break; + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + + return enabled ? 0 : -EINVAL; +} + +static int sg2042_pinconf_compute_config(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, + unsigned long *configs, + unsigned int num_configs, + u32 *value, u32 *mask) +{ + int i; + u16 v = 0, m = 0; + int ret; + + if (!sp) + return -EINVAL; + + for (i = 0; i < num_configs; i++) { + int param = pinconf_to_config_param(configs[i]); + u32 arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + if (sp->flags & PIN_FLAG_ONLY_ONE_PULL) { + v &= ~PIN_IO_PULL_ONE_ENABLE; + m |= PIN_IO_PULL_ONE_ENABLE; + } else { + v &= ~PIN_IO_PULL_UP_MASK; + m |= PIN_IO_PULL_UP_MASK; + } + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (sp->flags & PIN_FLAG_ONLY_ONE_PULL) { + v &= ~PIN_IO_PULL_ONE_MASK; + v |= PIN_IO_PULL_DIR_DOWN; + m |= PIN_IO_PULL_ONE_MASK; + } else { + v |= PIN_IO_PULL_UP_DONW; + m |= PIN_IO_PULL_UP_DONW; + } + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (sp->flags & PIN_FLAG_ONLY_ONE_PULL) { + v &= ~PIN_IO_PULL_ONE_MASK; + v |= PIN_IO_PULL_DIR_UP; + m |= PIN_IO_PULL_ONE_MASK; + } else { + v |= PIN_IO_PULL_UP; + m |= PIN_IO_PULL_UP; + } + break; + case PIN_CONFIG_DRIVE_STRENGTH_UA: + v &= ~(PIN_IO_DRIVE | PIN_IO_OUTPUT_ENABLE); + if (arg != 0) { + ret = sophgo_pinctrl_oc2reg(pctrl, sp, NULL, arg); + if (ret < 0) + return ret; + if (!(sp->flags & PIN_FLAG_NO_OEX_EN)) + v |= PIN_IO_OUTPUT_ENABLE; + v |= FIELD_PREP(PIN_IO_DRIVE, ret); + } + m |= PIN_IO_DRIVE | PIN_IO_OUTPUT_ENABLE; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + v |= PIN_IO_SCHMITT_ENABLE; + m |= PIN_IO_SCHMITT_ENABLE; + break; + default: + return -ENOTSUPP; + } + } + + *value = v; + *mask = m; + + return 0; +} + +const struct pinconf_ops sg2042_pconf_ops = { + .pin_config_get = sg2042_pconf_get, + .pin_config_set = sophgo_pconf_set, + .pin_config_group_set = sophgo_pconf_group_set, + .is_generic = true, +}; +EXPORT_SYMBOL_GPL(sg2042_pconf_ops); + +static int sophgo_pinctrl_init(struct platform_device *pdev, + struct sophgo_pinctrl *pctrl) +{ + struct sg2042_priv *priv; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->regs)) + return PTR_ERR(priv->regs); + + pctrl->priv_ctrl = priv; + + return 0; +} + +const struct sophgo_cfg_ops sg2042_cfg_ops = { + .pctrl_init = sophgo_pinctrl_init, + .compute_pinconf_config = sg2042_pinconf_compute_config, + .set_pinconf_config = sg2042_set_pin_reg, + .set_pinmux_config = sg2042_set_pinmux_config, +}; +EXPORT_SYMBOL_GPL(sg2042_cfg_ops); diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2042.c b/drivers/pinctrl/sophgo/pinctrl-sg2042.c new file mode 100644 index 000000000000..185305ac897d --- /dev/null +++ b/drivers/pinctrl/sophgo/pinctrl-sg2042.c @@ -0,0 +1,655 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sophgo SG2042 SoC pinctrl driver. + * + * Copyright (C) 2024 Inochi Amaoto + */ + +#include +#include +#include + +#include +#include + +#include + +#include "pinctrl-sg2042.h" + +static int sg2042_get_pull_up(const struct sophgo_pin *sp, const u32 *psmap) +{ + return 35000; +} + +static int sg2042_get_pull_down(const struct sophgo_pin *sp, const u32 *psmap) +{ + return 28000; +} + +static const u32 sg2042_oc_map[] = { + 5400, 8100, 10700, 13400, + 16100, 18800, 21400, 24100, + 26800, 29400, 32100, 34800, + 37400, 40100, 42800, 45400 +}; + +static int sg2042_get_oc_map(const struct sophgo_pin *sp, const u32 *psmap, + const u32 **map) +{ + *map = sg2042_oc_map; + return ARRAY_SIZE(sg2042_oc_map); +} + +static const struct sophgo_vddio_cfg_ops sg2042_vddio_cfg_ops = { + .get_pull_up = sg2042_get_pull_up, + .get_pull_down = sg2042_get_pull_down, + .get_oc_map = sg2042_get_oc_map, +}; + +static const struct pinctrl_pin_desc sg2042_pins[] = { + PINCTRL_PIN(PIN_LPC_LCLK, "lpc_lclk"), + PINCTRL_PIN(PIN_LPC_LFRAME, "lpc_lframe"), + PINCTRL_PIN(PIN_LPC_LAD0, "lpc_lad0"), + PINCTRL_PIN(PIN_LPC_LAD1, "lpc_lad1"), + PINCTRL_PIN(PIN_LPC_LAD2, "lpc_lad2"), + PINCTRL_PIN(PIN_LPC_LAD3, "lpc_lad3"), + PINCTRL_PIN(PIN_LPC_LDRQ0, "lpc_ldrq0"), + PINCTRL_PIN(PIN_LPC_LDRQ1, "lpc_ldrq1"), + PINCTRL_PIN(PIN_LPC_SERIRQ, "lpc_serirq"), + PINCTRL_PIN(PIN_LPC_CLKRUN, "lpc_clkrun"), + PINCTRL_PIN(PIN_LPC_LPME, "lpc_lpme"), + PINCTRL_PIN(PIN_LPC_LPCPD, "lpc_lpcpd"), + PINCTRL_PIN(PIN_LPC_LSMI, "lpc_lsmi"), + PINCTRL_PIN(PIN_PCIE0_L0_RESET, "pcie0_l0_reset"), + PINCTRL_PIN(PIN_PCIE0_L1_RESET, "pcie0_l1_reset"), + PINCTRL_PIN(PIN_PCIE0_L0_WAKEUP, "pcie0_l0_wakeup"), + PINCTRL_PIN(PIN_PCIE0_L1_WAKEUP, "pcie0_l1_wakeup"), + PINCTRL_PIN(PIN_PCIE0_L0_CLKREQ_IN, "pcie0_l0_clkreq_in"), + PINCTRL_PIN(PIN_PCIE0_L1_CLKREQ_IN, "pcie0_l1_clkreq_in"), + PINCTRL_PIN(PIN_PCIE1_L0_RESET, "pcie1_l0_reset"), + PINCTRL_PIN(PIN_PCIE1_L1_RESET, "pcie1_l1_reset"), + PINCTRL_PIN(PIN_PCIE1_L0_WAKEUP, "pcie1_l0_wakeup"), + PINCTRL_PIN(PIN_PCIE1_L1_WAKEUP, "pcie1_l1_wakeup"), + PINCTRL_PIN(PIN_PCIE1_L0_CLKREQ_IN, "pcie1_l0_clkreq_in"), + PINCTRL_PIN(PIN_PCIE1_L1_CLKREQ_IN, "pcie1_l1_clkreq_in"), + PINCTRL_PIN(PIN_SPIF0_CLK_SEL1, "spif0_clk_sel1"), + PINCTRL_PIN(PIN_SPIF0_CLK_SEL0, "spif0_clk_sel0"), + PINCTRL_PIN(PIN_SPIF0_WP, "spif0_wp"), + PINCTRL_PIN(PIN_SPIF0_HOLD, "spif0_hold"), + PINCTRL_PIN(PIN_SPIF0_SDI, "spif0_sdi"), + PINCTRL_PIN(PIN_SPIF0_CS, "spif0_cs"), + PINCTRL_PIN(PIN_SPIF0_SCK, "spif0_sck"), + PINCTRL_PIN(PIN_SPIF0_SDO, "spif0_sdo"), + PINCTRL_PIN(PIN_SPIF1_CLK_SEL1, "spif1_clk_sel1"), + PINCTRL_PIN(PIN_SPIF1_CLK_SEL0, "spif1_clk_sel0"), + PINCTRL_PIN(PIN_SPIF1_WP, "spif1_wp"), + PINCTRL_PIN(PIN_SPIF1_HOLD, "spif1_hold"), + PINCTRL_PIN(PIN_SPIF1_SDI, "spif1_sdi"), + PINCTRL_PIN(PIN_SPIF1_CS, "spif1_cs"), + PINCTRL_PIN(PIN_SPIF1_SCK, "spif1_sck"), + PINCTRL_PIN(PIN_SPIF1_SDO, "spif1_sdo"), + PINCTRL_PIN(PIN_EMMC_WP, "emmc_wp"), + PINCTRL_PIN(PIN_EMMC_CD, "emmc_cd"), + PINCTRL_PIN(PIN_EMMC_RST, "emmc_rst"), + PINCTRL_PIN(PIN_EMMC_PWR_EN, "emmc_pwr_en"), + PINCTRL_PIN(PIN_SDIO_CD, "sdio_cd"), + PINCTRL_PIN(PIN_SDIO_WP, "sdio_wp"), + PINCTRL_PIN(PIN_SDIO_RST, "sdio_rst"), + PINCTRL_PIN(PIN_SDIO_PWR_EN, "sdio_pwr_en"), + PINCTRL_PIN(PIN_RGMII0_TXD0, "rgmii0_txd0"), + PINCTRL_PIN(PIN_RGMII0_TXD1, "rgmii0_txd1"), + PINCTRL_PIN(PIN_RGMII0_TXD2, "rgmii0_txd2"), + PINCTRL_PIN(PIN_RGMII0_TXD3, "rgmii0_txd3"), + PINCTRL_PIN(PIN_RGMII0_TXCTRL, "rgmii0_txctrl"), + PINCTRL_PIN(PIN_RGMII0_RXD0, "rgmii0_rxd0"), + PINCTRL_PIN(PIN_RGMII0_RXD1, "rgmii0_rxd1"), + PINCTRL_PIN(PIN_RGMII0_RXD2, "rgmii0_rxd2"), + PINCTRL_PIN(PIN_RGMII0_RXD3, "rgmii0_rxd3"), + PINCTRL_PIN(PIN_RGMII0_RXCTRL, "rgmii0_rxctrl"), + PINCTRL_PIN(PIN_RGMII0_TXC, "rgmii0_txc"), + PINCTRL_PIN(PIN_RGMII0_RXC, "rgmii0_rxc"), + PINCTRL_PIN(PIN_RGMII0_REFCLKO, "rgmii0_refclko"), + PINCTRL_PIN(PIN_RGMII0_IRQ, "rgmii0_irq"), + PINCTRL_PIN(PIN_RGMII0_MDC, "rgmii0_mdc"), + PINCTRL_PIN(PIN_RGMII0_MDIO, "rgmii0_mdio"), + PINCTRL_PIN(PIN_PWM0, "pwm0"), + PINCTRL_PIN(PIN_PWM1, "pwm1"), + PINCTRL_PIN(PIN_PWM2, "pwm2"), + PINCTRL_PIN(PIN_PWM3, "pwm3"), + PINCTRL_PIN(PIN_FAN0, "fan0"), + PINCTRL_PIN(PIN_FAN1, "fan1"), + PINCTRL_PIN(PIN_FAN2, "fan2"), + PINCTRL_PIN(PIN_FAN3, "fan3"), + PINCTRL_PIN(PIN_IIC0_SDA, "iic0_sda"), + PINCTRL_PIN(PIN_IIC0_SCL, "iic0_scl"), + PINCTRL_PIN(PIN_IIC1_SDA, "iic1_sda"), + PINCTRL_PIN(PIN_IIC1_SCL, "iic1_scl"), + PINCTRL_PIN(PIN_IIC2_SDA, "iic2_sda"), + PINCTRL_PIN(PIN_IIC2_SCL, "iic2_scl"), + PINCTRL_PIN(PIN_IIC3_SDA, "iic3_sda"), + PINCTRL_PIN(PIN_IIC3_SCL, "iic3_scl"), + PINCTRL_PIN(PIN_UART0_TX, "uart0_tx"), + PINCTRL_PIN(PIN_UART0_RX, "uart0_rx"), + PINCTRL_PIN(PIN_UART0_RTS, "uart0_rts"), + PINCTRL_PIN(PIN_UART0_CTS, "uart0_cts"), + PINCTRL_PIN(PIN_UART1_TX, "uart1_tx"), + PINCTRL_PIN(PIN_UART1_RX, "uart1_rx"), + PINCTRL_PIN(PIN_UART1_RTS, "uart1_rts"), + PINCTRL_PIN(PIN_UART1_CTS, "uart1_cts"), + PINCTRL_PIN(PIN_UART2_TX, "uart2_tx"), + PINCTRL_PIN(PIN_UART2_RX, "uart2_rx"), + PINCTRL_PIN(PIN_UART2_RTS, "uart2_rts"), + PINCTRL_PIN(PIN_UART2_CTS, "uart2_cts"), + PINCTRL_PIN(PIN_UART3_TX, "uart3_tx"), + PINCTRL_PIN(PIN_UART3_RX, "uart3_rx"), + PINCTRL_PIN(PIN_UART3_RTS, "uart3_rts"), + PINCTRL_PIN(PIN_UART3_CTS, "uart3_cts"), + PINCTRL_PIN(PIN_SPI0_CS0, "spi0_cs0"), + PINCTRL_PIN(PIN_SPI0_CS1, "spi0_cs1"), + PINCTRL_PIN(PIN_SPI0_SDI, "spi0_sdi"), + PINCTRL_PIN(PIN_SPI0_SDO, "spi0_sdo"), + PINCTRL_PIN(PIN_SPI0_SCK, "spi0_sck"), + PINCTRL_PIN(PIN_SPI1_CS0, "spi1_cs0"), + PINCTRL_PIN(PIN_SPI1_CS1, "spi1_cs1"), + PINCTRL_PIN(PIN_SPI1_SDI, "spi1_sdi"), + PINCTRL_PIN(PIN_SPI1_SDO, "spi1_sdo"), + PINCTRL_PIN(PIN_SPI1_SCK, "spi1_sck"), + PINCTRL_PIN(PIN_JTAG0_TDO, "jtag0_tdo"), + PINCTRL_PIN(PIN_JTAG0_TCK, "jtag0_tck"), + PINCTRL_PIN(PIN_JTAG0_TDI, "jtag0_tdi"), + PINCTRL_PIN(PIN_JTAG0_TMS, "jtag0_tms"), + PINCTRL_PIN(PIN_JTAG0_TRST, "jtag0_trst"), + PINCTRL_PIN(PIN_JTAG0_SRST, "jtag0_srst"), + PINCTRL_PIN(PIN_JTAG1_TDO, "jtag1_tdo"), + PINCTRL_PIN(PIN_JTAG1_TCK, "jtag1_tck"), + PINCTRL_PIN(PIN_JTAG1_TDI, "jtag1_tdi"), + PINCTRL_PIN(PIN_JTAG1_TMS, "jtag1_tms"), + PINCTRL_PIN(PIN_JTAG1_TRST, "jtag1_trst"), + PINCTRL_PIN(PIN_JTAG1_SRST, "jtag1_srst"), + PINCTRL_PIN(PIN_JTAG2_TDO, "jtag2_tdo"), + PINCTRL_PIN(PIN_JTAG2_TCK, "jtag2_tck"), + PINCTRL_PIN(PIN_JTAG2_TDI, "jtag2_tdi"), + PINCTRL_PIN(PIN_JTAG2_TMS, "jtag2_tms"), + PINCTRL_PIN(PIN_JTAG2_TRST, "jtag2_trst"), + PINCTRL_PIN(PIN_JTAG2_SRST, "jtag2_srst"), + PINCTRL_PIN(PIN_GPIO0, "gpio0"), + PINCTRL_PIN(PIN_GPIO1, "gpio1"), + PINCTRL_PIN(PIN_GPIO2, "gpio2"), + PINCTRL_PIN(PIN_GPIO3, "gpio3"), + PINCTRL_PIN(PIN_GPIO4, "gpio4"), + PINCTRL_PIN(PIN_GPIO5, "gpio5"), + PINCTRL_PIN(PIN_GPIO6, "gpio6"), + PINCTRL_PIN(PIN_GPIO7, "gpio7"), + PINCTRL_PIN(PIN_GPIO8, "gpio8"), + PINCTRL_PIN(PIN_GPIO9, "gpio9"), + PINCTRL_PIN(PIN_GPIO10, "gpio10"), + PINCTRL_PIN(PIN_GPIO11, "gpio11"), + PINCTRL_PIN(PIN_GPIO12, "gpio12"), + PINCTRL_PIN(PIN_GPIO13, "gpio13"), + PINCTRL_PIN(PIN_GPIO14, "gpio14"), + PINCTRL_PIN(PIN_GPIO15, "gpio15"), + PINCTRL_PIN(PIN_GPIO16, "gpio16"), + PINCTRL_PIN(PIN_GPIO17, "gpio17"), + PINCTRL_PIN(PIN_GPIO18, "gpio18"), + PINCTRL_PIN(PIN_GPIO19, "gpio19"), + PINCTRL_PIN(PIN_GPIO20, "gpio20"), + PINCTRL_PIN(PIN_GPIO21, "gpio21"), + PINCTRL_PIN(PIN_GPIO22, "gpio22"), + PINCTRL_PIN(PIN_GPIO23, "gpio23"), + PINCTRL_PIN(PIN_GPIO24, "gpio24"), + PINCTRL_PIN(PIN_GPIO25, "gpio25"), + PINCTRL_PIN(PIN_GPIO26, "gpio26"), + PINCTRL_PIN(PIN_GPIO27, "gpio27"), + PINCTRL_PIN(PIN_GPIO28, "gpio28"), + PINCTRL_PIN(PIN_GPIO29, "gpio29"), + PINCTRL_PIN(PIN_GPIO30, "gpio30"), + PINCTRL_PIN(PIN_GPIO31, "gpio31"), + PINCTRL_PIN(PIN_MODE_SEL0, "mode_sel0"), + PINCTRL_PIN(PIN_MODE_SEL1, "mode_sel1"), + PINCTRL_PIN(PIN_MODE_SEL2, "mode_sel2"), + PINCTRL_PIN(PIN_BOOT_SEL0, "boot_sel0"), + PINCTRL_PIN(PIN_BOOT_SEL1, "boot_sel1"), + PINCTRL_PIN(PIN_BOOT_SEL2, "boot_sel2"), + PINCTRL_PIN(PIN_BOOT_SEL3, "boot_sel3"), + PINCTRL_PIN(PIN_BOOT_SEL4, "boot_sel4"), + PINCTRL_PIN(PIN_BOOT_SEL5, "boot_sel5"), + PINCTRL_PIN(PIN_BOOT_SEL6, "boot_sel6"), + PINCTRL_PIN(PIN_BOOT_SEL7, "boot_sel7"), + PINCTRL_PIN(PIN_MULTI_SCKT, "multi_sckt"), + PINCTRL_PIN(PIN_SCKT_ID0, "sckt_id0"), + PINCTRL_PIN(PIN_SCKT_ID1, "sckt_id1"), + PINCTRL_PIN(PIN_PLL_CLK_IN_MAIN, "pll_clk_in_main"), + PINCTRL_PIN(PIN_PLL_CLK_IN_DDR_L, "pll_clk_in_ddr_l"), + PINCTRL_PIN(PIN_PLL_CLK_IN_DDR_R, "pll_clk_in_ddr_r"), + PINCTRL_PIN(PIN_XTAL_32K, "xtal_32k"), + PINCTRL_PIN(PIN_SYS_RST, "sys_rst"), + PINCTRL_PIN(PIN_PWR_BUTTON, "pwr_button"), + PINCTRL_PIN(PIN_TEST_EN, "test_en"), + PINCTRL_PIN(PIN_TEST_MODE_MBIST, "test_mode_mbist"), + PINCTRL_PIN(PIN_TEST_MODE_SCAN, "test_mode_scan"), + PINCTRL_PIN(PIN_TEST_MODE_BSD, "test_mode_bsd"), + PINCTRL_PIN(PIN_BISR_BYP, "bisr_byp"), +}; + +static const struct sg2042_pin sg2042_pin_data[ARRAY_SIZE(sg2042_pins)] = { + SG2042_GENERAL_PIN(PIN_LPC_LCLK, 0x000, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LFRAME, 0x000, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LAD0, 0x004, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LAD1, 0x004, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LAD2, 0x008, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LAD3, 0x008, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LDRQ0, 0x00c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LDRQ1, 0x00c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_SERIRQ, 0x010, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_CLKRUN, 0x010, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LPME, 0x014, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LPCPD, 0x014, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_LPC_LSMI, 0x018, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE0_L0_RESET, 0x018, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE0_L1_RESET, 0x01c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE0_L0_WAKEUP, 0x01c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE0_L1_WAKEUP, 0x020, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE0_L0_CLKREQ_IN, 0x020, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE0_L1_CLKREQ_IN, 0x024, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE1_L0_RESET, 0x024, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE1_L1_RESET, 0x028, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE1_L0_WAKEUP, 0x028, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE1_L1_WAKEUP, 0x02c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE1_L0_CLKREQ_IN, 0x02c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PCIE1_L1_CLKREQ_IN, 0x030, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF0_CLK_SEL1, 0x030, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF0_CLK_SEL0, 0x034, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF0_WP, 0x034, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF0_HOLD, 0x038, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF0_SDI, 0x038, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF0_CS, 0x03c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF0_SCK, 0x03c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF0_SDO, 0x040, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF1_CLK_SEL1, 0x040, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF1_CLK_SEL0, 0x044, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF1_WP, 0x044, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF1_HOLD, 0x048, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF1_SDI, 0x048, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF1_CS, 0x04c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF1_SCK, 0x04c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPIF1_SDO, 0x050, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_EMMC_WP, 0x050, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_EMMC_CD, 0x054, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_EMMC_RST, 0x054, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_EMMC_PWR_EN, 0x058, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SDIO_CD, 0x058, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SDIO_WP, 0x05c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SDIO_RST, 0x05c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SDIO_PWR_EN, 0x060, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_RGMII0_TXD0, 0x060, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_TXD1, 0x064, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_TXD2, 0x064, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_TXD3, 0x068, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_TXCTRL, 0x068, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_RXD0, 0x06c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_RXD1, 0x06c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_RXD2, 0x070, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_RXD3, 0x070, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_RXCTRL, 0x074, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_TXC, 0x074, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_RXC, 0x078, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_REFCLKO, 0x078, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_IRQ, 0x07c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_MDC, 0x07c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_MDIO, 0x080, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PWM0, 0x080, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PWM1, 0x084, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PWM2, 0x084, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_PWM3, 0x088, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_FAN0, 0x088, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_FAN1, 0x08c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_FAN2, 0x08c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_FAN3, 0x090, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_IIC0_SDA, 0x090, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC0_SCL, 0x094, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC1_SDA, 0x094, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC1_SCL, 0x098, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC2_SDA, 0x098, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC2_SCL, 0x09c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC3_SDA, 0x09c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC3_SCL, 0x0a0, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART0_TX, 0x0a0, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART0_RX, 0x0a4, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART0_RTS, 0x0a4, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART0_CTS, 0x0a8, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART1_TX, 0x0a8, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART1_RX, 0x0ac, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART1_RTS, 0x0ac, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART1_CTS, 0x0b0, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART2_TX, 0x0b0, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART2_RX, 0x0b4, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART2_RTS, 0x0b4, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART2_CTS, 0x0b8, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART3_TX, 0x0b8, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART3_RX, 0x0bc, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART3_RTS, 0x0bc, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_UART3_CTS, 0x0c0, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI0_CS0, 0x0c0, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI0_CS1, 0x0c4, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI0_SDI, 0x0c4, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI0_SDO, 0x0c8, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI0_SCK, 0x0c8, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI1_CS0, 0x0cc, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI1_CS1, 0x0cc, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI1_SDI, 0x0d0, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI1_SDO, 0x0d0, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_SPI1_SCK, 0x0d4, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG0_TDO, 0x0d4, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG0_TCK, 0x0d8, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG0_TDI, 0x0d8, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG0_TMS, 0x0dc, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG0_TRST, 0x0dc, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG0_SRST, 0x0e0, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG1_TDO, 0x0e0, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG1_TCK, 0x0e4, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG1_TDI, 0x0e4, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG1_TMS, 0x0e8, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG1_TRST, 0x0e8, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG1_SRST, 0x0ec, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG2_TDO, 0x0ec, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG2_TCK, 0x0f0, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG2_TDI, 0x0f0, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG2_TMS, 0x0f4, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG2_TRST, 0x0f4, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_JTAG2_SRST, 0x0f8, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO0, 0x0f8, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO1, 0x0fc, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO2, 0x0fc, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO3, 0x100, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO4, 0x100, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO5, 0x104, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO6, 0x104, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO7, 0x108, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO8, 0x108, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO9, 0x10c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO10, 0x10c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO11, 0x110, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO12, 0x110, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO13, 0x114, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO14, 0x114, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO15, 0x118, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO16, 0x118, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO17, 0x11c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO18, 0x11c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO19, 0x120, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO20, 0x120, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO21, 0x124, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO22, 0x124, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO23, 0x128, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO24, 0x128, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO25, 0x12c, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO26, 0x12c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO27, 0x130, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO28, 0x130, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO29, 0x134, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO30, 0x134, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_GPIO31, 0x138, + PIN_FLAG_ONLY_ONE_PULL), + SG2042_GENERAL_PIN(PIN_MODE_SEL0, 0x138, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_MODE_SEL1, 0x13c, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_MODE_SEL2, 0x13c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL0, 0x140, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL1, 0x140, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL2, 0x144, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL3, 0x144, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL4, 0x148, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL5, 0x148, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL6, 0x14c, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL7, 0x14c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_MULTI_SCKT, 0x150, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_SCKT_ID0, 0x150, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_SCKT_ID1, 0x154, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PLL_CLK_IN_MAIN, 0x154, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PLL_CLK_IN_DDR_L, 0x158, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PLL_CLK_IN_DDR_R, 0x158, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_XTAL_32K, 0x15c, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_SYS_RST, 0x15c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PWR_BUTTON, 0x160, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_TEST_EN, 0x160, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_TEST_MODE_MBIST, 0x164, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_TEST_MODE_SCAN, 0x164, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_TEST_MODE_BSD, 0x168, + PIN_FLAG_ONLY_ONE_PULL | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BISR_BYP, 0x168, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_ONLY_ONE_PULL | + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), +}; + +static const struct sophgo_pinctrl_data sg2042_pindata = { + .pins = sg2042_pins, + .pindata = sg2042_pin_data, + .vddio_ops = &sg2042_vddio_cfg_ops, + .cfg_ops = &sg2042_cfg_ops, + .pctl_ops = &sg2042_pctrl_ops, + .pmx_ops = &sg2042_pmx_ops, + .pconf_ops = &sg2042_pconf_ops, + .npins = ARRAY_SIZE(sg2042_pins), + .pinsize = sizeof(struct sg2042_pin), +}; + +static const struct of_device_id sg2042_pinctrl_ids[] = { + { .compatible = "sophgo,sg2042-pinctrl", .data = &sg2042_pindata }, + { } +}; +MODULE_DEVICE_TABLE(of, sg2042_pinctrl_ids); + +static struct platform_driver sg2042_pinctrl_driver = { + .probe = sophgo_pinctrl_probe, + .driver = { + .name = "sg2042-pinctrl", + .suppress_bind_attrs = true, + .of_match_table = sg2042_pinctrl_ids, + }, +}; +module_platform_driver(sg2042_pinctrl_driver); + +MODULE_DESCRIPTION("Pinctrl driver for the SG2002 series SoC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2042.h b/drivers/pinctrl/sophgo/pinctrl-sg2042.h new file mode 100644 index 000000000000..d481973fcf97 --- /dev/null +++ b/drivers/pinctrl/sophgo/pinctrl-sg2042.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2024 Inochi Amaoto + */ + +#ifndef _PINCTRL_SOPHGO_SG2042_H +#define _PINCTRL_SOPHGO_SG2042_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pinctrl-sophgo.h" + +#define PIN_FLAG_DEFAULT 0 +#define PIN_FLAG_WRITE_HIGH BIT(0) +#define PIN_FLAG_ONLY_ONE_PULL BIT(1) +#define PIN_FLAG_NO_PINMUX BIT(2) +#define PIN_FLAG_NO_OEX_EN BIT(3) +#define PIN_FLAG_IS_ETH BIT(4) + +struct sg2042_pin { + struct sophgo_pin pin; + u16 offset; +}; + +#define sophgo_to_sg2042_pin(_pin) \ + container_of((_pin), struct sg2042_pin, pin) + +extern const struct pinctrl_ops sg2042_pctrl_ops; +extern const struct pinmux_ops sg2042_pmx_ops; +extern const struct pinconf_ops sg2042_pconf_ops; +extern const struct sophgo_cfg_ops sg2042_cfg_ops; + +#define SG2042_GENERAL_PIN(_id, _offset, _flag) \ + { \ + .pin = { \ + .id = (_id), \ + .flags = (_flag), \ + }, \ + .offset = (_offset), \ + } + +#endif -- cgit v1.2.3-59-g8ed1b From 614a54cb5ac3c4883358ea7a2271f4495db7aef9 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Tue, 11 Feb 2025 13:17:55 +0800 Subject: pinctrl: sophgo: add support for SG2044 SoC SG2044 share the share common control logic with SG2042. So only pin definition is needed. Add pin definition driver for SG2044 SoC. Signed-off-by: Inochi Amaoto Link: https://lore.kernel.org/20250211051801.470800-8-inochiama@gmail.com Signed-off-by: Linus Walleij --- drivers/pinctrl/sophgo/Kconfig | 12 + drivers/pinctrl/sophgo/Makefile | 1 + drivers/pinctrl/sophgo/pinctrl-sg2044.c | 718 ++++++++++++++++++++++++++++++++ 3 files changed, 731 insertions(+) create mode 100644 drivers/pinctrl/sophgo/pinctrl-sg2044.c (limited to 'drivers') diff --git a/drivers/pinctrl/sophgo/Kconfig b/drivers/pinctrl/sophgo/Kconfig index 94f3646c5d5b..9b0a3a4753b1 100644 --- a/drivers/pinctrl/sophgo/Kconfig +++ b/drivers/pinctrl/sophgo/Kconfig @@ -74,3 +74,15 @@ config PINCTRL_SOPHGO_SG2042 This pin controller allows selecting the mux function for each pin. This driver can also be built as a module called pinctrl-sg2042. + +config PINCTRL_SOPHGO_SG2044 + tristate "Sophgo SG2044 SoC Pinctrl driver" + depends on ARCH_SOPHGO || COMPILE_TEST + depends on OF + select PINCTRL_SOPHGO_COMMON + select PINCTRL_SOPHGO_SG2042_OPS + help + Say Y to select the pinctrl driver for SG2044 SoC. + This pin controller allows selecting the mux function for + each pin. This driver can also be built as a module called + pinctrl-sg2044. diff --git a/drivers/pinctrl/sophgo/Makefile b/drivers/pinctrl/sophgo/Makefile index 7be7a1006e09..479c65e6dbc0 100644 --- a/drivers/pinctrl/sophgo/Makefile +++ b/drivers/pinctrl/sophgo/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_PINCTRL_SOPHGO_CV1812H) += pinctrl-cv1812h.o obj-$(CONFIG_PINCTRL_SOPHGO_SG2000) += pinctrl-sg2000.o obj-$(CONFIG_PINCTRL_SOPHGO_SG2002) += pinctrl-sg2002.o obj-$(CONFIG_PINCTRL_SOPHGO_SG2042) += pinctrl-sg2042.o +obj-$(CONFIG_PINCTRL_SOPHGO_SG2044) += pinctrl-sg2044.o diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2044.c b/drivers/pinctrl/sophgo/pinctrl-sg2044.c new file mode 100644 index 000000000000..b0c46d8954ca --- /dev/null +++ b/drivers/pinctrl/sophgo/pinctrl-sg2044.c @@ -0,0 +1,718 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sophgo SG2042 SoC pinctrl driver. + * + * Copyright (C) 2024 Inochi Amaoto + */ + +#include +#include +#include + +#include +#include + +#include + +#include "pinctrl-sg2042.h" + +static int sg2044_get_pull_up(const struct sophgo_pin *sp, const u32 *psmap) +{ + return 19500; +} + +static int sg2044_get_pull_down(const struct sophgo_pin *sp, const u32 *psmap) +{ + return 23200; +} + +static const u32 sg2044_oc_map[] = { + 3200, 6400, 9600, 12700, + 15900, 19100, 22200, 25300, + 29500, 32700, 35900, 39000, + 42000, 45200, 48300, 51400 +}; + +static int sg2044_get_oc_map(const struct sophgo_pin *sp, const u32 *psmap, + const u32 **map) +{ + *map = sg2044_oc_map; + return ARRAY_SIZE(sg2044_oc_map); +} + +static const struct sophgo_vddio_cfg_ops sg2044_vddio_cfg_ops = { + .get_pull_up = sg2044_get_pull_up, + .get_pull_down = sg2044_get_pull_down, + .get_oc_map = sg2044_get_oc_map, +}; + +static const struct pinctrl_pin_desc sg2044_pins[] = { + PINCTRL_PIN(PIN_IIC0_SMBSUS_IN, "iic0_smbsus_in"), + PINCTRL_PIN(PIN_IIC0_SMBSUS_OUT, "iic0_smbsus_out"), + PINCTRL_PIN(PIN_IIC0_SMBALERT, "iic0_smbalert"), + PINCTRL_PIN(PIN_IIC1_SMBSUS_IN, "iic1_smbsus_in"), + PINCTRL_PIN(PIN_IIC1_SMBSUS_OUT, "iic1_smbsus_out"), + PINCTRL_PIN(PIN_IIC1_SMBALERT, "iic1_smbalert"), + PINCTRL_PIN(PIN_IIC2_SMBSUS_IN, "iic2_smbsus_in"), + PINCTRL_PIN(PIN_IIC2_SMBSUS_OUT, "iic2_smbsus_out"), + PINCTRL_PIN(PIN_IIC2_SMBALERT, "iic2_smbalert"), + PINCTRL_PIN(PIN_IIC3_SMBSUS_IN, "iic3_smbsus_in"), + PINCTRL_PIN(PIN_IIC3_SMBSUS_OUT, "iic3_smbsus_out"), + PINCTRL_PIN(PIN_IIC3_SMBALERT, "iic3_smbalert"), + PINCTRL_PIN(PIN_PCIE0_L0_RESET, "pcie0_l0_reset"), + PINCTRL_PIN(PIN_PCIE0_L1_RESET, "pcie0_l1_reset"), + PINCTRL_PIN(PIN_PCIE0_L0_WAKEUP, "pcie0_l0_wakeup"), + PINCTRL_PIN(PIN_PCIE0_L1_WAKEUP, "pcie0_l1_wakeup"), + PINCTRL_PIN(PIN_PCIE0_L0_CLKREQ_IN, "pcie0_l0_clkreq_in"), + PINCTRL_PIN(PIN_PCIE0_L1_CLKREQ_IN, "pcie0_l1_clkreq_in"), + PINCTRL_PIN(PIN_PCIE1_L0_RESET, "pcie1_l0_reset"), + PINCTRL_PIN(PIN_PCIE1_L1_RESET, "pcie1_l1_reset"), + PINCTRL_PIN(PIN_PCIE1_L0_WAKEUP, "pcie1_l0_wakeup"), + PINCTRL_PIN(PIN_PCIE1_L1_WAKEUP, "pcie1_l1_wakeup"), + PINCTRL_PIN(PIN_PCIE1_L0_CLKREQ_IN, "pcie1_l0_clkreq_in"), + PINCTRL_PIN(PIN_PCIE1_L1_CLKREQ_IN, "pcie1_l1_clkreq_in"), + PINCTRL_PIN(PIN_PCIE2_L0_RESET, "pcie2_l0_reset"), + PINCTRL_PIN(PIN_PCIE2_L1_RESET, "pcie2_l1_reset"), + PINCTRL_PIN(PIN_PCIE2_L0_WAKEUP, "pcie2_l0_wakeup"), + PINCTRL_PIN(PIN_PCIE2_L1_WAKEUP, "pcie2_l1_wakeup"), + PINCTRL_PIN(PIN_PCIE2_L0_CLKREQ_IN, "pcie2_l0_clkreq_in"), + PINCTRL_PIN(PIN_PCIE2_L1_CLKREQ_IN, "pcie2_l1_clkreq_in"), + PINCTRL_PIN(PIN_PCIE3_L0_RESET, "pcie3_l0_reset"), + PINCTRL_PIN(PIN_PCIE3_L1_RESET, "pcie3_l1_reset"), + PINCTRL_PIN(PIN_PCIE3_L0_WAKEUP, "pcie3_l0_wakeup"), + PINCTRL_PIN(PIN_PCIE3_L1_WAKEUP, "pcie3_l1_wakeup"), + PINCTRL_PIN(PIN_PCIE3_L0_CLKREQ_IN, "pcie3_l0_clkreq_in"), + PINCTRL_PIN(PIN_PCIE3_L1_CLKREQ_IN, "pcie3_l1_clkreq_in"), + PINCTRL_PIN(PIN_PCIE4_L0_RESET, "pcie4_l0_reset"), + PINCTRL_PIN(PIN_PCIE4_L1_RESET, "pcie4_l1_reset"), + PINCTRL_PIN(PIN_PCIE4_L0_WAKEUP, "pcie4_l0_wakeup"), + PINCTRL_PIN(PIN_PCIE4_L1_WAKEUP, "pcie4_l1_wakeup"), + PINCTRL_PIN(PIN_PCIE4_L0_CLKREQ_IN, "pcie4_l0_clkreq_in"), + PINCTRL_PIN(PIN_PCIE4_L1_CLKREQ_IN, "pcie4_l1_clkreq_in"), + PINCTRL_PIN(PIN_SPIF0_CLK_SEL1, "spif0_clk_sel1"), + PINCTRL_PIN(PIN_SPIF0_CLK_SEL0, "spif0_clk_sel0"), + PINCTRL_PIN(PIN_SPIF0_WP, "spif0_wp"), + PINCTRL_PIN(PIN_SPIF0_HOLD, "spif0_hold"), + PINCTRL_PIN(PIN_SPIF0_SDI, "spif0_sdi"), + PINCTRL_PIN(PIN_SPIF0_CS, "spif0_cs"), + PINCTRL_PIN(PIN_SPIF0_SCK, "spif0_sck"), + PINCTRL_PIN(PIN_SPIF0_SDO, "spif0_sdo"), + PINCTRL_PIN(PIN_SPIF1_CLK_SEL1, "spif1_clk_sel1"), + PINCTRL_PIN(PIN_SPIF1_CLK_SEL0, "spif1_clk_sel0"), + PINCTRL_PIN(PIN_SPIF1_WP, "spif1_wp"), + PINCTRL_PIN(PIN_SPIF1_HOLD, "spif1_hold"), + PINCTRL_PIN(PIN_SPIF1_SDI, "spif1_sdi"), + PINCTRL_PIN(PIN_SPIF1_CS, "spif1_cs"), + PINCTRL_PIN(PIN_SPIF1_SCK, "spif1_sck"), + PINCTRL_PIN(PIN_SPIF1_SDO, "spif1_sdo"), + PINCTRL_PIN(PIN_EMMC_WP, "emmc_wp"), + PINCTRL_PIN(PIN_EMMC_CD, "emmc_cd"), + PINCTRL_PIN(PIN_EMMC_RST, "emmc_rst"), + PINCTRL_PIN(PIN_EMMC_PWR_EN, "emmc_pwr_en"), + PINCTRL_PIN(PIN_SDIO_CD, "sdio_cd"), + PINCTRL_PIN(PIN_SDIO_WP, "sdio_wp"), + PINCTRL_PIN(PIN_SDIO_RST, "sdio_rst"), + PINCTRL_PIN(PIN_SDIO_PWR_EN, "sdio_pwr_en"), + PINCTRL_PIN(PIN_RGMII0_TXD0, "rgmii0_txd0"), + PINCTRL_PIN(PIN_RGMII0_TXD1, "rgmii0_txd1"), + PINCTRL_PIN(PIN_RGMII0_TXD2, "rgmii0_txd2"), + PINCTRL_PIN(PIN_RGMII0_TXD3, "rgmii0_txd3"), + PINCTRL_PIN(PIN_RGMII0_TXCTRL, "rgmii0_txctrl"), + PINCTRL_PIN(PIN_RGMII0_RXD0, "rgmii0_rxd0"), + PINCTRL_PIN(PIN_RGMII0_RXD1, "rgmii0_rxd1"), + PINCTRL_PIN(PIN_RGMII0_RXD2, "rgmii0_rxd2"), + PINCTRL_PIN(PIN_RGMII0_RXD3, "rgmii0_rxd3"), + PINCTRL_PIN(PIN_RGMII0_RXCTRL, "rgmii0_rxctrl"), + PINCTRL_PIN(PIN_RGMII0_TXC, "rgmii0_txc"), + PINCTRL_PIN(PIN_RGMII0_RXC, "rgmii0_rxc"), + PINCTRL_PIN(PIN_RGMII0_REFCLKO, "rgmii0_refclko"), + PINCTRL_PIN(PIN_RGMII0_IRQ, "rgmii0_irq"), + PINCTRL_PIN(PIN_RGMII0_MDC, "rgmii0_mdc"), + PINCTRL_PIN(PIN_RGMII0_MDIO, "rgmii0_mdio"), + PINCTRL_PIN(PIN_PWM0, "pwm0"), + PINCTRL_PIN(PIN_PWM1, "pwm1"), + PINCTRL_PIN(PIN_PWM2, "pwm2"), + PINCTRL_PIN(PIN_PWM3, "pwm3"), + PINCTRL_PIN(PIN_FAN0, "fan0"), + PINCTRL_PIN(PIN_FAN1, "fan1"), + PINCTRL_PIN(PIN_FAN2, "fan2"), + PINCTRL_PIN(PIN_FAN3, "fan3"), + PINCTRL_PIN(PIN_IIC0_SDA, "iic0_sda"), + PINCTRL_PIN(PIN_IIC0_SCL, "iic0_scl"), + PINCTRL_PIN(PIN_IIC1_SDA, "iic1_sda"), + PINCTRL_PIN(PIN_IIC1_SCL, "iic1_scl"), + PINCTRL_PIN(PIN_IIC2_SDA, "iic2_sda"), + PINCTRL_PIN(PIN_IIC2_SCL, "iic2_scl"), + PINCTRL_PIN(PIN_IIC3_SDA, "iic3_sda"), + PINCTRL_PIN(PIN_IIC3_SCL, "iic3_scl"), + PINCTRL_PIN(PIN_UART0_TX, "uart0_tx"), + PINCTRL_PIN(PIN_UART0_RX, "uart0_rx"), + PINCTRL_PIN(PIN_UART0_RTS, "uart0_rts"), + PINCTRL_PIN(PIN_UART0_CTS, "uart0_cts"), + PINCTRL_PIN(PIN_UART1_TX, "uart1_tx"), + PINCTRL_PIN(PIN_UART1_RX, "uart1_rx"), + PINCTRL_PIN(PIN_UART1_RTS, "uart1_rts"), + PINCTRL_PIN(PIN_UART1_CTS, "uart1_cts"), + PINCTRL_PIN(PIN_UART2_TX, "uart2_tx"), + PINCTRL_PIN(PIN_UART2_RX, "uart2_rx"), + PINCTRL_PIN(PIN_UART2_RTS, "uart2_rts"), + PINCTRL_PIN(PIN_UART2_CTS, "uart2_cts"), + PINCTRL_PIN(PIN_UART3_TX, "uart3_tx"), + PINCTRL_PIN(PIN_UART3_RX, "uart3_rx"), + PINCTRL_PIN(PIN_UART3_RTS, "uart3_rts"), + PINCTRL_PIN(PIN_UART3_CTS, "uart3_cts"), + PINCTRL_PIN(PIN_SPI0_CS0, "spi0_cs0"), + PINCTRL_PIN(PIN_SPI0_CS1, "spi0_cs1"), + PINCTRL_PIN(PIN_SPI0_SDI, "spi0_sdi"), + PINCTRL_PIN(PIN_SPI0_SDO, "spi0_sdo"), + PINCTRL_PIN(PIN_SPI0_SCK, "spi0_sck"), + PINCTRL_PIN(PIN_SPI1_CS0, "spi1_cs0"), + PINCTRL_PIN(PIN_SPI1_CS1, "spi1_cs1"), + PINCTRL_PIN(PIN_SPI1_SDI, "spi1_sdi"), + PINCTRL_PIN(PIN_SPI1_SDO, "spi1_sdo"), + PINCTRL_PIN(PIN_SPI1_SCK, "spi1_sck"), + PINCTRL_PIN(PIN_JTAG0_TDO, "jtag0_tdo"), + PINCTRL_PIN(PIN_JTAG0_TCK, "jtag0_tck"), + PINCTRL_PIN(PIN_JTAG0_TDI, "jtag0_tdi"), + PINCTRL_PIN(PIN_JTAG0_TMS, "jtag0_tms"), + PINCTRL_PIN(PIN_JTAG0_TRST, "jtag0_trst"), + PINCTRL_PIN(PIN_JTAG0_SRST, "jtag0_srst"), + PINCTRL_PIN(PIN_JTAG1_TDO, "jtag1_tdo"), + PINCTRL_PIN(PIN_JTAG1_TCK, "jtag1_tck"), + PINCTRL_PIN(PIN_JTAG1_TDI, "jtag1_tdi"), + PINCTRL_PIN(PIN_JTAG1_TMS, "jtag1_tms"), + PINCTRL_PIN(PIN_JTAG1_TRST, "jtag1_trst"), + PINCTRL_PIN(PIN_JTAG1_SRST, "jtag1_srst"), + PINCTRL_PIN(PIN_JTAG2_TDO, "jtag2_tdo"), + PINCTRL_PIN(PIN_JTAG2_TCK, "jtag2_tck"), + PINCTRL_PIN(PIN_JTAG2_TDI, "jtag2_tdi"), + PINCTRL_PIN(PIN_JTAG2_TMS, "jtag2_tms"), + PINCTRL_PIN(PIN_JTAG2_TRST, "jtag2_trst"), + PINCTRL_PIN(PIN_JTAG2_SRST, "jtag2_srst"), + PINCTRL_PIN(PIN_JTAG3_TDO, "jtag3_tdo"), + PINCTRL_PIN(PIN_JTAG3_TCK, "jtag3_tck"), + PINCTRL_PIN(PIN_JTAG3_TDI, "jtag3_tdi"), + PINCTRL_PIN(PIN_JTAG3_TMS, "jtag3_tms"), + PINCTRL_PIN(PIN_JTAG3_TRST, "jtag3_trst"), + PINCTRL_PIN(PIN_JTAG3_SRST, "jtag3_srst"), + PINCTRL_PIN(PIN_GPIO0, "gpio0"), + PINCTRL_PIN(PIN_GPIO1, "gpio1"), + PINCTRL_PIN(PIN_GPIO2, "gpio2"), + PINCTRL_PIN(PIN_GPIO3, "gpio3"), + PINCTRL_PIN(PIN_GPIO4, "gpio4"), + PINCTRL_PIN(PIN_GPIO5, "gpio5"), + PINCTRL_PIN(PIN_GPIO6, "gpio6"), + PINCTRL_PIN(PIN_GPIO7, "gpio7"), + PINCTRL_PIN(PIN_GPIO8, "gpio8"), + PINCTRL_PIN(PIN_GPIO9, "gpio9"), + PINCTRL_PIN(PIN_GPIO10, "gpio10"), + PINCTRL_PIN(PIN_GPIO11, "gpio11"), + PINCTRL_PIN(PIN_GPIO12, "gpio12"), + PINCTRL_PIN(PIN_GPIO13, "gpio13"), + PINCTRL_PIN(PIN_GPIO14, "gpio14"), + PINCTRL_PIN(PIN_GPIO15, "gpio15"), + PINCTRL_PIN(PIN_GPIO16, "gpio16"), + PINCTRL_PIN(PIN_GPIO17, "gpio17"), + PINCTRL_PIN(PIN_GPIO18, "gpio18"), + PINCTRL_PIN(PIN_GPIO19, "gpio19"), + PINCTRL_PIN(PIN_GPIO20, "gpio20"), + PINCTRL_PIN(PIN_GPIO21, "gpio21"), + PINCTRL_PIN(PIN_GPIO22, "gpio22"), + PINCTRL_PIN(PIN_GPIO23, "gpio23"), + PINCTRL_PIN(PIN_GPIO24, "gpio24"), + PINCTRL_PIN(PIN_GPIO25, "gpio25"), + PINCTRL_PIN(PIN_GPIO26, "gpio26"), + PINCTRL_PIN(PIN_GPIO27, "gpio27"), + PINCTRL_PIN(PIN_GPIO28, "gpio28"), + PINCTRL_PIN(PIN_GPIO29, "gpio29"), + PINCTRL_PIN(PIN_GPIO30, "gpio30"), + PINCTRL_PIN(PIN_GPIO31, "gpio31"), + PINCTRL_PIN(PIN_MODE_SEL0, "mode_sel0"), + PINCTRL_PIN(PIN_MODE_SEL1, "mode_sel1"), + PINCTRL_PIN(PIN_MODE_SEL2, "mode_sel2"), + PINCTRL_PIN(PIN_BOOT_SEL0, "boot_sel0"), + PINCTRL_PIN(PIN_BOOT_SEL1, "boot_sel1"), + PINCTRL_PIN(PIN_BOOT_SEL2, "boot_sel2"), + PINCTRL_PIN(PIN_BOOT_SEL3, "boot_sel3"), + PINCTRL_PIN(PIN_BOOT_SEL4, "boot_sel4"), + PINCTRL_PIN(PIN_BOOT_SEL5, "boot_sel5"), + PINCTRL_PIN(PIN_BOOT_SEL6, "boot_sel6"), + PINCTRL_PIN(PIN_BOOT_SEL7, "boot_sel7"), + PINCTRL_PIN(PIN_MULTI_SCKT, "multi_sckt"), + PINCTRL_PIN(PIN_SCKT_ID0, "sckt_id0"), + PINCTRL_PIN(PIN_SCKT_ID1, "sckt_id1"), + PINCTRL_PIN(PIN_PLL_CLK_IN_MAIN, "pll_clk_in_main"), + PINCTRL_PIN(PIN_PLL_CLK_IN_DDR_0, "pll_clk_in_ddr_0"), + PINCTRL_PIN(PIN_PLL_CLK_IN_DDR_1, "pll_clk_in_ddr_1"), + PINCTRL_PIN(PIN_PLL_CLK_IN_DDR_2, "pll_clk_in_ddr_2"), + PINCTRL_PIN(PIN_PLL_CLK_IN_DDR_3, "pll_clk_in_ddr_3"), + PINCTRL_PIN(PIN_XTAL_32K, "xtal_32k"), + PINCTRL_PIN(PIN_SYS_RST, "sys_rst"), + PINCTRL_PIN(PIN_PWR_BUTTON, "pwr_button"), + PINCTRL_PIN(PIN_TEST_EN, "test_en"), + PINCTRL_PIN(PIN_TEST_MODE_MBIST, "test_mode_mbist"), + PINCTRL_PIN(PIN_TEST_MODE_SCAN, "test_mode_scan"), + PINCTRL_PIN(PIN_TEST_MODE_BSD, "test_mode_bsd"), + PINCTRL_PIN(PIN_BISR_BYP, "bisr_byp"), +}; + +static const struct sg2042_pin sg2044_pin_data[ARRAY_SIZE(sg2044_pins)] = { + SG2042_GENERAL_PIN(PIN_IIC0_SMBSUS_IN, 0x000, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC0_SMBSUS_OUT, 0x000, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC0_SMBALERT, 0x004, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC1_SMBSUS_IN, 0x004, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC1_SMBSUS_OUT, 0x008, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC1_SMBALERT, 0x008, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC2_SMBSUS_IN, 0x00c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC2_SMBSUS_OUT, 0x00c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC2_SMBALERT, 0x010, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC3_SMBSUS_IN, 0x010, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC3_SMBSUS_OUT, 0x014, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC3_SMBALERT, 0x014, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE0_L0_RESET, 0x018, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE0_L1_RESET, 0x018, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE0_L0_WAKEUP, 0x01c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE0_L1_WAKEUP, 0x01c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE0_L0_CLKREQ_IN, 0x020, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE0_L1_CLKREQ_IN, 0x020, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE1_L0_RESET, 0x024, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE1_L1_RESET, 0x024, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE1_L0_WAKEUP, 0x028, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE1_L1_WAKEUP, 0x028, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE1_L0_CLKREQ_IN, 0x02c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE1_L1_CLKREQ_IN, 0x02c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE2_L0_RESET, 0x030, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE2_L1_RESET, 0x030, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE2_L0_WAKEUP, 0x034, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE2_L1_WAKEUP, 0x034, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE2_L0_CLKREQ_IN, 0x038, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE2_L1_CLKREQ_IN, 0x038, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE3_L0_RESET, 0x03c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE3_L1_RESET, 0x03c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE3_L0_WAKEUP, 0x040, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE3_L1_WAKEUP, 0x040, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE3_L0_CLKREQ_IN, 0x044, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE3_L1_CLKREQ_IN, 0x044, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE4_L0_RESET, 0x048, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE4_L1_RESET, 0x048, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE4_L0_WAKEUP, 0x04c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE4_L1_WAKEUP, 0x04c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PCIE4_L0_CLKREQ_IN, 0x050, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PCIE4_L1_CLKREQ_IN, 0x050, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPIF0_CLK_SEL1, 0x054, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPIF0_CLK_SEL0, 0x054, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPIF0_WP, 0x058, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPIF0_HOLD, 0x058, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPIF0_SDI, 0x05c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPIF0_CS, 0x05c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPIF0_SCK, 0x060, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPIF0_SDO, 0x060, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPIF1_CLK_SEL1, 0x064, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPIF1_CLK_SEL0, 0x064, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPIF1_WP, 0x068, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPIF1_HOLD, 0x068, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPIF1_SDI, 0x06c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPIF1_CS, 0x06c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPIF1_SCK, 0x070, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPIF1_SDO, 0x070, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_EMMC_WP, 0x074, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_EMMC_CD, 0x074, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_EMMC_RST, 0x078, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_EMMC_PWR_EN, 0x078, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SDIO_CD, 0x07c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SDIO_WP, 0x07c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SDIO_RST, 0x080, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SDIO_PWR_EN, 0x080, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_TXD0, 0x084, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_TXD1, 0x084, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_TXD2, 0x088, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_TXD3, 0x088, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_TXCTRL, 0x08c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_RXD0, 0x08c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_RXD1, 0x090, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_RXD2, 0x090, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_RXD3, 0x094, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_RXCTRL, 0x094, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_TXC, 0x098, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_RXC, 0x098, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_REFCLKO, 0x09c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_IRQ, 0x09c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_RGMII0_MDC, 0x0a0, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_RGMII0_MDIO, 0x0a0, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PWM0, 0x0a4, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PWM1, 0x0a4, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_PWM2, 0x0a8, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_PWM3, 0x0a8, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_FAN0, 0x0ac, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_FAN1, 0x0ac, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_FAN2, 0x0b0, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_FAN3, 0x0b0, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC0_SDA, 0x0b4, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC0_SCL, 0x0b4, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC1_SDA, 0x0b8, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC1_SCL, 0x0b8, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC2_SDA, 0x0bc, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC2_SCL, 0x0bc, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_IIC3_SDA, 0x0c0, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_IIC3_SCL, 0x0c0, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_UART0_TX, 0x0c4, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART0_RX, 0x0c4, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_UART0_RTS, 0x0c8, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART0_CTS, 0x0c8, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_UART1_TX, 0x0cc, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART1_RX, 0x0cc, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_UART1_RTS, 0x0d0, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART1_CTS, 0x0d0, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_UART2_TX, 0x0d4, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART2_RX, 0x0d4, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_UART2_RTS, 0x0d8, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART2_CTS, 0x0d8, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_UART3_TX, 0x0dc, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART3_RX, 0x0dc, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_UART3_RTS, 0x0e0, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_UART3_CTS, 0x0e0, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPI0_CS0, 0x0e4, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPI0_CS1, 0x0e4, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPI0_SDI, 0x0e8, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPI0_SDO, 0x0e8, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPI0_SCK, 0x0ec, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPI1_CS0, 0x0ec, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPI1_CS1, 0x0f0, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPI1_SDI, 0x0f0, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_SPI1_SDO, 0x0f4, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_SPI1_SCK, 0x0f4, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG0_TDO, 0x0f8, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG0_TCK, 0x0f8, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG0_TDI, 0x0fc, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG0_TMS, 0x0fc, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG0_TRST, 0x100, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG0_SRST, 0x100, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG1_TDO, 0x104, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG1_TCK, 0x104, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG1_TDI, 0x108, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG1_TMS, 0x108, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG1_TRST, 0x10c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG1_SRST, 0x10c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG2_TDO, 0x110, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG2_TCK, 0x110, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG2_TDI, 0x114, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG2_TMS, 0x114, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG2_TRST, 0x118, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG2_SRST, 0x118, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG3_TDO, 0x11c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG3_TCK, 0x11c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG3_TDI, 0x120, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG3_TMS, 0x120, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_JTAG3_TRST, 0x124, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_JTAG3_SRST, 0x124, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO0, 0x128, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO1, 0x128, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO2, 0x12c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO3, 0x12c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO4, 0x130, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO5, 0x130, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO6, 0x134, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO7, 0x134, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO8, 0x138, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO9, 0x138, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO10, 0x13c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO11, 0x13c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO12, 0x140, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO13, 0x140, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO14, 0x144, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO15, 0x144, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO16, 0x148, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO17, 0x148, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO18, 0x14c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO19, 0x14c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO20, 0x150, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO21, 0x150, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO22, 0x154, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO23, 0x154, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO24, 0x158, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO25, 0x158, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO26, 0x15c, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO27, 0x15c, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO28, 0x160, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO29, 0x160, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_GPIO30, 0x164, + PIN_FLAG_DEFAULT), + SG2042_GENERAL_PIN(PIN_GPIO31, 0x164, + PIN_FLAG_WRITE_HIGH), + SG2042_GENERAL_PIN(PIN_MODE_SEL0, 0x168, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_MODE_SEL1, 0x168, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_MODE_SEL2, 0x16c, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL0, 0x16c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL1, 0x170, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL2, 0x170, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL3, 0x174, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL4, 0x174, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL5, 0x178, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL6, 0x178, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BOOT_SEL7, 0x17c, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_MULTI_SCKT, 0x17c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_SCKT_ID0, 0x180, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_SCKT_ID1, 0x180, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PLL_CLK_IN_MAIN, 0x184, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PLL_CLK_IN_DDR_0, 0x184, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PLL_CLK_IN_DDR_1, 0x188, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PLL_CLK_IN_DDR_2, 0x188, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PLL_CLK_IN_DDR_3, 0x18c, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_XTAL_32K, 0x18c, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_SYS_RST, 0x190, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_PWR_BUTTON, 0x190, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_TEST_EN, 0x194, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_TEST_MODE_MBIST, 0x194, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_TEST_MODE_SCAN, 0x198, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_TEST_MODE_BSD, 0x198, + PIN_FLAG_WRITE_HIGH | PIN_FLAG_NO_PINMUX | + PIN_FLAG_NO_OEX_EN), + SG2042_GENERAL_PIN(PIN_BISR_BYP, 0x19c, + PIN_FLAG_NO_PINMUX | PIN_FLAG_NO_OEX_EN), +}; + +static const struct sophgo_pinctrl_data sg2044_pindata = { + .pins = sg2044_pins, + .pindata = sg2044_pin_data, + .vddio_ops = &sg2044_vddio_cfg_ops, + .cfg_ops = &sg2042_cfg_ops, + .pctl_ops = &sg2042_pctrl_ops, + .pmx_ops = &sg2042_pmx_ops, + .pconf_ops = &sg2042_pconf_ops, + .npins = ARRAY_SIZE(sg2044_pins), + .pinsize = sizeof(struct sg2042_pin), +}; + +static const struct of_device_id sg2044_pinctrl_ids[] = { + { .compatible = "sophgo,sg2044-pinctrl", .data = &sg2044_pindata }, + { } +}; +MODULE_DEVICE_TABLE(of, sg2044_pinctrl_ids); + +static struct platform_driver sg2044_pinctrl_driver = { + .probe = sophgo_pinctrl_probe, + .driver = { + .name = "sg2044-pinctrl", + .suppress_bind_attrs = true, + .of_match_table = sg2044_pinctrl_ids, + }, +}; +module_platform_driver(sg2044_pinctrl_driver); + +MODULE_DESCRIPTION("Pinctrl driver for the SG2002 series SoC"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 7112c05fff83e15726dd60a10248b76474e3cdf9 Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Wed, 12 Feb 2025 13:20:51 +0800 Subject: pinctrl: pinconf-generic: Add API for pinmux propertity in DTS file When describing pin mux func through pinmux propertity, a standard API is added for support. The pinmux contains pin identification and mux values, which can include multiple pins. And groups configuration use other word. DTS such as: func-name { group_alias: group-name{ pinmux= , ; bias-pull-up; drive-strength-microamp = <4000>; }; }; Signed-off-by: Xianwei Zhao Link: https://lore.kernel.org/20250212-amlogic-pinctrl-v5-2-282bc2516804@amlogic.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinconf-generic.c | 130 ++++++++++++++++++++++++++++++++ drivers/pinctrl/pinconf.h | 4 + include/linux/pinctrl/pinconf-generic.h | 4 + 3 files changed, 138 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 0b13d7f17b32..b8e5e441e67c 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -233,6 +233,67 @@ static void parse_dt_cfg(struct device_node *np, } } +/** + * pinconf_generic_parse_dt_pinmux() + * parse the pinmux properties into generic pin mux values. + * @np: node containing the pinmux properties + * @dev: pincontrol core device + * @pid: array with pin identity entries + * @pmux: array with pin mux value entries + * @npins: number of pins + * + * pinmux propertity: mux value [0,7]bits and pin identity [8,31]bits. + */ +int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev, + unsigned int **pid, unsigned int **pmux, + unsigned int *npins) +{ + unsigned int *pid_t; + unsigned int *pmux_t; + struct property *prop; + unsigned int npins_t, i; + u32 value; + int ret; + + prop = of_find_property(np, "pinmux", NULL); + if (!prop) { + dev_info(dev, "Missing pinmux property\n"); + return -ENOENT; + } + + if (!pid || !pmux || !npins) { + dev_err(dev, "paramers error\n"); + return -EINVAL; + } + + npins_t = prop->length / sizeof(u32); + pid_t = devm_kcalloc(dev, npins_t, sizeof(*pid_t), GFP_KERNEL); + pmux_t = devm_kcalloc(dev, npins_t, sizeof(*pmux_t), GFP_KERNEL); + if (!pid_t || !pmux_t) { + dev_err(dev, "kalloc memory fail\n"); + return -ENOMEM; + } + for (i = 0; i < npins_t; i++) { + ret = of_property_read_u32_index(np, "pinmux", i, &value); + if (ret) { + dev_err(dev, "get pinmux value fail\n"); + goto exit; + } + pmux_t[i] = value & 0xff; + pid_t[i] = (value >> 8) & 0xffffff; + } + *pid = pid_t; + *pmux = pmux_t; + *npins = npins_t; + + return 0; +exit: + devm_kfree(dev, pid_t); + devm_kfree(dev, pmux_t); + return ret; +} +EXPORT_SYMBOL_GPL(pinconf_generic_parse_dt_pinmux); + /** * pinconf_generic_parse_dt_config() * parse the config properties into generic pinconfig values. @@ -295,6 +356,75 @@ out: } EXPORT_SYMBOL_GPL(pinconf_generic_parse_dt_config); +int pinconf_generic_dt_node_to_map_pinmux(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + struct device *dev = pctldev->dev; + struct device_node *pnode; + unsigned long *configs = NULL; + unsigned int num_configs = 0; + struct property *prop; + unsigned int reserved_maps; + int reserve; + int ret; + + prop = of_find_property(np, "pinmux", NULL); + if (!prop) { + dev_info(dev, "Missing pinmux property\n"); + return -ENOENT; + } + + pnode = of_get_parent(np); + if (!pnode) { + dev_info(dev, "Missing function node\n"); + return -EINVAL; + } + + reserved_maps = 0; + *map = NULL; + *num_maps = 0; + + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, + &num_configs); + if (ret < 0) { + dev_err(dev, "%pOF: could not parse node property\n", np); + return ret; + } + + reserve = 1; + if (num_configs) + reserve++; + + ret = pinctrl_utils_reserve_map(pctldev, map, &reserved_maps, + num_maps, reserve); + if (ret < 0) + goto exit; + + ret = pinctrl_utils_add_map_mux(pctldev, map, + &reserved_maps, num_maps, np->name, + pnode->name); + if (ret < 0) + goto exit; + + if (num_configs) { + ret = pinctrl_utils_add_map_configs(pctldev, map, &reserved_maps, + num_maps, np->name, configs, + num_configs, PIN_MAP_TYPE_CONFIGS_GROUP); + if (ret < 0) + goto exit; + } + +exit: + kfree(configs); + if (ret) + pinctrl_utils_free_map(pctldev, *map, *num_maps); + + return ret; +} +EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map_pinmux); + int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, struct device_node *np, struct pinctrl_map **map, unsigned int *reserved_maps, unsigned int *num_maps, diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h index a14c950bc700..a171195b3615 100644 --- a/drivers/pinctrl/pinconf.h +++ b/drivers/pinctrl/pinconf.h @@ -138,4 +138,8 @@ int pinconf_generic_parse_dt_config(struct device_node *np, struct pinctrl_dev *pctldev, unsigned long **configs, unsigned int *nconfigs); + +int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev, + unsigned int **pid, unsigned int **pmux, + unsigned int *npins); #endif diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index 53cfde98433d..1bcf071b860e 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -232,4 +232,8 @@ static inline int pinconf_generic_dt_node_to_map_all(struct pinctrl_dev *pctldev PIN_MAP_TYPE_INVALID); } +int pinconf_generic_dt_node_to_map_pinmux(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *num_maps); #endif /* __LINUX_PINCTRL_PINCONF_GENERIC_H */ -- cgit v1.2.3-59-g8ed1b From 6e9be3abb78c2f6c97a51070004a5165702f0ed9 Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Wed, 12 Feb 2025 13:20:52 +0800 Subject: pinctrl: Add driver support for Amlogic SoCs Add a new pinctrl driver for Amlogic SoCs. All future Amlogic SoCs pinctrl drives use this, such A4, A5, S6, S7 etc. To support new Amlogic SoCs, only need to add the corresponding dts file. Signed-off-by: Xianwei Zhao Link: https://lore.kernel.org/20250212-amlogic-pinctrl-v5-3-282bc2516804@amlogic.com Signed-off-by: Linus Walleij --- drivers/pinctrl/meson/Kconfig | 11 + drivers/pinctrl/meson/Makefile | 1 + drivers/pinctrl/meson/pinctrl-amlogic-a4.c | 1053 ++++++++++++++++++++++++++++ 3 files changed, 1065 insertions(+) create mode 100644 drivers/pinctrl/meson/pinctrl-amlogic-a4.c (limited to 'drivers') diff --git a/drivers/pinctrl/meson/Kconfig b/drivers/pinctrl/meson/Kconfig index cc397896762c..90639bc171f6 100644 --- a/drivers/pinctrl/meson/Kconfig +++ b/drivers/pinctrl/meson/Kconfig @@ -67,6 +67,17 @@ config PINCTRL_MESON_S4 select PINCTRL_MESON_AXG_PMX default y +config PINCTRL_AMLOGIC_A4 + bool "AMLOGIC pincontrol" + depends on ARM64 + default y + help + This is the driver for the pin controller found on Amlogic SoCs. + + This driver is simplify subsequent support for new amlogic SoCs, + to support new Amlogic SoCs, only need to add the corresponding dts file, + no additional binding header files or C file are added. + config PINCTRL_AMLOGIC_C3 tristate "Amlogic C3 SoC pinctrl driver" depends on ARM64 diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile index 9e538b9ffb9b..c92a65a83344 100644 --- a/drivers/pinctrl/meson/Makefile +++ b/drivers/pinctrl/meson/Makefile @@ -10,5 +10,6 @@ obj-$(CONFIG_PINCTRL_MESON_AXG) += pinctrl-meson-axg.o obj-$(CONFIG_PINCTRL_MESON_G12A) += pinctrl-meson-g12a.o obj-$(CONFIG_PINCTRL_MESON_A1) += pinctrl-meson-a1.o obj-$(CONFIG_PINCTRL_MESON_S4) += pinctrl-meson-s4.o +obj-$(CONFIG_PINCTRL_AMLOGIC_A4) += pinctrl-amlogic-a4.o obj-$(CONFIG_PINCTRL_AMLOGIC_C3) += pinctrl-amlogic-c3.o obj-$(CONFIG_PINCTRL_AMLOGIC_T7) += pinctrl-amlogic-t7.o diff --git a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c new file mode 100644 index 000000000000..a5218e8f1e03 --- /dev/null +++ b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c @@ -0,0 +1,1053 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +/* + * Copyright (c) 2024 Amlogic, Inc. All rights reserved. + * Author: Xianwei Zhao + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../core.h" +#include "../pinconf.h" + +#define gpio_chip_to_bank(chip) \ + container_of(chip, struct aml_gpio_bank, gpio_chip) + +#define AML_REG_PULLEN 0 +#define AML_REG_PULL 1 +#define AML_REG_DIR 2 +#define AML_REG_OUT 3 +#define AML_REG_IN 4 +#define AML_REG_DS 5 +#define AML_NUM_REG 6 + +enum aml_pinconf_drv { + PINCONF_DRV_500UA, + PINCONF_DRV_2500UA, + PINCONF_DRV_3000UA, + PINCONF_DRV_4000UA, +}; + +struct aml_pio_control { + u32 gpio_offset; + u32 reg_offset[AML_NUM_REG]; + u32 bit_offset[AML_NUM_REG]; +}; + +struct aml_reg_bit { + u32 bank_id; + u32 reg_offs[AML_NUM_REG]; + u32 bit_offs[AML_NUM_REG]; +}; + +struct aml_pctl_data { + unsigned int number; + struct aml_reg_bit rb_offs[]; +}; + +struct aml_pmx_func { + const char *name; + const char **groups; + unsigned int ngroups; +}; + +struct aml_pctl_group { + const char *name; + unsigned int npins; + unsigned int *pins; + unsigned int *func; +}; + +struct aml_gpio_bank { + struct gpio_chip gpio_chip; + struct aml_pio_control pc; + u32 bank_id; + unsigned int pin_base; + struct regmap *reg_mux; + struct regmap *reg_gpio; + struct regmap *reg_ds; +}; + +struct aml_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl; + struct aml_gpio_bank *banks; + int nbanks; + struct aml_pmx_func *functions; + int nfunctions; + struct aml_pctl_group *groups; + int ngroups; + + const struct aml_pctl_data *data; +}; + +static const unsigned int aml_bit_strides[AML_NUM_REG] = { + 1, 1, 1, 1, 1, 2 +}; + +static const unsigned int aml_def_regoffs[AML_NUM_REG] = { + 3, 4, 2, 1, 0, 7 +}; + +static const char *aml_bank_name[31] = { +"GPIOA", "GPIOB", "GPIOC", "GPIOD", "GPIOE", "GPIOF", "GPIOG", +"GPIOH", "GPIOI", "GPIOJ", "GPIOK", "GPIOL", "GPIOM", "GPION", +"GPIOO", "GPIOP", "GPIOQ", "GPIOR", "GPIOS", "GPIOT", "GPIOU", +"GPIOV", "GPIOW", "GPIOX", "GPIOY", "GPIOZ", "GPIODV", "GPIOAO", +"GPIOCC", "TEST_N", "ANALOG" +}; + +static int aml_pmx_calc_reg_and_offset(struct pinctrl_gpio_range *range, + unsigned int pin, unsigned int *reg, + unsigned int *offset) +{ + unsigned int shift; + + shift = (pin - range->pin_base) << 2; + *reg = (shift / 32) * 4; + *offset = shift % 32; + + return 0; +} + +static int aml_pctl_set_function(struct aml_pinctrl *info, + struct pinctrl_gpio_range *range, + int pin_id, int func) +{ + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + int reg; + int offset; + + if (!bank->reg_mux) + return 0; + + aml_pmx_calc_reg_and_offset(range, pin_id, ®, &offset); + return regmap_update_bits(bank->reg_mux, reg, + 0xf << offset, (func & 0xf) << offset); +} + +static int aml_pmx_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->nfunctions; +} + +static const char *aml_pmx_get_fname(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->functions[selector].name; +} + +static int aml_pmx_get_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **grps, + unsigned * const ngrps) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + *grps = info->functions[selector].groups; + *ngrps = info->functions[selector].ngroups; + + return 0; +} + +static int aml_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned int fselector, + unsigned int group_id) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct aml_pctl_group *group = &info->groups[group_id]; + struct pinctrl_gpio_range *range; + int i; + + for (i = 0; i < group->npins; i++) { + range = pinctrl_find_gpio_range_from_pin(pctldev, group->pins[i]); + aml_pctl_set_function(info, range, group->pins[i], group->func[i]); + } + + return 0; +} + +static int aml_pmx_request_gpio(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return aml_pctl_set_function(info, range, pin, 0); +} + +static const struct pinmux_ops aml_pmx_ops = { + .set_mux = aml_pmx_set_mux, + .get_functions_count = aml_pmx_get_funcs_count, + .get_function_name = aml_pmx_get_fname, + .get_function_groups = aml_pmx_get_groups, + .gpio_request_enable = aml_pmx_request_gpio, +}; + +static int aml_calc_reg_and_bit(struct pinctrl_gpio_range *range, + unsigned int pin, + unsigned int reg_type, + unsigned int *reg, unsigned int *bit) +{ + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + + *bit = (pin - range->pin_base) * aml_bit_strides[reg_type] + + bank->pc.bit_offset[reg_type]; + *reg = (bank->pc.reg_offset[reg_type] + (*bit / 32)) * 4; + *bit &= 0x1f; + + return 0; +} + +static int aml_pinconf_get_pull(struct aml_pinctrl *info, unsigned int pin) +{ + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(info->pctl, pin); + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + unsigned int reg, bit, val; + int ret, conf; + + aml_calc_reg_and_bit(range, pin, AML_REG_PULLEN, ®, &bit); + + ret = regmap_read(bank->reg_gpio, reg, &val); + if (ret) + return ret; + + if (!(val & BIT(bit))) { + conf = PIN_CONFIG_BIAS_DISABLE; + } else { + aml_calc_reg_and_bit(range, pin, AML_REG_PULL, ®, &bit); + + ret = regmap_read(bank->reg_gpio, reg, &val); + if (ret) + return ret; + + if (val & BIT(bit)) + conf = PIN_CONFIG_BIAS_PULL_UP; + else + conf = PIN_CONFIG_BIAS_PULL_DOWN; + } + + return conf; +} + +static int aml_pinconf_get_drive_strength(struct aml_pinctrl *info, + unsigned int pin, + u16 *drive_strength_ua) +{ + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(info->pctl, pin); + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + unsigned int reg, bit; + unsigned int val; + int ret; + + if (!bank->reg_ds) + return -EOPNOTSUPP; + + aml_calc_reg_and_bit(range, pin, AML_REG_DS, ®, &bit); + ret = regmap_read(bank->reg_ds, reg, &val); + if (ret) + return ret; + + switch ((val >> bit) & 0x3) { + case PINCONF_DRV_500UA: + *drive_strength_ua = 500; + break; + case PINCONF_DRV_2500UA: + *drive_strength_ua = 2500; + break; + case PINCONF_DRV_3000UA: + *drive_strength_ua = 3000; + break; + case PINCONF_DRV_4000UA: + *drive_strength_ua = 4000; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int aml_pinconf_get_gpio_bit(struct aml_pinctrl *info, + unsigned int pin, + unsigned int reg_type) +{ + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(info->pctl, pin); + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + unsigned int reg, bit, val; + int ret; + + aml_calc_reg_and_bit(range, pin, reg_type, ®, &bit); + ret = regmap_read(bank->reg_gpio, reg, &val); + if (ret) + return ret; + + return BIT(bit) & val ? 1 : 0; +} + +static int aml_pinconf_get_output(struct aml_pinctrl *info, + unsigned int pin) +{ + int ret = aml_pinconf_get_gpio_bit(info, pin, AML_REG_DIR); + + if (ret < 0) + return ret; + + return !ret; +} + +static int aml_pinconf_get_drive(struct aml_pinctrl *info, + unsigned int pin) +{ + return aml_pinconf_get_gpio_bit(info, pin, AML_REG_OUT); +} + +static int aml_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin, + unsigned long *config) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pcdev); + enum pin_config_param param = pinconf_to_config_param(*config); + u16 arg; + int ret; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + if (aml_pinconf_get_pull(info, pin) == param) + arg = 1; + else + return -EINVAL; + break; + case PIN_CONFIG_DRIVE_STRENGTH_UA: + ret = aml_pinconf_get_drive_strength(info, pin, &arg); + if (ret) + return ret; + break; + case PIN_CONFIG_OUTPUT_ENABLE: + ret = aml_pinconf_get_output(info, pin); + if (ret <= 0) + return -EINVAL; + arg = 1; + break; + case PIN_CONFIG_OUTPUT: + ret = aml_pinconf_get_output(info, pin); + if (ret <= 0) + return -EINVAL; + + ret = aml_pinconf_get_drive(info, pin); + if (ret < 0) + return -EINVAL; + + arg = ret; + break; + + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + dev_dbg(info->dev, "pinconf for pin %u is %lu\n", pin, *config); + + return 0; +} + +static int aml_pinconf_disable_bias(struct aml_pinctrl *info, + unsigned int pin) +{ + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(info->pctl, pin); + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + unsigned int reg, bit = 0; + + aml_calc_reg_and_bit(range, pin, AML_REG_PULLEN, ®, &bit); + + return regmap_update_bits(bank->reg_gpio, reg, BIT(bit), 0); +} + +static int aml_pinconf_enable_bias(struct aml_pinctrl *info, unsigned int pin, + bool pull_up) +{ + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(info->pctl, pin); + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + unsigned int reg, bit, val = 0; + int ret; + + aml_calc_reg_and_bit(range, pin, AML_REG_PULL, ®, &bit); + if (pull_up) + val = BIT(bit); + + ret = regmap_update_bits(bank->reg_gpio, reg, BIT(bit), val); + if (ret) + return ret; + + aml_calc_reg_and_bit(range, pin, AML_REG_PULLEN, ®, &bit); + return regmap_update_bits(bank->reg_gpio, reg, BIT(bit), BIT(bit)); +} + +static int aml_pinconf_set_drive_strength(struct aml_pinctrl *info, + unsigned int pin, + u16 drive_strength_ua) +{ + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(info->pctl, pin); + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + unsigned int reg, bit, ds_val; + + if (!bank->reg_ds) { + dev_err(info->dev, "drive-strength not supported\n"); + return -EOPNOTSUPP; + } + + aml_calc_reg_and_bit(range, pin, AML_REG_DS, ®, &bit); + + if (drive_strength_ua <= 500) { + ds_val = PINCONF_DRV_500UA; + } else if (drive_strength_ua <= 2500) { + ds_val = PINCONF_DRV_2500UA; + } else if (drive_strength_ua <= 3000) { + ds_val = PINCONF_DRV_3000UA; + } else if (drive_strength_ua <= 4000) { + ds_val = PINCONF_DRV_4000UA; + } else { + dev_warn_once(info->dev, + "pin %u: invalid drive-strength : %d , default to 4mA\n", + pin, drive_strength_ua); + ds_val = PINCONF_DRV_4000UA; + } + + return regmap_update_bits(bank->reg_ds, reg, 0x3 << bit, ds_val << bit); +} + +static int aml_pinconf_set_gpio_bit(struct aml_pinctrl *info, + unsigned int pin, + unsigned int reg_type, + bool arg) +{ + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(info->pctl, pin); + struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); + unsigned int reg, bit; + + aml_calc_reg_and_bit(range, pin, reg_type, ®, &bit); + return regmap_update_bits(bank->reg_gpio, reg, BIT(bit), + arg ? BIT(bit) : 0); +} + +static int aml_pinconf_set_output(struct aml_pinctrl *info, + unsigned int pin, + bool out) +{ + return aml_pinconf_set_gpio_bit(info, pin, AML_REG_DIR, !out); +} + +static int aml_pinconf_set_drive(struct aml_pinctrl *info, + unsigned int pin, + bool high) +{ + return aml_pinconf_set_gpio_bit(info, pin, AML_REG_OUT, high); +} + +static int aml_pinconf_set_output_drive(struct aml_pinctrl *info, + unsigned int pin, + bool high) +{ + int ret; + + ret = aml_pinconf_set_output(info, pin, true); + if (ret) + return ret; + + return aml_pinconf_set_drive(info, pin, high); +} + +static int aml_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, + unsigned long *configs, unsigned int num_configs) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pcdev); + enum pin_config_param param; + unsigned int arg = 0; + int i, ret; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + + switch (param) { + case PIN_CONFIG_DRIVE_STRENGTH_UA: + case PIN_CONFIG_OUTPUT_ENABLE: + case PIN_CONFIG_OUTPUT: + arg = pinconf_to_config_argument(configs[i]); + break; + + default: + break; + } + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + ret = aml_pinconf_disable_bias(info, pin); + break; + case PIN_CONFIG_BIAS_PULL_UP: + ret = aml_pinconf_enable_bias(info, pin, true); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + ret = aml_pinconf_enable_bias(info, pin, false); + break; + case PIN_CONFIG_DRIVE_STRENGTH_UA: + ret = aml_pinconf_set_drive_strength(info, pin, arg); + break; + case PIN_CONFIG_OUTPUT_ENABLE: + ret = aml_pinconf_set_output(info, pin, arg); + break; + case PIN_CONFIG_OUTPUT: + ret = aml_pinconf_set_output_drive(info, pin, arg); + break; + default: + ret = -ENOTSUPP; + } + + if (ret) + return ret; + } + + return 0; +} + +static int aml_pinconf_group_set(struct pinctrl_dev *pcdev, + unsigned int num_group, + unsigned long *configs, + unsigned int num_configs) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pcdev); + int i; + + for (i = 0; i < info->groups[num_group].npins; i++) { + aml_pinconf_set(pcdev, info->groups[num_group].pins[i], configs, + num_configs); + } + + return 0; +} + +static int aml_pinconf_group_get(struct pinctrl_dev *pcdev, + unsigned int group, unsigned long *config) +{ + return -EOPNOTSUPP; +} + +static const struct pinconf_ops aml_pinconf_ops = { + .pin_config_get = aml_pinconf_get, + .pin_config_set = aml_pinconf_set, + .pin_config_group_get = aml_pinconf_group_get, + .pin_config_group_set = aml_pinconf_group_set, + .is_generic = true, +}; + +static int aml_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->ngroups; +} + +static const char *aml_get_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->groups[selector].name; +} + +static int aml_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int selector, const unsigned int **pins, + unsigned int *npins) +{ + struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + if (selector >= info->ngroups) + return -EINVAL; + + *pins = info->groups[selector].pins; + *npins = info->groups[selector].npins; + + return 0; +} + +static inline const struct aml_pctl_group * + aml_pctl_find_group_by_name(const struct aml_pinctrl *info, + const char *name) +{ + int i; + + for (i = 0; i < info->ngroups; i++) { + if (!strcmp(info->groups[i].name, name)) + return &info->groups[i]; + } + + return NULL; +} + +static void aml_pin_dbg_show(struct pinctrl_dev *pcdev, struct seq_file *s, + unsigned int offset) +{ + seq_printf(s, " %s", dev_name(pcdev->dev)); +} + +static const struct pinctrl_ops aml_pctrl_ops = { + .get_groups_count = aml_get_groups_count, + .get_group_name = aml_get_group_name, + .get_group_pins = aml_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pinmux, + .dt_free_map = pinconf_generic_dt_free_map, + .pin_dbg_show = aml_pin_dbg_show, +}; + +static int aml_pctl_parse_functions(struct device_node *np, + struct aml_pinctrl *info, u32 index, + int *grp_index) +{ + struct device *dev = info->dev; + struct aml_pmx_func *func; + struct aml_pctl_group *grp; + int ret, i; + + func = &info->functions[index]; + func->name = np->name; + func->ngroups = of_get_child_count(np); + if (func->ngroups == 0) + return dev_err_probe(dev, -EINVAL, "No groups defined\n"); + + func->groups = devm_kcalloc(dev, func->ngroups, sizeof(*func->groups), GFP_KERNEL); + if (!func->groups) + return -ENOMEM; + + i = 0; + for_each_child_of_node_scoped(np, child) { + func->groups[i++] = child->name; + grp = &info->groups[*grp_index]; + grp->name = child->name; + *grp_index += 1; + ret = pinconf_generic_parse_dt_pinmux(child, dev, &grp->pins, + &grp->func, &grp->npins); + if (ret) { + dev_err(dev, "function :%s, groups:%s fail\n", func->name, child->name); + return ret; + } + } + dev_dbg(dev, "Function[%d\t name:%s,\tgroups:%d]\n", index, func->name, func->ngroups); + + return 0; +} + +static u32 aml_bank_pins(struct device_node *np) +{ + struct of_phandle_args of_args; + + if (of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, + 0, &of_args)) + return 0; + else + return of_args.args[2]; +} + +static int aml_bank_number(struct device_node *np) +{ + struct of_phandle_args of_args; + + if (of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, + 0, &of_args)) + return -EINVAL; + else + return of_args.args[1] >> 8; +} + +static unsigned int aml_count_pins(struct device_node *np) +{ + struct device_node *child; + unsigned int pins = 0; + + for_each_child_of_node(np, child) { + if (of_property_read_bool(child, "gpio-controller")) + pins += aml_bank_pins(child); + } + + return pins; +} + +/* + * A pinctrl device contains two types of nodes. The one named GPIO + * bank which includes gpio-controller property. The other one named + * function which includes one or more pin groups. The pin group + * include pinmux property(global index in pinctrl dev, and mux vlaue + * in mux reg) and pin configuration properties. + */ +static void aml_pctl_dt_child_count(struct aml_pinctrl *info, + struct device_node *np) +{ + struct device_node *child; + + for_each_child_of_node(np, child) { + if (of_property_read_bool(child, "gpio-controller")) { + info->nbanks++; + } else { + info->nfunctions++; + info->ngroups += of_get_child_count(child); + } + } +} + +static struct regmap *aml_map_resource(struct device *dev, unsigned int id, + struct device_node *node, char *name) +{ + struct resource res; + void __iomem *base; + int i; + + struct regmap_config aml_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + }; + + i = of_property_match_string(node, "reg-names", name); + if (i < 0) + return NULL; + if (of_address_to_resource(node, i, &res)) + return NULL; + base = devm_ioremap_resource(dev, &res); + if (IS_ERR(base)) + return ERR_CAST(base); + + aml_regmap_config.max_register = resource_size(&res) - 4; + aml_regmap_config.name = devm_kasprintf(dev, GFP_KERNEL, + "%s-%s", aml_bank_name[id], name); + if (!aml_regmap_config.name) + return ERR_PTR(-ENOMEM); + + return devm_regmap_init_mmio(dev, base, &aml_regmap_config); +} + +static inline int aml_gpio_calc_reg_and_bit(struct aml_gpio_bank *bank, + unsigned int reg_type, + unsigned int gpio, + unsigned int *reg, + unsigned int *bit) +{ + *bit = gpio * aml_bit_strides[reg_type] + bank->pc.bit_offset[reg_type]; + *reg = (bank->pc.reg_offset[reg_type] + (*bit / 32)) * 4; + *bit &= 0x1f; + + return 0; +} + +static int aml_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio) +{ + struct aml_gpio_bank *bank = gpiochip_get_data(chip); + unsigned int bit, reg, val; + int ret; + + aml_gpio_calc_reg_and_bit(bank, AML_REG_DIR, gpio, ®, &bit); + + ret = regmap_read(bank->reg_gpio, reg, &val); + if (ret) + return ret; + + return BIT(bit) & val ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; +} + +static int aml_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio) +{ + struct aml_gpio_bank *bank = gpiochip_get_data(chip); + unsigned int bit, reg; + + aml_gpio_calc_reg_and_bit(bank, AML_REG_DIR, gpio, ®, &bit); + + return regmap_update_bits(bank->reg_gpio, reg, BIT(bit), 0); +} + +static int aml_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, + int value) +{ + struct aml_gpio_bank *bank = gpiochip_get_data(chip); + unsigned int bit, reg; + int ret; + + aml_gpio_calc_reg_and_bit(bank, AML_REG_DIR, gpio, ®, &bit); + ret = regmap_update_bits(bank->reg_gpio, reg, BIT(bit), BIT(bit)); + if (ret < 0) + return ret; + + aml_gpio_calc_reg_and_bit(bank, AML_REG_OUT, gpio, ®, &bit); + + return regmap_update_bits(bank->reg_gpio, reg, BIT(bit), + value ? BIT(bit) : 0); +} + +static void aml_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value) +{ + struct aml_gpio_bank *bank = gpiochip_get_data(chip); + unsigned int bit, reg; + + aml_gpio_calc_reg_and_bit(bank, AML_REG_OUT, gpio, ®, &bit); + + regmap_update_bits(bank->reg_gpio, reg, BIT(bit), + value ? BIT(bit) : 0); +} + +static int aml_gpio_get(struct gpio_chip *chip, unsigned int gpio) +{ + struct aml_gpio_bank *bank = gpiochip_get_data(chip); + unsigned int reg, bit, val; + + aml_gpio_calc_reg_and_bit(bank, AML_REG_IN, gpio, ®, &bit); + regmap_read(bank->reg_gpio, reg, &val); + + return !!(val & BIT(bit)); +} + +static const struct gpio_chip aml_gpio_template = { + .request = gpiochip_generic_request, + .free = gpiochip_generic_free, + .set_config = gpiochip_generic_config, + .set = aml_gpio_set, + .get = aml_gpio_get, + .direction_input = aml_gpio_direction_input, + .direction_output = aml_gpio_direction_output, + .get_direction = aml_gpio_get_direction, + .can_sleep = false, +}; + +static void init_bank_register_bit(struct aml_pinctrl *info, + struct aml_gpio_bank *bank) +{ + const struct aml_pctl_data *data = info->data; + const struct aml_reg_bit *aml_rb; + bool def_offs = true; + int i; + + if (data) { + for (i = 0; i < data->number; i++) { + aml_rb = &data->rb_offs[i]; + if (bank->bank_id == aml_rb->bank_id) { + def_offs = false; + break; + } + } + }; + + if (def_offs) { + for (i = 0; i < AML_NUM_REG; i++) { + bank->pc.reg_offset[i] = aml_def_regoffs[i]; + bank->pc.bit_offset[i] = 0; + } + } else { + for (i = 0; i < AML_NUM_REG; i++) { + bank->pc.reg_offset[i] = aml_rb->reg_offs[i]; + bank->pc.bit_offset[i] = aml_rb->bit_offs[i]; + } + } +} + +static int aml_gpiolib_register_bank(struct aml_pinctrl *info, + int bank_nr, struct device_node *np) +{ + struct aml_gpio_bank *bank = &info->banks[bank_nr]; + struct device *dev = info->dev; + int ret = 0; + + ret = aml_bank_number(np); + if (ret < 0) { + dev_err(dev, "get num=%d bank identity fail\n", bank_nr); + return -EINVAL; + } + bank->bank_id = ret; + + bank->reg_mux = aml_map_resource(dev, bank->bank_id, np, "mux"); + if (IS_ERR_OR_NULL(bank->reg_mux)) { + if (bank->bank_id == AMLOGIC_GPIO_TEST_N || + bank->bank_id == AMLOGIC_GPIO_ANALOG) + bank->reg_mux = NULL; + else + return dev_err_probe(dev, bank->reg_mux ? PTR_ERR(bank->reg_mux) : -ENOENT, + "mux registers not found\n"); + } + + bank->reg_gpio = aml_map_resource(dev, bank->bank_id, np, "gpio"); + if (IS_ERR_OR_NULL(bank->reg_gpio)) + return dev_err_probe(dev, bank->reg_gpio ? PTR_ERR(bank->reg_gpio) : -ENOENT, + "gpio registers not found\n"); + + bank->reg_ds = aml_map_resource(dev, bank->bank_id, np, "ds"); + if (IS_ERR_OR_NULL(bank->reg_ds)) { + dev_dbg(info->dev, "ds registers not found - skipping\n"); + bank->reg_ds = bank->reg_gpio; + } + + bank->gpio_chip = aml_gpio_template; + bank->gpio_chip.base = -1; + bank->gpio_chip.ngpio = aml_bank_pins(np); + bank->gpio_chip.fwnode = of_fwnode_handle(np); + bank->gpio_chip.parent = dev; + + init_bank_register_bit(info, bank); + bank->gpio_chip.label = aml_bank_name[bank->bank_id]; + + bank->pin_base = bank->bank_id << 8; + + return 0; +} + +static int aml_pctl_probe_dt(struct platform_device *pdev, + struct pinctrl_desc *pctl_desc, + struct aml_pinctrl *info) +{ + struct device *dev = &pdev->dev; + struct pinctrl_pin_desc *pdesc; + struct device_node *np = dev->of_node; + int grp_index = 0; + int i = 0, j = 0, k = 0, bank; + int ret = 0; + + aml_pctl_dt_child_count(info, np); + if (!info->nbanks) + return dev_err_probe(dev, -EINVAL, "you need at least one gpio bank\n"); + + dev_dbg(dev, "nbanks = %d\n", info->nbanks); + dev_dbg(dev, "nfunctions = %d\n", info->nfunctions); + dev_dbg(dev, "ngroups = %d\n", info->ngroups); + + info->functions = devm_kcalloc(dev, info->nfunctions, sizeof(*info->functions), GFP_KERNEL); + + info->groups = devm_kcalloc(dev, info->ngroups, sizeof(*info->groups), GFP_KERNEL); + + info->banks = devm_kcalloc(dev, info->nbanks, sizeof(*info->banks), GFP_KERNEL); + + if (!info->functions || !info->groups || !info->banks) + return -ENOMEM; + + info->data = (struct aml_pctl_data *)of_device_get_match_data(dev); + + pctl_desc->npins = aml_count_pins(np); + + pdesc = devm_kcalloc(dev, pctl_desc->npins, sizeof(*pdesc), GFP_KERNEL); + if (!pdesc) + return -ENOMEM; + + pctl_desc->pins = pdesc; + + bank = 0; + for_each_child_of_node_scoped(np, child) { + if (of_property_read_bool(child, "gpio-controller")) { + const char *bank_name = NULL; + char **pin_names; + + ret = aml_gpiolib_register_bank(info, bank, child); + if (ret) + return ret; + + k = info->banks[bank].pin_base; + bank_name = info->banks[bank].gpio_chip.label; + + pin_names = devm_kasprintf_strarray(dev, bank_name, + info->banks[bank].gpio_chip.ngpio); + if (IS_ERR(pin_names)) + return PTR_ERR(pin_names); + + for (j = 0; j < info->banks[bank].gpio_chip.ngpio; j++, k++) { + pdesc->number = k; + pdesc->name = pin_names[j]; + pdesc++; + } + bank++; + } else { + ret = aml_pctl_parse_functions(child, info, + i++, &grp_index); + if (ret) + return ret; + } + } + + return 0; +} + +static int aml_pctl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct aml_pinctrl *info; + struct pinctrl_desc *pctl_desc; + int ret, i; + + pctl_desc = devm_kzalloc(dev, sizeof(*pctl_desc), GFP_KERNEL); + if (!pctl_desc) + return -ENOMEM; + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->dev = dev; + platform_set_drvdata(pdev, info); + ret = aml_pctl_probe_dt(pdev, pctl_desc, info); + if (ret) + return ret; + + pctl_desc->owner = THIS_MODULE; + pctl_desc->pctlops = &aml_pctrl_ops; + pctl_desc->pmxops = &aml_pmx_ops; + pctl_desc->confops = &aml_pinconf_ops; + pctl_desc->name = dev_name(dev); + + info->pctl = devm_pinctrl_register(dev, pctl_desc, info); + if (IS_ERR(info->pctl)) + return dev_err_probe(dev, PTR_ERR(info->pctl), "Failed pinctrl registration\n"); + + for (i = 0; i < info->nbanks; i++) { + ret = gpiochip_add_data(&info->banks[i].gpio_chip, &info->banks[i]); + if (ret) + return dev_err_probe(dev, ret, "Failed to add gpiochip(%d)!\n", i); + } + + return 0; +} + +static const struct of_device_id aml_pctl_of_match[] = { + { .compatible = "amlogic,pinctrl-a4", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, aml_pctl_dt_match); + +static struct platform_driver aml_pctl_driver = { + .driver = { + .name = "amlogic-pinctrl", + .of_match_table = aml_pctl_of_match, + }, + .probe = aml_pctl_probe, +}; +module_platform_driver(aml_pctl_driver); + +MODULE_AUTHOR("Xianwei Zhao "); +MODULE_DESCRIPTION("Pin controller and GPIO driver for Amlogic SoC"); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3-59-g8ed1b From e2a9df2fe119f030f30b7dcba5c734058fd37487 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 20 Feb 2025 17:50:11 +0200 Subject: pinctrl: wpcm450: Switch to use for_each_gpiochip_node() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch the code to use for_each_gpiochip_node() helper. While at it, correct header inclusion as device property APIs are provided in property.h. Reviewed-by: J. Neuschäfer Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/20250220155036.2734838-1-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/pinctrl/nuvoton/pinctrl-wpcm450.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c b/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c index cdad4ef11a2f..2f97accef837 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c +++ b/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c @@ -10,7 +10,6 @@ // block, shared between all GPIO banks #include -#include #include #include #include @@ -18,6 +17,7 @@ #include #include #include +#include #include #include @@ -1033,7 +1033,7 @@ static int wpcm450_gpio_register(struct platform_device *pdev, return dev_err_probe(dev, PTR_ERR(pctrl->gpio_base), "Resource fail for GPIO controller\n"); - device_for_each_child_node(dev, child) { + for_each_gpiochip_node(dev, child) { void __iomem *dat = NULL; void __iomem *set = NULL; void __iomem *dirout = NULL; @@ -1044,9 +1044,6 @@ static int wpcm450_gpio_register(struct platform_device *pdev, u32 reg; int i; - if (!fwnode_property_read_bool(child, "gpio-controller")) - continue; - ret = fwnode_property_read_u32(child, "reg", ®); if (ret < 0) return ret; -- cgit v1.2.3-59-g8ed1b From 7da6a3578ab4bcff5f6bdea5fcef08a82139c868 Mon Sep 17 00:00:00 2001 From: Prathamesh Shete Date: Tue, 17 Dec 2024 21:02:49 +0530 Subject: pinctrl-tegra: Add config property GPIO mode The SFIO/GPIO select bit is a crucial part of Tegra's pin multiplexing system: - When set to 1, the pin operates in SFIO mode, controlled by the pin's assigned special function. - When set to 0, the pin operates as a general-purpose GPIO. This SFIO/GPIO select bit that is set for a given pin is not displayed, adding the support to retrieve this information from the pinmux set for each pin. Signed-off-by: Prathamesh Shete Link: https://lore.kernel.org/20241217153249.5712-1-pshete@nvidia.com Signed-off-by: Linus Walleij --- drivers/pinctrl/tegra/pinctrl-tegra.c | 11 +++++++++++ drivers/pinctrl/tegra/pinctrl-tegra.h | 2 ++ 2 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c index c83e5a65e680..314309c797d7 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c @@ -96,6 +96,7 @@ static const struct cfg_param { {"nvidia,slew-rate-falling", TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING}, {"nvidia,slew-rate-rising", TEGRA_PINCONF_PARAM_SLEW_RATE_RISING}, {"nvidia,drive-type", TEGRA_PINCONF_PARAM_DRIVE_TYPE}, + {"nvidia,gpio-mode", TEGRA_PINCONF_PARAM_GPIO_MODE}, }; static int tegra_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, @@ -468,6 +469,16 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx, *bit = g->drvtype_bit; *width = 2; break; + case TEGRA_PINCONF_PARAM_GPIO_MODE: + if (pmx->soc->sfsel_in_mux) { + *bank = g->mux_bank; + *reg = g->mux_reg; + *bit = g->sfsel_bit; + *width = 1; + } else { + *reg = -EINVAL; + } + break; default: dev_err(pmx->dev, "Invalid config param %04x\n", param); return -ENOTSUPP; diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h index b3289bdf727d..216cc59b62b4 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra.h +++ b/drivers/pinctrl/tegra/pinctrl-tegra.h @@ -54,6 +54,8 @@ enum tegra_pinconf_param { TEGRA_PINCONF_PARAM_SLEW_RATE_RISING, /* argument: Integer, range is HW-dependant */ TEGRA_PINCONF_PARAM_DRIVE_TYPE, + /* argument: Boolean */ + TEGRA_PINCONF_PARAM_GPIO_MODE, }; enum tegra_pinconf_pull { -- cgit v1.2.3-59-g8ed1b From c7984dc0a2b93255bc8fb924754da8b3b263ed1d Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 27 Feb 2025 12:39:30 -0800 Subject: pinctrl: qcom: Add test case for TLMM interrupt handling While looking at the X1E PDC GPIO interrupts it became clear that we're lacking a convenient and accessible way to validate if the TLMM interrupt code performing as expected. This introduces a kunit-based "hack" that relies on pin bias/pull configuration to tickle the interrupt logic in non-connected pins to allow us to evaluate that an expected number of interrupts are delivered. The bias/pull configuration is done with mmio accesses directly from the test code, to avoid having to programmatically acquire and drive the pinconf interface for the test pin. This limits the scalability of the code to targets with a particular register layout, but serves our needs for now. The pin to be used for testing is specified by the tester using the "tlmm-test.gpio" module parameter. Worth mentioning is that some of the test cases currently fails for GPIOs that is not backed by PDC (i.e. "non-wakeup" GPIOs), as lingering latched interrupt state is being delivered at IRQ request time. Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/20250227-tlmm-test-v1-1-d18877b4a5db@oss.qualcomm.com Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/Kconfig.msm | 10 + drivers/pinctrl/qcom/Makefile | 1 + drivers/pinctrl/qcom/tlmm-test.c | 626 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 637 insertions(+) create mode 100644 drivers/pinctrl/qcom/tlmm-test.c (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/Kconfig.msm b/drivers/pinctrl/qcom/Kconfig.msm index a0d63a672539..0bb44c9a4c06 100644 --- a/drivers/pinctrl/qcom/Kconfig.msm +++ b/drivers/pinctrl/qcom/Kconfig.msm @@ -437,4 +437,14 @@ config PINCTRL_X1E80100 Say Y here to compile statically, or M here to compile it as a module. If unsure, say N. +config PINCTRL_TLMM_TEST + tristate "Qualcomm TLMM test driver" + depends on ARM64 || COMPILE_TEST + depends on KUNIT + help + This driver provides test cases for the interrupt capabilities of + TLMM driver (pinctrl-msm). Specify a floating gpio to use for testing + using the module parameter "gpio" and execute the kunit suite. + If unsure, say N. + endif diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 5c4100925cf9..954f5291cc37 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -71,3 +71,4 @@ obj-$(CONFIG_PINCTRL_SM8750) += pinctrl-sm8750.o obj-$(CONFIG_PINCTRL_SC8280XP_LPASS_LPI) += pinctrl-sc8280xp-lpass-lpi.o obj-$(CONFIG_PINCTRL_LPASS_LPI) += pinctrl-lpass-lpi.o obj-$(CONFIG_PINCTRL_X1E80100) += pinctrl-x1e80100.o +obj-$(CONFIG_PINCTRL_TLMM_TEST) += tlmm-test.o diff --git a/drivers/pinctrl/qcom/tlmm-test.c b/drivers/pinctrl/qcom/tlmm-test.c new file mode 100644 index 000000000000..9c31798b3c08 --- /dev/null +++ b/drivers/pinctrl/qcom/tlmm-test.c @@ -0,0 +1,626 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#define pr_fmt(fmt) "tlmm-test: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This TLMM test module serves the purpose of validating that the TLMM driver + * (pinctrl-msm) delivers expected number of interrupts in response to changing + * GPIO state. + * + * To achieve this without external equipment the test takes a module parameter + * "gpio", which the tester is expected to specify an unused and non-connected + * pin. The GPIO state is then driven by adjusting the bias of the pin, at + * suitable times through the different test cases. + * + * Upon execution, the test initialization will find the TLMM node (subject to + * tlmm_of_match[] allow listing) and create the necessary references + * dynamically, rather then relying on e.g. Devicetree and phandles. + */ + +#define MSM_PULL_MASK GENMASK(2, 0) +#define MSM_PULL_DOWN 1 +#define MSM_PULL_UP 3 +#define TLMM_REG_SIZE 0x1000 + +static int tlmm_test_gpio = -1; +module_param_named(gpio, tlmm_test_gpio, int, 0600); + +static struct { + void __iomem *base; + void __iomem *reg; + int irq; + + u32 low_val; + u32 high_val; +} tlmm_suite; + +/** + * struct tlmm_test_priv - Per-test context + * @intr_count: number of times hard handler was hit with TLMM_TEST_COUNT op set + * @thread_count: number of times thread handler was hit with TLMM_TEST_COUNT op set + * @intr_op: operations to be performed by the hard IRQ handler + * @intr_op_remain: number of times the TLMM_TEST_THEN_* operations should be + * performed by the hard IRQ handler + * @thread_op: operations to be performed by the threaded IRQ handler + * @thread_op_remain: number of times the TLMM_TEST_THEN_* operations should + * be performed by the threaded IRQ handler + */ +struct tlmm_test_priv { + atomic_t intr_count; + atomic_t thread_count; + + unsigned int intr_op; + atomic_t intr_op_remain; + + unsigned int thread_op; + atomic_t thread_op_remain; +}; + +/* Operation masks for @intr_op and @thread_op */ +#define TLMM_TEST_COUNT BIT(0) +#define TLMM_TEST_OUTPUT_LOW BIT(1) +#define TLMM_TEST_OUTPUT_HIGH BIT(2) +#define TLMM_TEST_THEN_HIGH BIT(3) +#define TLMM_TEST_THEN_LOW BIT(4) +#define TLMM_TEST_WAKE_THREAD BIT(5) + +static void tlmm_output_low(void) +{ + writel(tlmm_suite.low_val, tlmm_suite.reg); + readl(tlmm_suite.reg); +} + +static void tlmm_output_high(void) +{ + writel(tlmm_suite.high_val, tlmm_suite.reg); + readl(tlmm_suite.reg); +} + +static irqreturn_t tlmm_test_intr_fn(int irq, void *dev_id) +{ + struct tlmm_test_priv *priv = dev_id; + + if (priv->intr_op & TLMM_TEST_COUNT) + atomic_inc(&priv->intr_count); + + if (priv->intr_op & TLMM_TEST_OUTPUT_LOW) + tlmm_output_low(); + if (priv->intr_op & TLMM_TEST_OUTPUT_HIGH) + tlmm_output_high(); + + if (atomic_dec_if_positive(&priv->intr_op_remain) > 0) { + udelay(1); + + if (priv->intr_op & TLMM_TEST_THEN_LOW) + tlmm_output_low(); + if (priv->intr_op & TLMM_TEST_THEN_HIGH) + tlmm_output_high(); + } + + return priv->intr_op & TLMM_TEST_WAKE_THREAD ? IRQ_WAKE_THREAD : IRQ_HANDLED; +} + +static irqreturn_t tlmm_test_intr_thread_fn(int irq, void *dev_id) +{ + struct tlmm_test_priv *priv = dev_id; + + if (priv->thread_op & TLMM_TEST_COUNT) + atomic_inc(&priv->thread_count); + + if (priv->thread_op & TLMM_TEST_OUTPUT_LOW) + tlmm_output_low(); + if (priv->thread_op & TLMM_TEST_OUTPUT_HIGH) + tlmm_output_high(); + + if (atomic_dec_if_positive(&priv->thread_op_remain) > 0) { + udelay(1); + if (priv->thread_op & TLMM_TEST_THEN_LOW) + tlmm_output_low(); + if (priv->thread_op & TLMM_TEST_THEN_HIGH) + tlmm_output_high(); + } + + return IRQ_HANDLED; +} + +static void tlmm_test_request_hard_irq(struct kunit *test, unsigned long irqflags) +{ + struct tlmm_test_priv *priv = test->priv; + int ret; + + ret = request_irq(tlmm_suite.irq, tlmm_test_intr_fn, irqflags, test->name, priv); + KUNIT_EXPECT_EQ(test, ret, 0); +} + +static void tlmm_test_request_threaded_irq(struct kunit *test, unsigned long irqflags) +{ + struct tlmm_test_priv *priv = test->priv; + int ret; + + ret = request_threaded_irq(tlmm_suite.irq, + tlmm_test_intr_fn, tlmm_test_intr_thread_fn, + irqflags, test->name, priv); + + KUNIT_EXPECT_EQ(test, ret, 0); +} + +static void tlmm_test_silent(struct kunit *test, unsigned long irqflags) +{ + struct tlmm_test_priv *priv = test->priv; + + priv->intr_op = TLMM_TEST_COUNT; + + /* GPIO line at non-triggering level */ + if (irqflags == IRQF_TRIGGER_LOW || irqflags == IRQF_TRIGGER_FALLING) + tlmm_output_high(); + else + tlmm_output_low(); + + tlmm_test_request_hard_irq(test, irqflags); + msleep(100); + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 0); +} + +/* + * Test that no RISING interrupts are triggered on a silent pin + */ +static void tlmm_test_silent_rising(struct kunit *test) +{ + tlmm_test_silent(test, IRQF_TRIGGER_RISING); +} + +/* + * Test that no FALLING interrupts are triggered on a silent pin + */ +static void tlmm_test_silent_falling(struct kunit *test) +{ + tlmm_test_silent(test, IRQF_TRIGGER_FALLING); +} + +/* + * Test that no LOW interrupts are triggered on a silent pin + */ +static void tlmm_test_silent_low(struct kunit *test) +{ + tlmm_test_silent(test, IRQF_TRIGGER_LOW); +} + +/* + * Test that no HIGH interrupts are triggered on a silent pin + */ +static void tlmm_test_silent_high(struct kunit *test) +{ + tlmm_test_silent(test, IRQF_TRIGGER_HIGH); +} + +/* + * Square wave with 10 high pulses, assert that we get 10 rising interrupts + */ +static void tlmm_test_rising(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + int i; + + priv->intr_op = TLMM_TEST_COUNT; + + tlmm_output_low(); + + tlmm_test_request_hard_irq(test, IRQF_TRIGGER_RISING); + for (i = 0; i < 10; i++) { + tlmm_output_low(); + msleep(20); + tlmm_output_high(); + msleep(20); + } + + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); +} + +/* + * Square wave with 10 low pulses, assert that we get 10 falling interrupts + */ +static void tlmm_test_falling(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + int i; + + priv->intr_op = TLMM_TEST_COUNT; + + tlmm_output_high(); + + tlmm_test_request_hard_irq(test, IRQF_TRIGGER_FALLING); + for (i = 0; i < 10; i++) { + tlmm_output_high(); + msleep(20); + tlmm_output_low(); + msleep(20); + } + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); +} + +/* + * Drive line low 10 times, handler drives it high to "clear the interrupt + * source", assert we get 10 interrupts + */ +static void tlmm_test_low(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + int i; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_HIGH; + atomic_set(&priv->intr_op_remain, 9); + + tlmm_output_high(); + + tlmm_test_request_hard_irq(test, IRQF_TRIGGER_LOW); + for (i = 0; i < 10; i++) { + msleep(20); + tlmm_output_low(); + } + msleep(100); + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); +} + +/* + * Drive line high 10 times, handler drives it low to "clear the interrupt + * source", assert we get 10 interrupts + */ +static void tlmm_test_high(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + int i; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_LOW; + atomic_set(&priv->intr_op_remain, 9); + + tlmm_output_low(); + + tlmm_test_request_hard_irq(test, IRQF_TRIGGER_HIGH); + for (i = 0; i < 10; i++) { + msleep(20); + tlmm_output_high(); + } + msleep(100); + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); +} + +/* + * Handler drives GPIO high to "clear the interrupt source", then low to + * simulate a new interrupt, repeated 10 times, assert we get 10 interrupts + */ +static void tlmm_test_falling_in_handler(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_HIGH | TLMM_TEST_THEN_LOW; + atomic_set(&priv->intr_op_remain, 10); + + tlmm_output_high(); + + tlmm_test_request_hard_irq(test, IRQF_TRIGGER_FALLING); + msleep(20); + tlmm_output_low(); + msleep(100); + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); +} + +/* + * Handler drives GPIO low to "clear the interrupt source", then high to + * simulate a new interrupt, repeated 10 times, assert we get 10 interrupts + */ +static void tlmm_test_rising_in_handler(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_LOW | TLMM_TEST_THEN_HIGH; + atomic_set(&priv->intr_op_remain, 10); + + tlmm_output_low(); + + tlmm_test_request_hard_irq(test, IRQF_TRIGGER_RISING); + msleep(20); + tlmm_output_high(); + msleep(100); + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); +} + +/* + * Square wave with 10 high pulses, assert that we get 10 rising hard and + * 10 threaded interrupts + */ +static void tlmm_test_thread_rising(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + int i; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_WAKE_THREAD; + priv->thread_op = TLMM_TEST_COUNT; + + tlmm_output_low(); + + tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_RISING); + for (i = 0; i < 10; i++) { + tlmm_output_low(); + msleep(20); + tlmm_output_high(); + msleep(20); + } + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); + KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10); +} + +/* + * Square wave with 10 low pulses, assert that we get 10 falling interrupts + */ +static void tlmm_test_thread_falling(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + int i; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_WAKE_THREAD; + priv->thread_op = TLMM_TEST_COUNT; + + tlmm_output_high(); + + tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_FALLING); + for (i = 0; i < 10; i++) { + tlmm_output_high(); + msleep(20); + tlmm_output_low(); + msleep(20); + } + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); + KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10); +} + +/* + * Drive line high 10 times, threaded handler drives it low to "clear the + * interrupt source", assert we get 10 interrupts + */ +static void tlmm_test_thread_high(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + int i; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_WAKE_THREAD; + priv->thread_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_LOW; + + tlmm_output_low(); + + tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_HIGH | IRQF_ONESHOT); + for (i = 0; i < 10; i++) { + tlmm_output_high(); + msleep(20); + } + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); + KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10); +} + +/* + * Drive line low 10 times, threaded handler drives it high to "clear the + * interrupt source", assert we get 10 interrupts + */ +static void tlmm_test_thread_low(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + int i; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_WAKE_THREAD; + priv->thread_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_HIGH; + + tlmm_output_high(); + + tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_LOW | IRQF_ONESHOT); + for (i = 0; i < 10; i++) { + tlmm_output_low(); + msleep(20); + } + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); + KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10); +} + +/* + * Handler drives GPIO low to "clear the interrupt source", then high in the + * threaded handler to simulate a new interrupt, repeated 10 times, assert we + * get 10 interrupts + */ +static void tlmm_test_thread_rising_in_handler(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_LOW | TLMM_TEST_WAKE_THREAD; + priv->thread_op = TLMM_TEST_COUNT | TLMM_TEST_THEN_HIGH; + atomic_set(&priv->thread_op_remain, 10); + + tlmm_output_low(); + + tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_RISING); + msleep(20); + tlmm_output_high(); + msleep(100); + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); + KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10); +} + +/* + * Handler drives GPIO high to "clear the interrupt source", then low in the + * threaded handler to simulate a new interrupt, repeated 10 times, assert we + * get 10 interrupts + */ +static void tlmm_test_thread_falling_in_handler(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + + priv->intr_op = TLMM_TEST_COUNT | TLMM_TEST_OUTPUT_HIGH | TLMM_TEST_WAKE_THREAD; + priv->thread_op = TLMM_TEST_COUNT | TLMM_TEST_THEN_LOW; + atomic_set(&priv->thread_op_remain, 10); + + tlmm_output_high(); + + tlmm_test_request_threaded_irq(test, IRQF_TRIGGER_FALLING); + msleep(20); + tlmm_output_low(); + msleep(100); + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 10); + KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10); +} + +static int tlmm_test_init(struct kunit *test) +{ + struct tlmm_test_priv *priv; + + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); + + atomic_set(&priv->intr_count, 0); + atomic_set(&priv->thread_count, 0); + + atomic_set(&priv->intr_op_remain, 0); + atomic_set(&priv->thread_op_remain, 0); + + test->priv = priv; + + return 0; +} + +/* + * NOTE: When adding compatibles to this list, ensure that TLMM_REG_SIZE and + * pull configuration values are supported and correct. + */ +static const struct of_device_id tlmm_of_match[] = { + { .compatible = "qcom,sc8280xp-tlmm" }, + { .compatible = "qcom,x1e80100-tlmm" }, + {} +}; + +static int tlmm_test_init_suite(struct kunit_suite *suite) +{ + struct of_phandle_args args = {}; + struct resource res; + int ret; + u32 val; + + if (tlmm_test_gpio < 0) { + pr_err("use the tlmm-test.gpio module parameter to specify which GPIO to use\n"); + return -EINVAL; + } + + struct device_node *tlmm __free(device_node) = of_find_matching_node(NULL, tlmm_of_match); + if (!tlmm) { + pr_err("failed to find tlmm node\n"); + return -EINVAL; + } + + ret = of_address_to_resource(tlmm, 0, &res); + if (ret < 0) + return ret; + + tlmm_suite.base = ioremap(res.start, resource_size(&res)); + if (!tlmm_suite.base) + return -ENOMEM; + + args.np = tlmm; + args.args_count = 2; + args.args[0] = tlmm_test_gpio; + args.args[1] = 0; + + tlmm_suite.irq = irq_create_of_mapping(&args); + if (!tlmm_suite.irq) { + pr_err("failed to map TLMM irq %d\n", args.args[0]); + goto err_unmap; + } + + tlmm_suite.reg = tlmm_suite.base + tlmm_test_gpio * TLMM_REG_SIZE; + val = readl(tlmm_suite.reg) & ~MSM_PULL_MASK; + tlmm_suite.low_val = val | MSM_PULL_DOWN; + tlmm_suite.high_val = val | MSM_PULL_UP; + + return 0; + +err_unmap: + iounmap(tlmm_suite.base); + tlmm_suite.base = NULL; + return -EINVAL; +} + +static void tlmm_test_exit_suite(struct kunit_suite *suite) +{ + irq_dispose_mapping(tlmm_suite.irq); + iounmap(tlmm_suite.base); + + tlmm_suite.base = NULL; + tlmm_suite.irq = -1; +} + +static struct kunit_case tlmm_test_cases[] = { + KUNIT_CASE(tlmm_test_silent_rising), + KUNIT_CASE(tlmm_test_silent_falling), + KUNIT_CASE(tlmm_test_silent_low), + KUNIT_CASE(tlmm_test_silent_high), + KUNIT_CASE(tlmm_test_rising), + KUNIT_CASE(tlmm_test_falling), + KUNIT_CASE(tlmm_test_high), + KUNIT_CASE(tlmm_test_low), + KUNIT_CASE(tlmm_test_rising_in_handler), + KUNIT_CASE(tlmm_test_falling_in_handler), + KUNIT_CASE(tlmm_test_thread_rising), + KUNIT_CASE(tlmm_test_thread_falling), + KUNIT_CASE(tlmm_test_thread_high), + KUNIT_CASE(tlmm_test_thread_low), + KUNIT_CASE(tlmm_test_thread_rising_in_handler), + KUNIT_CASE(tlmm_test_thread_falling_in_handler), + {} +}; + +static struct kunit_suite tlmm_test_suite = { + .name = "tlmm-test", + .init = tlmm_test_init, + .suite_init = tlmm_test_init_suite, + .suite_exit = tlmm_test_exit_suite, + .test_cases = tlmm_test_cases, +}; + +kunit_test_suites(&tlmm_test_suite); + +MODULE_DESCRIPTION("Qualcomm TLMM test"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From eb76dc973cef741f74ce17d3bba8a7c9f2cc6113 Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Sat, 1 Mar 2025 01:05:19 +0530 Subject: pinctrl: samsung: add support for exynos7870 pinctrl Add support for the Exynos7870 SoC pin-controller in the pinctrl driver. It has 8 GPIO banks, and 3-bit PINCFG_TYPE_DRV width. Signed-off-by: Kaustabh Chakraborty Link: https://lore.kernel.org/r/20250301-exynos7870-pinctrl-v3-3-ba1da9d3cd2f@disroot.org Signed-off-by: Krzysztof Kozlowski --- drivers/pinctrl/samsung/pinctrl-exynos-arm64.c | 139 +++++++++++++++++++++++++ drivers/pinctrl/samsung/pinctrl-exynos.h | 19 ++++ drivers/pinctrl/samsung/pinctrl-samsung.c | 2 + drivers/pinctrl/samsung/pinctrl-samsung.h | 1 + 4 files changed, 161 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c index 0e310c095e99..e35e5a8e23a0 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c @@ -40,6 +40,15 @@ static const struct samsung_pin_bank_type exynos5433_bank_type_alive = { .reg_offset = { 0x00, 0x04, 0x08, 0x0c, }, }; +/* + * Bank type for alive type. Bit fields: + * CON: 4, DAT: 1, PUD: 2, DRV: 3 + */ +static const struct samsung_pin_bank_type exynos7870_bank_type_alive = { + .fld_width = { 4, 1, 2, 3, }, + .reg_offset = { 0x00, 0x04, 0x08, 0x0c, }, +}; + /* * Bank type for non-alive type. Bit fields: * CON: 4, DAT: 1, PUD: 4, DRV: 4, CONPDN: 2, PUDPDN: 4 @@ -618,6 +627,136 @@ const struct samsung_pinctrl_of_match_data exynos7_of_data __initconst = { .num_ctrl = ARRAY_SIZE(exynos7_pin_ctrl), }; +/* pin banks of exynos7870 pin-controller 0 (ALIVE) */ +static const struct samsung_pin_bank_data exynos7870_pin_banks0[] __initconst = { + EXYNOS7870_PIN_BANK_EINTN(6, 0x000, "etc0"), + EXYNOS7870_PIN_BANK_EINTN(3, 0x020, "etc1"), + EXYNOS7870_PIN_BANK_EINTW(8, 0x040, "gpa0", 0x00), + EXYNOS7870_PIN_BANK_EINTW(8, 0x060, "gpa1", 0x04), + EXYNOS7870_PIN_BANK_EINTW(8, 0x080, "gpa2", 0x08), + EXYNOS7870_PIN_BANK_EINTN(2, 0x0c0, "gpq0"), +}; + +/* pin banks of exynos7870 pin-controller 1 (DISPAUD) */ +static const struct samsung_pin_bank_data exynos7870_pin_banks1[] __initconst = { + EXYNOS8895_PIN_BANK_EINTG(4, 0x000, "gpz0", 0x00), + EXYNOS8895_PIN_BANK_EINTG(6, 0x020, "gpz1", 0x04), + EXYNOS8895_PIN_BANK_EINTG(4, 0x040, "gpz2", 0x08), +}; + +/* pin banks of exynos7870 pin-controller 2 (ESE) */ +static const struct samsung_pin_bank_data exynos7870_pin_banks2[] __initconst = { + EXYNOS8895_PIN_BANK_EINTG(5, 0x000, "gpc7", 0x00), +}; + +/* pin banks of exynos7870 pin-controller 3 (FSYS) */ +static const struct samsung_pin_bank_data exynos7870_pin_banks3[] __initconst = { + EXYNOS8895_PIN_BANK_EINTG(3, 0x000, "gpr0", 0x00), + EXYNOS8895_PIN_BANK_EINTG(8, 0x020, "gpr1", 0x04), + EXYNOS8895_PIN_BANK_EINTG(2, 0x040, "gpr2", 0x08), + EXYNOS8895_PIN_BANK_EINTG(4, 0x060, "gpr3", 0x0c), + EXYNOS8895_PIN_BANK_EINTG(6, 0x080, "gpr4", 0x10), +}; + +/* pin banks of exynos7870 pin-controller 4 (MIF) */ +static const struct samsung_pin_bank_data exynos7870_pin_banks4[] __initconst = { + EXYNOS8895_PIN_BANK_EINTG(2, 0x000, "gpm0", 0x00), +}; + +/* pin banks of exynos7870 pin-controller 5 (NFC) */ +static const struct samsung_pin_bank_data exynos7870_pin_banks5[] __initconst = { + EXYNOS8895_PIN_BANK_EINTG(4, 0x000, "gpc2", 0x00), +}; + +/* pin banks of exynos7870 pin-controller 6 (TOP) */ +static const struct samsung_pin_bank_data exynos7870_pin_banks6[] __initconst = { + EXYNOS8895_PIN_BANK_EINTG(4, 0x000, "gpb0", 0x00), + EXYNOS8895_PIN_BANK_EINTG(3, 0x020, "gpc0", 0x04), + EXYNOS8895_PIN_BANK_EINTG(4, 0x040, "gpc1", 0x08), + EXYNOS8895_PIN_BANK_EINTG(4, 0x060, "gpc4", 0x0c), + EXYNOS8895_PIN_BANK_EINTG(2, 0x080, "gpc5", 0x10), + EXYNOS8895_PIN_BANK_EINTG(4, 0x0a0, "gpc6", 0x14), + EXYNOS8895_PIN_BANK_EINTG(2, 0x0c0, "gpc8", 0x18), + EXYNOS8895_PIN_BANK_EINTG(2, 0x0e0, "gpc9", 0x1c), + EXYNOS8895_PIN_BANK_EINTG(7, 0x100, "gpd1", 0x20), + EXYNOS8895_PIN_BANK_EINTG(6, 0x120, "gpd2", 0x24), + EXYNOS8895_PIN_BANK_EINTG(8, 0x140, "gpd3", 0x28), + EXYNOS8895_PIN_BANK_EINTG(7, 0x160, "gpd4", 0x2c), + EXYNOS8895_PIN_BANK_EINTG(3, 0x1a0, "gpe0", 0x34), + EXYNOS8895_PIN_BANK_EINTG(4, 0x1c0, "gpf0", 0x38), + EXYNOS8895_PIN_BANK_EINTG(2, 0x1e0, "gpf1", 0x3c), + EXYNOS8895_PIN_BANK_EINTG(2, 0x200, "gpf2", 0x40), + EXYNOS8895_PIN_BANK_EINTG(4, 0x220, "gpf3", 0x44), + EXYNOS8895_PIN_BANK_EINTG(5, 0x240, "gpf4", 0x48), +}; + +/* pin banks of exynos7870 pin-controller 7 (TOUCH) */ +static const struct samsung_pin_bank_data exynos7870_pin_banks7[] __initconst = { + EXYNOS8895_PIN_BANK_EINTG(3, 0x000, "gpc3", 0x00), +}; + +static const struct samsung_pin_ctrl exynos7870_pin_ctrl[] __initconst = { + { + /* pin-controller instance 0 Alive data */ + .pin_banks = exynos7870_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos7870_pin_banks0), + .eint_wkup_init = exynos_eint_wkup_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 1 DISPAUD data */ + .pin_banks = exynos7870_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos7870_pin_banks1), + }, { + /* pin-controller instance 2 ESE data */ + .pin_banks = exynos7870_pin_banks2, + .nr_banks = ARRAY_SIZE(exynos7870_pin_banks2), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 3 FSYS data */ + .pin_banks = exynos7870_pin_banks3, + .nr_banks = ARRAY_SIZE(exynos7870_pin_banks3), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 4 MIF data */ + .pin_banks = exynos7870_pin_banks4, + .nr_banks = ARRAY_SIZE(exynos7870_pin_banks4), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 5 NFC data */ + .pin_banks = exynos7870_pin_banks5, + .nr_banks = ARRAY_SIZE(exynos7870_pin_banks5), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 6 TOP data */ + .pin_banks = exynos7870_pin_banks6, + .nr_banks = ARRAY_SIZE(exynos7870_pin_banks6), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 7 TOUCH data */ + .pin_banks = exynos7870_pin_banks7, + .nr_banks = ARRAY_SIZE(exynos7870_pin_banks7), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, +}; + +const struct samsung_pinctrl_of_match_data exynos7870_of_data __initconst = { + .ctrl = exynos7870_pin_ctrl, + .num_ctrl = ARRAY_SIZE(exynos7870_pin_ctrl), +}; + /* pin banks of exynos7885 pin-controller 0 (ALIVE) */ static const struct samsung_pin_bank_data exynos7885_pin_banks0[] __initconst = { EXYNOS_PIN_BANK_EINTN(3, 0x000, "etc0"), diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h index 7b7ff7ffeb56..f78da2e4cda8 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.h +++ b/drivers/pinctrl/samsung/pinctrl-exynos.h @@ -112,6 +112,25 @@ .pctl_res_idx = pctl_idx, \ } \ +#define EXYNOS7870_PIN_BANK_EINTN(pins, reg, id) \ + { \ + .type = &exynos7870_bank_type_alive, \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .eint_type = EINT_TYPE_NONE, \ + .name = id \ + } + +#define EXYNOS7870_PIN_BANK_EINTW(pins, reg, id, offs) \ + { \ + .type = &exynos7870_bank_type_alive, \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .eint_type = EINT_TYPE_WKUP, \ + .eint_offset = offs, \ + .name = id \ + } + #define EXYNOS850_PIN_BANK_EINTN(pins, reg, id) \ { \ .type = &exynos850_bank_type_alive, \ diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 04a8a23f4bf1..24e96d919d8f 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -1475,6 +1475,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { .data = &exynos5433_of_data }, { .compatible = "samsung,exynos7-pinctrl", .data = &exynos7_of_data }, + { .compatible = "samsung,exynos7870-pinctrl", + .data = &exynos7870_of_data }, { .compatible = "samsung,exynos7885-pinctrl", .data = &exynos7885_of_data }, { .compatible = "samsung,exynos850-pinctrl", diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index a43803027aa8..2f452f592655 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -383,6 +383,7 @@ extern const struct samsung_pinctrl_of_match_data exynos5410_of_data; extern const struct samsung_pinctrl_of_match_data exynos5420_of_data; extern const struct samsung_pinctrl_of_match_data exynos5433_of_data; extern const struct samsung_pinctrl_of_match_data exynos7_of_data; +extern const struct samsung_pinctrl_of_match_data exynos7870_of_data; extern const struct samsung_pinctrl_of_match_data exynos7885_of_data; extern const struct samsung_pinctrl_of_match_data exynos850_of_data; extern const struct samsung_pinctrl_of_match_data exynos8895_of_data; -- cgit v1.2.3-59-g8ed1b From 0ee2261d08aa21a7327f145cbf1bfb6ac2205c7d Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Mon, 3 Mar 2025 19:25:06 +0530 Subject: pinctrl: intel: drop repeated config dependency We already have ACPI dependency for Intel pinctrl menu. No need to repeat it. Signed-off-by: Raag Jadav Acked-by: Mika Westerberg Signed-off-by: Andy Shevchenko --- drivers/pinctrl/intel/Kconfig | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/Kconfig b/drivers/pinctrl/intel/Kconfig index 14c26c023590..248c2e558ff3 100644 --- a/drivers/pinctrl/intel/Kconfig +++ b/drivers/pinctrl/intel/Kconfig @@ -39,7 +39,6 @@ config PINCTRL_INTEL config PINCTRL_INTEL_PLATFORM tristate "Intel pinctrl and GPIO platform driver" - depends on ACPI select PINCTRL_INTEL help This pinctrl driver provides an interface that allows configuring @@ -141,7 +140,6 @@ config PINCTRL_METEORLAKE config PINCTRL_METEORPOINT tristate "Intel Meteor Point pinctrl and GPIO driver" - depends on ACPI select PINCTRL_INTEL help Meteor Point is the PCH of Intel Meteor Lake. This pinctrl driver -- cgit v1.2.3-59-g8ed1b From a5e4cde647851ed67f19a5cb54a99282f32aae99 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Fri, 28 Feb 2025 06:40:09 +0000 Subject: pinctrl: rockchip: Add support for RK3528 Add gpio and pinctrl support for the 5 GPIO banks on RK3528. Signed-off-by: Steven Liu Signed-off-by: Jonas Karlman Reviewed-by: Heiko Stuebner Link: https://lore.kernel.org/20250228064024.3200000-4-jonas@kwiboo.se Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-rockchip.c | 160 ++++++++++++++++++++++++++++++++++++- drivers/pinctrl/pinctrl-rockchip.h | 1 + 2 files changed, 160 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 15145882950f..930c454e0cec 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -2003,6 +2003,115 @@ static int rk3399_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, return 0; } +#define RK3528_DRV_BITS_PER_PIN 8 +#define RK3528_DRV_PINS_PER_REG 2 +#define RK3528_DRV_GPIO0_OFFSET 0x100 +#define RK3528_DRV_GPIO1_OFFSET 0x20120 +#define RK3528_DRV_GPIO2_OFFSET 0x30160 +#define RK3528_DRV_GPIO3_OFFSET 0x20190 +#define RK3528_DRV_GPIO4_OFFSET 0x101C0 + +static int rk3528_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) +{ + struct rockchip_pinctrl *info = bank->drvdata; + + *regmap = info->regmap_base; + + if (bank->bank_num == 0) + *reg = RK3528_DRV_GPIO0_OFFSET; + else if (bank->bank_num == 1) + *reg = RK3528_DRV_GPIO1_OFFSET; + else if (bank->bank_num == 2) + *reg = RK3528_DRV_GPIO2_OFFSET; + else if (bank->bank_num == 3) + *reg = RK3528_DRV_GPIO3_OFFSET; + else if (bank->bank_num == 4) + *reg = RK3528_DRV_GPIO4_OFFSET; + else + dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num); + + *reg += ((pin_num / RK3528_DRV_PINS_PER_REG) * 4); + *bit = pin_num % RK3528_DRV_PINS_PER_REG; + *bit *= RK3528_DRV_BITS_PER_PIN; + + return 0; +} + +#define RK3528_PULL_BITS_PER_PIN 2 +#define RK3528_PULL_PINS_PER_REG 8 +#define RK3528_PULL_GPIO0_OFFSET 0x200 +#define RK3528_PULL_GPIO1_OFFSET 0x20210 +#define RK3528_PULL_GPIO2_OFFSET 0x30220 +#define RK3528_PULL_GPIO3_OFFSET 0x20230 +#define RK3528_PULL_GPIO4_OFFSET 0x10240 + +static int rk3528_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) +{ + struct rockchip_pinctrl *info = bank->drvdata; + + *regmap = info->regmap_base; + + if (bank->bank_num == 0) + *reg = RK3528_PULL_GPIO0_OFFSET; + else if (bank->bank_num == 1) + *reg = RK3528_PULL_GPIO1_OFFSET; + else if (bank->bank_num == 2) + *reg = RK3528_PULL_GPIO2_OFFSET; + else if (bank->bank_num == 3) + *reg = RK3528_PULL_GPIO3_OFFSET; + else if (bank->bank_num == 4) + *reg = RK3528_PULL_GPIO4_OFFSET; + else + dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num); + + *reg += ((pin_num / RK3528_PULL_PINS_PER_REG) * 4); + *bit = pin_num % RK3528_PULL_PINS_PER_REG; + *bit *= RK3528_PULL_BITS_PER_PIN; + + return 0; +} + +#define RK3528_SMT_BITS_PER_PIN 1 +#define RK3528_SMT_PINS_PER_REG 8 +#define RK3528_SMT_GPIO0_OFFSET 0x400 +#define RK3528_SMT_GPIO1_OFFSET 0x20410 +#define RK3528_SMT_GPIO2_OFFSET 0x30420 +#define RK3528_SMT_GPIO3_OFFSET 0x20430 +#define RK3528_SMT_GPIO4_OFFSET 0x10440 + +static int rk3528_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, + struct regmap **regmap, + int *reg, u8 *bit) +{ + struct rockchip_pinctrl *info = bank->drvdata; + + *regmap = info->regmap_base; + + if (bank->bank_num == 0) + *reg = RK3528_SMT_GPIO0_OFFSET; + else if (bank->bank_num == 1) + *reg = RK3528_SMT_GPIO1_OFFSET; + else if (bank->bank_num == 2) + *reg = RK3528_SMT_GPIO2_OFFSET; + else if (bank->bank_num == 3) + *reg = RK3528_SMT_GPIO3_OFFSET; + else if (bank->bank_num == 4) + *reg = RK3528_SMT_GPIO4_OFFSET; + else + dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num); + + *reg += ((pin_num / RK3528_SMT_PINS_PER_REG) * 4); + *bit = pin_num % RK3528_SMT_PINS_PER_REG; + *bit *= RK3528_SMT_BITS_PER_PIN; + + return 0; +} + #define RK3562_DRV_BITS_PER_PIN 8 #define RK3562_DRV_PINS_PER_REG 2 #define RK3562_DRV_GPIO0_OFFSET 0x20070 @@ -2640,7 +2749,8 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank, rmask_bits = RK3588_DRV_BITS_PER_PIN; ret = strength; goto config; - } else if (ctrl->type == RK3562 || + } else if (ctrl->type == RK3528 || + ctrl->type == RK3562 || ctrl->type == RK3568) { rmask_bits = RK3568_DRV_BITS_PER_PIN; ret = (1 << (strength + 1)) - 1; @@ -2785,6 +2895,7 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num) case RK3328: case RK3368: case RK3399: + case RK3528: case RK3562: case RK3568: case RK3576: @@ -2846,6 +2957,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, case RK3328: case RK3368: case RK3399: + case RK3528: case RK3562: case RK3568: case RK3576: @@ -3115,6 +3227,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl, case RK3328: case RK3368: case RK3399: + case RK3528: case RK3562: case RK3568: case RK3576: @@ -4237,6 +4350,49 @@ static struct rockchip_pin_ctrl rk3399_pin_ctrl = { .drv_calc_reg = rk3399_calc_drv_reg_and_bit, }; +static struct rockchip_pin_bank rk3528_pin_banks[] = { + PIN_BANK_IOMUX_FLAGS_OFFSET(0, 32, "gpio0", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0, 0, 0, 0), + PIN_BANK_IOMUX_FLAGS_OFFSET(1, 32, "gpio1", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0x20020, 0x20028, 0x20030, 0x20038), + PIN_BANK_IOMUX_FLAGS_OFFSET(2, 32, "gpio2", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0x30040, 0, 0, 0), + PIN_BANK_IOMUX_FLAGS_OFFSET(3, 32, "gpio3", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0x20060, 0x20068, 0x20070, 0), + PIN_BANK_IOMUX_FLAGS_OFFSET(4, 32, "gpio4", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0x10080, 0x10088, 0x10090, 0x10098), +}; + +static struct rockchip_pin_ctrl rk3528_pin_ctrl = { + .pin_banks = rk3528_pin_banks, + .nr_banks = ARRAY_SIZE(rk3528_pin_banks), + .label = "RK3528-GPIO", + .type = RK3528, + .pull_calc_reg = rk3528_calc_pull_reg_and_bit, + .drv_calc_reg = rk3528_calc_drv_reg_and_bit, + .schmitt_calc_reg = rk3528_calc_schmitt_reg_and_bit, +}; + static struct rockchip_pin_bank rk3562_pin_banks[] = { PIN_BANK_IOMUX_FLAGS_OFFSET(0, 32, "gpio0", IOMUX_WIDTH_4BIT, @@ -4404,6 +4560,8 @@ static const struct of_device_id rockchip_pinctrl_dt_match[] = { .data = &rk3368_pin_ctrl }, { .compatible = "rockchip,rk3399-pinctrl", .data = &rk3399_pin_ctrl }, + { .compatible = "rockchip,rk3528-pinctrl", + .data = &rk3528_pin_ctrl }, { .compatible = "rockchip,rk3562-pinctrl", .data = &rk3562_pin_ctrl }, { .compatible = "rockchip,rk3568-pinctrl", diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h index 87a20cec8e21..35cd38079d1e 100644 --- a/drivers/pinctrl/pinctrl-rockchip.h +++ b/drivers/pinctrl/pinctrl-rockchip.h @@ -196,6 +196,7 @@ enum rockchip_pinctrl_type { RK3328, RK3368, RK3399, + RK3528, RK3562, RK3568, RK3576, -- cgit v1.2.3-59-g8ed1b From 75f87f5d04f73645136d7a603c331d844fc5704a Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 19 Feb 2025 11:27:50 +0100 Subject: pinctrl: bcm2835: don't -EINVAL on alternate funcs from get_direction() Since commit 9d846b1aebbe ("gpiolib: check the return value of gpio_chip::get_direction()") we check the return value of the get_direction() callback as per its API contract. This driver returns -EINVAL if the pin in question is set to one of the alternative (non-GPIO) functions. This isn't really an error that should be communicated to GPIOLIB so default to returning the "safe" value of INPUT in this case. The GPIO subsystem does not have the notion of "unknown" direction. Fixes: 9d846b1aebbe ("gpiolib: check the return value of gpio_chip::get_direction()") Reported-by: Mark Brown Closes: https://lore.kernel.org/all/Z7VFB1nST6lbmBIo@finisterre.sirena.org.uk/ Signed-off-by: Bartosz Golaszewski Tested-by: Marek Szyprowski Reviewed-by: Stefan Wahren Link: https://lore.kernel.org/20250219102750.38519-1-brgl@bgdev.pl Signed-off-by: Linus Walleij --- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c index cc1fe0555e19..eaeec096bc9a 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c @@ -346,14 +346,14 @@ static int bcm2835_gpio_get_direction(struct gpio_chip *chip, unsigned int offse struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, offset); - /* Alternative function doesn't clearly provide a direction */ - if (fsel > BCM2835_FSEL_GPIO_OUT) - return -EINVAL; - - if (fsel == BCM2835_FSEL_GPIO_IN) - return GPIO_LINE_DIRECTION_IN; + if (fsel == BCM2835_FSEL_GPIO_OUT) + return GPIO_LINE_DIRECTION_OUT; - return GPIO_LINE_DIRECTION_OUT; + /* + * Alternative function doesn't clearly provide a direction. Default + * to INPUT. + */ + return GPIO_LINE_DIRECTION_IN; } static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -- cgit v1.2.3-59-g8ed1b From c3a0b61e498e915baa7d74bacd0d20d9aa34638a Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Mon, 3 Mar 2025 15:53:20 +0800 Subject: pinctrl: meson: fix pin input property for a4 The register of pin input attribute means the opposite. value of reigster meaning is 1 for input and 0 for output. So fix it. Fixes: 6e9be3abb78c ("pinctrl: Add driver support for Amlogic SoCs") Signed-off-by: Xianwei Zhao Link: https://lore.kernel.org/20250303-fix-a4-pinctl-v1-1-6579888b4272@amlogic.com Signed-off-by: Linus Walleij --- drivers/pinctrl/meson/pinctrl-amlogic-a4.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c index a5218e8f1e03..35d5540b8eaa 100644 --- a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c +++ b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c @@ -775,7 +775,7 @@ static int aml_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio) if (ret) return ret; - return BIT(bit) & val ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; + return BIT(bit) & val ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; } static int aml_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio) @@ -785,7 +785,7 @@ static int aml_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio) aml_gpio_calc_reg_and_bit(bank, AML_REG_DIR, gpio, ®, &bit); - return regmap_update_bits(bank->reg_gpio, reg, BIT(bit), 0); + return regmap_update_bits(bank->reg_gpio, reg, BIT(bit), BIT(bit)); } static int aml_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, @@ -796,7 +796,7 @@ static int aml_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, int ret; aml_gpio_calc_reg_and_bit(bank, AML_REG_DIR, gpio, ®, &bit); - ret = regmap_update_bits(bank->reg_gpio, reg, BIT(bit), BIT(bit)); + ret = regmap_update_bits(bank->reg_gpio, reg, BIT(bit), 0); if (ret < 0) return ret; -- cgit v1.2.3-59-g8ed1b From 7f7a793d71da26d4a1582f8c1e127ac6917d2056 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 3 Mar 2025 09:28:26 +0000 Subject: pinctrl: pinconf-generic: Fix spelling mistake "paramers" -> "parameters" There is a spelling mistake in a dev_err message. Fix it. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/20250303092826.318638-1-colin.i.king@gmail.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinconf-generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index ecb7bc175283..d67838afb085 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -262,7 +262,7 @@ int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev, } if (!pid || !pmux || !npins) { - dev_err(dev, "paramers error\n"); + dev_err(dev, "parameters error\n"); return -EINVAL; } -- cgit v1.2.3-59-g8ed1b From e97435ab09f3ad7b6a588dd7c4e45a96699bbb4a Mon Sep 17 00:00:00 2001 From: Pratap Nirujogi Date: Tue, 4 Mar 2025 18:20:31 -0500 Subject: pinctrl: amd: isp411: Add amdisp GPIO pinctrl Add pinctrl driver support for AMD SoC with isp41 hw ip block. Signed-off-by: Pratap Nirujogi Link: https://lore.kernel.org/20250304232051.2936557-1-pratap.nirujogi@amd.com Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 13 +++ drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-amdisp.c | 231 +++++++++++++++++++++++++++++++++++++++ drivers/pinctrl/pinctrl-amdisp.h | 95 ++++++++++++++++ 4 files changed, 340 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-amdisp.c create mode 100644 drivers/pinctrl/pinctrl-amdisp.h (limited to 'drivers') diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 95a8e2b9a614..5819f18b2ddc 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -49,6 +49,19 @@ config PINCTRL_AMD Requires ACPI/FDT device enumeration code to set up a platform device. +config PINCTRL_AMDISP + tristate "AMDISP GPIO pin control" + depends on HAS_IOMEM + select GPIOLIB + select PINCONF + select GENERIC_PINCONF + help + The driver for memory mapped GPIO functionality on AMD platforms + with ISP support. All the pins are output controlled only + + Requires AMDGPU to MFD add device for enumeration to set up as + platform device. + config PINCTRL_APPLE_GPIO tristate "Apple SoC GPIO pin controller driver" depends on ARCH_APPLE diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index fba1c56624c0..ac27e88677d1 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o obj-$(CONFIG_OF) += devicetree.o obj-$(CONFIG_PINCTRL_AMD) += pinctrl-amd.o +obj-$(CONFIG_PINCTRL_AMDISP) += pinctrl-amdisp.o obj-$(CONFIG_PINCTRL_APPLE_GPIO) += pinctrl-apple-gpio.o obj-$(CONFIG_PINCTRL_ARTPEC6) += pinctrl-artpec6.o obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o diff --git a/drivers/pinctrl/pinctrl-amdisp.c b/drivers/pinctrl/pinctrl-amdisp.c new file mode 100644 index 000000000000..ce21ed84b929 --- /dev/null +++ b/drivers/pinctrl/pinctrl-amdisp.c @@ -0,0 +1,231 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * AMD ISP Pinctrl Driver + * + * Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved. + * + */ + +#include +#include +#include + +#include "pinctrl-amdisp.h" + +#define DRV_NAME "amdisp-pinctrl" +#define GPIO_CONTROL_PIN 4 +#define GPIO_OFFSET_0 0x0 +#define GPIO_OFFSET_1 0x4 +#define GPIO_OFFSET_2 0x50 + +static const u32 gpio_offset[] = { + GPIO_OFFSET_0, + GPIO_OFFSET_1, + GPIO_OFFSET_2 +}; + +struct amdisp_pinctrl_data { + const struct pinctrl_pin_desc *pins; + unsigned int npins; + const struct amdisp_function *functions; + unsigned int nfunctions; + const struct amdisp_pingroup *groups; + unsigned int ngroups; +}; + +static const struct amdisp_pinctrl_data amdisp_pinctrl_data = { + .pins = amdisp_pins, + .npins = ARRAY_SIZE(amdisp_pins), + .functions = amdisp_functions, + .nfunctions = ARRAY_SIZE(amdisp_functions), + .groups = amdisp_groups, + .ngroups = ARRAY_SIZE(amdisp_groups), +}; + +struct amdisp_pinctrl { + struct device *dev; + struct pinctrl_dev *pctrl; + struct pinctrl_desc desc; + struct pinctrl_gpio_range gpio_range; + struct gpio_chip gc; + const struct amdisp_pinctrl_data *data; + void __iomem *gpiobase; + raw_spinlock_t lock; +}; + +static int amdisp_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct amdisp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->data->ngroups; +} + +static const char *amdisp_get_group_name(struct pinctrl_dev *pctldev, + unsigned int group) +{ + struct amdisp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->data->groups[group].name; +} + +static int amdisp_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int group, + const unsigned int **pins, + unsigned int *num_pins) +{ + struct amdisp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *pins = pctrl->data->groups[group].pins; + *num_pins = pctrl->data->groups[group].npins; + return 0; +} + +const struct pinctrl_ops amdisp_pinctrl_ops = { + .get_groups_count = amdisp_get_groups_count, + .get_group_name = amdisp_get_group_name, + .get_group_pins = amdisp_get_group_pins, +}; + +static int amdisp_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio) +{ + /* amdisp gpio only has output mode */ + return GPIO_LINE_DIRECTION_OUT; +} + +static int amdisp_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio) +{ + return -EOPNOTSUPP; +} + +static int amdisp_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio, + int value) +{ + /* Nothing to do, amdisp gpio only has output mode */ + return 0; +} + +static int amdisp_gpio_get(struct gpio_chip *gc, unsigned int gpio) +{ + unsigned long flags; + u32 pin_reg; + struct amdisp_pinctrl *pctrl = gpiochip_get_data(gc); + + raw_spin_lock_irqsave(&pctrl->lock, flags); + pin_reg = readl(pctrl->gpiobase + gpio_offset[gpio]); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + return !!(pin_reg & BIT(GPIO_CONTROL_PIN)); +} + +static void amdisp_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) +{ + unsigned long flags; + u32 pin_reg; + struct amdisp_pinctrl *pctrl = gpiochip_get_data(gc); + + raw_spin_lock_irqsave(&pctrl->lock, flags); + pin_reg = readl(pctrl->gpiobase + gpio_offset[gpio]); + if (value) + pin_reg |= BIT(GPIO_CONTROL_PIN); + else + pin_reg &= ~BIT(GPIO_CONTROL_PIN); + writel(pin_reg, pctrl->gpiobase + gpio_offset[gpio]); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); +} + +static int amdisp_gpiochip_add(struct platform_device *pdev, + struct amdisp_pinctrl *pctrl) +{ + struct gpio_chip *gc = &pctrl->gc; + struct pinctrl_gpio_range *grange = &pctrl->gpio_range; + int ret; + + gc->label = dev_name(pctrl->dev); + gc->parent = &pdev->dev; + gc->names = amdisp_range_pins_name; + gc->request = gpiochip_generic_request; + gc->free = gpiochip_generic_free; + gc->get_direction = amdisp_gpio_get_direction; + gc->direction_input = amdisp_gpio_direction_input; + gc->direction_output = amdisp_gpio_direction_output; + gc->get = amdisp_gpio_get; + gc->set = amdisp_gpio_set; + gc->base = -1; + gc->ngpio = ARRAY_SIZE(amdisp_range_pins); + + grange->id = 0; + grange->pin_base = 0; + grange->base = 0; + grange->pins = amdisp_range_pins; + grange->npins = ARRAY_SIZE(amdisp_range_pins); + grange->name = gc->label; + grange->gc = gc; + + ret = devm_gpiochip_add_data(&pdev->dev, gc, pctrl); + if (ret) + return ret; + + pinctrl_add_gpio_range(pctrl->pctrl, grange); + + return 0; +} + +static int amdisp_pinctrl_probe(struct platform_device *pdev) +{ + struct amdisp_pinctrl *pctrl; + struct resource *res; + int ret; + + pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pdev->dev.init_name = DRV_NAME; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (IS_ERR(res)) + return PTR_ERR(res); + + pctrl->gpiobase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pctrl->gpiobase)) + return PTR_ERR(pctrl->gpiobase); + + platform_set_drvdata(pdev, pctrl); + + pctrl->dev = &pdev->dev; + pctrl->data = &amdisp_pinctrl_data; + pctrl->desc.owner = THIS_MODULE; + pctrl->desc.pctlops = &amdisp_pinctrl_ops; + pctrl->desc.pmxops = NULL; + pctrl->desc.name = dev_name(&pdev->dev); + pctrl->desc.pins = pctrl->data->pins; + pctrl->desc.npins = pctrl->data->npins; + ret = devm_pinctrl_register_and_init(&pdev->dev, &pctrl->desc, + pctrl, &pctrl->pctrl); + if (ret) + return ret; + + ret = pinctrl_enable(pctrl->pctrl); + if (ret) + return ret; + + ret = amdisp_gpiochip_add(pdev, pctrl); + if (ret) + return ret; + + return 0; +} + +static struct platform_driver amdisp_pinctrl_driver = { + .driver = { + .name = DRV_NAME, + }, + .probe = amdisp_pinctrl_probe, +}; +module_platform_driver(amdisp_pinctrl_driver); + +MODULE_AUTHOR("Benjamin Chan "); +MODULE_AUTHOR("Pratap Nirujogi "); +MODULE_DESCRIPTION("AMDISP pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/pinctrl/pinctrl-amdisp.h b/drivers/pinctrl/pinctrl-amdisp.h new file mode 100644 index 000000000000..9e3597a03227 --- /dev/null +++ b/drivers/pinctrl/pinctrl-amdisp.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * AMD ISP Pinctrl Driver + * + * Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved. + * + */ + +static const struct pinctrl_pin_desc amdisp_pins[] = { + PINCTRL_PIN(0, "GPIO_0"), /* sensor0 control */ + PINCTRL_PIN(1, "GPIO_1"), /* sensor1 control */ + PINCTRL_PIN(2, "GPIO_2"), /* sensor2 control */ +}; + +#define AMDISP_GPIO_PINS(pin) \ +static const unsigned int gpio##pin##_pins[] = { pin } +AMDISP_GPIO_PINS(0); +AMDISP_GPIO_PINS(1); +AMDISP_GPIO_PINS(2); + +static const unsigned int amdisp_range_pins[] = { + 0, 1, 2 +}; + +static const char * const amdisp_range_pins_name[] = { + "gpio0", "gpio1", "gpio2" +}; + +enum amdisp_functions { + mux_gpio, + mux_NA +}; + +static const char * const gpio_groups[] = { + "gpio0", "gpio1", "gpio2" +}; + +/** + * struct amdisp_function - a pinmux function + * @name: Name of the pinmux function. + * @groups: List of pingroups for this function. + * @ngroups: Number of entries in @groups. + */ +struct amdisp_function { + const char *name; + const char * const *groups; + unsigned int ngroups; +}; + +#define FUNCTION(fname) \ + [mux_##fname] = { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + +static const struct amdisp_function amdisp_functions[] = { + FUNCTION(gpio), +}; + +/** + * struct amdisp_pingroup - a pinmux group + * @name: Name of the pinmux group. + * @pins: List of pins for this group. + * @npins: Number of entries in @pins. + * @funcs: List of functions belongs to this group. + * @nfuncs: Number of entries in @funcs. + * @offset: Group offset in amdisp pinmux groups. + */ +struct amdisp_pingroup { + const char *name; + const unsigned int *pins; + unsigned int npins; + unsigned int *funcs; + unsigned int nfuncs; + unsigned int offset; +}; + +#define PINGROUP(id, f0) \ + { \ + .name = "gpio" #id, \ + .pins = gpio##id##_pins, \ + .npins = ARRAY_SIZE(gpio##id##_pins), \ + .funcs = (int[]){ \ + mux_##f0, \ + }, \ + .nfuncs = 1, \ + .offset = id, \ + } + +static const struct amdisp_pingroup amdisp_groups[] = { + PINGROUP(0, gpio), + PINGROUP(1, gpio), + PINGROUP(2, gpio), +}; -- cgit v1.2.3-59-g8ed1b From 07b5a2a13f4704c5eae3be7277ec54ffdba45f72 Mon Sep 17 00:00:00 2001 From: Artur Weber Date: Mon, 3 Mar 2025 21:54:47 +0100 Subject: pinctrl: bcm281xx: Use "unsigned int" instead of bare "unsigned" Replace uses of bare "unsigned" with "unsigned int" to fix checkpatch warnings. No functional change. Signed-off-by: Artur Weber Link: https://lore.kernel.org/20250303-bcm21664-pinctrl-v3-2-5f8b80e4ab51@gmail.com Signed-off-by: Linus Walleij --- drivers/pinctrl/bcm/pinctrl-bcm281xx.c | 44 +++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c index 73dbf29c002f..3d774ee97aac 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c @@ -72,7 +72,7 @@ static enum bcm281xx_pin_type hdmi_pin = BCM281XX_PIN_TYPE_HDMI; struct bcm281xx_pin_function { const char *name; const char * const *groups; - const unsigned ngroups; + const unsigned int ngroups; }; /* @@ -84,10 +84,10 @@ struct bcm281xx_pinctrl_data { /* List of all pins */ const struct pinctrl_pin_desc *pins; - const unsigned npins; + const unsigned int npins; const struct bcm281xx_pin_function *functions; - const unsigned nfunctions; + const unsigned int nfunctions; struct regmap *regmap; }; @@ -941,7 +941,7 @@ static struct bcm281xx_pinctrl_data bcm281xx_pinctrl = { }; static inline enum bcm281xx_pin_type pin_type_get(struct pinctrl_dev *pctldev, - unsigned pin) + unsigned int pin) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); @@ -985,7 +985,7 @@ static int bcm281xx_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) } static const char *bcm281xx_pinctrl_get_group_name(struct pinctrl_dev *pctldev, - unsigned group) + unsigned int group) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); @@ -993,9 +993,9 @@ static const char *bcm281xx_pinctrl_get_group_name(struct pinctrl_dev *pctldev, } static int bcm281xx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, - unsigned group, + unsigned int group, const unsigned **pins, - unsigned *num_pins) + unsigned int *num_pins) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); @@ -1007,7 +1007,7 @@ static int bcm281xx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, static void bcm281xx_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, - unsigned offset) + unsigned int offset) { seq_printf(s, " %s", dev_name(pctldev->dev)); } @@ -1029,7 +1029,7 @@ static int bcm281xx_pinctrl_get_fcns_count(struct pinctrl_dev *pctldev) } static const char *bcm281xx_pinctrl_get_fcn_name(struct pinctrl_dev *pctldev, - unsigned function) + unsigned int function) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); @@ -1037,9 +1037,9 @@ static const char *bcm281xx_pinctrl_get_fcn_name(struct pinctrl_dev *pctldev, } static int bcm281xx_pinctrl_get_fcn_groups(struct pinctrl_dev *pctldev, - unsigned function, + unsigned int function, const char * const **groups, - unsigned * const num_groups) + unsigned int * const num_groups) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); @@ -1050,8 +1050,8 @@ static int bcm281xx_pinctrl_get_fcn_groups(struct pinctrl_dev *pctldev, } static int bcm281xx_pinmux_set(struct pinctrl_dev *pctldev, - unsigned function, - unsigned group) + unsigned int function, + unsigned int group) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); const struct bcm281xx_pin_function *f = &pdata->functions[function]; @@ -1082,7 +1082,7 @@ static const struct pinmux_ops bcm281xx_pinctrl_pinmux_ops = { }; static int bcm281xx_pinctrl_pin_config_get(struct pinctrl_dev *pctldev, - unsigned pin, + unsigned int pin, unsigned long *config) { return -ENOTSUPP; @@ -1091,9 +1091,9 @@ static int bcm281xx_pinctrl_pin_config_get(struct pinctrl_dev *pctldev, /* Goes through the configs and update register val/mask */ static int bcm281xx_std_pin_update(struct pinctrl_dev *pctldev, - unsigned pin, + unsigned int pin, unsigned long *configs, - unsigned num_configs, + unsigned int num_configs, u32 *val, u32 *mask) { @@ -1207,9 +1207,9 @@ static const u16 bcm281xx_pullup_map[] = { /* Goes through the configs and update register val/mask */ static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev, - unsigned pin, + unsigned int pin, unsigned long *configs, - unsigned num_configs, + unsigned int num_configs, u32 *val, u32 *mask) { @@ -1277,9 +1277,9 @@ static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev, /* Goes through the configs and update register val/mask */ static int bcm281xx_hdmi_pin_update(struct pinctrl_dev *pctldev, - unsigned pin, + unsigned int pin, unsigned long *configs, - unsigned num_configs, + unsigned int num_configs, u32 *val, u32 *mask) { @@ -1321,9 +1321,9 @@ static int bcm281xx_hdmi_pin_update(struct pinctrl_dev *pctldev, } static int bcm281xx_pinctrl_pin_config_set(struct pinctrl_dev *pctldev, - unsigned pin, + unsigned int pin, unsigned long *configs, - unsigned num_configs) + unsigned int num_configs) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); enum bcm281xx_pin_type pin_type; -- cgit v1.2.3-59-g8ed1b From 596c185284a6509dbb723a2dcd16b37ac1646039 Mon Sep 17 00:00:00 2001 From: Artur Weber Date: Mon, 3 Mar 2025 21:54:48 +0100 Subject: pinctrl: bcm281xx: Provide pinctrl device info as OF platform data Introduce a new struct type, "bcm281xx_pinctrl_info", that holds information about the pins, pin functions and regmap config for a pin control chip. Create such a struct for the BCM218xx and pass it as device data for the OF compatible match. This is done in preparation for introducing additional chip types to the driver. Signed-off-by: Artur Weber Link: https://lore.kernel.org/20250303-bcm21664-pinctrl-v3-3-5f8b80e4ab51@gmail.com Signed-off-by: Linus Walleij --- drivers/pinctrl/bcm/pinctrl-bcm281xx.c | 119 +++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c index 3d774ee97aac..f5aeb8a56e6f 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c @@ -76,20 +76,40 @@ struct bcm281xx_pin_function { }; /* - * bcm281xx_pinctrl_data - Broadcom-specific pinctrl data - * @reg_base - base of pinctrl registers + * Device types (used in bcm281xx_pinctrl_desc to differentiate + * the two device types from each other) */ -struct bcm281xx_pinctrl_data { - void __iomem *reg_base; +enum bcm281xx_pinctrl_type { + BCM281XX_PINCTRL_TYPE, +}; + +/* + * bcm281xx_pinctrl_info - description of a pinctrl device supported + * by this driver, intended to be used as a provider of OF match data. + */ +struct bcm281xx_pinctrl_info { + enum bcm281xx_pinctrl_type device_type; /* List of all pins */ const struct pinctrl_pin_desc *pins; - const unsigned int npins; + unsigned int npins; const struct bcm281xx_pin_function *functions; - const unsigned int nfunctions; + unsigned int nfunctions; + + const struct regmap_config *regmap_config; +}; + +/* + * bcm281xx_pinctrl_data - Broadcom-specific pinctrl data + * @reg_base - base of pinctrl registers + */ +struct bcm281xx_pinctrl_data { + struct device *dev; + void __iomem *reg_base; struct regmap *regmap; + const struct bcm281xx_pinctrl_info *info; }; /* @@ -933,11 +953,22 @@ static const struct bcm281xx_pin_function bcm281xx_functions[] = { BCM281XX_PIN_FUNCTION(alt4), }; -static struct bcm281xx_pinctrl_data bcm281xx_pinctrl = { +static const struct regmap_config bcm281xx_pinctrl_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = BCM281XX_PIN_VC_CAM3_SDA * 4, +}; + +static const struct bcm281xx_pinctrl_info bcm281xx_pinctrl = { + .device_type = BCM281XX_PINCTRL_TYPE, + .pins = bcm281xx_pinctrl_pins, .npins = ARRAY_SIZE(bcm281xx_pinctrl_pins), .functions = bcm281xx_functions, .nfunctions = ARRAY_SIZE(bcm281xx_functions), + + .regmap_config = &bcm281xx_pinctrl_regmap_config, }; static inline enum bcm281xx_pin_type pin_type_get(struct pinctrl_dev *pctldev, @@ -945,10 +976,10 @@ static inline enum bcm281xx_pin_type pin_type_get(struct pinctrl_dev *pctldev, { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - if (pin >= pdata->npins) + if (pin >= pdata->info->npins) return BCM281XX_PIN_TYPE_UNKNOWN; - return *(enum bcm281xx_pin_type *)(pdata->pins[pin].drv_data); + return *(enum bcm281xx_pin_type *)(pdata->info->pins[pin].drv_data); } #define BCM281XX_PIN_SHIFT(type, param) \ @@ -970,18 +1001,11 @@ static inline void bcm281xx_pin_update(u32 *reg_val, u32 *reg_mask, *reg_mask |= param_mask; } -static const struct regmap_config bcm281xx_pinctrl_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = BCM281XX_PIN_VC_CAM3_SDA, -}; - static int bcm281xx_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - return pdata->npins; + return pdata->info->npins; } static const char *bcm281xx_pinctrl_get_group_name(struct pinctrl_dev *pctldev, @@ -989,7 +1013,7 @@ static const char *bcm281xx_pinctrl_get_group_name(struct pinctrl_dev *pctldev, { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - return pdata->pins[group].name; + return pdata->info->pins[group].name; } static int bcm281xx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, @@ -999,7 +1023,7 @@ static int bcm281xx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - *pins = &pdata->pins[group].number; + *pins = &pdata->info->pins[group].number; *num_pins = 1; return 0; @@ -1025,7 +1049,7 @@ static int bcm281xx_pinctrl_get_fcns_count(struct pinctrl_dev *pctldev) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - return pdata->nfunctions; + return pdata->info->nfunctions; } static const char *bcm281xx_pinctrl_get_fcn_name(struct pinctrl_dev *pctldev, @@ -1033,7 +1057,7 @@ static const char *bcm281xx_pinctrl_get_fcn_name(struct pinctrl_dev *pctldev, { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - return pdata->functions[function].name; + return pdata->info->functions[function].name; } static int bcm281xx_pinctrl_get_fcn_groups(struct pinctrl_dev *pctldev, @@ -1043,8 +1067,8 @@ static int bcm281xx_pinctrl_get_fcn_groups(struct pinctrl_dev *pctldev, { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - *groups = pdata->functions[function].groups; - *num_groups = pdata->functions[function].ngroups; + *groups = pdata->info->functions[function].groups; + *num_groups = pdata->info->functions[function].ngroups; return 0; } @@ -1054,14 +1078,15 @@ static int bcm281xx_pinmux_set(struct pinctrl_dev *pctldev, unsigned int group) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - const struct bcm281xx_pin_function *f = &pdata->functions[function]; - u32 offset = 4 * pdata->pins[group].number; + const struct bcm281xx_pin_function *f = &pdata->info->functions[function]; + unsigned int pin = pdata->info->pins[group].number; + u32 offset = 4 * pin; int rc = 0; dev_dbg(pctldev->dev, "%s(): Enable function %s (%d) of pin %s (%d) @offset 0x%x.\n", - __func__, f->name, function, pdata->pins[group].name, - pdata->pins[group].number, offset); + __func__, f->name, function, pdata->info->pins[group].name, + pin, offset); rc = regmap_update_bits(pdata->regmap, offset, BCM281XX_PIN_REG_F_SEL_MASK, @@ -1069,7 +1094,7 @@ static int bcm281xx_pinmux_set(struct pinctrl_dev *pctldev, if (rc) dev_err(pctldev->dev, "Error updating register for pin %s (%d).\n", - pdata->pins[group].name, pdata->pins[group].number); + pdata->info->pins[group].name, pin); return rc; } @@ -1168,7 +1193,7 @@ static int bcm281xx_std_pin_update(struct pinctrl_dev *pctldev, "Invalid Drive Strength value (%d) for " "pin %s (%d). Valid values are " "(2..16) mA, even numbers only.\n", - arg, pdata->pins[pin].name, pin); + arg, pdata->info->pins[pin].name, pin); return -EINVAL; } bcm281xx_pin_update(val, mask, (arg/2)-1, @@ -1179,7 +1204,7 @@ static int bcm281xx_std_pin_update(struct pinctrl_dev *pctldev, default: dev_err(pctldev->dev, "Unrecognized pin config %d for pin %s (%d).\n", - param, pdata->pins[pin].name, pin); + param, pdata->info->pins[pin].name, pin); return -EINVAL; } /* switch config */ @@ -1233,7 +1258,7 @@ static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev, "Invalid pull-up value (%d) for pin %s " "(%d). Valid values are 568, 720, 831, " "1080, 1200, 1800, 2700 Ohms.\n", - arg, pdata->pins[pin].name, pin); + arg, pdata->info->pins[pin].name, pin); return -EINVAL; } @@ -1266,7 +1291,7 @@ static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev, default: dev_err(pctldev->dev, "Unrecognized pin config %d for pin %s (%d).\n", - param, pdata->pins[pin].name, pin); + param, pdata->info->pins[pin].name, pin); return -EINVAL; } /* switch config */ @@ -1311,7 +1336,7 @@ static int bcm281xx_hdmi_pin_update(struct pinctrl_dev *pctldev, default: dev_err(pctldev->dev, "Unrecognized pin config %d for pin %s (%d).\n", - param, pdata->pins[pin].name, pin); + param, pdata->info->pins[pin].name, pin); return -EINVAL; } /* switch config */ @@ -1354,7 +1379,7 @@ static int bcm281xx_pinctrl_pin_config_set(struct pinctrl_dev *pctldev, default: dev_err(pctldev->dev, "Unknown pin type for pin %s (%d).\n", - pdata->pins[pin].name, pin); + pdata->info->pins[pin].name, pin); return -EINVAL; } /* switch pin type */ @@ -1364,13 +1389,13 @@ static int bcm281xx_pinctrl_pin_config_set(struct pinctrl_dev *pctldev, dev_dbg(pctldev->dev, "%s(): Set pin %s (%d) with config 0x%x, mask 0x%x\n", - __func__, pdata->pins[pin].name, pin, cfg_val, cfg_mask); + __func__, pdata->info->pins[pin].name, pin, cfg_val, cfg_mask); rc = regmap_update_bits(pdata->regmap, offset, cfg_mask, cfg_val); if (rc) { dev_err(pctldev->dev, "Error updating register for pin %s (%d).\n", - pdata->pins[pin].name, pin); + pdata->info->pins[pin].name, pin); return rc; } @@ -1390,11 +1415,23 @@ static struct pinctrl_desc bcm281xx_pinctrl_desc = { .owner = THIS_MODULE, }; +static struct bcm281xx_pinctrl_data bcm281xx_pinctrl_pdata; + static int __init bcm281xx_pinctrl_probe(struct platform_device *pdev) { - struct bcm281xx_pinctrl_data *pdata = &bcm281xx_pinctrl; + struct bcm281xx_pinctrl_data *pdata = &bcm281xx_pinctrl_pdata; struct pinctrl_dev *pctl; + /* Set device pointer in platform data */ + pdata->dev = &pdev->dev; + + /* Get the data to use from OF match */ + pdata->info = of_device_get_match_data(&pdev->dev); + if (!pdata->info) { + dev_err(&pdev->dev, "Failed to get data from OF match\n"); + return -ENODEV; + } + /* So far We can assume there is only 1 bank of registers */ pdata->reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pdata->reg_base)) { @@ -1404,15 +1441,15 @@ static int __init bcm281xx_pinctrl_probe(struct platform_device *pdev) /* Initialize the dynamic part of pinctrl_desc */ pdata->regmap = devm_regmap_init_mmio(&pdev->dev, pdata->reg_base, - &bcm281xx_pinctrl_regmap_config); + pdata->info->regmap_config); if (IS_ERR(pdata->regmap)) { dev_err(&pdev->dev, "Regmap MMIO init failed.\n"); return -ENODEV; } bcm281xx_pinctrl_desc.name = dev_name(&pdev->dev); - bcm281xx_pinctrl_desc.pins = bcm281xx_pinctrl.pins; - bcm281xx_pinctrl_desc.npins = bcm281xx_pinctrl.npins; + bcm281xx_pinctrl_desc.pins = pdata->info->pins; + bcm281xx_pinctrl_desc.npins = pdata->info->npins; pctl = devm_pinctrl_register(&pdev->dev, &bcm281xx_pinctrl_desc, pdata); if (IS_ERR(pctl)) { @@ -1426,7 +1463,7 @@ static int __init bcm281xx_pinctrl_probe(struct platform_device *pdev) } static const struct of_device_id bcm281xx_pinctrl_of_match[] = { - { .compatible = "brcm,bcm11351-pinctrl", }, + { .compatible = "brcm,bcm11351-pinctrl", .data = &bcm281xx_pinctrl }, { }, }; -- cgit v1.2.3-59-g8ed1b From 60d69769c851d309047d0c79a05011e9b2158b35 Mon Sep 17 00:00:00 2001 From: Artur Weber Date: Mon, 3 Mar 2025 21:54:49 +0100 Subject: pinctrl: bcm281xx: Add support for BCM21664 pinmux BCM21664 is another chip from the Kona line of Broadcom SoCs, and its pinmux shares a lot of similarities with the BCM281xx pinmux. Add support for the BCM21664 pinmux controller to the BCM281xx driver. This also enables pinmux support for the BCM23550, which has an identical pinmux config to the BCM21664 (hence they can share a single compatible, brcm,bcm21664-pinctrl). Signed-off-by: Artur Weber Link: https://lore.kernel.org/20250303-bcm21664-pinctrl-v3-4-5f8b80e4ab51@gmail.com Signed-off-by: Linus Walleij --- drivers/pinctrl/bcm/pinctrl-bcm281xx.c | 690 ++++++++++++++++++++++++++++++++- 1 file changed, 688 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c index f5aeb8a56e6f..7c8f8bd7da12 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c @@ -52,6 +52,12 @@ #define BCM281XX_HDMI_PIN_REG_MODE_MASK 0x0010 #define BCM281XX_HDMI_PIN_REG_MODE_SHIFT 4 +/* BCM21664 access lock registers */ +#define BCM21664_WR_ACCESS_OFFSET 0x07F0 +#define BCM21664_WR_ACCESS_PASSWORD 0xA5A501 +#define BCM21664_ACCESS_LOCK_OFFSET(lock) (0x0780 + (lock * 4)) +#define BCM21664_ACCESS_LOCK_COUNT 5 + /* * bcm281xx_pin_type - types of pin register */ @@ -81,6 +87,7 @@ struct bcm281xx_pin_function { */ enum bcm281xx_pinctrl_type { BCM281XX_PINCTRL_TYPE, + BCM21664_PINCTRL_TYPE, }; /* @@ -971,6 +978,571 @@ static const struct bcm281xx_pinctrl_info bcm281xx_pinctrl = { .regmap_config = &bcm281xx_pinctrl_regmap_config, }; +/* BCM21664 data */ +#define BCM21664_PIN_ADCSYN 0 +#define BCM21664_PIN_BATRM 1 +#define BCM21664_PIN_BSC1CLK 2 +#define BCM21664_PIN_BSC1DAT 3 +#define BCM21664_PIN_CAMCS0 4 +#define BCM21664_PIN_CAMCS1 5 +#define BCM21664_PIN_CLK32K 6 +#define BCM21664_PIN_CLK_CX8 7 +#define BCM21664_PIN_DCLK1 8 +#define BCM21664_PIN_DCLK4 9 +#define BCM21664_PIN_DCLKREQ1 10 +#define BCM21664_PIN_DCLKREQ4 11 +#define BCM21664_PIN_DMIC0CLK 12 +#define BCM21664_PIN_DMIC0DQ 13 +#define BCM21664_PIN_DSI0TE 14 +#define BCM21664_PIN_GPIO00 15 +#define BCM21664_PIN_GPIO01 16 +#define BCM21664_PIN_GPIO02 17 +#define BCM21664_PIN_GPIO03 18 +#define BCM21664_PIN_GPIO04 19 +#define BCM21664_PIN_GPIO05 20 +#define BCM21664_PIN_GPIO06 21 +#define BCM21664_PIN_GPIO07 22 +#define BCM21664_PIN_GPIO08 23 +#define BCM21664_PIN_GPIO09 24 +#define BCM21664_PIN_GPIO10 25 +#define BCM21664_PIN_GPIO11 26 +#define BCM21664_PIN_GPIO12 27 +#define BCM21664_PIN_GPIO13 28 +#define BCM21664_PIN_GPIO14 29 +#define BCM21664_PIN_GPIO15 30 +#define BCM21664_PIN_GPIO16 31 +#define BCM21664_PIN_GPIO17 32 +#define BCM21664_PIN_GPIO18 33 +#define BCM21664_PIN_GPIO19 34 +#define BCM21664_PIN_GPIO20 35 +#define BCM21664_PIN_GPIO21 36 +#define BCM21664_PIN_GPIO22 37 +#define BCM21664_PIN_GPIO23 38 +#define BCM21664_PIN_GPIO24 39 +#define BCM21664_PIN_GPIO25 40 +#define BCM21664_PIN_GPIO26 41 +#define BCM21664_PIN_GPIO27 42 +#define BCM21664_PIN_GPIO28 43 +#define BCM21664_PIN_GPIO32 44 +#define BCM21664_PIN_GPIO33 45 +#define BCM21664_PIN_GPIO34 46 +#define BCM21664_PIN_GPS_CALREQ 47 +#define BCM21664_PIN_GPS_HOSTREQ 48 +#define BCM21664_PIN_GPS_PABLANK 49 +#define BCM21664_PIN_GPS_TMARK 50 +#define BCM21664_PIN_ICUSBDM 51 +#define BCM21664_PIN_ICUSBDP 52 +#define BCM21664_PIN_LCDCS0 53 +#define BCM21664_PIN_LCDRES 54 +#define BCM21664_PIN_LCDSCL 55 +#define BCM21664_PIN_LCDSDA 56 +#define BCM21664_PIN_LCDTE 57 +#define BCM21664_PIN_MDMGPIO00 58 +#define BCM21664_PIN_MDMGPIO01 59 +#define BCM21664_PIN_MDMGPIO02 60 +#define BCM21664_PIN_MDMGPIO03 61 +#define BCM21664_PIN_MDMGPIO04 62 +#define BCM21664_PIN_MDMGPIO05 63 +#define BCM21664_PIN_MDMGPIO06 64 +#define BCM21664_PIN_MDMGPIO07 65 +#define BCM21664_PIN_MDMGPIO08 66 +#define BCM21664_PIN_MMC0CK 67 +#define BCM21664_PIN_MMC0CMD 68 +#define BCM21664_PIN_MMC0DAT0 69 +#define BCM21664_PIN_MMC0DAT1 70 +#define BCM21664_PIN_MMC0DAT2 71 +#define BCM21664_PIN_MMC0DAT3 72 +#define BCM21664_PIN_MMC0DAT4 73 +#define BCM21664_PIN_MMC0DAT5 74 +#define BCM21664_PIN_MMC0DAT6 75 +#define BCM21664_PIN_MMC0DAT7 76 +#define BCM21664_PIN_MMC0RST 77 +#define BCM21664_PIN_MMC1CK 78 +#define BCM21664_PIN_MMC1CMD 79 +#define BCM21664_PIN_MMC1DAT0 80 +#define BCM21664_PIN_MMC1DAT1 81 +#define BCM21664_PIN_MMC1DAT2 82 +#define BCM21664_PIN_MMC1DAT3 83 +#define BCM21664_PIN_MMC1DAT4 84 +#define BCM21664_PIN_MMC1DAT5 85 +#define BCM21664_PIN_MMC1DAT6 86 +#define BCM21664_PIN_MMC1DAT7 87 +#define BCM21664_PIN_MMC1RST 88 +#define BCM21664_PIN_PC1 89 +#define BCM21664_PIN_PC2 90 +#define BCM21664_PIN_PMBSCCLK 91 +#define BCM21664_PIN_PMBSCDAT 92 +#define BCM21664_PIN_PMUINT 93 +#define BCM21664_PIN_RESETN 94 +#define BCM21664_PIN_RFST2G_MTSLOTEN3G 95 +#define BCM21664_PIN_RTXDATA2G_TXDATA3G1 96 +#define BCM21664_PIN_RTXEN2G_TXDATA3G2 97 +#define BCM21664_PIN_RXDATA3G0 98 +#define BCM21664_PIN_RXDATA3G1 99 +#define BCM21664_PIN_RXDATA3G2 100 +#define BCM21664_PIN_SDCK 101 +#define BCM21664_PIN_SDCMD 102 +#define BCM21664_PIN_SDDAT0 103 +#define BCM21664_PIN_SDDAT1 104 +#define BCM21664_PIN_SDDAT2 105 +#define BCM21664_PIN_SDDAT3 106 +#define BCM21664_PIN_SIMCLK 107 +#define BCM21664_PIN_SIMDAT 108 +#define BCM21664_PIN_SIMDET 109 +#define BCM21664_PIN_SIMRST 110 +#define BCM21664_PIN_GPIO93 111 +#define BCM21664_PIN_GPIO94 112 +#define BCM21664_PIN_SPI0CLK 113 +#define BCM21664_PIN_SPI0FSS 114 +#define BCM21664_PIN_SPI0RXD 115 +#define BCM21664_PIN_SPI0TXD 116 +#define BCM21664_PIN_SRI_C 117 +#define BCM21664_PIN_SRI_D 118 +#define BCM21664_PIN_SRI_E 119 +#define BCM21664_PIN_SSPCK 120 +#define BCM21664_PIN_SSPDI 121 +#define BCM21664_PIN_SSPDO 122 +#define BCM21664_PIN_SSPSYN 123 +#define BCM21664_PIN_STAT1 124 +#define BCM21664_PIN_STAT2 125 +#define BCM21664_PIN_SWCLKTCK 126 +#define BCM21664_PIN_SWDIOTMS 127 +#define BCM21664_PIN_SYSCLKEN 128 +#define BCM21664_PIN_TDI 129 +#define BCM21664_PIN_TDO 130 +#define BCM21664_PIN_TESTMODE 131 +#define BCM21664_PIN_TRACECLK 132 +#define BCM21664_PIN_TRACEDT00 133 +#define BCM21664_PIN_TRACEDT01 134 +#define BCM21664_PIN_TRACEDT02 135 +#define BCM21664_PIN_TRACEDT03 136 +#define BCM21664_PIN_TRACEDT04 137 +#define BCM21664_PIN_TRACEDT05 138 +#define BCM21664_PIN_TRACEDT06 139 +#define BCM21664_PIN_TRACEDT07 140 +#define BCM21664_PIN_TRSTB 141 +#define BCM21664_PIN_TXDATA3G0 142 +#define BCM21664_PIN_UBCTSN 143 +#define BCM21664_PIN_UBRTSN 144 +#define BCM21664_PIN_UBRX 145 +#define BCM21664_PIN_UBTX 146 +#define BCM21664_PIN_TRACEDT08 147 +#define BCM21664_PIN_TRACEDT09 148 +#define BCM21664_PIN_TRACEDT10 149 +#define BCM21664_PIN_TRACEDT11 150 +#define BCM21664_PIN_TRACEDT12 151 +#define BCM21664_PIN_TRACEDT13 152 +#define BCM21664_PIN_TRACEDT14 153 +#define BCM21664_PIN_TRACEDT15 154 + +static const struct pinctrl_pin_desc bcm21664_pinctrl_pins[] = { + BCM281XX_PIN_DESC(BCM21664_PIN_ADCSYN, "adcsyn", std), + BCM281XX_PIN_DESC(BCM21664_PIN_BATRM, "batrm", std), + BCM281XX_PIN_DESC(BCM21664_PIN_BSC1CLK, "bsc1clk", i2c), + BCM281XX_PIN_DESC(BCM21664_PIN_BSC1DAT, "bsc1dat", i2c), + BCM281XX_PIN_DESC(BCM21664_PIN_CAMCS0, "camcs0", std), + BCM281XX_PIN_DESC(BCM21664_PIN_CAMCS1, "camcs1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_CLK32K, "clk32k", std), + BCM281XX_PIN_DESC(BCM21664_PIN_CLK_CX8, "clk_cx8", std), + BCM281XX_PIN_DESC(BCM21664_PIN_DCLK1, "dclk1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_DCLK4, "dclk4", std), + BCM281XX_PIN_DESC(BCM21664_PIN_DCLKREQ1, "dclkreq1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_DCLKREQ4, "dclkreq4", std), + BCM281XX_PIN_DESC(BCM21664_PIN_DMIC0CLK, "dmic0clk", std), + BCM281XX_PIN_DESC(BCM21664_PIN_DMIC0DQ, "dmic0dq", std), + BCM281XX_PIN_DESC(BCM21664_PIN_DSI0TE, "dsi0te", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO00, "gpio00", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO01, "gpio01", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO02, "gpio02", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO03, "gpio03", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO04, "gpio04", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO05, "gpio05", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO06, "gpio06", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO07, "gpio07", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO08, "gpio08", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO09, "gpio09", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO10, "gpio10", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO11, "gpio11", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO12, "gpio12", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO13, "gpio13", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO14, "gpio14", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO15, "gpio15", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO16, "gpio16", i2c), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO17, "gpio17", i2c), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO18, "gpio18", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO19, "gpio19", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO20, "gpio20", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO21, "gpio21", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO22, "gpio22", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO23, "gpio23", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO24, "gpio24", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO25, "gpio25", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO26, "gpio26", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO27, "gpio27", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO28, "gpio28", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO32, "gpio32", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO33, "gpio33", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO34, "gpio34", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPS_CALREQ, "gps_calreq", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPS_HOSTREQ, "gps_hostreq", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPS_PABLANK, "gps_pablank", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPS_TMARK, "gps_tmark", std), + BCM281XX_PIN_DESC(BCM21664_PIN_ICUSBDM, "icusbdm", std), + BCM281XX_PIN_DESC(BCM21664_PIN_ICUSBDP, "icusbdp", std), + BCM281XX_PIN_DESC(BCM21664_PIN_LCDCS0, "lcdcs0", std), + BCM281XX_PIN_DESC(BCM21664_PIN_LCDRES, "lcdres", std), + BCM281XX_PIN_DESC(BCM21664_PIN_LCDSCL, "lcdscl", std), + BCM281XX_PIN_DESC(BCM21664_PIN_LCDSDA, "lcdsda", std), + BCM281XX_PIN_DESC(BCM21664_PIN_LCDTE, "lcdte", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO00, "mdmgpio00", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO01, "mdmgpio01", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO02, "mdmgpio02", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO03, "mdmgpio03", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO04, "mdmgpio04", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO05, "mdmgpio05", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO06, "mdmgpio06", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO07, "mdmgpio07", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MDMGPIO08, "mdmgpio08", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0CK, "mmc0ck", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0CMD, "mmc0cmd", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0DAT0, "mmc0dat0", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0DAT1, "mmc0dat1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0DAT2, "mmc0dat2", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0DAT3, "mmc0dat3", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0DAT4, "mmc0dat4", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0DAT5, "mmc0dat5", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0DAT6, "mmc0dat6", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0DAT7, "mmc0dat7", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC0RST, "mmc0rst", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1CK, "mmc1ck", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1CMD, "mmc1cmd", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1DAT0, "mmc1dat0", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1DAT1, "mmc1dat1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1DAT2, "mmc1dat2", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1DAT3, "mmc1dat3", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1DAT4, "mmc1dat4", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1DAT5, "mmc1dat5", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1DAT6, "mmc1dat6", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1DAT7, "mmc1dat7", std), + BCM281XX_PIN_DESC(BCM21664_PIN_MMC1RST, "mmc1rst", std), + BCM281XX_PIN_DESC(BCM21664_PIN_PC1, "pc1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_PC2, "pc2", std), + BCM281XX_PIN_DESC(BCM21664_PIN_PMBSCCLK, "pmbscclk", i2c), + BCM281XX_PIN_DESC(BCM21664_PIN_PMBSCDAT, "pmbscdat", i2c), + BCM281XX_PIN_DESC(BCM21664_PIN_PMUINT, "pmuint", std), + BCM281XX_PIN_DESC(BCM21664_PIN_RESETN, "resetn", std), + BCM281XX_PIN_DESC(BCM21664_PIN_RFST2G_MTSLOTEN3G, "rfst2g_mtsloten3g", std), + BCM281XX_PIN_DESC(BCM21664_PIN_RTXDATA2G_TXDATA3G1, "rtxdata2g_txdata3g1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_RTXEN2G_TXDATA3G2, "rtxen2g_txdata3g2", std), + BCM281XX_PIN_DESC(BCM21664_PIN_RXDATA3G0, "rxdata3g0", std), + BCM281XX_PIN_DESC(BCM21664_PIN_RXDATA3G1, "rxdata3g1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_RXDATA3G2, "rxdata3g2", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SDCK, "sdck", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SDCMD, "sdcmd", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SDDAT0, "sddat0", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SDDAT1, "sddat1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SDDAT2, "sddat2", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SDDAT3, "sddat3", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SIMCLK, "simclk", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SIMDAT, "simdat", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SIMDET, "simdet", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SIMRST, "simrst", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO93, "gpio93", std), + BCM281XX_PIN_DESC(BCM21664_PIN_GPIO94, "gpio94", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SPI0CLK, "spi0clk", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SPI0FSS, "spi0fss", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SPI0RXD, "spi0rxd", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SPI0TXD, "spi0txd", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SRI_C, "sri_c", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SRI_D, "sri_d", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SRI_E, "sri_e", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SSPCK, "sspck", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SSPDI, "sspdi", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SSPDO, "sspdo", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SSPSYN, "sspsyn", std), + BCM281XX_PIN_DESC(BCM21664_PIN_STAT1, "stat1", std), + BCM281XX_PIN_DESC(BCM21664_PIN_STAT2, "stat2", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SWCLKTCK, "swclktck", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SWDIOTMS, "swdiotms", std), + BCM281XX_PIN_DESC(BCM21664_PIN_SYSCLKEN, "sysclken", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TDI, "tdi", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TDO, "tdo", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TESTMODE, "testmode", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACECLK, "traceclk", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT00, "tracedt00", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT01, "tracedt01", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT02, "tracedt02", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT03, "tracedt03", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT04, "tracedt04", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT05, "tracedt05", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT06, "tracedt06", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT07, "tracedt07", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRSTB, "trstb", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TXDATA3G0, "txdata3g0", std), + BCM281XX_PIN_DESC(BCM21664_PIN_UBCTSN, "ubctsn", std), + BCM281XX_PIN_DESC(BCM21664_PIN_UBRTSN, "ubrtsn", std), + BCM281XX_PIN_DESC(BCM21664_PIN_UBRX, "ubrx", std), + BCM281XX_PIN_DESC(BCM21664_PIN_UBTX, "ubtx", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT08, "tracedt08", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT09, "tracedt09", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT10, "tracedt10", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT11, "tracedt11", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT12, "tracedt12", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT13, "tracedt13", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT14, "tracedt14", std), + BCM281XX_PIN_DESC(BCM21664_PIN_TRACEDT15, "tracedt15", std), +}; + +static const char * const bcm21664_alt_groups[] = { + "adcsyn", + "batrm", + "bsc1clk", + "bsc1dat", + "camcs0", + "camcs1", + "clk32k", + "clk_cx8", + "dclk1", + "dclk4", + "dclkreq1", + "dclkreq4", + "dmic0clk", + "dmic0dq", + "dsi0te", + "gpio00", + "gpio01", + "gpio02", + "gpio03", + "gpio04", + "gpio05", + "gpio06", + "gpio07", + "gpio08", + "gpio09", + "gpio10", + "gpio11", + "gpio12", + "gpio13", + "gpio14", + "gpio15", + "gpio16", + "gpio17", + "gpio18", + "gpio19", + "gpio20", + "gpio21", + "gpio22", + "gpio23", + "gpio24", + "gpio25", + "gpio26", + "gpio27", + "gpio28", + "gpio32", + "gpio33", + "gpio34", + "gps_calreq", + "gps_hostreq", + "gps_pablank", + "gps_tmark", + "icusbdm", + "icusbdp", + "lcdcs0", + "lcdres", + "lcdscl", + "lcdsda", + "lcdte", + "mdmgpio00", + "mdmgpio01", + "mdmgpio02", + "mdmgpio03", + "mdmgpio04", + "mdmgpio05", + "mdmgpio06", + "mdmgpio07", + "mdmgpio08", + "mmc0ck", + "mmc0cmd", + "mmc0dat0", + "mmc0dat1", + "mmc0dat2", + "mmc0dat3", + "mmc0dat4", + "mmc0dat5", + "mmc0dat6", + "mmc0dat7", + "mmc0rst", + "mmc1ck", + "mmc1cmd", + "mmc1dat0", + "mmc1dat1", + "mmc1dat2", + "mmc1dat3", + "mmc1dat4", + "mmc1dat5", + "mmc1dat6", + "mmc1dat7", + "mmc1rst", + "pc1", + "pc2", + "pmbscclk", + "pmbscdat", + "pmuint", + "resetn", + "rfst2g_mtsloten3g", + "rtxdata2g_txdata3g1", + "rtxen2g_txdata3g2", + "rxdata3g0", + "rxdata3g1", + "rxdata3g2", + "sdck", + "sdcmd", + "sddat0", + "sddat1", + "sddat2", + "sddat3", + "simclk", + "simdat", + "simdet", + "simrst", + "gpio93", + "gpio94", + "spi0clk", + "spi0fss", + "spi0rxd", + "spi0txd", + "sri_c", + "sri_d", + "sri_e", + "sspck", + "sspdi", + "sspdo", + "sspsyn", + "stat1", + "stat2", + "swclktck", + "swdiotms", + "sysclken", + "tdi", + "tdo", + "testmode", + "traceclk", + "tracedt00", + "tracedt01", + "tracedt02", + "tracedt03", + "tracedt04", + "tracedt05", + "tracedt06", + "tracedt07", + "trstb", + "txdata3g0", + "ubctsn", + "ubrtsn", + "ubrx", + "ubtx", + "tracedt08", + "tracedt09", + "tracedt10", + "tracedt11", + "tracedt12", + "tracedt13", + "tracedt14", + "tracedt15", +}; + +#define BCM21664_PIN_FUNCTION(fcn_name) \ +{ \ + .name = #fcn_name, \ + .groups = bcm21664_alt_groups, \ + .ngroups = ARRAY_SIZE(bcm21664_alt_groups), \ +} + +static const struct bcm281xx_pin_function bcm21664_functions[] = { + BCM21664_PIN_FUNCTION(alt1), + BCM21664_PIN_FUNCTION(alt2), + BCM21664_PIN_FUNCTION(alt3), + BCM21664_PIN_FUNCTION(alt4), + BCM21664_PIN_FUNCTION(alt5), + BCM21664_PIN_FUNCTION(alt6), +}; + +static const struct regmap_config bcm21664_pinctrl_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = BCM21664_WR_ACCESS_OFFSET, +}; + +static const struct bcm281xx_pinctrl_info bcm21664_pinctrl = { + .device_type = BCM21664_PINCTRL_TYPE, + + .pins = bcm21664_pinctrl_pins, + .npins = ARRAY_SIZE(bcm21664_pinctrl_pins), + .functions = bcm21664_functions, + .nfunctions = ARRAY_SIZE(bcm21664_functions), + + .regmap_config = &bcm21664_pinctrl_regmap_config, +}; + +/* BCM21664 pinctrl access lock handlers */ +static int bcm21664_pinctrl_lock_all(struct bcm281xx_pinctrl_data *pdata) +{ + int i, rc; + + for (i = 0; i < BCM21664_ACCESS_LOCK_COUNT; i++) { + rc = regmap_write(pdata->regmap, BCM21664_WR_ACCESS_OFFSET, + BCM21664_WR_ACCESS_PASSWORD); + if (rc) { + dev_err(pdata->dev, "Failed to enable write access: %d\n", + rc); + return rc; + } + regmap_write(pdata->regmap, BCM21664_ACCESS_LOCK_OFFSET(i), + 0xffffffff); + if (rc) { + dev_err(pdata->dev, "Failed to write access lock: %d\n", + rc); + return rc; + } + } + + return 0; +} + +static int bcm21664_pinctrl_set_pin_lock(struct bcm281xx_pinctrl_data *pdata, + unsigned int pin, bool lock) +{ + unsigned int access_lock = pin / 32; + int rc; + + dev_dbg(pdata->dev, + "%s(): %s pin %s (%d)\n", + __func__, lock ? "Lock" : "Unlock", pdata->info->pins[pin].name, + pin); + + rc = regmap_write(pdata->regmap, BCM21664_WR_ACCESS_OFFSET, + BCM21664_WR_ACCESS_PASSWORD); + if (rc) { + dev_err(pdata->dev, "Failed to enable write access: %d\n", + rc); + return rc; + } + + rc = regmap_update_bits(pdata->regmap, + BCM21664_ACCESS_LOCK_OFFSET(access_lock), + BIT(pin % 32), + (int)lock << (pin % 32)); + + if (rc) { + dev_err(pdata->dev, "Failed to %s pin: %d\n", + lock ? "lock" : "unlock", rc); + return rc; + } + + return 0; +} + static inline enum bcm281xx_pin_type pin_type_get(struct pinctrl_dev *pctldev, unsigned int pin) { @@ -1079,6 +1651,7 @@ static int bcm281xx_pinmux_set(struct pinctrl_dev *pctldev, { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); const struct bcm281xx_pin_function *f = &pdata->info->functions[function]; + enum bcm281xx_pinctrl_type device_type = pdata->info->device_type; unsigned int pin = pdata->info->pins[group].number; u32 offset = 4 * pin; int rc = 0; @@ -1088,6 +1661,14 @@ static int bcm281xx_pinmux_set(struct pinctrl_dev *pctldev, __func__, f->name, function, pdata->info->pins[group].name, pin, offset); + if (device_type == BCM21664_PINCTRL_TYPE) { + rc = bcm21664_pinctrl_set_pin_lock(pdata, pin, false); + if (rc) { + /* Error is printed in bcm21664_pinctrl_set_pin_lock */ + return rc; + } + } + rc = regmap_update_bits(pdata->regmap, offset, BCM281XX_PIN_REG_F_SEL_MASK, function << BCM281XX_PIN_REG_F_SEL_SHIFT); @@ -1096,6 +1677,14 @@ static int bcm281xx_pinmux_set(struct pinctrl_dev *pctldev, "Error updating register for pin %s (%d).\n", pdata->info->pins[group].name, pin); + if (device_type == BCM21664_PINCTRL_TYPE) { + rc = bcm21664_pinctrl_set_pin_lock(pdata, pin, true); + if (rc) { + /* Error is printed in bcm21664_pinctrl_set_pin_lock */ + return rc; + } + } + return rc; } @@ -1300,6 +1889,68 @@ static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev, return 0; } +/* Goes through the configs and update register val/mask */ +static int bcm21664_i2c_pin_update(struct pinctrl_dev *pctldev, + unsigned int pin, + unsigned long *configs, + unsigned int num_configs, + u32 *val, + u32 *mask) +{ + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + int i; + enum pin_config_param param; + u32 arg; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + /* + * BCM21664 I2C pins use the same config bits as standard pins, + * but only pull up/none, slew rate and input enable/disable + * options are supported. + */ + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + bcm281xx_pin_update(val, mask, 1, + BCM281XX_PIN_SHIFT(STD, PULL_UP), + BCM281XX_PIN_MASK(STD, PULL_UP)); + break; + + case PIN_CONFIG_BIAS_DISABLE: + bcm281xx_pin_update(val, mask, 0, + BCM281XX_PIN_SHIFT(STD, PULL_UP), + BCM281XX_PIN_MASK(STD, PULL_UP)); + break; + + case PIN_CONFIG_SLEW_RATE: + arg = (arg >= 1 ? 1 : 0); + bcm281xx_pin_update(val, mask, arg, + BCM281XX_PIN_SHIFT(STD, SLEW), + BCM281XX_PIN_MASK(STD, SLEW)); + break; + + case PIN_CONFIG_INPUT_ENABLE: + /* inversed since register is for input _disable_ */ + arg = (arg >= 1 ? 0 : 1); + bcm281xx_pin_update(val, mask, arg, + BCM281XX_PIN_SHIFT(STD, INPUT_DIS), + BCM281XX_PIN_MASK(STD, INPUT_DIS)); + break; + + default: + dev_err(pctldev->dev, + "Unrecognized pin config %d for pin %s (%d).\n", + param, pdata->info->pins[pin].name, pin); + return -EINVAL; + + } /* switch config */ + } /* for each config */ + + return 0; +} + /* Goes through the configs and update register val/mask */ static int bcm281xx_hdmi_pin_update(struct pinctrl_dev *pctldev, unsigned int pin, @@ -1351,6 +2002,7 @@ static int bcm281xx_pinctrl_pin_config_set(struct pinctrl_dev *pctldev, unsigned int num_configs) { struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + enum bcm281xx_pinctrl_type device_type = pdata->info->device_type; enum bcm281xx_pin_type pin_type; u32 offset = 4 * pin; u32 cfg_val, cfg_mask; @@ -1368,8 +2020,12 @@ static int bcm281xx_pinctrl_pin_config_set(struct pinctrl_dev *pctldev, break; case BCM281XX_PIN_TYPE_I2C: - rc = bcm281xx_i2c_pin_update(pctldev, pin, configs, - num_configs, &cfg_val, &cfg_mask); + if (device_type == BCM21664_PINCTRL_TYPE) + rc = bcm21664_i2c_pin_update(pctldev, pin, configs, + num_configs, &cfg_val, &cfg_mask); + else + rc = bcm281xx_i2c_pin_update(pctldev, pin, configs, + num_configs, &cfg_val, &cfg_mask); break; case BCM281XX_PIN_TYPE_HDMI: @@ -1391,6 +2047,14 @@ static int bcm281xx_pinctrl_pin_config_set(struct pinctrl_dev *pctldev, "%s(): Set pin %s (%d) with config 0x%x, mask 0x%x\n", __func__, pdata->info->pins[pin].name, pin, cfg_val, cfg_mask); + if (device_type == BCM21664_PINCTRL_TYPE) { + rc = bcm21664_pinctrl_set_pin_lock(pdata, pin, false); + if (rc) { + /* Error is printed in bcm21664_pinctrl_set_pin_lock */ + return rc; + } + } + rc = regmap_update_bits(pdata->regmap, offset, cfg_mask, cfg_val); if (rc) { dev_err(pctldev->dev, @@ -1399,6 +2063,14 @@ static int bcm281xx_pinctrl_pin_config_set(struct pinctrl_dev *pctldev, return rc; } + if (device_type == BCM21664_PINCTRL_TYPE) { + rc = bcm21664_pinctrl_set_pin_lock(pdata, pin, true); + if (rc) { + /* Error is printed in bcm21664_pinctrl_set_pin_lock */ + return rc; + } + } + return 0; } @@ -1421,6 +2093,7 @@ static int __init bcm281xx_pinctrl_probe(struct platform_device *pdev) { struct bcm281xx_pinctrl_data *pdata = &bcm281xx_pinctrl_pdata; struct pinctrl_dev *pctl; + int rc; /* Set device pointer in platform data */ pdata->dev = &pdev->dev; @@ -1451,6 +2124,18 @@ static int __init bcm281xx_pinctrl_probe(struct platform_device *pdev) bcm281xx_pinctrl_desc.pins = pdata->info->pins; bcm281xx_pinctrl_desc.npins = pdata->info->npins; + /* + * For BCM21664, lock all pins by default; they will be unlocked + * as needed + */ + if (pdata->info->device_type == BCM21664_PINCTRL_TYPE) { + rc = bcm21664_pinctrl_lock_all(pdata); + if (rc) { + dev_err(&pdev->dev, "Failed to lock all pins\n"); + return rc; + } + } + pctl = devm_pinctrl_register(&pdev->dev, &bcm281xx_pinctrl_desc, pdata); if (IS_ERR(pctl)) { dev_err(&pdev->dev, "Failed to register pinctrl\n"); @@ -1464,6 +2149,7 @@ static int __init bcm281xx_pinctrl_probe(struct platform_device *pdev) static const struct of_device_id bcm281xx_pinctrl_of_match[] = { { .compatible = "brcm,bcm11351-pinctrl", .data = &bcm281xx_pinctrl }, + { .compatible = "brcm,bcm21664-pinctrl", .data = &bcm21664_pinctrl }, { }, }; -- cgit v1.2.3-59-g8ed1b From a5779e625e2b377f16a6675c432aaf299ce5028c Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Wed, 5 Mar 2025 16:37:51 +0000 Subject: pinctrl: renesas: rzg2l: Fix missing of_node_put() call of_parse_phandle_with_fixed_args() requires its caller to call into of_node_put() on the node pointer from the output structure, but such a call is currently missing. Call into of_node_put() to rectify that. Fixes: c4c4637eb57f ("pinctrl: renesas: Add RZ/G2L pin and gpio controller driver") Signed-off-by: Fabrizio Castro Reviewed-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250305163753.34913-3-fabrizio.castro.jz@renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/renesas/pinctrl-rzg2l.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index 9280bc37a623..c72e250f4a15 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -2763,6 +2763,8 @@ static int rzg2l_gpio_register(struct rzg2l_pinctrl *pctrl) if (ret) return dev_err_probe(pctrl->dev, ret, "Unable to parse gpio-ranges\n"); + of_node_put(of_args.np); + if (of_args.args[0] != 0 || of_args.args[1] != 0 || of_args.args[2] != pctrl->data->n_port_pins) return dev_err_probe(pctrl->dev, -EINVAL, -- cgit v1.2.3-59-g8ed1b From 5a550b00704d3a2cd9d766a9427b0f8166da37df Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Wed, 5 Mar 2025 16:37:52 +0000 Subject: pinctrl: renesas: rzv2m: Fix missing of_node_put() call of_parse_phandle_with_fixed_args() requires its caller to call into of_node_put() on the node pointer from the output structure, but such a call is currently missing. Call into of_node_put() to rectify that. Fixes: 92a9b8252576 ("pinctrl: renesas: Add RZ/V2M pin and gpio controller driver") Signed-off-by: Fabrizio Castro Reviewed-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250305163753.34913-4-fabrizio.castro.jz@renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/renesas/pinctrl-rzv2m.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/renesas/pinctrl-rzv2m.c b/drivers/pinctrl/renesas/pinctrl-rzv2m.c index 4062c56619f5..8c7169db4fcc 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzv2m.c +++ b/drivers/pinctrl/renesas/pinctrl-rzv2m.c @@ -940,6 +940,8 @@ static int rzv2m_gpio_register(struct rzv2m_pinctrl *pctrl) return ret; } + of_node_put(of_args.np); + if (of_args.args[0] != 0 || of_args.args[1] != 0 || of_args.args[2] != pctrl->data->n_port_pins) { dev_err(pctrl->dev, "gpio-ranges does not match selected SOC\n"); -- cgit v1.2.3-59-g8ed1b From abcdeb4e299a11ecb5a3ea0cce00e68e8f540375 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Wed, 5 Mar 2025 16:37:53 +0000 Subject: pinctrl: renesas: rza2: Fix missing of_node_put() call of_parse_phandle_with_fixed_args() requires its caller to call into of_node_put() on the node pointer from the output structure, but such a call is currently missing. Call into of_node_put() to rectify that. Fixes: b59d0e782706 ("pinctrl: Add RZ/A2 pin and gpio controller") Signed-off-by: Fabrizio Castro Reviewed-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250305163753.34913-5-fabrizio.castro.jz@renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/pinctrl/renesas/pinctrl-rza2.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/renesas/pinctrl-rza2.c b/drivers/pinctrl/renesas/pinctrl-rza2.c index a654ede01f70..3b5812963850 100644 --- a/drivers/pinctrl/renesas/pinctrl-rza2.c +++ b/drivers/pinctrl/renesas/pinctrl-rza2.c @@ -259,6 +259,8 @@ static int rza2_gpio_register(struct rza2_pinctrl_priv *priv) return ret; } + of_node_put(of_args.np); + if ((of_args.args[0] != 0) || (of_args.args[1] != 0) || (of_args.args[2] != priv->npins)) { -- cgit v1.2.3-59-g8ed1b From 701d0e910955627734917c3587258aa7e73068bb Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Fri, 7 Mar 2025 10:29:05 +0000 Subject: pinctrl: samsung: add support for eint_fltcon_offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On gs101 SoC the fltcon0 (filter configuration 0) offset isn't at a fixed offset like previous SoCs as the fltcon1 register only exists when there are more than 4 pins in the bank. Add a eint_fltcon_offset and new GS101_PIN_BANK_EINT* macros that take an additional fltcon_offs variable. This can then be used in suspend/resume callbacks to save and restore the fltcon0 and fltcon1 registers. Fixes: 4a8be01a1a7a ("pinctrl: samsung: Add gs101 SoC pinctrl configuration") Cc: stable@vger.kernel.org Reviewed-by: André Draszik Signed-off-by: Peter Griffin Link: https://lore.kernel.org/r/20250307-pinctrl-fltcon-suspend-v4-1-2d775e486036@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/pinctrl/samsung/pinctrl-exynos-arm64.c | 98 +++++++++++++------------- drivers/pinctrl/samsung/pinctrl-exynos.h | 22 ++++++ drivers/pinctrl/samsung/pinctrl-samsung.c | 1 + drivers/pinctrl/samsung/pinctrl-samsung.h | 4 ++ 4 files changed, 76 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c index e35e5a8e23a0..dd07720e32cc 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c @@ -1677,83 +1677,83 @@ const struct samsung_pinctrl_of_match_data fsd_of_data __initconst = { /* pin banks of gs101 pin-controller (ALIVE) */ static const struct samsung_pin_bank_data gs101_pin_alive[] = { - EXYNOS850_PIN_BANK_EINTW(8, 0x0, "gpa0", 0x00), - EXYNOS850_PIN_BANK_EINTW(7, 0x20, "gpa1", 0x04), - EXYNOS850_PIN_BANK_EINTW(5, 0x40, "gpa2", 0x08), - EXYNOS850_PIN_BANK_EINTW(4, 0x60, "gpa3", 0x0c), - EXYNOS850_PIN_BANK_EINTW(4, 0x80, "gpa4", 0x10), - EXYNOS850_PIN_BANK_EINTW(7, 0xa0, "gpa5", 0x14), - EXYNOS850_PIN_BANK_EINTW(8, 0xc0, "gpa9", 0x18), - EXYNOS850_PIN_BANK_EINTW(2, 0xe0, "gpa10", 0x1c), + GS101_PIN_BANK_EINTW(8, 0x0, "gpa0", 0x00, 0x00), + GS101_PIN_BANK_EINTW(7, 0x20, "gpa1", 0x04, 0x08), + GS101_PIN_BANK_EINTW(5, 0x40, "gpa2", 0x08, 0x10), + GS101_PIN_BANK_EINTW(4, 0x60, "gpa3", 0x0c, 0x18), + GS101_PIN_BANK_EINTW(4, 0x80, "gpa4", 0x10, 0x1c), + GS101_PIN_BANK_EINTW(7, 0xa0, "gpa5", 0x14, 0x20), + GS101_PIN_BANK_EINTW(8, 0xc0, "gpa9", 0x18, 0x28), + GS101_PIN_BANK_EINTW(2, 0xe0, "gpa10", 0x1c, 0x30), }; /* pin banks of gs101 pin-controller (FAR_ALIVE) */ static const struct samsung_pin_bank_data gs101_pin_far_alive[] = { - EXYNOS850_PIN_BANK_EINTW(8, 0x0, "gpa6", 0x00), - EXYNOS850_PIN_BANK_EINTW(4, 0x20, "gpa7", 0x04), - EXYNOS850_PIN_BANK_EINTW(8, 0x40, "gpa8", 0x08), - EXYNOS850_PIN_BANK_EINTW(2, 0x60, "gpa11", 0x0c), + GS101_PIN_BANK_EINTW(8, 0x0, "gpa6", 0x00, 0x00), + GS101_PIN_BANK_EINTW(4, 0x20, "gpa7", 0x04, 0x08), + GS101_PIN_BANK_EINTW(8, 0x40, "gpa8", 0x08, 0x0c), + GS101_PIN_BANK_EINTW(2, 0x60, "gpa11", 0x0c, 0x14), }; /* pin banks of gs101 pin-controller (GSACORE) */ static const struct samsung_pin_bank_data gs101_pin_gsacore[] = { - EXYNOS850_PIN_BANK_EINTG(2, 0x0, "gps0", 0x00), - EXYNOS850_PIN_BANK_EINTG(8, 0x20, "gps1", 0x04), - EXYNOS850_PIN_BANK_EINTG(3, 0x40, "gps2", 0x08), + GS101_PIN_BANK_EINTG(2, 0x0, "gps0", 0x00, 0x00), + GS101_PIN_BANK_EINTG(8, 0x20, "gps1", 0x04, 0x04), + GS101_PIN_BANK_EINTG(3, 0x40, "gps2", 0x08, 0x0c), }; /* pin banks of gs101 pin-controller (GSACTRL) */ static const struct samsung_pin_bank_data gs101_pin_gsactrl[] = { - EXYNOS850_PIN_BANK_EINTW(6, 0x0, "gps3", 0x00), + GS101_PIN_BANK_EINTW(6, 0x0, "gps3", 0x00, 0x00), }; /* pin banks of gs101 pin-controller (PERIC0) */ static const struct samsung_pin_bank_data gs101_pin_peric0[] = { - EXYNOS850_PIN_BANK_EINTG(5, 0x0, "gpp0", 0x00), - EXYNOS850_PIN_BANK_EINTG(4, 0x20, "gpp1", 0x04), - EXYNOS850_PIN_BANK_EINTG(4, 0x40, "gpp2", 0x08), - EXYNOS850_PIN_BANK_EINTG(2, 0x60, "gpp3", 0x0c), - EXYNOS850_PIN_BANK_EINTG(4, 0x80, "gpp4", 0x10), - EXYNOS850_PIN_BANK_EINTG(2, 0xa0, "gpp5", 0x14), - EXYNOS850_PIN_BANK_EINTG(4, 0xc0, "gpp6", 0x18), - EXYNOS850_PIN_BANK_EINTG(2, 0xe0, "gpp7", 0x1c), - EXYNOS850_PIN_BANK_EINTG(4, 0x100, "gpp8", 0x20), - EXYNOS850_PIN_BANK_EINTG(2, 0x120, "gpp9", 0x24), - EXYNOS850_PIN_BANK_EINTG(4, 0x140, "gpp10", 0x28), - EXYNOS850_PIN_BANK_EINTG(2, 0x160, "gpp11", 0x2c), - EXYNOS850_PIN_BANK_EINTG(4, 0x180, "gpp12", 0x30), - EXYNOS850_PIN_BANK_EINTG(2, 0x1a0, "gpp13", 0x34), - EXYNOS850_PIN_BANK_EINTG(4, 0x1c0, "gpp14", 0x38), - EXYNOS850_PIN_BANK_EINTG(2, 0x1e0, "gpp15", 0x3c), - EXYNOS850_PIN_BANK_EINTG(4, 0x200, "gpp16", 0x40), - EXYNOS850_PIN_BANK_EINTG(2, 0x220, "gpp17", 0x44), - EXYNOS850_PIN_BANK_EINTG(4, 0x240, "gpp18", 0x48), - EXYNOS850_PIN_BANK_EINTG(4, 0x260, "gpp19", 0x4c), + GS101_PIN_BANK_EINTG(5, 0x0, "gpp0", 0x00, 0x00), + GS101_PIN_BANK_EINTG(4, 0x20, "gpp1", 0x04, 0x08), + GS101_PIN_BANK_EINTG(4, 0x40, "gpp2", 0x08, 0x0c), + GS101_PIN_BANK_EINTG(2, 0x60, "gpp3", 0x0c, 0x10), + GS101_PIN_BANK_EINTG(4, 0x80, "gpp4", 0x10, 0x14), + GS101_PIN_BANK_EINTG(2, 0xa0, "gpp5", 0x14, 0x18), + GS101_PIN_BANK_EINTG(4, 0xc0, "gpp6", 0x18, 0x1c), + GS101_PIN_BANK_EINTG(2, 0xe0, "gpp7", 0x1c, 0x20), + GS101_PIN_BANK_EINTG(4, 0x100, "gpp8", 0x20, 0x24), + GS101_PIN_BANK_EINTG(2, 0x120, "gpp9", 0x24, 0x28), + GS101_PIN_BANK_EINTG(4, 0x140, "gpp10", 0x28, 0x2c), + GS101_PIN_BANK_EINTG(2, 0x160, "gpp11", 0x2c, 0x30), + GS101_PIN_BANK_EINTG(4, 0x180, "gpp12", 0x30, 0x34), + GS101_PIN_BANK_EINTG(2, 0x1a0, "gpp13", 0x34, 0x38), + GS101_PIN_BANK_EINTG(4, 0x1c0, "gpp14", 0x38, 0x3c), + GS101_PIN_BANK_EINTG(2, 0x1e0, "gpp15", 0x3c, 0x40), + GS101_PIN_BANK_EINTG(4, 0x200, "gpp16", 0x40, 0x44), + GS101_PIN_BANK_EINTG(2, 0x220, "gpp17", 0x44, 0x48), + GS101_PIN_BANK_EINTG(4, 0x240, "gpp18", 0x48, 0x4c), + GS101_PIN_BANK_EINTG(4, 0x260, "gpp19", 0x4c, 0x50), }; /* pin banks of gs101 pin-controller (PERIC1) */ static const struct samsung_pin_bank_data gs101_pin_peric1[] = { - EXYNOS850_PIN_BANK_EINTG(8, 0x0, "gpp20", 0x00), - EXYNOS850_PIN_BANK_EINTG(4, 0x20, "gpp21", 0x04), - EXYNOS850_PIN_BANK_EINTG(2, 0x40, "gpp22", 0x08), - EXYNOS850_PIN_BANK_EINTG(8, 0x60, "gpp23", 0x0c), - EXYNOS850_PIN_BANK_EINTG(4, 0x80, "gpp24", 0x10), - EXYNOS850_PIN_BANK_EINTG(4, 0xa0, "gpp25", 0x14), - EXYNOS850_PIN_BANK_EINTG(5, 0xc0, "gpp26", 0x18), - EXYNOS850_PIN_BANK_EINTG(4, 0xe0, "gpp27", 0x1c), + GS101_PIN_BANK_EINTG(8, 0x0, "gpp20", 0x00, 0x00), + GS101_PIN_BANK_EINTG(4, 0x20, "gpp21", 0x04, 0x08), + GS101_PIN_BANK_EINTG(2, 0x40, "gpp22", 0x08, 0x0c), + GS101_PIN_BANK_EINTG(8, 0x60, "gpp23", 0x0c, 0x10), + GS101_PIN_BANK_EINTG(4, 0x80, "gpp24", 0x10, 0x18), + GS101_PIN_BANK_EINTG(4, 0xa0, "gpp25", 0x14, 0x1c), + GS101_PIN_BANK_EINTG(5, 0xc0, "gpp26", 0x18, 0x20), + GS101_PIN_BANK_EINTG(4, 0xe0, "gpp27", 0x1c, 0x28), }; /* pin banks of gs101 pin-controller (HSI1) */ static const struct samsung_pin_bank_data gs101_pin_hsi1[] = { - EXYNOS850_PIN_BANK_EINTG(6, 0x0, "gph0", 0x00), - EXYNOS850_PIN_BANK_EINTG(7, 0x20, "gph1", 0x04), + GS101_PIN_BANK_EINTG(6, 0x0, "gph0", 0x00, 0x00), + GS101_PIN_BANK_EINTG(7, 0x20, "gph1", 0x04, 0x08), }; /* pin banks of gs101 pin-controller (HSI2) */ static const struct samsung_pin_bank_data gs101_pin_hsi2[] = { - EXYNOS850_PIN_BANK_EINTG(6, 0x0, "gph2", 0x00), - EXYNOS850_PIN_BANK_EINTG(2, 0x20, "gph3", 0x04), - EXYNOS850_PIN_BANK_EINTG(6, 0x40, "gph4", 0x08), + GS101_PIN_BANK_EINTG(6, 0x0, "gph2", 0x00, 0x00), + GS101_PIN_BANK_EINTG(2, 0x20, "gph3", 0x04, 0x08), + GS101_PIN_BANK_EINTG(6, 0x40, "gph4", 0x08, 0x0c), }; static const struct samsung_pin_ctrl gs101_pin_ctrl[] __initconst = { diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h index f78da2e4cda8..b483270ddc53 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.h +++ b/drivers/pinctrl/samsung/pinctrl-exynos.h @@ -194,6 +194,28 @@ .name = id \ } +#define GS101_PIN_BANK_EINTG(pins, reg, id, offs, fltcon_offs) \ + { \ + .type = &exynos850_bank_type_off, \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .eint_type = EINT_TYPE_GPIO, \ + .eint_offset = offs, \ + .eint_fltcon_offset = fltcon_offs, \ + .name = id \ + } + +#define GS101_PIN_BANK_EINTW(pins, reg, id, offs, fltcon_offs) \ + { \ + .type = &exynos850_bank_type_alive, \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .eint_type = EINT_TYPE_WKUP, \ + .eint_offset = offs, \ + .eint_fltcon_offset = fltcon_offs, \ + .name = id \ + } + /** * struct exynos_weint_data: irq specific data for all the wakeup interrupts * generated by the external wakeup interrupt controller. diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 24e96d919d8f..2896eb2de2c0 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -1230,6 +1230,7 @@ samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d, bank->eint_con_offset = bdata->eint_con_offset; bank->eint_mask_offset = bdata->eint_mask_offset; bank->eint_pend_offset = bdata->eint_pend_offset; + bank->eint_fltcon_offset = bdata->eint_fltcon_offset; bank->name = bdata->name; raw_spin_lock_init(&bank->slock); diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index 2f452f592655..3cf758df7d69 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -144,6 +144,7 @@ struct samsung_pin_bank_type { * @eint_con_offset: ExynosAuto SoC-specific EINT control register offset of bank. * @eint_mask_offset: ExynosAuto SoC-specific EINT mask register offset of bank. * @eint_pend_offset: ExynosAuto SoC-specific EINT pend register offset of bank. + * @eint_fltcon_offset: GS101 SoC-specific EINT filter config register offset. * @name: name to be prefixed for each pin in this pin bank. */ struct samsung_pin_bank_data { @@ -158,6 +159,7 @@ struct samsung_pin_bank_data { u32 eint_con_offset; u32 eint_mask_offset; u32 eint_pend_offset; + u32 eint_fltcon_offset; const char *name; }; @@ -175,6 +177,7 @@ struct samsung_pin_bank_data { * @eint_con_offset: ExynosAuto SoC-specific EINT register or interrupt offset of bank. * @eint_mask_offset: ExynosAuto SoC-specific EINT mask register offset of bank. * @eint_pend_offset: ExynosAuto SoC-specific EINT pend register offset of bank. + * @eint_fltcon_offset: GS101 SoC-specific EINT filter config register offset. * @name: name to be prefixed for each pin in this pin bank. * @id: id of the bank, propagated to the pin range. * @pin_base: starting pin number of the bank. @@ -201,6 +204,7 @@ struct samsung_pin_bank { u32 eint_con_offset; u32 eint_mask_offset; u32 eint_pend_offset; + u32 eint_fltcon_offset; const char *name; u32 id; -- cgit v1.2.3-59-g8ed1b From 12966fdfbadbce5758a6d73f794778e10296cb64 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 6 Mar 2025 23:58:20 +0000 Subject: pinctrl: sunxi: refactor pinctrl variants into flags For some Allwinner SoCs we have one pinctrl driver caring for multiple very similar chips, and are tagging certain pins with a variant bitmask. The Allwinner D1 introduced a slightly extended register layout, and we were abusing this variant mask to convey this bit of information into the common code part. Now there will be more pinctrl device properties to consider (has PortF voltage switch, for instance), so shoehorning this into the variant bitmask will not fly anymore. Refactor the "variant" field into a more generic "flags" field. It turns out that we don't need the variant bits to be unique across all SoCs, but only among those SoCs that share one driver (table), of which there are at most three variants at the moment. So the actual variant field can be limited to say 8 bits, and the other bits in the flag register can be re-purposed to hold other information, like this extended register layout. As a side effect we can move the variant definition into the per-SoC pinctrl driver file, which makes it more obvious that this is just a private definition, only relevant for this particular table. This also changes the artificial sun20i-d1 "variant" into the actual flag bit that we are after. Signed-off-by: Andre Przywara Reviewed-by: Jernej Skrabec Link: https://lore.kernel.org/20250306235827.4895-2-andre.przywara@arm.com Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c | 6 ++---- drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c | 8 ++++++-- drivers/pinctrl/sunxi/pinctrl-sun5i.c | 8 ++++++-- drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c | 8 +++++--- drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c | 7 +++++-- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 10 +++++----- drivers/pinctrl/sunxi/pinctrl-sunxi.h | 23 +++++++---------------- 7 files changed, 36 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c b/drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c index 8e2aab542fcf..8efe35b77af4 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c +++ b/drivers/pinctrl/sunxi/pinctrl-sun20i-d1.c @@ -820,15 +820,13 @@ static const struct sunxi_pinctrl_desc d1_pinctrl_data = { static int d1_pinctrl_probe(struct platform_device *pdev) { - unsigned long variant = (unsigned long)of_device_get_match_data(&pdev->dev); - - return sunxi_pinctrl_init_with_variant(pdev, &d1_pinctrl_data, variant); + return sunxi_pinctrl_init_with_flags(pdev, &d1_pinctrl_data, + SUNXI_PINCTRL_NEW_REG_LAYOUT); } static const struct of_device_id d1_pinctrl_match[] = { { .compatible = "allwinner,sun20i-d1-pinctrl", - .data = (void *)PINCTRL_SUN20I_D1 }, {} }; diff --git a/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c b/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c index fa47fe36ee5b..b2e82bf927b3 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c +++ b/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c @@ -17,6 +17,10 @@ #include "pinctrl-sunxi.h" +#define PINCTRL_SUN4I_A10 BIT(0) +#define PINCTRL_SUN7I_A20 BIT(1) +#define PINCTRL_SUN8I_R40 BIT(2) + static const struct sunxi_desc_pin sun4i_a10_pins[] = { SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 0), SUNXI_FUNCTION(0x0, "gpio_in"), @@ -1295,8 +1299,8 @@ static int sun4i_a10_pinctrl_probe(struct platform_device *pdev) { unsigned long variant = (unsigned long)of_device_get_match_data(&pdev->dev); - return sunxi_pinctrl_init_with_variant(pdev, &sun4i_a10_pinctrl_data, - variant); + return sunxi_pinctrl_init_with_flags(pdev, &sun4i_a10_pinctrl_data, + variant); } static const struct of_device_id sun4i_a10_pinctrl_match[] = { diff --git a/drivers/pinctrl/sunxi/pinctrl-sun5i.c b/drivers/pinctrl/sunxi/pinctrl-sun5i.c index 06ecb121c827..6eef314c9377 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sun5i.c +++ b/drivers/pinctrl/sunxi/pinctrl-sun5i.c @@ -16,6 +16,10 @@ #include "pinctrl-sunxi.h" +#define PINCTRL_SUN5I_A10S BIT(0) +#define PINCTRL_SUN5I_A13 BIT(1) +#define PINCTRL_SUN5I_GR8 BIT(2) + static const struct sunxi_desc_pin sun5i_pins[] = { SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 0), PINCTRL_SUN5I_A10S, @@ -719,8 +723,8 @@ static int sun5i_pinctrl_probe(struct platform_device *pdev) { unsigned long variant = (unsigned long)of_device_get_match_data(&pdev->dev); - return sunxi_pinctrl_init_with_variant(pdev, &sun5i_pinctrl_data, - variant); + return sunxi_pinctrl_init_with_flags(pdev, &sun5i_pinctrl_data, + variant); } static const struct of_device_id sun5i_pinctrl_match[] = { diff --git a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c index 82ac064931df..8d8c92ce41cf 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c +++ b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c @@ -17,6 +17,9 @@ #include "pinctrl-sunxi.h" +#define PINCTRL_SUN6I_A31 BIT(0) +#define PINCTRL_SUN6I_A31S BIT(1) + static const struct sunxi_desc_pin sun6i_a31_pins[] = { SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 0), SUNXI_FUNCTION(0x0, "gpio_in"), @@ -972,9 +975,8 @@ static int sun6i_a31_pinctrl_probe(struct platform_device *pdev) unsigned long variant = (unsigned long)of_device_get_match_data(&pdev->dev); - return sunxi_pinctrl_init_with_variant(pdev, - &sun6i_a31_pinctrl_data, - variant); + return sunxi_pinctrl_init_with_flags(pdev, &sun6i_a31_pinctrl_data, + variant); } static const struct of_device_id sun6i_a31_pinctrl_match[] = { diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c index 49c9a0b6a0eb..696d7dd8d87b 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c +++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c @@ -22,6 +22,9 @@ #include "pinctrl-sunxi.h" +#define PINCTRL_SUN8I_V3 BIT(0) +#define PINCTRL_SUN8I_V3S BIT(1) + static const struct sunxi_desc_pin sun8i_v3s_pins[] = { /* Hole */ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0), @@ -552,8 +555,8 @@ static int sun8i_v3s_pinctrl_probe(struct platform_device *pdev) { unsigned long variant = (unsigned long)of_device_get_match_data(&pdev->dev); - return sunxi_pinctrl_init_with_variant(pdev, &sun8i_v3s_pinctrl_data, - variant); + return sunxi_pinctrl_init_with_flags(pdev, &sun8i_v3s_pinctrl_data, + variant); } static const struct of_device_id sun8i_v3s_pinctrl_match[] = { diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index bde67ee31417..ae281a3c2ed3 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -1472,9 +1472,9 @@ static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl, return 0; } -int sunxi_pinctrl_init_with_variant(struct platform_device *pdev, - const struct sunxi_pinctrl_desc *desc, - unsigned long variant) +int sunxi_pinctrl_init_with_flags(struct platform_device *pdev, + const struct sunxi_pinctrl_desc *desc, + unsigned long flags) { struct device_node *node = pdev->dev.of_node; struct pinctrl_desc *pctrl_desc; @@ -1497,8 +1497,8 @@ int sunxi_pinctrl_init_with_variant(struct platform_device *pdev, pctl->dev = &pdev->dev; pctl->desc = desc; - pctl->variant = variant; - if (pctl->variant >= PINCTRL_SUN20I_D1) { + pctl->variant = flags & SUNXI_PINCTRL_VARIANT_MASK; + if (flags & SUNXI_PINCTRL_NEW_REG_LAYOUT) { pctl->bank_mem_size = D1_BANK_MEM_SIZE; pctl->pull_regs_offset = D1_PULL_REGS_OFFSET; pctl->dlevel_field_width = D1_DLEVEL_FIELD_WIDTH; diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h index a87a2f944d60..8e2eca45b57f 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h @@ -82,18 +82,9 @@ #define SUN4I_FUNC_INPUT 0 #define SUN4I_FUNC_IRQ 6 -#define PINCTRL_SUN5I_A10S BIT(1) -#define PINCTRL_SUN5I_A13 BIT(2) -#define PINCTRL_SUN5I_GR8 BIT(3) -#define PINCTRL_SUN6I_A31 BIT(4) -#define PINCTRL_SUN6I_A31S BIT(5) -#define PINCTRL_SUN4I_A10 BIT(6) -#define PINCTRL_SUN7I_A20 BIT(7) -#define PINCTRL_SUN8I_R40 BIT(8) -#define PINCTRL_SUN8I_V3 BIT(9) -#define PINCTRL_SUN8I_V3S BIT(10) -/* Variants below here have an updated register layout. */ -#define PINCTRL_SUN20I_D1 BIT(11) +#define SUNXI_PINCTRL_VARIANT_MASK GENMASK(7, 0) +#define SUNXI_PINCTRL_NEW_REG_LAYOUT BIT(8) +#define SUNXI_PINCTRL_PORTF_SWITCH BIT(9) #define PIO_POW_MOD_SEL_REG 0x340 #define PIO_POW_MOD_CTL_REG 0x344 @@ -299,11 +290,11 @@ static inline u32 sunxi_grp_config_reg(u16 pin) return GRP_CFG_REG + bank * 0x4; } -int sunxi_pinctrl_init_with_variant(struct platform_device *pdev, - const struct sunxi_pinctrl_desc *desc, - unsigned long variant); +int sunxi_pinctrl_init_with_flags(struct platform_device *pdev, + const struct sunxi_pinctrl_desc *desc, + unsigned long flags); #define sunxi_pinctrl_init(_dev, _desc) \ - sunxi_pinctrl_init_with_variant(_dev, _desc, 0) + sunxi_pinctrl_init_with_flags(_dev, _desc, 0) #endif /* __PINCTRL_SUNXI_H */ -- cgit v1.2.3-59-g8ed1b From 4713b70cc4bd46fd47899e0f4c5b3ecae213db9f Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 6 Mar 2025 23:58:21 +0000 Subject: pinctrl: sunxi: increase number of GPIO bank regulators By design, the Allwinner pinctrl IP always supported up to 11 GPIO banks, though no SoC ever used more than 9 banks so far. The Allwinner A523 has pins in all 11 banks, which exceeds the number of per-bank regulators that we currently support, as this was set to 9. Increase the size of the array to hold up to 11 regulator structs, to support pins in bank J and K as well. Signed-off-by: Andre Przywara Reviewed-by: Chen-Yu Tsai Link: https://lore.kernel.org/20250306235827.4895-3-andre.przywara@arm.com Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/pinctrl-sunxi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h index 8e2eca45b57f..fbbf070a8754 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h @@ -155,7 +155,7 @@ struct sunxi_pinctrl { struct gpio_chip *chip; const struct sunxi_pinctrl_desc *desc; struct device *dev; - struct sunxi_pinctrl_regulator regulators[9]; + struct sunxi_pinctrl_regulator regulators[11]; struct irq_domain *domain; struct sunxi_pinctrl_function *functions; unsigned nfunctions; -- cgit v1.2.3-59-g8ed1b From c6c4dc75a1a71c45042815ce761f2c448a7afd48 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 6 Mar 2025 23:58:22 +0000 Subject: pinctrl: sunxi: move bank K register offset The Allwinner pincontroller register layout used to allow for at least 11 banks per controller, any more banks would reside at a second controller instance. When the per-bank register map size was increased with the D1, it turned out that the last bank (port K) of those maximum 11 banks actually would not fit anymore in the 512 bytes reserved for the pincontroller registers. On new SoCs Allwinner thus moved the last bank beyond the existing registers, at offset 0x500. So far SoCs never used more than 9 banks per controller, but the new Allwinner A523 actually uses all 11 banks. Since that SoC also uses the extended layout, its PortK needs to be programmed at offset 0x500. Factor out the bank offset calculation into a new function, and handle the case for the last bank separately. Since none of the older SoCs ever used PortK, we can ignore this case, and just always use offset 0x500 for the last bank. Signed-off-by: Andre Przywara Reviewed-by: Chen-Yu Tsai Link: https://lore.kernel.org/20250306235827.4895-4-andre.przywara@arm.com Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 29 +++++++++++++++++++++-------- drivers/pinctrl/sunxi/pinctrl-sunxi.h | 4 ++++ 2 files changed, 25 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index ae281a3c2ed3..83a031ceb29f 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -58,13 +58,29 @@ static struct irq_chip sunxi_pinctrl_level_irq_chip; * The following functions calculate the register and the bit offset to access. * They take a pin number which is relative to the start of the current device. */ + +/* + * When using the extended register layout, Bank K does not fit into the + * space used for the other banks. Instead it lives at offset 0x500. + */ +static u32 sunxi_bank_offset(const struct sunxi_pinctrl *pctl, u32 pin) +{ + u32 offset = 0; + + if (pin >= PK_BASE) { + pin -= PK_BASE; + offset = PIO_BANK_K_OFFSET; + } + + return offset + (pin / PINS_PER_BANK) * pctl->bank_mem_size; +} + static void sunxi_mux_reg(const struct sunxi_pinctrl *pctl, u32 pin, u32 *reg, u32 *shift, u32 *mask) { - u32 bank = pin / PINS_PER_BANK; u32 offset = pin % PINS_PER_BANK * MUX_FIELD_WIDTH; - *reg = bank * pctl->bank_mem_size + MUX_REGS_OFFSET + + *reg = sunxi_bank_offset(pctl, pin) + MUX_REGS_OFFSET + offset / BITS_PER_TYPE(u32) * sizeof(u32); *shift = offset % BITS_PER_TYPE(u32); *mask = (BIT(MUX_FIELD_WIDTH) - 1) << *shift; @@ -73,10 +89,9 @@ static void sunxi_mux_reg(const struct sunxi_pinctrl *pctl, static void sunxi_data_reg(const struct sunxi_pinctrl *pctl, u32 pin, u32 *reg, u32 *shift, u32 *mask) { - u32 bank = pin / PINS_PER_BANK; u32 offset = pin % PINS_PER_BANK * DATA_FIELD_WIDTH; - *reg = bank * pctl->bank_mem_size + DATA_REGS_OFFSET + + *reg = sunxi_bank_offset(pctl, pin) + DATA_REGS_OFFSET + offset / BITS_PER_TYPE(u32) * sizeof(u32); *shift = offset % BITS_PER_TYPE(u32); *mask = (BIT(DATA_FIELD_WIDTH) - 1) << *shift; @@ -85,10 +100,9 @@ static void sunxi_data_reg(const struct sunxi_pinctrl *pctl, static void sunxi_dlevel_reg(const struct sunxi_pinctrl *pctl, u32 pin, u32 *reg, u32 *shift, u32 *mask) { - u32 bank = pin / PINS_PER_BANK; u32 offset = pin % PINS_PER_BANK * pctl->dlevel_field_width; - *reg = bank * pctl->bank_mem_size + DLEVEL_REGS_OFFSET + + *reg = sunxi_bank_offset(pctl, pin) + DLEVEL_REGS_OFFSET + offset / BITS_PER_TYPE(u32) * sizeof(u32); *shift = offset % BITS_PER_TYPE(u32); *mask = (BIT(pctl->dlevel_field_width) - 1) << *shift; @@ -97,10 +111,9 @@ static void sunxi_dlevel_reg(const struct sunxi_pinctrl *pctl, static void sunxi_pull_reg(const struct sunxi_pinctrl *pctl, u32 pin, u32 *reg, u32 *shift, u32 *mask) { - u32 bank = pin / PINS_PER_BANK; u32 offset = pin % PINS_PER_BANK * PULL_FIELD_WIDTH; - *reg = bank * pctl->bank_mem_size + pctl->pull_regs_offset + + *reg = sunxi_bank_offset(pctl, pin) + pctl->pull_regs_offset + offset / BITS_PER_TYPE(u32) * sizeof(u32); *shift = offset % BITS_PER_TYPE(u32); *mask = (BIT(PULL_FIELD_WIDTH) - 1) << *shift; diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h index fbbf070a8754..6cf721876d89 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h @@ -25,6 +25,8 @@ #define PG_BASE 192 #define PH_BASE 224 #define PI_BASE 256 +#define PJ_BASE 288 +#define PK_BASE 320 #define PL_BASE 352 #define PM_BASE 384 #define PN_BASE 416 @@ -89,6 +91,8 @@ #define PIO_POW_MOD_SEL_REG 0x340 #define PIO_POW_MOD_CTL_REG 0x344 +#define PIO_BANK_K_OFFSET 0x500 + enum sunxi_desc_bias_voltage { BIAS_VOLTAGE_NONE, /* -- cgit v1.2.3-59-g8ed1b From 6d079d93e4df90235ec15a9f11866881c2fe3a40 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 6 Mar 2025 23:58:23 +0000 Subject: pinctrl: sunxi: support moved power configuration registers The Allwinner pincontroller IP features some registers to control the withstand voltage of each pin group. So far those registers were always located at the same offset, but the A523 SoC has moved them (probably to accommodate all eleven pin banks). Add a flag to note this feature, and use that to program the registers either at offset 0x340 or 0x380. So far no pincontroller driver uses this flag, but we need it for the upcoming A523 support. Signed-off-by: Andre Przywara Reviewed-by: Jernej Skrabec Link: https://lore.kernel.org/20250306235827.4895-5-andre.przywara@arm.com Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 15 +++++++++++---- drivers/pinctrl/sunxi/pinctrl-sunxi.h | 7 +++++-- 2 files changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 83a031ceb29f..f1c5a991cf7b 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -736,9 +736,11 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl, val = uV > 1800000 && uV <= 2500000 ? BIT(bank) : 0; raw_spin_lock_irqsave(&pctl->lock, flags); - reg = readl(pctl->membase + PIO_POW_MOD_CTL_REG); + reg = readl(pctl->membase + pctl->pow_mod_sel_offset + + PIO_POW_MOD_CTL_OFS); reg &= ~BIT(bank); - writel(reg | val, pctl->membase + PIO_POW_MOD_CTL_REG); + writel(reg | val, pctl->membase + pctl->pow_mod_sel_offset + + PIO_POW_MOD_CTL_OFS); raw_spin_unlock_irqrestore(&pctl->lock, flags); fallthrough; @@ -746,9 +748,10 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl, val = uV <= 1800000 ? 1 : 0; raw_spin_lock_irqsave(&pctl->lock, flags); - reg = readl(pctl->membase + PIO_POW_MOD_SEL_REG); + reg = readl(pctl->membase + pctl->pow_mod_sel_offset); reg &= ~(1 << bank); - writel(reg | val << bank, pctl->membase + PIO_POW_MOD_SEL_REG); + writel(reg | val << bank, + pctl->membase + pctl->pow_mod_sel_offset); raw_spin_unlock_irqrestore(&pctl->lock, flags); return 0; default: @@ -1520,6 +1523,10 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev, pctl->pull_regs_offset = PULL_REGS_OFFSET; pctl->dlevel_field_width = DLEVEL_FIELD_WIDTH; } + if (flags & SUNXI_PINCTRL_ELEVEN_BANKS) + pctl->pow_mod_sel_offset = PIO_11B_POW_MOD_SEL_REG; + else + pctl->pow_mod_sel_offset = PIO_POW_MOD_SEL_REG; pctl->irq_array = devm_kcalloc(&pdev->dev, IRQ_PER_BANK * pctl->desc->irq_banks, diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h index 6cf721876d89..742fc795c766 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h @@ -87,9 +87,11 @@ #define SUNXI_PINCTRL_VARIANT_MASK GENMASK(7, 0) #define SUNXI_PINCTRL_NEW_REG_LAYOUT BIT(8) #define SUNXI_PINCTRL_PORTF_SWITCH BIT(9) +#define SUNXI_PINCTRL_ELEVEN_BANKS BIT(10) -#define PIO_POW_MOD_SEL_REG 0x340 -#define PIO_POW_MOD_CTL_REG 0x344 +#define PIO_POW_MOD_SEL_REG 0x340 +#define PIO_11B_POW_MOD_SEL_REG 0x380 +#define PIO_POW_MOD_CTL_OFS 0x004 #define PIO_BANK_K_OFFSET 0x500 @@ -173,6 +175,7 @@ struct sunxi_pinctrl { u32 bank_mem_size; u32 pull_regs_offset; u32 dlevel_field_width; + u32 pow_mod_sel_offset; }; #define SUNXI_PIN(_pin, ...) \ -- cgit v1.2.3-59-g8ed1b From f5e2cd34b12f03208b7fcc89bf1b6c3b3508b085 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 6 Mar 2025 23:58:24 +0000 Subject: pinctrl: sunxi: allow reading mux values from DT So far every Allwinner SoC needs a large table in the kernel code, to describe the mapping between the pinctrl function names ("uart") and the actual pincontroller mux value to be written into the registers. This adds a lot of data into a single image kernel, and also looks somewhat weird, as the DT can easily store the mux value. Add some code that allows to avoid that table: the struct that describes the existing pins will be build at *runtime*, based on very basic information provided by the respective SoC's pinctrl driver. This consists of the number of pins per bank, plus information which bank provides IRQ support, along with the mux value to use for that. The code will then iterate over all children of the pincontroller DT node (which describe each pin group), and populate that struct with the mapping between function names and mux values. The only thing that needs adding in the DT is a property with that value, per pin group. When this table is built, it will be handed over to the existing sunxi pinctrl driver, which cannot tell a difference between a hardcoded struct and this new one built at runtime. It will take care of registering the pinctrl device with the pinctrl subsystem. All a new SoC driver would need to do is to provide two arrays, and then call the sunxi_pinctrl_dt_table_init() function. Signed-off-by: Andre Przywara Reviewed-by: Jernej Skrabec Link: https://lore.kernel.org/20250306235827.4895-6-andre.przywara@arm.com Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/Makefile | 1 + drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c | 374 +++++++++++++++++++++++++++++++ drivers/pinctrl/sunxi/pinctrl-sunxi.h | 9 + 3 files changed, 384 insertions(+) create mode 100644 drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c (limited to 'drivers') diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile index 2ff5a55927ad..f5bad7a52951 100644 --- a/drivers/pinctrl/sunxi/Makefile +++ b/drivers/pinctrl/sunxi/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # Core obj-y += pinctrl-sunxi.o +obj-y += pinctrl-sunxi-dt.o # SoC Drivers obj-$(CONFIG_PINCTRL_SUNIV_F1C100S) += pinctrl-suniv-f1c100s.o diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c b/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c new file mode 100644 index 000000000000..1833078f6877 --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c @@ -0,0 +1,374 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017-2025 Arm Ltd. + * + * Generic DT driven Allwinner pinctrl driver routines. + * Builds the pin tables from minimal driver information and pin groups + * described in the DT. Then hands those tables of to the traditional + * sunxi pinctrl driver. + * sunxi_pinctrl_init() expects a table like shown below, previously spelled + * out in a per-SoC .c file. This code generates this table, like so: + * + * SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1), // code iterates over every implemented + * // pin, based on pins_per_bank[] array passed in + * + * SUNXI_FUNCTION(0x0, "gpio_in"), // always added, for every pin + * SUNXI_FUNCTION(0x1, "gpio_out"), // always added, for every pin + * + * SUNXI_FUNCTION(0x2, "mmc0"), // based on pingroup found in DT: + * // mmc0-pins { + * // pins = "PF0", "PF1", ... + * // function = "mmc0"; + * // allwinner,pinmux = <2>; + * + * SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 1)), // derived by irq_bank_muxes[] + * // array passed in + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pinctrl-sunxi.h" + +#define INVALID_MUX 0xff + +/* + * Return the "index"th element from the "allwinner,pinmux" property. If the + * property does not hold enough entries, return the last one instead. + * For almost every group the pinmux value is actually the same, so this + * allows to just list one value in the property. + */ +static u8 sunxi_pinctrl_dt_read_pinmux(const struct device_node *node, + int index) +{ + int ret, num_elems; + u32 value; + + num_elems = of_property_count_u32_elems(node, "allwinner,pinmux"); + if (num_elems <= 0) + return INVALID_MUX; + + if (index >= num_elems) + index = num_elems - 1; + + ret = of_property_read_u32_index(node, "allwinner,pinmux", index, + &value); + if (ret) + return INVALID_MUX; + + return value; +} + +/* + * Allocate a table with a sunxi_desc_pin structure for every pin needed. + * Fills in the respective pin names ("PA0") and their pin numbers. + * Returns the pins array. We cannot use the member in *desc yet, as this + * is marked as const, and we will need to change the array still. + */ +static struct sunxi_desc_pin *init_pins_table(struct device *dev, + const u8 *pins_per_bank, + struct sunxi_pinctrl_desc *desc) +{ + struct sunxi_desc_pin *pins, *cur_pin; + int name_size = 0; + int port_base = desc->pin_base / PINS_PER_BANK; + char *pin_names, *cur_name; + int i, j; + + /* + * Find the total number of pins. + * Also work out how much memory we need to store all the pin names. + */ + for (i = 0; i < SUNXI_PINCTRL_MAX_BANKS; i++) { + desc->npins += pins_per_bank[i]; + if (pins_per_bank[i] < 10) { + /* 4 bytes for "PXy\0" */ + name_size += pins_per_bank[i] * 4; + } else { + /* 4 bytes for each "PXy\0" */ + name_size += 10 * 4; + + /* 5 bytes for each "PXyy\0" */ + name_size += (pins_per_bank[i] - 10) * 5; + } + } + + if (desc->npins == 0) { + dev_err(dev, "no ports defined\n"); + return ERR_PTR(-EINVAL); + } + + pins = devm_kzalloc(dev, desc->npins * sizeof(*pins), GFP_KERNEL); + if (!pins) + return ERR_PTR(-ENOMEM); + + /* Allocate memory to store the name for every pin. */ + pin_names = devm_kmalloc(dev, name_size, GFP_KERNEL); + if (!pin_names) + return ERR_PTR(-ENOMEM); + + /* Fill the pins array with the name and the number for each pin. */ + cur_name = pin_names; + cur_pin = pins; + for (i = 0; i < SUNXI_PINCTRL_MAX_BANKS; i++) { + for (j = 0; j < pins_per_bank[i]; j++, cur_pin++) { + int nchars = sprintf(cur_name, "P%c%d", + port_base + 'A' + i, j); + + cur_pin->pin.number = (port_base + i) * PINS_PER_BANK + j; + cur_pin->pin.name = cur_name; + cur_name += nchars + 1; + } + } + + return pins; +} + +/* + * Work out the number of functions for each pin. This will visit every + * child node of the pinctrl DT node to find all advertised functions. + * Provide memory to hold the per-function information and assign it to + * the pin table. + * Fill in the GPIO in/out functions already (that every pin has), also add + * an "irq" function at the end, for those pins in IRQ-capable ports. + * We do not fill in the extra functions (those describe in DT nodes) yet. + * We (ab)use the "variant" member in each pin to keep track of the number of + * extra functions needed. At the end this will get reset to 2, so that we + * can add extra function later, after the two GPIO functions. + */ +static int prepare_function_table(struct device *dev, struct device_node *pnode, + struct sunxi_desc_pin *pins, int npins, + const u8 *irq_bank_muxes) +{ + struct device_node *node; + struct property *prop; + struct sunxi_desc_function *func; + int num_funcs, irq_bank, last_bank, i; + + /* + * We need at least three functions per pin: + * - one for GPIO in + * - one for GPIO out + * - one for the sentinel signalling the end of the list + */ + num_funcs = 3 * npins; + + /* + * Add a function for each pin in a bank supporting interrupts. + * We temporarily (ab)use the variant field to store the number of + * functions per pin. This will be cleaned back to 0 before we hand + * over the whole structure to the generic sunxi pinctrl setup code. + */ + for (i = 0; i < npins; i++) { + struct sunxi_desc_pin *pin = &pins[i]; + int bank = pin->pin.number / PINS_PER_BANK; + + if (irq_bank_muxes[bank]) { + pin->variant++; + num_funcs++; + } + } + + /* + * Go over each pin group (every child of the pinctrl DT node) and + * add the number of special functions each pins has. Also update the + * total number of functions required. + * We might slightly overshoot here in case of double definitions. + */ + for_each_child_of_node(pnode, node) { + const char *name; + + of_property_for_each_string(node, "pins", prop, name) { + for (i = 0; i < npins; i++) { + if (strcmp(pins[i].pin.name, name)) + continue; + + pins[i].variant++; + num_funcs++; + break; + } + } + } + + /* + * Allocate the memory needed for the functions in one table. + * We later use pointers into this table to mark each pin. + */ + func = devm_kzalloc(dev, num_funcs * sizeof(*func), GFP_KERNEL); + if (!func) + return -ENOMEM; + + /* + * Assign the function's memory and fill in GPIOs, IRQ and a sentinel. + * The extra functions will be filled in later. + */ + irq_bank = 0; + last_bank = 0; + for (i = 0; i < npins; i++) { + struct sunxi_desc_pin *pin = &pins[i]; + int bank = pin->pin.number / PINS_PER_BANK; + int lastfunc = pin->variant + 1; + int irq_mux = irq_bank_muxes[bank]; + + func[0].name = "gpio_in"; + func[0].muxval = 0; + func[1].name = "gpio_out"; + func[1].muxval = 1; + + if (irq_mux) { + if (bank > last_bank) + irq_bank++; + func[lastfunc].muxval = irq_mux; + func[lastfunc].irqbank = irq_bank; + func[lastfunc].irqnum = pin->pin.number % PINS_PER_BANK; + func[lastfunc].name = "irq"; + } + + if (bank > last_bank) + last_bank = bank; + + pin->functions = func; + + /* Skip over the other needed functions and the sentinel. */ + func += pin->variant + 3; + + /* + * Reset the value for filling in the remaining functions + * behind the GPIOs later. + */ + pin->variant = 2; + } + + return 0; +} + +/* + * Iterate over all pins in a single group and add the function name and its + * mux value to the respective pin. + * The "variant" member is again used to temporarily track the number of + * already added functions. + */ +static void fill_pin_function(struct device *dev, struct device_node *node, + struct sunxi_desc_pin *pins, int npins) +{ + const char *name, *funcname; + struct sunxi_desc_function *func; + struct property *prop; + int pin, i, index; + u8 muxval; + + if (of_property_read_string(node, "function", &funcname)) { + dev_warn(dev, "missing \"function\" property\n"); + return; + } + + index = 0; + of_property_for_each_string(node, "pins", prop, name) { + /* Find the index of this pin in our table. */ + for (pin = 0; pin < npins; pin++) + if (!strcmp(pins[pin].pin.name, name)) + break; + if (pin == npins) { + dev_warn(dev, "%s: cannot find pin %s\n", + of_node_full_name(node), name); + index++; + continue; + } + + /* Read the associated mux value. */ + muxval = sunxi_pinctrl_dt_read_pinmux(node, index); + if (muxval == INVALID_MUX) { + dev_warn(dev, "%s: invalid mux value for pin %s\n", + of_node_full_name(node), name); + index++; + continue; + } + + /* + * Check for double definitions by comparing the to-be-added + * function with already assigned ones. + * Ignore identical pairs (function name and mux value the + * same), but warn about conflicting assignments. + */ + for (i = 2; i < pins[pin].variant; i++) { + func = &pins[pin].functions[i]; + + /* Skip over totally unrelated functions. */ + if (strcmp(func->name, funcname) && + func->muxval != muxval) + continue; + + /* Ignore (but skip below) any identical functions. */ + if (!strcmp(func->name, funcname) && + muxval == func->muxval) + break; + + dev_warn(dev, + "pin %s: function %s redefined to mux %d\n", + name, funcname, muxval); + break; + } + + /* Skip any pins with that function already assigned. */ + if (i < pins[pin].variant) { + index++; + continue; + } + + /* Assign function and muxval to the next free slot. */ + func = &pins[pin].functions[pins[pin].variant]; + func->muxval = muxval; + func->name = funcname; + + pins[pin].variant++; + index++; + } +} + +/* + * Initialise the pinctrl table, by building it from driver provided + * information: the number of pins per bank, the IRQ capable banks and their + * IRQ mux value. + * Then iterate over all pinctrl DT node children to enter the function name + * and mux values for each mentioned pin. + * At the end hand over this structure to the actual sunxi pinctrl driver. + */ +int sunxi_pinctrl_dt_table_init(struct platform_device *pdev, + const u8 *pins_per_bank, + const u8 *irq_bank_muxes, + struct sunxi_pinctrl_desc *desc, + unsigned long flags) +{ + struct device_node *pnode = pdev->dev.of_node, *node; + struct sunxi_desc_pin *pins; + int ret, i; + + pins = init_pins_table(&pdev->dev, pins_per_bank, desc); + if (IS_ERR(pins)) + return PTR_ERR(pins); + + ret = prepare_function_table(&pdev->dev, pnode, pins, desc->npins, + irq_bank_muxes); + if (ret) + return ret; + + /* + * Now iterate over all groups and add the respective function name + * and mux values to each pin listed within. + */ + for_each_child_of_node(pnode, node) + fill_pin_function(&pdev->dev, node, pins, desc->npins); + + /* Clear the temporary storage. */ + for (i = 0; i < desc->npins; i++) + pins[i].variant = 0; + + desc->pins = pins; + + return sunxi_pinctrl_init_with_flags(pdev, desc, flags); +} diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h index 742fc795c766..ad26e4de16a8 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h @@ -31,6 +31,9 @@ #define PM_BASE 384 #define PN_BASE 416 +/* maximum number of banks per controller (PA -> PK) */ +#define SUNXI_PINCTRL_MAX_BANKS 11 + #define SUNXI_PINCTRL_PIN(bank, pin) \ PINCTRL_PIN(P ## bank ## _BASE + (pin), "P" #bank #pin) @@ -304,4 +307,10 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev, #define sunxi_pinctrl_init(_dev, _desc) \ sunxi_pinctrl_init_with_flags(_dev, _desc, 0) +int sunxi_pinctrl_dt_table_init(struct platform_device *pdev, + const u8 *pins_per_bank, + const u8 *irq_bank_muxes, + struct sunxi_pinctrl_desc *desc, + unsigned long flags); + #endif /* __PINCTRL_SUNXI_H */ -- cgit v1.2.3-59-g8ed1b From 648be4cd95172167fd4cc7262c1827bd37cea8e3 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 6 Mar 2025 23:58:26 +0000 Subject: pinctrl: sunxi: Add support for the Allwinner A523 The Allwinner A523 contains pins in 10 out of the 11 possible pin banks; it just skips port A. Use the newly introduced DT based pinctrl driver to describe just the generic pinctrl properties, so advertise the number of pins per bank and the interrupt capabilities. The actual function/mux assignment is taken from the devicetree. Signed-off-by: Andre Przywara Reviewed-by: Jernej Skrabec Link: https://lore.kernel.org/20250306235827.4895-8-andre.przywara@arm.com Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/Kconfig | 5 +++ drivers/pinctrl/sunxi/Makefile | 1 + drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c | 54 +++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c (limited to 'drivers') diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig index a78fdbbdfc0c..0cbe46668365 100644 --- a/drivers/pinctrl/sunxi/Kconfig +++ b/drivers/pinctrl/sunxi/Kconfig @@ -131,4 +131,9 @@ config PINCTRL_SUN50I_H616_R default ARM64 && ARCH_SUNXI select PINCTRL_SUNXI +config PINCTRL_SUN55I_A523 + bool "Support for the Allwinner A523 PIO" + default ARM64 && ARCH_SUNXI + select PINCTRL_SUNXI + endif diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile index f5bad7a52951..4e55508ff7f7 100644 --- a/drivers/pinctrl/sunxi/Makefile +++ b/drivers/pinctrl/sunxi/Makefile @@ -27,5 +27,6 @@ obj-$(CONFIG_PINCTRL_SUN50I_H6) += pinctrl-sun50i-h6.o obj-$(CONFIG_PINCTRL_SUN50I_H6_R) += pinctrl-sun50i-h6-r.o obj-$(CONFIG_PINCTRL_SUN50I_H616) += pinctrl-sun50i-h616.o obj-$(CONFIG_PINCTRL_SUN50I_H616_R) += pinctrl-sun50i-h616-r.o +obj-$(CONFIG_PINCTRL_SUN55I_A523) += pinctrl-sun55i-a523.o obj-$(CONFIG_PINCTRL_SUN9I_A80) += pinctrl-sun9i-a80.o obj-$(CONFIG_PINCTRL_SUN9I_A80_R) += pinctrl-sun9i-a80-r.o diff --git a/drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c b/drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c new file mode 100644 index 000000000000..7d2308c37d29 --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Allwinner A523 SoC pinctrl driver. + * + * Copyright (C) 2023 Arm Ltd. + */ + +#include +#include +#include +#include +#include + +#include "pinctrl-sunxi.h" + +static const u8 a523_nr_bank_pins[SUNXI_PINCTRL_MAX_BANKS] = +/* PA PB PC PD PE PF PG PH PI PJ PK */ + { 0, 15, 17, 24, 16, 7, 15, 20, 17, 28, 24 }; + +static const unsigned int a523_irq_bank_map[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + +static const u8 a523_irq_bank_muxes[SUNXI_PINCTRL_MAX_BANKS] = +/* PA PB PC PD PE PF PG PH PI PJ PK */ + { 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14}; + +static struct sunxi_pinctrl_desc a523_pinctrl_data = { + .irq_banks = ARRAY_SIZE(a523_irq_bank_map), + .irq_bank_map = a523_irq_bank_map, + .irq_read_needs_mux = true, + .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_SEL, +}; + +static int a523_pinctrl_probe(struct platform_device *pdev) +{ + return sunxi_pinctrl_dt_table_init(pdev, a523_nr_bank_pins, + a523_irq_bank_muxes, + &a523_pinctrl_data, + SUNXI_PINCTRL_NEW_REG_LAYOUT | + SUNXI_PINCTRL_ELEVEN_BANKS); +} + +static const struct of_device_id a523_pinctrl_match[] = { + { .compatible = "allwinner,sun55i-a523-pinctrl", }, + {} +}; + +static struct platform_driver a523_pinctrl_driver = { + .probe = a523_pinctrl_probe, + .driver = { + .name = "sun55i-a523-pinctrl", + .of_match_table = a523_pinctrl_match, + }, +}; +builtin_platform_driver(a523_pinctrl_driver); -- cgit v1.2.3-59-g8ed1b From b8a51e95b376c9a1fe66a831d44901214e2ea2e3 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 6 Mar 2025 23:58:27 +0000 Subject: pinctrl: sunxi: Add support for the secondary A523 GPIO ports As most other Allwinner SoCs before, the A523 chip contains a second GPIO controller, managing banks PL and PM. Use the newly introduced DT based pinctrl driver to describe just the generic pinctrl properties, so advertise the number of pins per bank and the interrupt capabilities. The actual function/mux assignment is taken from the devicetree. Signed-off-by: Andre Przywara Reviewed-by: Jernej Skrabec Link: https://lore.kernel.org/20250306235827.4895-9-andre.przywara@arm.com Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/Kconfig | 5 +++ drivers/pinctrl/sunxi/Makefile | 1 + drivers/pinctrl/sunxi/pinctrl-sun55i-a523-r.c | 54 +++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun55i-a523-r.c (limited to 'drivers') diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig index 0cbe46668365..dc62eba96348 100644 --- a/drivers/pinctrl/sunxi/Kconfig +++ b/drivers/pinctrl/sunxi/Kconfig @@ -136,4 +136,9 @@ config PINCTRL_SUN55I_A523 default ARM64 && ARCH_SUNXI select PINCTRL_SUNXI +config PINCTRL_SUN55I_A523_R + bool "Support for the Allwinner A523 R-PIO" + default ARM64 && ARCH_SUNXI + select PINCTRL_SUNXI + endif diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile index 4e55508ff7f7..951b3f1e4b4f 100644 --- a/drivers/pinctrl/sunxi/Makefile +++ b/drivers/pinctrl/sunxi/Makefile @@ -28,5 +28,6 @@ obj-$(CONFIG_PINCTRL_SUN50I_H6_R) += pinctrl-sun50i-h6-r.o obj-$(CONFIG_PINCTRL_SUN50I_H616) += pinctrl-sun50i-h616.o obj-$(CONFIG_PINCTRL_SUN50I_H616_R) += pinctrl-sun50i-h616-r.o obj-$(CONFIG_PINCTRL_SUN55I_A523) += pinctrl-sun55i-a523.o +obj-$(CONFIG_PINCTRL_SUN55I_A523_R) += pinctrl-sun55i-a523-r.o obj-$(CONFIG_PINCTRL_SUN9I_A80) += pinctrl-sun9i-a80.o obj-$(CONFIG_PINCTRL_SUN9I_A80_R) += pinctrl-sun9i-a80-r.o diff --git a/drivers/pinctrl/sunxi/pinctrl-sun55i-a523-r.c b/drivers/pinctrl/sunxi/pinctrl-sun55i-a523-r.c new file mode 100644 index 000000000000..69cd2b4ebd7d --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sun55i-a523-r.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Allwinner A523 SoC r-pinctrl driver. + * + * Copyright (C) 2024 Arm Ltd. + */ + +#include +#include +#include +#include +#include + +#include "pinctrl-sunxi.h" + +static const u8 a523_r_nr_bank_pins[SUNXI_PINCTRL_MAX_BANKS] = +/* PL PM */ + { 14, 6 }; + +static const unsigned int a523_r_irq_bank_map[] = { 0, 1 }; + +static const u8 a523_r_irq_bank_muxes[SUNXI_PINCTRL_MAX_BANKS] = +/* PL PM */ + { 14, 14 }; + +static struct sunxi_pinctrl_desc a523_r_pinctrl_data = { + .irq_banks = ARRAY_SIZE(a523_r_irq_bank_map), + .irq_bank_map = a523_r_irq_bank_map, + .irq_read_needs_mux = true, + .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_SEL, + .pin_base = PL_BASE, +}; + +static int a523_r_pinctrl_probe(struct platform_device *pdev) +{ + return sunxi_pinctrl_dt_table_init(pdev, a523_r_nr_bank_pins, + a523_r_irq_bank_muxes, + &a523_r_pinctrl_data, + SUNXI_PINCTRL_NEW_REG_LAYOUT); +} + +static const struct of_device_id a523_r_pinctrl_match[] = { + { .compatible = "allwinner,sun55i-a523-r-pinctrl", }, + {} +}; + +static struct platform_driver a523_r_pinctrl_driver = { + .probe = a523_r_pinctrl_probe, + .driver = { + .name = "sun55i-a523-r-pinctrl", + .of_match_table = a523_r_pinctrl_match, + }, +}; +builtin_platform_driver(a523_r_pinctrl_driver); -- cgit v1.2.3-59-g8ed1b From 4da56f9c6f1434236e52285157f93673443d586c Mon Sep 17 00:00:00 2001 From: Paul Boddie Date: Sat, 1 Mar 2025 11:00:39 +0100 Subject: pinctrl: ingenic: add x1600 support Add support for the Lumissil/Ingenic X1600 SoC. It uses shadow registers to commit changes to multiple pinctrl registers in parallel. Define specific Chip ID, register offsets, pin tables etc. Handling the unique X1600_GPIO_PU only for the x1600 but not for x1830 and above must be carefully taken into account. Reviewed-by: Paul Cercueil Co-authored-by: Andreas Kemnade Co-authored-by: H. Nikolaus Schaller Signed-off-by: Paul Boddie Signed-off-by: Andreas Kemnade Signed-off-by: H. Nikolaus Schaller Link: https://lore.kernel.org/84477ec9cb9ed13bf4f6f87d5fb3b55542d31097.1740823241.git.hns@goldelico.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-ingenic.c | 244 +++++++++++++++++++++++++++++++++++++- 1 file changed, 242 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c index bc7ee54e062b..8413cb8bd355 100644 --- a/drivers/pinctrl/pinctrl-ingenic.c +++ b/drivers/pinctrl/pinctrl-ingenic.c @@ -3,7 +3,7 @@ * Ingenic SoCs pinctrl driver * * Copyright (c) 2017 Paul Cercueil - * Copyright (c) 2017, 2019 Paul Boddie + * Copyright (c) 2017, 2019, 2020, 2023 Paul Boddie * Copyright (c) 2019, 2020 周琰杰 (Zhou Yanjie) */ @@ -58,6 +58,8 @@ #define JZ4770_GPIO_FLAG 0x50 #define JZ4770_GPIO_PEN 0x70 +#define X1600_GPIO_PU 0x80 + #define X1830_GPIO_PEL 0x110 #define X1830_GPIO_PEH 0x120 #define X1830_GPIO_SR 0x150 @@ -112,6 +114,7 @@ enum jz_version { ID_JZ4780, ID_X1000, ID_X1500, + ID_X1600, ID_X1830, ID_X2000, ID_X2100, @@ -162,6 +165,7 @@ static const unsigned long enabled_socs = IS_ENABLED(CONFIG_MACH_JZ4780) << ID_JZ4780 | IS_ENABLED(CONFIG_MACH_X1000) << ID_X1000 | IS_ENABLED(CONFIG_MACH_X1500) << ID_X1500 | + IS_ENABLED(CONFIG_MACH_X1600) << ID_X1600 | IS_ENABLED(CONFIG_MACH_X1830) << ID_X1830 | IS_ENABLED(CONFIG_MACH_X2000) << ID_X2000 | IS_ENABLED(CONFIG_MACH_X2100) << ID_X2100; @@ -2351,6 +2355,233 @@ static const struct ingenic_chip_info x1500_chip_info = { .access_table = &x1000_access_table, }; +static const u32 x1600_pull_ups[4] = { + 0xffffffff, 0xdffbf7bf, 0x987e0000, 0x0000003f, +}; + +static const u32 x1600_pull_downs[4] = { + 0x00000000, 0x00000000, 0x07000007, 0x00000000, +}; + +static int x1600_uart0_data_pins[] = { 0x27, 0x28, }; +static int x1600_uart0_hwflow_pins[] = { 0x29, 0x2a, }; +static int x1600_uart1_data_pins[] = { 0x23, 0x22, }; +static int x1600_uart1_hwflow_pins[] = { 0x25, 0x24, }; +static int x1600_uart2_data_a_pins[] = { 0x1f, 0x1e, }; +static int x1600_uart2_data_b_pins[] = { 0x21, 0x20, }; +static int x1600_uart3_data_b_pins[] = { 0x25, 0x24, }; +static int x1600_uart3_data_d_pins[] = { 0x65, 0x64, }; +static int x1600_sfc_pins[] = { 0x53, 0x54, 0x55, 0x56, 0x51, 0x52, 0x24, }; +static int x1600_ssi_dt_a_pins[] = { 0x1e, }; +static int x1600_ssi_dt_b_pins[] = { 0x2d, }; +static int x1600_ssi_dr_a_pins[] = { 0x1d, }; +static int x1600_ssi_dr_b_pins[] = { 0x2e, }; +static int x1600_ssi_clk_a_pins[] = { 0x1f, }; +static int x1600_ssi_clk_b_pins[] = { 0x2c, }; +static int x1600_ssi_ce0_a_pins[] = { 0x1c, }; +static int x1600_ssi_ce0_b_pins[] = { 0x31, }; +static int x1600_ssi_ce1_a_pins[] = { 0x22, }; +static int x1600_ssi_ce1_b_pins[] = { 0x30, }; +static int x1600_mmc0_1bit_b_pins[] = { 0x2c, 0x2d, 0x2e, }; +static int x1600_mmc0_4bit_b_pins[] = { 0x2f, 0x30, 0x31, }; +static int x1600_mmc0_1bit_c_pins[] = { 0x51, 0x53, 0x54, }; +static int x1600_mmc0_4bit_c_pins[] = { 0x56, 0x55, 0x52, }; +static int x1600_mmc1_1bit_pins[] = { 0x60, 0x61, 0x62, }; +static int x1600_mmc1_4bit_pins[] = { 0x63, 0x64, 0x65, }; +static int x1600_i2c0_a_pins[] = { 0x1d, 0x1c, }; +static int x1600_i2c0_b_pins[] = { 0x3f, 0x3e, }; +static int x1600_i2c1_b_15_pins[] = { 0x30, 0x2f, }; +static int x1600_i2c1_b_19_pins[] = { 0x34, 0x33, }; +static int x1600_i2s_data_tx_pins[] = { 0x39, }; +static int x1600_i2s_data_rx_pins[] = { 0x35, }; +static int x1600_i2s_clk_rx_pins[] = { 0x37, 0x38, }; +static int x1600_i2s_clk_tx_pins[] = { 0x3b, 0x3c, }; +static int x1600_i2s_sysclk_pins[] = { 0x36, 0x3a, }; + +static int x1600_cim_pins[] = { + 0x14, 0x16, 0x15, 0x18, 0x13, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, +}; + +static int x1600_slcd_8bit_pins[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x17, 0x19, 0x1a, 0x1b, +}; + +static int x1600_slcd_16bit_pins[] = { + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, +}; + +static int x1600_lcd_16bit_pins[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x18, 0x19, 0x1a, 0x1b, +}; + +static int x1600_lcd_18bit_pins[] = { + 0x10, 0x11, +}; + +static int x1600_lcd_24bit_pins[] = { + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, +}; + +static int x1600_pwm_pwm0_pins[] = { 0x40, }; +static int x1600_pwm_pwm1_pins[] = { 0x41, }; +static int x1600_pwm_pwm2_pins[] = { 0x42, }; +static int x1600_pwm_pwm3_pins[] = { 0x58, }; +static int x1600_pwm_pwm4_pins[] = { 0x59, }; +static int x1600_pwm_pwm5_b_pins[] = { 0x33, }; +static int x1600_pwm_pwm5_c_pins[] = { 0x5a, }; +static int x1600_pwm_pwm6_b9_pins[] = { 0x29, }; +static int x1600_pwm_pwm6_b20_pins[] = { 0x34, }; +static int x1600_pwm_pwm7_b10_pins[] = { 0x2a, }; +static int x1600_pwm_pwm7_b21_pins[] = { 0x35, }; + +static int x1600_mac_pins[] = { + 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, +}; + +static int x1600_sfc_funcs[] = { 0, 0, 0, 0, 0, 0, 2, }; + +static const struct group_desc x1600_groups[] = { + INGENIC_PIN_GROUP("uart0-data", x1600_uart0_data, 0), + INGENIC_PIN_GROUP("uart0-hwflow", x1600_uart0_hwflow, 0), + INGENIC_PIN_GROUP("uart1-data", x1600_uart1_data, 1), + INGENIC_PIN_GROUP("uart1-hwflow", x1600_uart1_hwflow, 1), + INGENIC_PIN_GROUP("uart2-data-a", x1600_uart2_data_a, 2), + INGENIC_PIN_GROUP("uart2-data-b", x1600_uart2_data_b, 1), + INGENIC_PIN_GROUP("uart3-data-b", x1600_uart3_data_b, 0), + INGENIC_PIN_GROUP("uart3-data-d", x1600_uart3_data_d, 2), + INGENIC_PIN_GROUP_FUNCS("sfc", x1600_sfc, x1600_sfc_funcs), + INGENIC_PIN_GROUP("ssi-dt-a", x1600_ssi_dt_a, 0), + INGENIC_PIN_GROUP("ssi-dt-b", x1600_ssi_dt_b, 1), + INGENIC_PIN_GROUP("ssi-dr-a", x1600_ssi_dr_a, 0), + INGENIC_PIN_GROUP("ssi-dr-b", x1600_ssi_dr_b, 1), + INGENIC_PIN_GROUP("ssi-clk-a", x1600_ssi_clk_a, 0), + INGENIC_PIN_GROUP("ssi-clk-b", x1600_ssi_clk_b, 1), + INGENIC_PIN_GROUP("ssi-ce0-a", x1600_ssi_ce0_a, 0), + INGENIC_PIN_GROUP("ssi-ce0-b", x1600_ssi_ce0_b, 1), + INGENIC_PIN_GROUP("ssi-ce1-a", x1600_ssi_ce1_a, 2), + INGENIC_PIN_GROUP("ssi-ce1-b", x1600_ssi_ce1_b, 1), + INGENIC_PIN_GROUP("mmc0-1bit-b", x1600_mmc0_1bit_b, 0), + INGENIC_PIN_GROUP("mmc0-4bit-b", x1600_mmc0_4bit_b, 0), + INGENIC_PIN_GROUP("mmc0-1bit-c", x1600_mmc0_1bit_c, 1), + INGENIC_PIN_GROUP("mmc0-4bit-c", x1600_mmc0_4bit_c, 1), + INGENIC_PIN_GROUP("mmc1-1bit", x1600_mmc1_1bit, 0), + INGENIC_PIN_GROUP("mmc1-4bit", x1600_mmc1_4bit, 0), + INGENIC_PIN_GROUP("i2c0-data-a", x1600_i2c0_a, 2), + INGENIC_PIN_GROUP("i2c0-data-b", x1600_i2c0_b, 0), + INGENIC_PIN_GROUP("i2c1-data-b-15", x1600_i2c1_b_15, 2), + INGENIC_PIN_GROUP("i2c1-data-b-19", x1600_i2c1_b_19, 0), + INGENIC_PIN_GROUP("i2s-data-tx", x1600_i2s_data_tx, 0), + INGENIC_PIN_GROUP("i2s-data-rx", x1600_i2s_data_rx, 0), + INGENIC_PIN_GROUP("i2s-clk-rx", x1600_i2s_clk_rx, 0), + INGENIC_PIN_GROUP("i2s-clk-tx", x1600_i2s_clk_tx, 0), + INGENIC_PIN_GROUP("i2s-sysclk", x1600_i2s_sysclk, 0), + INGENIC_PIN_GROUP("cim-data", x1600_cim, 2), + INGENIC_PIN_GROUP("slcd-8bit", x1600_slcd_8bit, 1), + INGENIC_PIN_GROUP("slcd-16bit", x1600_slcd_16bit, 1), + INGENIC_PIN_GROUP("lcd-16bit", x1600_lcd_16bit, 0), + INGENIC_PIN_GROUP("lcd-18bit", x1600_lcd_18bit, 0), + INGENIC_PIN_GROUP("lcd-24bit", x1600_lcd_24bit, 0), + INGENIC_PIN_GROUP("pwm0", x1600_pwm_pwm0, 0), + INGENIC_PIN_GROUP("pwm1", x1600_pwm_pwm1, 0), + INGENIC_PIN_GROUP("pwm2", x1600_pwm_pwm2, 0), + INGENIC_PIN_GROUP("pwm3", x1600_pwm_pwm3, 1), + INGENIC_PIN_GROUP("pwm4", x1600_pwm_pwm4, 1), + INGENIC_PIN_GROUP("pwm5-b", x1600_pwm_pwm5_b, 2), + INGENIC_PIN_GROUP("pwm5-c", x1600_pwm_pwm5_c, 1), + INGENIC_PIN_GROUP("pwm6-b9", x1600_pwm_pwm6_b9, 1), + INGENIC_PIN_GROUP("pwm6-b20", x1600_pwm_pwm6_b20, 2), + INGENIC_PIN_GROUP("pwm7-b10", x1600_pwm_pwm7_b10, 1), + INGENIC_PIN_GROUP("pwm7-b21", x1600_pwm_pwm7_b21, 2), + INGENIC_PIN_GROUP("mac", x1600_mac, 1), +}; + +static const char * const x1600_uart0_groups[] = { "uart0-data", "uart0-hwflow", }; +static const char * const x1600_uart1_groups[] = { "uart1-data", "uart1-hwflow", }; +static const char * const x1600_uart2_groups[] = { "uart2-data-a", "uart2-data-b", }; +static const char * const x1600_uart3_groups[] = { "uart3-data-b", "uart3-data-d", }; + +static const char * const x1600_sfc_groups[] = { "sfc", }; + +static const char * const x1600_ssi_groups[] = { + "ssi-dt-a", "ssi-dt-b", + "ssi-dr-a", "ssi-dr-b", + "ssi-clk-a", "ssi-clk-b", + "ssi-ce0-a", "ssi-ce0-b", + "ssi-ce1-a", "ssi-ce1-b", +}; + +static const char * const x1600_mmc0_groups[] = { "mmc0-1bit-b", "mmc0-4bit-b", + "mmc0-1bit-c", "mmc0-4bit-c", +}; + +static const char * const x1600_mmc1_groups[] = { "mmc1-1bit", "mmc1-4bit", }; + +static const char * const x1600_i2c0_groups[] = { "i2c0-data-a", "i2c0-data-b", }; +static const char * const x1600_i2c1_groups[] = { "i2c1-data-b-15", "i2c1-data-b-19", }; + +static const char * const x1600_i2s_groups[] = { + "i2s-data-tx", "i2s-data-rx", "i2s-clk-rx", "i2s-clk-tx", "i2s-sysclk", +}; + +static const char * const x1600_cim_groups[] = { "cim-data", }; + +static const char * const x1600_lcd_groups[] = { "slcd-8bit", "slcd-16bit", + "lcd-16bit", "lcd-18bit", "lcd-24bit", "lcd-no-pins", +}; + +static const char * const x1600_pwm0_groups[] = { "pwm0", }; +static const char * const x1600_pwm1_groups[] = { "pwm1", }; +static const char * const x1600_pwm2_groups[] = { "pwm2", }; +static const char * const x1600_pwm3_groups[] = { "pwm3", }; +static const char * const x1600_pwm4_groups[] = { "pwm4", }; +static const char * const x1600_pwm5_groups[] = { "pwm5-b", "pwm5-c", }; +static const char * const x1600_pwm6_groups[] = { "pwm6-b9", "pwm6-b20", }; +static const char * const x1600_pwm7_groups[] = { "pwm7-b10", "pwm7-b21", }; + +static const char * const x1600_mac_groups[] = { "mac", }; + +static const struct function_desc x1600_functions[] = { + INGENIC_PIN_FUNCTION("uart0", x1600_uart0), + INGENIC_PIN_FUNCTION("uart1", x1600_uart1), + INGENIC_PIN_FUNCTION("uart2", x1600_uart2), + INGENIC_PIN_FUNCTION("uart3", x1600_uart3), + INGENIC_PIN_FUNCTION("sfc", x1600_sfc), + INGENIC_PIN_FUNCTION("ssi", x1600_ssi), + INGENIC_PIN_FUNCTION("mmc0", x1600_mmc0), + INGENIC_PIN_FUNCTION("mmc1", x1600_mmc1), + INGENIC_PIN_FUNCTION("i2c0", x1600_i2c0), + INGENIC_PIN_FUNCTION("i2c1", x1600_i2c1), + INGENIC_PIN_FUNCTION("i2s", x1600_i2s), + INGENIC_PIN_FUNCTION("cim", x1600_cim), + INGENIC_PIN_FUNCTION("lcd", x1600_lcd), + INGENIC_PIN_FUNCTION("pwm0", x1600_pwm0), + INGENIC_PIN_FUNCTION("pwm1", x1600_pwm1), + INGENIC_PIN_FUNCTION("pwm2", x1600_pwm2), + INGENIC_PIN_FUNCTION("pwm3", x1600_pwm3), + INGENIC_PIN_FUNCTION("pwm4", x1600_pwm4), + INGENIC_PIN_FUNCTION("pwm5", x1600_pwm5), + INGENIC_PIN_FUNCTION("pwm6", x1600_pwm6), + INGENIC_PIN_FUNCTION("pwm7", x1600_pwm7), + INGENIC_PIN_FUNCTION("mac", x1600_mac), +}; + +static const struct ingenic_chip_info x1600_chip_info = { + .num_chips = 4, + .reg_offset = 0x100, + .version = ID_X1600, + .groups = x1600_groups, + .num_groups = ARRAY_SIZE(x1600_groups), + .functions = x1600_functions, + .num_functions = ARRAY_SIZE(x1600_functions), + .pull_ups = x1600_pull_ups, + .pull_downs = x1600_pull_downs, + .access_table = &x1000_access_table, +}; + static const u32 x1830_pull_ups[4] = { 0x5fdfffc0, 0xffffefff, 0x1ffffbff, 0x0fcff3fc, }; @@ -3860,7 +4091,9 @@ static int ingenic_pinconf_get(struct pinctrl_dev *pctldev, pulldown = (bias == GPIO_PULL_DOWN) && (jzpc->info->pull_downs[offt] & BIT(idx)); } else { - if (is_soc_or_above(jzpc, ID_JZ4770)) + if (is_soc_or_above(jzpc, ID_X1600)) + pull = ingenic_get_pin_config(jzpc, pin, X1600_GPIO_PU); + else if (is_soc_or_above(jzpc, ID_JZ4770)) pull = !ingenic_get_pin_config(jzpc, pin, JZ4770_GPIO_PEN); else if (is_soc_or_above(jzpc, ID_JZ4740)) pull = !ingenic_get_pin_config(jzpc, pin, JZ4740_GPIO_PULL_DIS); @@ -3959,6 +4192,8 @@ static void ingenic_set_bias(struct ingenic_pinctrl *jzpc, REG_SET(X1830_GPIO_PEH), bias << idxh); } + } else if (is_soc_or_above(jzpc, ID_X1600)) { + ingenic_config_pin(jzpc, pin, X1600_GPIO_PU, bias); } else if (is_soc_or_above(jzpc, ID_JZ4770)) { ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PEN, !bias); } else if (is_soc_or_above(jzpc, ID_JZ4740)) { @@ -4150,6 +4385,7 @@ static const struct of_device_id ingenic_gpio_of_matches[] __initconst = { { .compatible = "ingenic,jz4775-gpio" }, { .compatible = "ingenic,jz4780-gpio" }, { .compatible = "ingenic,x1000-gpio" }, + { .compatible = "ingenic,x1600-gpio" }, { .compatible = "ingenic,x1830-gpio" }, { .compatible = "ingenic,x2000-gpio" }, { .compatible = "ingenic,x2100-gpio" }, @@ -4397,6 +4633,10 @@ static const struct of_device_id ingenic_pinctrl_of_matches[] = { .compatible = "ingenic,x1500-pinctrl", .data = IF_ENABLED(CONFIG_MACH_X1500, &x1500_chip_info) }, + { + .compatible = "ingenic,x1600-pinctrl", + .data = IF_ENABLED(CONFIG_MACH_X1600, &x1600_chip_info) + }, { .compatible = "ingenic,x1830-pinctrl", .data = IF_ENABLED(CONFIG_MACH_X1830, &x1830_chip_info) -- cgit v1.2.3-59-g8ed1b From 4b490ccbc3d3cba6069b213587fef7bcfec81faa Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Sat, 1 Mar 2025 11:00:40 +0100 Subject: pinctrl: ingenic: jz4730: add pinmux for MII The MII interface is used for the Ethernet connection of the Alpha400. Reviewed-by: Paul Cercueil Signed-off-by: H. Nikolaus Schaller Link: https://lore.kernel.org/972b31e1fce03808745e53df17315b29e2bcf696.1740823241.git.hns@goldelico.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-ingenic.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c index 8413cb8bd355..08e082e84f5c 100644 --- a/drivers/pinctrl/pinctrl-ingenic.c +++ b/drivers/pinctrl/pinctrl-ingenic.c @@ -210,6 +210,9 @@ static int jz4730_nand_cs5_pins[] = { 0x57, }; static int jz4730_pwm_pwm0_pins[] = { 0x5e, }; static int jz4730_pwm_pwm1_pins[] = { 0x5f, }; +static int jz4730_mii_pins[] = { 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, + 0x77, 0x78, 0x19, 0x7a, 0x1b, 0x7c, }; + static u8 jz4730_lcd_8bit_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, }; static const struct group_desc jz4730_groups[] = { @@ -231,6 +234,7 @@ static const struct group_desc jz4730_groups[] = { INGENIC_PIN_GROUP("nand-cs5", jz4730_nand_cs5, 1), INGENIC_PIN_GROUP("pwm0", jz4730_pwm_pwm0, 1), INGENIC_PIN_GROUP("pwm1", jz4730_pwm_pwm1, 1), + INGENIC_PIN_GROUP("mii", jz4730_mii, 1), }; static const char *jz4730_mmc_groups[] = { "mmc-1bit", "mmc-4bit", }; @@ -246,6 +250,7 @@ static const char *jz4730_nand_groups[] = { }; static const char *jz4730_pwm0_groups[] = { "pwm0", }; static const char *jz4730_pwm1_groups[] = { "pwm1", }; +static const char *jz4730_mii_groups[] = { "mii", }; static const struct function_desc jz4730_functions[] = { INGENIC_PIN_FUNCTION("mmc", jz4730_mmc), @@ -257,6 +262,7 @@ static const struct function_desc jz4730_functions[] = { INGENIC_PIN_FUNCTION("nand", jz4730_nand), INGENIC_PIN_FUNCTION("pwm0", jz4730_pwm0), INGENIC_PIN_FUNCTION("pwm1", jz4730_pwm1), + INGENIC_PIN_FUNCTION("mii", jz4730_mii), }; static const struct ingenic_chip_info jz4730_chip_info = { -- cgit v1.2.3-59-g8ed1b From 8171e7b929890e51d475148255cc4707ff8b205a Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Sat, 1 Mar 2025 11:00:41 +0100 Subject: pinctrl: ingenic: jz4730: add pinmux for I2S interface I2S is used for the sound codec of the Alpha400. Reviewed-by: Paul Cercueil Signed-off-by: H. Nikolaus Schaller Link: https://lore.kernel.org/7e79b16be569fb0f501032b2b6ec726e4a09411f.1740823241.git.hns@goldelico.com Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-ingenic.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c index 08e082e84f5c..a9e48eac15f6 100644 --- a/drivers/pinctrl/pinctrl-ingenic.c +++ b/drivers/pinctrl/pinctrl-ingenic.c @@ -213,6 +213,11 @@ static int jz4730_pwm_pwm1_pins[] = { 0x5f, }; static int jz4730_mii_pins[] = { 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x19, 0x7a, 0x1b, 0x7c, }; +static int jz4730_i2s_mclk_pins[] = { 0x44, }; +static int jz4730_i2s_acreset_pins[] = { 0x45, }; +static int jz4730_i2s_data_pins[] = { 0x46, 0x47, }; +static int jz4730_i2s_clock_pins[] = { 0x4d, 0x4e, }; + static u8 jz4730_lcd_8bit_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, }; static const struct group_desc jz4730_groups[] = { @@ -235,6 +240,11 @@ static const struct group_desc jz4730_groups[] = { INGENIC_PIN_GROUP("pwm0", jz4730_pwm_pwm0, 1), INGENIC_PIN_GROUP("pwm1", jz4730_pwm_pwm1, 1), INGENIC_PIN_GROUP("mii", jz4730_mii, 1), + INGENIC_PIN_GROUP("i2s-mclk-out", jz4730_i2s_mclk, 1), + INGENIC_PIN_GROUP("i2s-acreset", jz4730_i2s_acreset, 1), + INGENIC_PIN_GROUP("i2s-data", jz4730_i2s_data, 1), + INGENIC_PIN_GROUP("i2s-master", jz4730_i2s_clock, 1), + INGENIC_PIN_GROUP("i2s-slave", jz4730_i2s_clock, 2), }; static const char *jz4730_mmc_groups[] = { "mmc-1bit", "mmc-4bit", }; @@ -251,6 +261,7 @@ static const char *jz4730_nand_groups[] = { static const char *jz4730_pwm0_groups[] = { "pwm0", }; static const char *jz4730_pwm1_groups[] = { "pwm1", }; static const char *jz4730_mii_groups[] = { "mii", }; +static const char *jz4730_i2s_groups[] = { "i2s-data", "i2s-master", "i2s-slave", }; static const struct function_desc jz4730_functions[] = { INGENIC_PIN_FUNCTION("mmc", jz4730_mmc), @@ -263,6 +274,7 @@ static const struct function_desc jz4730_functions[] = { INGENIC_PIN_FUNCTION("pwm0", jz4730_pwm0), INGENIC_PIN_FUNCTION("pwm1", jz4730_pwm1), INGENIC_PIN_FUNCTION("mii", jz4730_mii), + INGENIC_PIN_FUNCTION("i2s", jz4730_i2s), }; static const struct ingenic_chip_info jz4730_chip_info = { -- cgit v1.2.3-59-g8ed1b From 597b3627d532e81436aa5d8ca4d78f42e5be3284 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 5 Mar 2025 11:27:10 +0100 Subject: pinctrl: spacemit: destroy mutex at driver detach The mutex initialized in probe() is never cleaned up. Use devm_mutex_init() to destroy it automatically. Signed-off-by: Bartosz Golaszewski Reviewed-by: Javier Martinez Canillas Reviewed-by: Yixun Lan Link: https://lore.kernel.org/20250305102710.52762-1-brgl@bgdev.pl Signed-off-by: Linus Walleij --- drivers/pinctrl/spacemit/pinctrl-k1.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/spacemit/pinctrl-k1.c b/drivers/pinctrl/spacemit/pinctrl-k1.c index a32579d73613..3e1c194e7961 100644 --- a/drivers/pinctrl/spacemit/pinctrl-k1.c +++ b/drivers/pinctrl/spacemit/pinctrl-k1.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -749,7 +750,10 @@ static int spacemit_pinctrl_probe(struct platform_device *pdev) pctrl->data = pctrl_data; pctrl->dev = dev; raw_spin_lock_init(&pctrl->lock); - mutex_init(&pctrl->mutex); + + ret = devm_mutex_init(dev, &pctrl->mutex); + if (ret) + return ret; platform_set_drvdata(pdev, pctrl); -- cgit v1.2.3-59-g8ed1b From 4fd41e74bd6ad87085001b0f3e2883422fab499a Mon Sep 17 00:00:00 2001 From: Prathamesh Shete Date: Wed, 5 Mar 2025 16:19:38 +0530 Subject: pinctrl: tegra: Add descriptions for SoC data fields Add detailed descriptions for the remaining fields in the tegra_pinctrl_soc_data structure. This improves code documentation and clarifies the purpose of each field, particularly for the pin-specific configuration options. Signed-off-by: Prathamesh Shete Link: https://lore.kernel.org/20250305104939.15168-1-pshete@nvidia.com Signed-off-by: Linus Walleij --- drivers/pinctrl/tegra/pinctrl-tegra.h | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h index 216cc59b62b4..be9268ddb83d 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra.h +++ b/drivers/pinctrl/tegra/pinctrl-tegra.h @@ -178,16 +178,22 @@ struct tegra_pingroup { /** * struct tegra_pinctrl_soc_data - Tegra pin controller driver configuration - * @ngpios: The number of GPIO pins the pin controller HW affects. - * @pins: An array describing all pins the pin controller affects. - * All pins which are also GPIOs must be listed first within the - * array, and be numbered identically to the GPIO controller's - * numbering. - * @npins: The numbmer of entries in @pins. - * @functions: An array describing all mux functions the SoC supports. - * @nfunctions: The numbmer of entries in @functions. - * @groups: An array describing all pin groups the pin SoC supports. - * @ngroups: The numbmer of entries in @groups. + * @ngpios: The number of GPIO pins the pin controller HW affects. + * @gpio_compatible: Device-tree GPIO compatible string. + * @pins: An array describing all pins the pin controller affects. + * All pins which are also GPIOs must be listed first within the + * array, and be numbered identically to the GPIO controller's + * numbering. + * @npins: The number of entries in @pins. + * @functions: An array describing all mux functions the SoC supports. + * @nfunctions: The number of entries in @functions. + * @groups: An array describing all pin groups the pin SoC supports. + * @ngroups: The number of entries in @groups. + * @hsm_in_mux: High-speed mode field. Only applicable to devices with one pin per group. + * @schmitt_in_mux: Schmitt trigger field. Only applicable to devices with one pin per group. + * @drvtype_in_mux: Drivetype field. Only applicable to devices with one pin per group. + * @sfsel_in_mux: Special function selection field. + * Only applicable to devices with one pin per group. */ struct tegra_pinctrl_soc_data { unsigned ngpios; -- cgit v1.2.3-59-g8ed1b From c12bfa0fee65940b10ff5187349f76c6f6b1df9c Mon Sep 17 00:00:00 2001 From: Prathamesh Shete Date: Wed, 5 Mar 2025 16:19:39 +0530 Subject: pinctrl-tegra: Restore SFSEL bit when freeing pins Each pin can be configured as a Special Function IO (SFIO) or GPIO, where the SFIO enables the pin to operate in alternative modes such as I2C, SPI, etc. The current implementation sets all the pins back to SFIO mode even if they were initially in GPIO mode. This can cause glitches on the pins when pinctrl_gpio_free() is called. Avoid these undesired glitches by storing the pin's SFIO/GPIO state on GPIO request and restoring it on GPIO free. Signed-off-by: Prathamesh Shete Link: https://lore.kernel.org/20250305104939.15168-2-pshete@nvidia.com Signed-off-by: Linus Walleij --- drivers/pinctrl/tegra/pinctrl-tegra.c | 59 ++++++++++++++++++++++++++++++----- drivers/pinctrl/tegra/pinctrl-tegra.h | 6 ++++ 2 files changed, 57 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c index 314309c797d7..23c19b6969d1 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c @@ -276,8 +276,8 @@ static int tegra_pinctrl_set_mux(struct pinctrl_dev *pctldev, return 0; } -static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *pctldev, - unsigned int offset) +static int tegra_pinctrl_get_group_index(struct pinctrl_dev *pctldev, + unsigned int offset) { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); unsigned int group, num_pins, j; @@ -290,12 +290,35 @@ static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev * continue; for (j = 0; j < num_pins; j++) { if (offset == pins[j]) - return &pmx->soc->groups[group]; + return group; } } - dev_err(pctldev->dev, "Pingroup not found for pin %u\n", offset); - return NULL; + return -EINVAL; +} + +static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *pctldev, + unsigned int offset, + int group_index) +{ + struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + + if (group_index < 0 || group_index > pmx->soc->ngroups) + return NULL; + + return &pmx->soc->groups[group_index]; +} + +static struct tegra_pingroup_config *tegra_pinctrl_get_group_config(struct pinctrl_dev *pctldev, + unsigned int offset, + int group_index) +{ + struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + + if (group_index < 0) + return NULL; + + return &pmx->pingroup_configs[group_index]; } static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, @@ -304,12 +327,15 @@ static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); const struct tegra_pingroup *group; + struct tegra_pingroup_config *config; + int group_index; u32 value; if (!pmx->soc->sfsel_in_mux) return 0; - group = tegra_pinctrl_get_group(pctldev, offset); + group_index = tegra_pinctrl_get_group_index(pctldev, offset); + group = tegra_pinctrl_get_group(pctldev, offset, group_index); if (!group) return -EINVAL; @@ -317,7 +343,11 @@ static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, if (group->mux_reg < 0 || group->sfsel_bit < 0) return -EINVAL; + config = tegra_pinctrl_get_group_config(pctldev, offset, group_index); + if (!config) + return -EINVAL; value = pmx_readl(pmx, group->mux_bank, group->mux_reg); + config->is_sfsel = (value & BIT(group->sfsel_bit)) != 0; value &= ~BIT(group->sfsel_bit); pmx_writel(pmx, value, group->mux_bank, group->mux_reg); @@ -330,12 +360,15 @@ static void tegra_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev, { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); const struct tegra_pingroup *group; + struct tegra_pingroup_config *config; + int group_index; u32 value; if (!pmx->soc->sfsel_in_mux) return; - group = tegra_pinctrl_get_group(pctldev, offset); + group_index = tegra_pinctrl_get_group_index(pctldev, offset); + group = tegra_pinctrl_get_group(pctldev, offset, group_index); if (!group) return; @@ -343,8 +376,12 @@ static void tegra_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev, if (group->mux_reg < 0 || group->sfsel_bit < 0) return; + config = tegra_pinctrl_get_group_config(pctldev, offset, group_index); + if (!config) + return; value = pmx_readl(pmx, group->mux_bank, group->mux_reg); - value |= BIT(group->sfsel_bit); + if (config->is_sfsel) + value |= BIT(group->sfsel_bit); pmx_writel(pmx, value, group->mux_bank, group->mux_reg); } @@ -799,6 +836,12 @@ int tegra_pinctrl_probe(struct platform_device *pdev, pmx->dev = &pdev->dev; pmx->soc = soc_data; + pmx->pingroup_configs = devm_kcalloc(&pdev->dev, + pmx->soc->ngroups, sizeof(*pmx->pingroup_configs), + GFP_KERNEL); + if (!pmx->pingroup_configs) + return -ENOMEM; + /* * Each mux group will appear in 4 functions' list of groups. * This over-allocates slightly, since not all groups are mux groups. diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h index be9268ddb83d..bc7b70913b89 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra.h +++ b/drivers/pinctrl/tegra/pinctrl-tegra.h @@ -8,6 +8,10 @@ #ifndef __PINMUX_TEGRA_H__ #define __PINMUX_TEGRA_H__ +struct tegra_pingroup_config { + bool is_sfsel; +}; + struct tegra_pmx { struct device *dev; struct pinctrl_dev *pctl; @@ -21,6 +25,8 @@ struct tegra_pmx { int nbanks; void __iomem **regs; u32 *backup_regs; + /* Array of size soc->ngroups */ + struct tegra_pingroup_config *pingroup_configs; }; enum tegra_pinconf_param { -- cgit v1.2.3-59-g8ed1b From 17013f0acb322e5052ff9b9d0fab0ab5a4bfd828 Mon Sep 17 00:00:00 2001 From: Prathamesh Shete Date: Thu, 6 Mar 2025 10:35:42 +0530 Subject: pinctrl: tegra: Set SFIO mode to Mux Register Tegra devices have an 'sfsel' bit field that determines whether a pin operates in SFIO (Special Function I/O) or GPIO mode. Currently, tegra_pinctrl_gpio_disable_free() sets this bit when releasing a GPIO. However, tegra_pinctrl_set_mux() can be called independently in certain code paths where gpio_disable_free() is not invoked. In such cases, failing to set the SFIO mode could lead to incorrect pin configurations, resulting in functional issues for peripherals relying on SFIO. This patch ensures that whenever set_mux() is called, the SFIO mode is correctly set in the Mux Register if the 'sfsel' bit is present. This prevents situations where the pin remains in GPIO mode despite being configured for SFIO use. Fixes: 971dac7123c7 ("pinctrl: add a driver for NVIDIA Tegra") Signed-off-by: Prathamesh Shete Link: https://lore.kernel.org/20250306050542.16335-1-pshete@nvidia.com Signed-off-by: Linus Walleij --- drivers/pinctrl/tegra/pinctrl-tegra.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c index 23c19b6969d1..0246acba7703 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c @@ -271,6 +271,9 @@ static int tegra_pinctrl_set_mux(struct pinctrl_dev *pctldev, val = pmx_readl(pmx, g->mux_bank, g->mux_reg); val &= ~(0x3 << g->mux_bit); val |= i << g->mux_bit; + /* Set the SFIO/GPIO selection to SFIO when under pinmux control*/ + if (pmx->soc->sfsel_in_mux) + val |= (1 << g->sfsel_bit); pmx_writel(pmx, val, g->mux_bank, g->mux_reg); return 0; -- cgit v1.2.3-59-g8ed1b From 465cf6767198817870c8da5659d4d309847ea954 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 10 Mar 2025 13:52:05 +0300 Subject: pinctrl: amd: isp411: Fix IS_ERR() vs NULL check in probe() The platform_get_resource() returns NULL on error. It doesn't return error pointers. Fix the error checking to match. Fixes: e97435ab09f3 ("pinctrl: amd: isp411: Add amdisp GPIO pinctrl") Signed-off-by: Dan Carpenter Reviewed-by: Pratap Nirujogi Link: https://lore.kernel.org/617f4c77-7837-4e24-9f4d-620ecfedf924@stanley.mountain Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-amdisp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-amdisp.c b/drivers/pinctrl/pinctrl-amdisp.c index ce21ed84b929..9256ed67bb20 100644 --- a/drivers/pinctrl/pinctrl-amdisp.c +++ b/drivers/pinctrl/pinctrl-amdisp.c @@ -183,8 +183,8 @@ static int amdisp_pinctrl_probe(struct platform_device *pdev) pdev->dev.init_name = DRV_NAME; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (IS_ERR(res)) - return PTR_ERR(res); + if (!res) + return -EINVAL; pctrl->gpiobase = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(pctrl->gpiobase)) -- cgit v1.2.3-59-g8ed1b From 774e3447162735e3a5ba6ada724c3174dd44f496 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 10 Mar 2025 13:48:34 +0300 Subject: pinctrl: bcm281xx: Add missing assignment in bcm21664_pinctrl_lock_all() The next line checks if this regmap_write() failed, but it doesn't work because the assignment was accidentally left out. Add the assignment. Fixes: 60d69769c851 ("pinctrl: bcm281xx: Add support for BCM21664 pinmux") Signed-off-by: Dan Carpenter Acked-by: Artur Weber Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/dfc15d59-7fa9-4f96-aacb-37c3df6d420d@stanley.mountain Signed-off-by: Linus Walleij --- drivers/pinctrl/bcm/pinctrl-bcm281xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c index 7c8f8bd7da12..9ea20fde3a24 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c @@ -1498,8 +1498,8 @@ static int bcm21664_pinctrl_lock_all(struct bcm281xx_pinctrl_data *pdata) rc); return rc; } - regmap_write(pdata->regmap, BCM21664_ACCESS_LOCK_OFFSET(i), - 0xffffffff); + rc = regmap_write(pdata->regmap, BCM21664_ACCESS_LOCK_OFFSET(i), + 0xffffffff); if (rc) { dev_err(pdata->dev, "Failed to write access lock: %d\n", rc); -- cgit v1.2.3-59-g8ed1b From e225128c3f8be879e7d4eb71a25949e188b420ae Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 12 Mar 2025 14:19:27 +0100 Subject: pinctrl: qcom: Clear latched interrupt status when changing IRQ type When submitting the TLMM test driver, Bjorn reported that some of the test cases are failing for GPIOs that not are backed by PDC (i.e. "non-wakeup" GPIOs that are handled directly in pinctrl-msm). Basically, lingering latched interrupt state is still being delivered at IRQ request time, e.g.: ok 1 tlmm_test_silent_rising tlmm_test_silent_falling: ASSERTION FAILED at drivers/pinctrl/qcom/tlmm-test.c:178 Expected atomic_read(&priv->intr_count) == 0, but atomic_read(&priv->intr_count) == 1 (0x1) not ok 2 tlmm_test_silent_falling tlmm_test_silent_low: ASSERTION FAILED at drivers/pinctrl/qcom/tlmm-test.c:178 Expected atomic_read(&priv->intr_count) == 0, but atomic_read(&priv->intr_count) == 1 (0x1) not ok 3 tlmm_test_silent_low ok 4 tlmm_test_silent_high Whether to report interrupts that came in while the IRQ was unclaimed doesn't seem to be well-defined in the Linux IRQ API. However, looking closer at these specific cases, we're actually reporting events that do not match the interrupt type requested by the driver: 1. After "ok 1 tlmm_test_silent_rising", the GPIO is in low state and configured for IRQF_TRIGGER_RISING. 2. (a) In preparation for "tlmm_test_silent_falling", the GPIO is switched to high state. The rising interrupt gets latched. (b) The GPIO is re-configured for IRQF_TRIGGER_FALLING, but the latched interrupt isn't cleared. (c) The IRQ handler is called for the latched interrupt, but there wasn't any falling edge. 3. (a) For "tlmm_test_silent_low", the GPIO remains in high state. (b) The GPIO is re-configured for IRQF_TRIGGER_LOW. This seems to result in a phantom interrupt that gets latched. (c) The IRQ handler is called for the latched interrupt, but the GPIO isn't in low state. 4. (a) For "tlmm_test_silent_high", the GPIO is switched to low state. (b) This doesn't result in a latched interrupt, because RAW_STATUS_EN was cleared when masking the level-triggered interrupt. Fix this by clearing the interrupt state whenever making any changes to the interrupt configuration. This includes previously disabled interrupts, but also any changes to interrupt polarity or detection type. With this change, all 16 test cases are now passing for the non-wakeup GPIOs in the TLMM. Cc: stable@vger.kernel.org Fixes: cf9d052aa600 ("pinctrl: qcom: Don't clear pending interrupts when enabling") Reported-by: Bjorn Andersson Closes: https://lore.kernel.org/r/20250227-tlmm-test-v1-1-d18877b4a5db@oss.qualcomm.com/ Signed-off-by: Stephan Gerhold Tested-by: Bjorn Andersson Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/20250312-pinctrl-msm-type-latch-v1-1-ce87c561d3d7@linaro.org Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/pinctrl-msm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 47daa47153c9..82f0cc43bbf4 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -1045,8 +1045,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) const struct msm_pingroup *g; u32 intr_target_mask = GENMASK(2, 0); unsigned long flags; - bool was_enabled; - u32 val; + u32 val, oldval; if (msm_gpio_needs_dual_edge_parent_workaround(d, type)) { set_bit(d->hwirq, pctrl->dual_edge_irqs); @@ -1108,8 +1107,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) * internal circuitry of TLMM, toggling the RAW_STATUS * could cause the INTR_STATUS to be set for EDGE interrupts. */ - val = msm_readl_intr_cfg(pctrl, g); - was_enabled = val & BIT(g->intr_raw_status_bit); + val = oldval = msm_readl_intr_cfg(pctrl, g); val |= BIT(g->intr_raw_status_bit); if (g->intr_detection_width == 2) { val &= ~(3 << g->intr_detection_bit); @@ -1162,9 +1160,11 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) /* * The first time we set RAW_STATUS_EN it could trigger an interrupt. * Clear the interrupt. This is safe because we have - * IRQCHIP_SET_TYPE_MASKED. + * IRQCHIP_SET_TYPE_MASKED. When changing the interrupt type, we could + * also still have a non-matching interrupt latched, so clear whenever + * making changes to the interrupt configuration. */ - if (!was_enabled) + if (val != oldval) msm_ack_intr_status(pctrl, g); if (test_bit(d->hwirq, pctrl->dual_edge_irqs)) -- cgit v1.2.3-59-g8ed1b From b938feb7909846b9120366ca3a4cf70dfa879e09 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 13 Mar 2025 14:27:27 -0700 Subject: pinctrl: qcom: tlmm-test: Validate irq_enable delivers edge irqs In commit 'cf9d052aa600 ("pinctrl: qcom: Don't clear pending interrupts when enabling")' Doug establishes an expectation that edge interrupts occurring while an interrupt is disabled should be delivered once the interrupt is enabled again. Implement a test to validate that this is the case. Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/20250313-tlmm-test-disabled-irq-delivered-v1-1-f0be903732ac@oss.qualcomm.com Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/tlmm-test.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/tlmm-test.c b/drivers/pinctrl/qcom/tlmm-test.c index 9c31798b3c08..fd02bf3a76cb 100644 --- a/drivers/pinctrl/qcom/tlmm-test.c +++ b/drivers/pinctrl/qcom/tlmm-test.c @@ -506,6 +506,42 @@ static void tlmm_test_thread_falling_in_handler(struct kunit *test) KUNIT_ASSERT_EQ(test, atomic_read(&priv->thread_count), 10); } +/* + * Validate that edge interrupts occurring while irq is disabled is delivered + * once the interrupt is reenabled. + */ +static void tlmm_test_rising_while_disabled(struct kunit *test) +{ + struct tlmm_test_priv *priv = test->priv; + unsigned int after_edge; + unsigned int before_edge; + + priv->intr_op = TLMM_TEST_COUNT; + atomic_set(&priv->thread_op_remain, 10); + + tlmm_output_low(); + + tlmm_test_request_hard_irq(test, IRQF_TRIGGER_RISING); + msleep(20); + + disable_irq(tlmm_suite.irq); + before_edge = atomic_read(&priv->intr_count); + + tlmm_output_high(); + msleep(20); + after_edge = atomic_read(&priv->intr_count); + + msleep(20); + enable_irq(tlmm_suite.irq); + msleep(20); + + free_irq(tlmm_suite.irq, priv); + + KUNIT_ASSERT_EQ(test, before_edge, 0); + KUNIT_ASSERT_EQ(test, after_edge, 0); + KUNIT_ASSERT_EQ(test, atomic_read(&priv->intr_count), 1); +} + static int tlmm_test_init(struct kunit *test) { struct tlmm_test_priv *priv; @@ -609,6 +645,7 @@ static struct kunit_case tlmm_test_cases[] = { KUNIT_CASE(tlmm_test_thread_low), KUNIT_CASE(tlmm_test_thread_rising_in_handler), KUNIT_CASE(tlmm_test_thread_falling_in_handler), + KUNIT_CASE(tlmm_test_rising_while_disabled), {} }; -- cgit v1.2.3-59-g8ed1b From a326b0523fc18ab612ff7c5ce7c4d3f23124b2c2 Mon Sep 17 00:00:00 2001 From: Wasim Nazir Date: Wed, 12 Mar 2025 12:55:09 +0530 Subject: pinctrl: qcom: sa8775p: Enable egpio function Egpio feature allows IsLand Domain IOs to be reused as TLMM GPIOs. sa8775p supports egpio feature for GPIOs ranging from 126 to 148. Signed-off-by: Wasim Nazir Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/20250312072509.3247885-3-quic_wasimn@quicinc.com Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/pinctrl-sa8775p.c | 58 ++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/pinctrl-sa8775p.c b/drivers/pinctrl/qcom/pinctrl-sa8775p.c index 8fdea25d8d67..a5b38221aea8 100644 --- a/drivers/pinctrl/qcom/pinctrl-sa8775p.c +++ b/drivers/pinctrl/qcom/pinctrl-sa8775p.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022,2025, Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2023, Linaro Limited */ @@ -467,6 +467,7 @@ enum sa8775p_functions { msm_mux_edp2_lcd, msm_mux_edp3_hot, msm_mux_edp3_lcd, + msm_mux_egpio, msm_mux_emac0_mcg0, msm_mux_emac0_mcg1, msm_mux_emac0_mcg2, @@ -744,6 +745,13 @@ static const char * const edp3_lcd_groups[] = { "gpio49", }; +static const char *const egpio_groups[] = { + "gpio126", "gpio127", "gpio128", "gpio129", "gpio130", "gpio131", + "gpio132", "gpio133", "gpio134", "gpio135", "gpio136", "gpio137", + "gpio138", "gpio139", "gpio140", "gpio141", "gpio142", "gpio143", + "gpio144", "gpio145", "gpio146", "gpio147", "gpio148", +}; + static const char * const emac0_mcg0_groups[] = { "gpio12", }; @@ -1209,6 +1217,7 @@ static const struct pinfunction sa8775p_functions[] = { MSM_PIN_FUNCTION(edp2_lcd), MSM_PIN_FUNCTION(edp3_hot), MSM_PIN_FUNCTION(edp3_lcd), + MSM_PIN_FUNCTION(egpio), MSM_PIN_FUNCTION(emac0_mcg0), MSM_PIN_FUNCTION(emac0_mcg1), MSM_PIN_FUNCTION(emac0_mcg2), @@ -1454,29 +1463,29 @@ static const struct msm_pingroup sa8775p_groups[] = { [123] = PINGROUP(123, hs2_mi2s, phase_flag, _, _, _, _, _, _, _), [124] = PINGROUP(124, hs2_mi2s, phase_flag, _, _, _, _, _, _, _), [125] = PINGROUP(125, hs2_mi2s, phase_flag, _, _, _, _, _, _, _), - [126] = PINGROUP(126, _, _, _, _, _, _, _, _, _), - [127] = PINGROUP(127, _, _, _, _, _, _, _, _, _), - [128] = PINGROUP(128, _, _, _, _, _, _, _, _, _), - [129] = PINGROUP(129, _, _, _, _, _, _, _, _, _), - [130] = PINGROUP(130, _, _, _, _, _, _, _, _, _), - [131] = PINGROUP(131, _, _, _, _, _, _, _, _, _), - [132] = PINGROUP(132, _, _, _, _, _, _, _, _, _), - [133] = PINGROUP(133, _, _, _, _, _, _, _, _, _), - [134] = PINGROUP(134, _, _, _, _, _, _, _, _, _), - [135] = PINGROUP(135, _, _, _, _, _, _, _, _, _), - [136] = PINGROUP(136, _, _, _, _, _, _, _, _, _), - [137] = PINGROUP(137, _, _, _, _, _, _, _, _, _), - [138] = PINGROUP(138, _, _, _, _, _, _, _, _, _), - [139] = PINGROUP(139, _, _, _, _, _, _, _, _, _), - [140] = PINGROUP(140, _, _, _, _, _, _, _, _, _), - [141] = PINGROUP(141, _, _, _, _, _, _, _, _, _), - [142] = PINGROUP(142, _, _, _, _, _, _, _, _, _), - [143] = PINGROUP(143, _, _, _, _, _, _, _, _, _), - [144] = PINGROUP(144, dbg_out, _, _, _, _, _, _, _, _), - [145] = PINGROUP(145, _, _, _, _, _, _, _, _, _), - [146] = PINGROUP(146, _, _, _, _, _, _, _, _, _), - [147] = PINGROUP(147, _, _, _, _, _, _, _, _, _), - [148] = PINGROUP(148, _, _, _, _, _, _, _, _, _), + [126] = PINGROUP(126, _, _, _, _, _, _, _, _, egpio), + [127] = PINGROUP(127, _, _, _, _, _, _, _, _, egpio), + [128] = PINGROUP(128, _, _, _, _, _, _, _, _, egpio), + [129] = PINGROUP(129, _, _, _, _, _, _, _, _, egpio), + [130] = PINGROUP(130, _, _, _, _, _, _, _, _, egpio), + [131] = PINGROUP(131, _, _, _, _, _, _, _, _, egpio), + [132] = PINGROUP(132, _, _, _, _, _, _, _, _, egpio), + [133] = PINGROUP(133, _, _, _, _, _, _, _, _, egpio), + [134] = PINGROUP(134, _, _, _, _, _, _, _, _, egpio), + [135] = PINGROUP(135, _, _, _, _, _, _, _, _, egpio), + [136] = PINGROUP(136, _, _, _, _, _, _, _, _, egpio), + [137] = PINGROUP(137, _, _, _, _, _, _, _, _, egpio), + [138] = PINGROUP(138, _, _, _, _, _, _, _, _, egpio), + [139] = PINGROUP(139, _, _, _, _, _, _, _, _, egpio), + [140] = PINGROUP(140, _, _, _, _, _, _, _, _, egpio), + [141] = PINGROUP(141, _, _, _, _, _, _, _, _, egpio), + [142] = PINGROUP(142, _, _, _, _, _, _, _, _, egpio), + [143] = PINGROUP(143, _, _, _, _, _, _, _, _, egpio), + [144] = PINGROUP(144, dbg_out, _, _, _, _, _, _, _, egpio), + [145] = PINGROUP(145, _, _, _, _, _, _, _, _, egpio), + [146] = PINGROUP(146, _, _, _, _, _, _, _, _, egpio), + [147] = PINGROUP(147, _, _, _, _, _, _, _, _, egpio), + [148] = PINGROUP(148, _, _, _, _, _, _, _, _, egpio), [149] = UFS_RESET(ufs_reset, 0x1a2000), [150] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x199000, 15, 0), [151] = SDC_QDSD_PINGROUP(sdc1_clk, 0x199000, 13, 6), @@ -1511,6 +1520,7 @@ static const struct msm_pinctrl_soc_data sa8775p_pinctrl = { .ngpios = 150, .wakeirq_map = sa8775p_pdc_map, .nwakeirq_map = ARRAY_SIZE(sa8775p_pdc_map), + .egpio_func = 9, }; static int sa8775p_pinctrl_probe(struct platform_device *pdev) -- cgit v1.2.3-59-g8ed1b From 813b1a1a21fea47405dc44694c3031c3efcf0f03 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 18 Mar 2025 14:58:40 +0100 Subject: pinctrl: PINCTRL_AMDISP should depend on DRM_AMD_ISP The AMD Image Signal Processor GPIO pin control functionality is only present on AMD platforms with ISP support, and its platform device is instantiated by the AMD ISP driver. Hence add a dependency on DRM_AMD_ISP, to prevent asking the user about this driver when configuring a kernel that does not support the AMD ISP. Fixes: e97435ab09f3ad7b ("pinctrl: amd: isp411: Add amdisp GPIO pinctrl") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/3685561e8e3cd1d94bce220eeb6001d659da615c.1742306024.git.geert+renesas@glider.be Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 5819f18b2ddc..464cc9aca157 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -51,6 +51,7 @@ config PINCTRL_AMD config PINCTRL_AMDISP tristate "AMDISP GPIO pin control" + depends on DRM_AMD_ISP || COMPILE_TEST depends on HAS_IOMEM select GPIOLIB select PINCONF -- cgit v1.2.3-59-g8ed1b From 5a062c3c3b82004766bc3ece82b594d337076152 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 19 Mar 2025 10:05:47 +0300 Subject: pinctrl: tegra: Fix off by one in tegra_pinctrl_get_group() This should be >= pmx->soc->ngroups instead of > to avoid an out of bounds access. The pmx->soc->groups[] array is allocated in tegra_pinctrl_probe(). Fixes: c12bfa0fee65 ("pinctrl-tegra: Restore SFSEL bit when freeing pins") Signed-off-by: Dan Carpenter Reviewed-by: Kunwu Chan Link: https://lore.kernel.org/82b40d9d-b437-42a9-9eb3-2328aa6877ac@stanley.mountain Signed-off-by: Linus Walleij --- drivers/pinctrl/tegra/pinctrl-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c index 0246acba7703..11ecbd6a9b2a 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c @@ -306,7 +306,7 @@ static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev * { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); - if (group_index < 0 || group_index > pmx->soc->ngroups) + if (group_index < 0 || group_index >= pmx->soc->ngroups) return NULL; return &pmx->soc->groups[group_index]; -- cgit v1.2.3-59-g8ed1b From 113ec87b0f26a17b02c58aa2714a9b8f1020eed9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 18 Mar 2025 12:57:14 +0200 Subject: pinctrl: npcm8xx: Fix incorrect struct npcm8xx_pincfg assignment Sparse is not happy about implementation of the NPCM8XX_PINCFG() pinctrl-npcm8xx.c:1314:9: warning: obsolete array initializer, use C99 syntax pinctrl-npcm8xx.c:1315:9: warning: obsolete array initializer, use C99 syntax ... pinctrl-npcm8xx.c:1412:9: warning: obsolete array initializer, use C99 syntax pinctrl-npcm8xx.c:1413:9: warning: too many warnings which uses index-based assignment in a wrong way, i.e. it missed the equal sign and hence the index is simply ignored, while the entries are indexed naturally. This is not a problem as the pin numbering repeats the natural order, but it might be in case of shuffling the entries. Fix this by adding missed equal sign and reformat a bit for better readability. Fixes: acf4884a5717 ("pinctrl: nuvoton: add NPCM8XX pinctrl and GPIO driver") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/20250318105932.2090926-2-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c index 70e6966049e4..309f66dde309 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c @@ -1290,12 +1290,14 @@ static struct npcm8xx_func npcm8xx_funcs[] = { }; #define NPCM8XX_PINCFG(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q) \ - [a] { .fn0 = fn_ ## b, .reg0 = NPCM8XX_GCR_ ## c, .bit0 = d, \ + [a] = { \ + .flag = q, \ + .fn0 = fn_ ## b, .reg0 = NPCM8XX_GCR_ ## c, .bit0 = d, \ .fn1 = fn_ ## e, .reg1 = NPCM8XX_GCR_ ## f, .bit1 = g, \ .fn2 = fn_ ## h, .reg2 = NPCM8XX_GCR_ ## i, .bit2 = j, \ .fn3 = fn_ ## k, .reg3 = NPCM8XX_GCR_ ## l, .bit3 = m, \ .fn4 = fn_ ## n, .reg4 = NPCM8XX_GCR_ ## o, .bit4 = p, \ - .flag = q } + } /* Drive strength controlled by NPCM8XX_GP_N_ODSC */ #define DRIVE_STRENGTH_LO_SHIFT 8 -- cgit v1.2.3-59-g8ed1b From 1a65846509237f2c78dbba8add772d9ce5daed7b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 18 Mar 2025 12:57:15 +0200 Subject: pinctrl: nuvoton: Convert to use struct pingroup and PINCTRL_PINGROUP() The pin control header provides struct pingroup and PINCTRL_PINGROUP() macro. Utilize them instead of open coded variants in the driver. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/20250318105932.2090926-3-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c | 16 ++-------------- drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c | 16 ++-------------- 2 files changed, 4 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c index 62a46d824b46..2601aacfb976 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c @@ -504,17 +504,6 @@ static const int lkgpo2_pins[] = { 9 }; static const int nprd_smi_pins[] = { 190 }; -/* - * pin: name, number - * group: name, npins, pins - * function: name, ngroups, groups - */ -struct npcm7xx_group { - const char *name; - const unsigned int *pins; - int npins; -}; - #define NPCM7XX_GRPS \ NPCM7XX_GRP(smb0), \ NPCM7XX_GRP(smb0b), \ @@ -642,9 +631,8 @@ enum { #undef NPCM7XX_GRP }; -static struct npcm7xx_group npcm7xx_groups[] = { -#define NPCM7XX_GRP(x) { .name = #x, .pins = x ## _pins, \ - .npins = ARRAY_SIZE(x ## _pins) } +static struct pingroup npcm7xx_groups[] = { +#define NPCM7XX_GRP(x) PINCTRL_PINGROUP(#x, x ## _pins, ARRAY_SIZE(x ## _pins)) NPCM7XX_GRPS #undef NPCM7XX_GRP }; diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c index 309f66dde309..dcfb58be7632 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c @@ -587,17 +587,6 @@ static const int hgpio5_pins[] = { 25 }; static const int hgpio6_pins[] = { 59 }; static const int hgpio7_pins[] = { 60 }; -/* - * pin: name, number - * group: name, npins, pins - * function: name, ngroups, groups - */ -struct npcm8xx_pingroup { - const char *name; - const unsigned int *pins; - int npins; -}; - #define NPCM8XX_GRPS \ NPCM8XX_GRP(gpi36), \ NPCM8XX_GRP(gpi35), \ @@ -829,9 +818,8 @@ enum { #undef NPCM8XX_GRP }; -static struct npcm8xx_pingroup npcm8xx_pingroups[] = { -#define NPCM8XX_GRP(x) { .name = #x, .pins = x ## _pins, \ - .npins = ARRAY_SIZE(x ## _pins) } +static struct pingroup npcm8xx_pingroups[] = { +#define NPCM8XX_GRP(x) PINCTRL_PINGROUP(#x, x ## _pins, ARRAY_SIZE(x ## _pins)) NPCM8XX_GRPS #undef NPCM8XX_GRP }; -- cgit v1.2.3-59-g8ed1b From 1bce744173dd665af73cd8a27954e23f8fa031ac Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 18 Mar 2025 12:57:16 +0200 Subject: pinctrl: nuvoton: Make use of struct pinfunction and PINCTRL_PINFUNCTION() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since pin control provides a generic data type and a macro for the pin function definition, use them in the driver. Reviewed-by: Jonathan Neuschäfer Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/20250318105932.2090926-4-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/pinctrl/nuvoton/pinctrl-ma35.c | 19 ++++++++----------- drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c | 11 +++-------- drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c | 11 +++-------- drivers/pinctrl/nuvoton/pinctrl-wpcm450.c | 11 +++-------- 4 files changed, 17 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nuvoton/pinctrl-ma35.c b/drivers/pinctrl/nuvoton/pinctrl-ma35.c index 59c4e7c6cdde..ad4f9ca414c8 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-ma35.c +++ b/drivers/pinctrl/nuvoton/pinctrl-ma35.c @@ -98,12 +98,6 @@ static const u32 ds_3300mv_tbl[] = { 17100, 25600, 34100, 42800, 48000, 56000, 77000, 82000, }; -struct ma35_pin_func { - const char *name; - const char **groups; - u32 ngroups; -}; - struct ma35_pin_setting { u32 offset; u32 shift; @@ -149,7 +143,7 @@ struct ma35_pinctrl { struct regmap *regmap; struct ma35_pin_group *groups; unsigned int ngroups; - struct ma35_pin_func *functions; + struct pinfunction *functions; unsigned int nfunctions; }; @@ -1041,9 +1035,10 @@ static int ma35_pinctrl_parse_functions(struct device_node *np, struct ma35_pinc u32 index) { struct device_node *child; - struct ma35_pin_func *func; + struct pinfunction *func; struct ma35_pin_group *grp; static u32 grp_index; + const char **groups; u32 ret, i = 0; dev_dbg(npctl->dev, "parse function(%d): %s\n", index, np->name); @@ -1055,12 +1050,12 @@ static int ma35_pinctrl_parse_functions(struct device_node *np, struct ma35_pinc if (func->ngroups <= 0) return 0; - func->groups = devm_kcalloc(npctl->dev, func->ngroups, sizeof(char *), GFP_KERNEL); - if (!func->groups) + groups = devm_kcalloc(npctl->dev, func->ngroups, sizeof(*groups), GFP_KERNEL); + if (!groups) return -ENOMEM; for_each_child_of_node(np, child) { - func->groups[i] = child->name; + groups[i] = child->name; grp = &npctl->groups[grp_index++]; ret = ma35_pinctrl_parse_groups(child, grp, npctl, i++); if (ret) { @@ -1068,6 +1063,8 @@ static int ma35_pinctrl_parse_functions(struct device_node *np, struct ma35_pinc return ret; } } + + func->groups = groups; return 0; } diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c index 2601aacfb976..c6b11a198c76 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c @@ -639,13 +639,6 @@ static struct pingroup npcm7xx_groups[] = { #define NPCM7XX_SFUNC(a) NPCM7XX_FUNC(a, #a) #define NPCM7XX_FUNC(a, b...) static const char *a ## _grp[] = { b } -#define NPCM7XX_MKFUNC(nm) { .name = #nm, .ngroups = ARRAY_SIZE(nm ## _grp), \ - .groups = nm ## _grp } -struct npcm7xx_func { - const char *name; - const unsigned int ngroups; - const char *const *groups; -}; NPCM7XX_SFUNC(smb0); NPCM7XX_SFUNC(smb0b); @@ -764,7 +757,8 @@ NPCM7XX_SFUNC(lkgpo2); NPCM7XX_SFUNC(nprd_smi); /* Function names */ -static struct npcm7xx_func npcm7xx_funcs[] = { +static struct pinfunction npcm7xx_funcs[] = { +#define NPCM7XX_MKFUNC(nm) PINCTRL_PINFUNCTION(#nm, nm ## _grp, ARRAY_SIZE(nm ## _grp)) NPCM7XX_MKFUNC(smb0), NPCM7XX_MKFUNC(smb0b), NPCM7XX_MKFUNC(smb0c), @@ -880,6 +874,7 @@ static struct npcm7xx_func npcm7xx_funcs[] = { NPCM7XX_MKFUNC(lkgpo1), NPCM7XX_MKFUNC(lkgpo2), NPCM7XX_MKFUNC(nprd_smi), +#undef NPCM7XX_MKFUNC }; #define NPCM7XX_PINCFG(a, b, c, d, e, f, g, h, i, j, k) \ diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c index dcfb58be7632..ef87cb929133 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c @@ -826,13 +826,6 @@ static struct pingroup npcm8xx_pingroups[] = { #define NPCM8XX_SFUNC(a) NPCM8XX_FUNC(a, #a) #define NPCM8XX_FUNC(a, b...) static const char *a ## _grp[] = { b } -#define NPCM8XX_MKFUNC(nm) { .name = #nm, .ngroups = ARRAY_SIZE(nm ## _grp), \ - .groups = nm ## _grp } -struct npcm8xx_func { - const char *name; - const unsigned int ngroups; - const char *const *groups; -}; NPCM8XX_SFUNC(gpi36); NPCM8XX_SFUNC(gpi35); @@ -1055,7 +1048,8 @@ NPCM8XX_SFUNC(hgpio6); NPCM8XX_SFUNC(hgpio7); /* Function names */ -static struct npcm8xx_func npcm8xx_funcs[] = { +static struct pinfunction npcm8xx_funcs[] = { +#define NPCM8XX_MKFUNC(nm) PINCTRL_PINFUNCTION(#nm, nm ## _grp, ARRAY_SIZE(nm ## _grp)) NPCM8XX_MKFUNC(gpi36), NPCM8XX_MKFUNC(gpi35), NPCM8XX_MKFUNC(tp_jtag3), @@ -1275,6 +1269,7 @@ static struct npcm8xx_func npcm8xx_funcs[] = { NPCM8XX_MKFUNC(hgpio5), NPCM8XX_MKFUNC(hgpio6), NPCM8XX_MKFUNC(hgpio7), +#undef NPCM8XX_MKFUNC }; #define NPCM8XX_PINCFG(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q) \ diff --git a/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c b/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c index 2f97accef837..4264ca749175 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c +++ b/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c @@ -482,13 +482,6 @@ static const struct pingroup wpcm450_groups[] = { #define WPCM450_SFUNC(a) WPCM450_FUNC(a, #a) #define WPCM450_FUNC(a, b...) static const char *a ## _grp[] = { b } -#define WPCM450_MKFUNC(nm) { .name = #nm, .ngroups = ARRAY_SIZE(nm ## _grp), \ - .groups = nm ## _grp } -struct wpcm450_func { - const char *name; - const unsigned int ngroups; - const char *const *groups; -}; WPCM450_SFUNC(smb3); WPCM450_SFUNC(smb4); @@ -555,7 +548,8 @@ WPCM450_FUNC(gpio, WPCM450_GRPS); #undef WPCM450_GRP /* Function names */ -static struct wpcm450_func wpcm450_funcs[] = { +static struct pinfunction wpcm450_funcs[] = { +#define WPCM450_MKFUNC(nm) PINCTRL_PINFUNCTION(#nm, nm ## _grp, ARRAY_SIZE(nm ## _grp)) WPCM450_MKFUNC(smb3), WPCM450_MKFUNC(smb4), WPCM450_MKFUNC(smb5), @@ -616,6 +610,7 @@ static struct wpcm450_func wpcm450_funcs[] = { WPCM450_MKFUNC(hg6), WPCM450_MKFUNC(hg7), WPCM450_MKFUNC(gpio), +#undef WPCM450_MKFUNC }; #define WPCM450_PINCFG(a, b, c, d, e, f, g) \ -- cgit v1.2.3-59-g8ed1b From d52ecc655a780da256e93575cd5b8a225a2fe601 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 18 Mar 2025 12:57:17 +0200 Subject: pinctrl: nuvoton: Convert to use struct group_desc The pin control core header provides struct group_desc. Utilize it instead of open coded variants in the driver. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/20250318105932.2090926-5-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/pinctrl/nuvoton/pinctrl-ma35.c | 70 ++++++++++++++++------------------ 1 file changed, 33 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nuvoton/pinctrl-ma35.c b/drivers/pinctrl/nuvoton/pinctrl-ma35.c index ad4f9ca414c8..da3c8d8e3eb3 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-ma35.c +++ b/drivers/pinctrl/nuvoton/pinctrl-ma35.c @@ -106,13 +106,6 @@ struct ma35_pin_setting { unsigned int nconfigs; }; -struct ma35_pin_group { - const char *name; - unsigned int npins; - unsigned int *pins; - struct ma35_pin_setting *settings; -}; - struct ma35_pin_bank { void __iomem *reg_base; struct clk *clk; @@ -141,7 +134,7 @@ struct ma35_pinctrl { struct pinctrl_dev *pctl; const struct ma35_pinctrl_soc_info *info; struct regmap *regmap; - struct ma35_pin_group *groups; + struct group_desc *groups; unsigned int ngroups; struct pinfunction *functions; unsigned int nfunctions; @@ -160,7 +153,7 @@ static const char *ma35_get_group_name(struct pinctrl_dev *pctldev, unsigned int { struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); - return npctl->groups[selector].name; + return npctl->groups[selector].grp.name; } static int ma35_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, @@ -171,19 +164,19 @@ static int ma35_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selecto if (selector >= npctl->ngroups) return -EINVAL; - *pins = npctl->groups[selector].pins; - *npins = npctl->groups[selector].npins; + *pins = npctl->groups[selector].grp.pins; + *npins = npctl->groups[selector].grp.npins; return 0; } -static struct ma35_pin_group *ma35_pinctrl_find_group_by_name( - const struct ma35_pinctrl *npctl, const char *name) +static struct group_desc * +ma35_pinctrl_find_group_by_name(const struct ma35_pinctrl *npctl, const char *name) { int i; for (i = 0; i < npctl->ngroups; i++) { - if (!strcmp(npctl->groups[i].name, name)) + if (!strcmp(npctl->groups[i].grp.name, name)) return &npctl->groups[i]; } return NULL; @@ -195,9 +188,10 @@ static int ma35_pinctrl_dt_node_to_map_func(struct pinctrl_dev *pctldev, unsigned int *num_maps) { struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); - struct ma35_pin_group *grp; + struct ma35_pin_setting *setting; struct pinctrl_map *new_map; struct device_node *parent; + struct group_desc *grp; int map_num = 1; int i; @@ -211,7 +205,7 @@ static int ma35_pinctrl_dt_node_to_map_func(struct pinctrl_dev *pctldev, return -EINVAL; } - map_num += grp->npins; + map_num += grp->grp.npins; new_map = kcalloc(map_num, sizeof(*new_map), GFP_KERNEL); if (!new_map) return -ENOMEM; @@ -223,17 +217,19 @@ static int ma35_pinctrl_dt_node_to_map_func(struct pinctrl_dev *pctldev, if (!parent) return -EINVAL; + setting = grp->data; + new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; new_map[0].data.mux.function = parent->name; new_map[0].data.mux.group = np->name; of_node_put(parent); new_map++; - for (i = 0; i < grp->npins; i++) { + for (i = 0; i < grp->grp.npins; i++) { new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN; - new_map[i].data.configs.group_or_pin = pin_get_name(pctldev, grp->pins[i]); - new_map[i].data.configs.configs = grp->settings[i].configs; - new_map[i].data.configs.num_configs = grp->settings[i].nconfigs; + new_map[i].data.configs.group_or_pin = pin_get_name(pctldev, grp->grp.pins[i]); + new_map[i].data.configs.configs = setting[i].configs; + new_map[i].data.configs.num_configs = setting[i].nconfigs; } dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n", (*map)->data.mux.function, (*map)->data.mux.group, map_num); @@ -281,14 +277,14 @@ static int ma35_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int selecto unsigned int group) { struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); - struct ma35_pin_group *grp = &npctl->groups[group]; - struct ma35_pin_setting *setting = grp->settings; + struct group_desc *grp = &npctl->groups[group]; + struct ma35_pin_setting *setting = grp->data; u32 i, regval; dev_dbg(npctl->dev, "enable function %s group %s\n", - npctl->functions[selector].name, npctl->groups[group].name); + npctl->functions[selector].name, grp->grp.name); - for (i = 0; i < grp->npins; i++) { + for (i = 0; i < grp->grp.npins; i++) { regmap_read(npctl->regmap, setting->offset, ®val); regval &= ~GENMASK(setting->shift + MA35_MFP_BITS_PER_PORT - 1, setting->shift); @@ -980,17 +976,16 @@ static const struct pinconf_ops ma35_pinconf_ops = { .is_generic = true, }; -static int ma35_pinctrl_parse_groups(struct device_node *np, struct ma35_pin_group *grp, +static int ma35_pinctrl_parse_groups(struct device_node *np, struct group_desc *grp, struct ma35_pinctrl *npctl, u32 index) { struct ma35_pin_setting *pin; unsigned long *configs; unsigned int nconfigs; + unsigned int *pins; int i, j, count, ret; u32 *elems; - grp->name = np->name; - ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &nconfigs); if (ret) return ret; @@ -1003,21 +998,22 @@ static int ma35_pinctrl_parse_groups(struct device_node *np, struct ma35_pin_gro if (!elems) return -ENOMEM; + grp->grp.name = np->name; + ret = of_property_read_u32_array(np, "nuvoton,pins", elems, count); if (ret) return -EINVAL; + grp->grp.npins = count / 3; - grp->npins = count / 3; - - grp->pins = devm_kcalloc(npctl->dev, grp->npins, sizeof(*grp->pins), GFP_KERNEL); - if (!grp->pins) + pins = devm_kcalloc(npctl->dev, grp->grp.npins, sizeof(*pins), GFP_KERNEL); + if (!pins) return -ENOMEM; + grp->grp.pins = pins; - grp->settings = devm_kcalloc(npctl->dev, grp->npins, sizeof(*grp->settings), GFP_KERNEL); - if (!grp->settings) + pin = devm_kcalloc(npctl->dev, grp->grp.npins, sizeof(*pin), GFP_KERNEL); + if (!pin) return -ENOMEM; - - pin = grp->settings; + grp->data = pin; for (i = 0, j = 0; i < count; i += 3, j++) { pin->offset = elems[i] * MA35_MFP_REG_SZ_PER_BANK + MA35_MFP_REG_BASE; @@ -1025,7 +1021,7 @@ static int ma35_pinctrl_parse_groups(struct device_node *np, struct ma35_pin_gro pin->muxval = elems[i + 2]; pin->configs = configs; pin->nconfigs = nconfigs; - grp->pins[j] = npctl->info->get_pin_num(pin->offset, pin->shift); + pins[j] = npctl->info->get_pin_num(pin->offset, pin->shift); pin++; } return 0; @@ -1036,7 +1032,7 @@ static int ma35_pinctrl_parse_functions(struct device_node *np, struct ma35_pinc { struct device_node *child; struct pinfunction *func; - struct ma35_pin_group *grp; + struct group_desc *grp; static u32 grp_index; const char **groups; u32 ret, i = 0; -- cgit v1.2.3-59-g8ed1b From 693c9ecd832669c55e8d8067eba064440d9a4709 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 18 Mar 2025 12:57:18 +0200 Subject: pinctrl: nuvoton: Reduce use of OF-specific APIs Some drivers are using device property APIs along with OF-specific ones. At the same time few of the latter can be converted to device property calls. Reduce use of OF-specific APIs in order to bring a bit more consistency into the drivers. Signed-off-by: Andy Shevchenko Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/20250318105932.2090926-6-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/pinctrl/nuvoton/pinctrl-ma35.c | 35 +++++++++++++++---------------- drivers/pinctrl/nuvoton/pinctrl-ma35d1.c | 1 - drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c | 17 +++------------ drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c | 2 +- 4 files changed, 21 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nuvoton/pinctrl-ma35.c b/drivers/pinctrl/nuvoton/pinctrl-ma35.c index da3c8d8e3eb3..06ae1fe8b8c5 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-ma35.c +++ b/drivers/pinctrl/nuvoton/pinctrl-ma35.c @@ -519,7 +519,6 @@ static int ma35_gpiolib_register(struct platform_device *pdev, struct ma35_pinct bank->irqtype = 0; bank->irqinten = 0; bank->chip.label = bank->name; - bank->chip.of_gpio_n_cells = 2; bank->chip.parent = &pdev->dev; bank->chip.request = ma35_gpio_core_to_request; bank->chip.direction_input = ma35_gpio_core_direction_in; @@ -976,9 +975,10 @@ static const struct pinconf_ops ma35_pinconf_ops = { .is_generic = true, }; -static int ma35_pinctrl_parse_groups(struct device_node *np, struct group_desc *grp, +static int ma35_pinctrl_parse_groups(struct fwnode_handle *fwnode, struct group_desc *grp, struct ma35_pinctrl *npctl, u32 index) { + struct device_node *np = to_of_node(fwnode); struct ma35_pin_setting *pin; unsigned long *configs; unsigned int nconfigs; @@ -990,7 +990,7 @@ static int ma35_pinctrl_parse_groups(struct device_node *np, struct group_desc * if (ret) return ret; - count = of_property_count_elems_of_size(np, "nuvoton,pins", sizeof(u32)); + count = fwnode_property_count_u32(fwnode, "nuvoton,pins"); if (!count || count % 3) return -EINVAL; @@ -1000,7 +1000,7 @@ static int ma35_pinctrl_parse_groups(struct device_node *np, struct group_desc * grp->grp.name = np->name; - ret = of_property_read_u32_array(np, "nuvoton,pins", elems, count); + ret = fwnode_property_read_u32_array(fwnode, "nuvoton,pins", elems, count); if (ret) return -EINVAL; grp->grp.npins = count / 3; @@ -1027,10 +1027,11 @@ static int ma35_pinctrl_parse_groups(struct device_node *np, struct group_desc * return 0; } -static int ma35_pinctrl_parse_functions(struct device_node *np, struct ma35_pinctrl *npctl, +static int ma35_pinctrl_parse_functions(struct fwnode_handle *fwnode, struct ma35_pinctrl *npctl, u32 index) { - struct device_node *child; + struct device_node *np = to_of_node(fwnode); + struct fwnode_handle *child; struct pinfunction *func; struct group_desc *grp; static u32 grp_index; @@ -1050,12 +1051,14 @@ static int ma35_pinctrl_parse_functions(struct device_node *np, struct ma35_pinc if (!groups) return -ENOMEM; - for_each_child_of_node(np, child) { - groups[i] = child->name; + fwnode_for_each_child_node(fwnode, child) { + struct device_node *node = to_of_node(child); + + groups[i] = node->name; grp = &npctl->groups[grp_index++]; ret = ma35_pinctrl_parse_groups(child, grp, npctl, i++); if (ret) { - of_node_put(child); + fwnode_handle_put(child); return ret; } } @@ -1066,13 +1069,12 @@ static int ma35_pinctrl_parse_functions(struct device_node *np, struct ma35_pinc static int ma35_pinctrl_probe_dt(struct platform_device *pdev, struct ma35_pinctrl *npctl) { + struct device *dev = &pdev->dev; struct fwnode_handle *child; u32 idx = 0; int ret; - device_for_each_child_node(&pdev->dev, child) { - if (fwnode_property_present(child, "gpio-controller")) - continue; + for_each_gpiochip_node(dev, child) { npctl->nfunctions++; npctl->ngroups += of_get_child_count(to_of_node(child)); } @@ -1090,11 +1092,8 @@ static int ma35_pinctrl_probe_dt(struct platform_device *pdev, struct ma35_pinct if (!npctl->groups) return -ENOMEM; - device_for_each_child_node(&pdev->dev, child) { - if (fwnode_property_present(child, "gpio-controller")) - continue; - - ret = ma35_pinctrl_parse_functions(to_of_node(child), npctl, idx++); + for_each_gpiochip_node(dev, child) { + ret = ma35_pinctrl_parse_functions(child, npctl, idx++); if (ret) { fwnode_handle_put(child); dev_err(&pdev->dev, "failed to parse function\n"); @@ -1139,7 +1138,7 @@ int ma35_pinctrl_probe(struct platform_device *pdev, const struct ma35_pinctrl_s npctl->info = info; npctl->dev = &pdev->dev; - npctl->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "nuvoton,sys"); + npctl->regmap = syscon_regmap_lookup_by_phandle(dev_of_node(dev), "nuvoton,sys"); if (IS_ERR(npctl->regmap)) return dev_err_probe(&pdev->dev, PTR_ERR(npctl->regmap), "No syscfg phandle specified\n"); diff --git a/drivers/pinctrl/nuvoton/pinctrl-ma35d1.c b/drivers/pinctrl/nuvoton/pinctrl-ma35d1.c index 8bb9a5a35954..eafa06ca0879 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-ma35d1.c +++ b/drivers/pinctrl/nuvoton/pinctrl-ma35d1.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c index c6b11a198c76..dfd32feb3428 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c @@ -7,10 +7,8 @@ #include #include #include +#include #include -#include -#include -#include #include #include #include @@ -1832,22 +1830,13 @@ static struct pinctrl_desc npcm7xx_pinctrl_desc = { static int npcm7xx_gpio_of(struct npcm7xx_pinctrl *pctrl) { int ret = -ENXIO; - struct resource res; struct device *dev = pctrl->dev; struct fwnode_reference_args args; struct fwnode_handle *child; int id = 0; for_each_gpiochip_node(dev, child) { - struct device_node *np = to_of_node(child); - - ret = of_address_to_resource(np, 0, &res); - if (ret < 0) { - dev_err(dev, "Resource fail for GPIO bank %u\n", id); - return ret; - } - - pctrl->gpio_bank[id].base = ioremap(res.start, resource_size(&res)); + pctrl->gpio_bank[id].base = fwnode_iomap(child, 0); if (!pctrl->gpio_bank[id].base) return -EINVAL; @@ -1869,7 +1858,7 @@ static int npcm7xx_gpio_of(struct npcm7xx_pinctrl *pctrl) return ret; } - ret = irq_of_parse_and_map(np, 0); + ret = fwnode_irq_get(child, 0); if (!ret) { dev_err(dev, "No IRQ for GPIO bank %u\n", id); return -EINVAL; diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c index ef87cb929133..934ceed4f57f 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c @@ -2421,7 +2421,7 @@ static int npcm8xx_pinctrl_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pctrl); pctrl->gcr_regmap = - syscon_regmap_lookup_by_phandle(dev->of_node, "nuvoton,sysgcr"); + syscon_regmap_lookup_by_phandle(dev_of_node(dev), "nuvoton,sysgcr"); if (IS_ERR(pctrl->gcr_regmap)) return dev_err_probe(dev, PTR_ERR(pctrl->gcr_regmap), "Failed to find nuvoton,sysgcr property\n"); -- cgit v1.2.3-59-g8ed1b From 5df0211a67dfd0cb2e2e0c0b6e08879420c7d8f6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 22 Mar 2025 21:33:43 +0100 Subject: pinctrl: amlogic-a4: Drop surplus semicolon The kernel bots complain about untidy code found using coccinelle, fix it up. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202503212354.Hx2qaDRe-lkp@intel.com/ Signed-off-by: Linus Walleij --- drivers/pinctrl/meson/pinctrl-amlogic-a4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c index 35d5540b8eaa..ee7bbc72f9b3 100644 --- a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c +++ b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c @@ -856,7 +856,7 @@ static void init_bank_register_bit(struct aml_pinctrl *info, break; } } - }; + } if (def_offs) { for (i = 0; i < AML_NUM_REG; i++) { -- cgit v1.2.3-59-g8ed1b From 3ef9f710efcb5cc1335b5b09c16c757f703d7e5f Mon Sep 17 00:00:00 2001 From: Hao Chang Date: Sat, 22 Mar 2025 11:52:28 +0800 Subject: pinctrl: mediatek: Add EINT support for multiple addresses For flexible routing, eint will be divided into 5 bases, and it will obtain the operation address through the pins array. Signed-off-by: Hao Chang Signed-off-by: Qingliang Li Link: https://lore.kernel.org/20250322035307.4811-2-ot_chhao.chang@mediatek.com Signed-off-by: Linus Walleij --- drivers/pinctrl/mediatek/mtk-eint.c | 313 ++++++++++++++--------- drivers/pinctrl/mediatek/mtk-eint.h | 23 +- drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c | 37 ++- drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h | 1 + drivers/pinctrl/mediatek/pinctrl-paris.h | 7 + 5 files changed, 254 insertions(+), 127 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c index 27f0a54e12bf..ced4ee509b5b 100644 --- a/drivers/pinctrl/mediatek/mtk-eint.c +++ b/drivers/pinctrl/mediatek/mtk-eint.c @@ -1,11 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2014-2018 MediaTek Inc. +// Copyright (c) 2014-2025 MediaTek Inc. /* * Library for MediaTek External Interrupt Support * * Author: Maoguang Meng * Sean Wang + * Hao Chang + * Qingliang Li * */ @@ -20,6 +22,7 @@ #include #include "mtk-eint.h" +#include "pinctrl-mtk-common-v2.h" #define MTK_EINT_EDGE_SENSITIVE 0 #define MTK_EINT_LEVEL_SENSITIVE 1 @@ -68,13 +71,11 @@ static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint, unsigned int eint_num, unsigned int offset) { - unsigned int eint_base = 0; + unsigned int idx = eint->pins[eint_num].index; + unsigned int inst = eint->pins[eint_num].instance; void __iomem *reg; - if (eint_num >= eint->hw->ap_num) - eint_base = eint->hw->ap_num; - - reg = eint->base + offset + ((eint_num - eint_base) / 32) * 4; + reg = eint->base[inst] + offset + (idx / 32 * 4); return reg; } @@ -83,7 +84,7 @@ static unsigned int mtk_eint_can_en_debounce(struct mtk_eint *eint, unsigned int eint_num) { unsigned int sens; - unsigned int bit = BIT(eint_num % 32); + unsigned int bit = BIT(eint->pins[eint_num].index % 32); void __iomem *reg = mtk_eint_get_offset(eint, eint_num, eint->regs->sens); @@ -92,7 +93,7 @@ static unsigned int mtk_eint_can_en_debounce(struct mtk_eint *eint, else sens = MTK_EINT_EDGE_SENSITIVE; - if (eint_num < eint->hw->db_cnt && sens != MTK_EINT_EDGE_SENSITIVE) + if (eint->pins[eint_num].debounce && sens != MTK_EINT_EDGE_SENSITIVE) return 1; else return 0; @@ -102,9 +103,9 @@ static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq) { int start_level, curr_level; unsigned int reg_offset; - u32 mask = BIT(hwirq & 0x1f); - u32 port = (hwirq >> 5) & eint->hw->port_mask; - void __iomem *reg = eint->base + (port << 2); + unsigned int mask = BIT(eint->pins[hwirq].index & 0x1f); + unsigned int port = (eint->pins[hwirq].index >> 5) & eint->hw->port_mask; + void __iomem *reg = eint->base[eint->pins[hwirq].instance] + (port << 2); curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, hwirq); @@ -126,11 +127,13 @@ static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq) static void mtk_eint_mask(struct irq_data *d) { struct mtk_eint *eint = irq_data_get_irq_chip_data(d); - u32 mask = BIT(d->hwirq & 0x1f); + unsigned int idx = eint->pins[d->hwirq].index; + unsigned int inst = eint->pins[d->hwirq].instance; + unsigned int mask = BIT(idx & 0x1f); void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->mask_set); - eint->cur_mask[d->hwirq >> 5] &= ~mask; + eint->cur_mask[inst][idx >> 5] &= ~mask; writel(mask, reg); } @@ -138,22 +141,24 @@ static void mtk_eint_mask(struct irq_data *d) static void mtk_eint_unmask(struct irq_data *d) { struct mtk_eint *eint = irq_data_get_irq_chip_data(d); - u32 mask = BIT(d->hwirq & 0x1f); + unsigned int idx = eint->pins[d->hwirq].index; + unsigned int inst = eint->pins[d->hwirq].instance; + unsigned int mask = BIT(idx & 0x1f); void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->mask_clr); - eint->cur_mask[d->hwirq >> 5] |= mask; + eint->cur_mask[inst][idx >> 5] |= mask; writel(mask, reg); - if (eint->dual_edge[d->hwirq]) + if (eint->pins[d->hwirq].dual_edge) mtk_eint_flip_edge(eint, d->hwirq); } static unsigned int mtk_eint_get_mask(struct mtk_eint *eint, unsigned int eint_num) { - unsigned int bit = BIT(eint_num % 32); + unsigned int bit = BIT(eint->pins[eint_num].index % 32); void __iomem *reg = mtk_eint_get_offset(eint, eint_num, eint->regs->mask); @@ -163,7 +168,7 @@ static unsigned int mtk_eint_get_mask(struct mtk_eint *eint, static void mtk_eint_ack(struct irq_data *d) { struct mtk_eint *eint = irq_data_get_irq_chip_data(d); - u32 mask = BIT(d->hwirq & 0x1f); + unsigned int mask = BIT(eint->pins[d->hwirq].index & 0x1f); void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->ack); @@ -174,7 +179,7 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type) { struct mtk_eint *eint = irq_data_get_irq_chip_data(d); bool masked; - u32 mask = BIT(d->hwirq & 0x1f); + unsigned int mask = BIT(eint->pins[d->hwirq].index & 0x1f); void __iomem *reg; if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) || @@ -186,9 +191,9 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type) } if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) - eint->dual_edge[d->hwirq] = 1; + eint->pins[d->hwirq].dual_edge = 1; else - eint->dual_edge[d->hwirq] = 0; + eint->pins[d->hwirq].dual_edge = 0; if (!mtk_eint_get_mask(eint, d->hwirq)) { mtk_eint_mask(d); @@ -223,27 +228,32 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type) static int mtk_eint_irq_set_wake(struct irq_data *d, unsigned int on) { struct mtk_eint *eint = irq_data_get_irq_chip_data(d); - int shift = d->hwirq & 0x1f; - int reg = d->hwirq >> 5; + unsigned int idx = eint->pins[d->hwirq].index; + unsigned int inst = eint->pins[d->hwirq].instance; + unsigned int shift = idx & 0x1f; + unsigned int port = idx >> 5; if (on) - eint->wake_mask[reg] |= BIT(shift); + eint->wake_mask[inst][port] |= BIT(shift); else - eint->wake_mask[reg] &= ~BIT(shift); + eint->wake_mask[inst][port] &= ~BIT(shift); return 0; } static void mtk_eint_chip_write_mask(const struct mtk_eint *eint, - void __iomem *base, u32 *buf) + void __iomem *base, unsigned int **buf) { - int port; + int inst, port, port_num; void __iomem *reg; - for (port = 0; port < eint->hw->ports; port++) { - reg = base + (port << 2); - writel_relaxed(~buf[port], reg + eint->regs->mask_set); - writel_relaxed(buf[port], reg + eint->regs->mask_clr); + for (inst = 0; inst < eint->nbase; inst++) { + port_num = DIV_ROUND_UP(eint->base_pin_num[inst], 32); + for (port = 0; port < port_num; port++) { + reg = eint->base[inst] + (port << 2); + writel_relaxed(~buf[inst][port], reg + eint->regs->mask_set); + writel_relaxed(buf[inst][port], reg + eint->regs->mask_clr); + } } } @@ -303,15 +313,18 @@ static struct irq_chip mtk_eint_irq_chip = { static unsigned int mtk_eint_hw_init(struct mtk_eint *eint) { - void __iomem *dom_en = eint->base + eint->regs->dom_en; - void __iomem *mask_set = eint->base + eint->regs->mask_set; - unsigned int i; - - for (i = 0; i < eint->hw->ap_num; i += 32) { - writel(0xffffffff, dom_en); - writel(0xffffffff, mask_set); - dom_en += 4; - mask_set += 4; + void __iomem *dom_reg, *mask_reg; + unsigned int i, j; + + for (i = 0; i < eint->nbase; i++) { + dom_reg = eint->base[i] + eint->regs->dom_en; + mask_reg = eint->base[i] + eint->regs->mask_set; + for (j = 0; j < eint->base_pin_num[i]; j += 32) { + writel(0xffffffff, dom_reg); + writel(0xffffffff, mask_reg); + dom_reg += 4; + mask_reg += 4; + } } return 0; @@ -322,14 +335,16 @@ mtk_eint_debounce_process(struct mtk_eint *eint, int index) { unsigned int rst, ctrl_offset; unsigned int bit, dbnc; + unsigned int inst = eint->pins[index].instance; + unsigned int idx = eint->pins[index].index; - ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_ctrl; - dbnc = readl(eint->base + ctrl_offset); - bit = MTK_EINT_DBNC_SET_EN << ((index % 4) * 8); + ctrl_offset = (idx / 4) * 4 + eint->regs->dbnc_ctrl; + dbnc = readl(eint->base[inst] + ctrl_offset); + bit = MTK_EINT_DBNC_SET_EN << ((idx % 4) * 8); if ((bit & dbnc) > 0) { - ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_set; - rst = MTK_EINT_DBNC_RST_BIT << ((index % 4) * 8); - writel(rst, eint->base + ctrl_offset); + ctrl_offset = (idx / 4) * 4 + eint->regs->dbnc_set; + rst = MTK_EINT_DBNC_RST_BIT << ((idx % 4) * 8); + writel(rst, eint->base[inst] + ctrl_offset); } } @@ -337,65 +352,68 @@ static void mtk_eint_irq_handler(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct mtk_eint *eint = irq_desc_get_handler_data(desc); - unsigned int status, eint_num; - int offset, mask_offset, index; - void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat); + unsigned int i, j, port, status, shift, mask, eint_num; + void __iomem *reg; int dual_edge, start_level, curr_level; chained_irq_enter(chip, desc); - for (eint_num = 0; eint_num < eint->hw->ap_num; eint_num += 32, - reg += 4) { - status = readl(reg); - while (status) { - offset = __ffs(status); - mask_offset = eint_num >> 5; - index = eint_num + offset; - status &= ~BIT(offset); - - /* - * If we get an interrupt on pin that was only required - * for wake (but no real interrupt requested), mask the - * interrupt (as would mtk_eint_resume do anyway later - * in the resume sequence). - */ - if (eint->wake_mask[mask_offset] & BIT(offset) && - !(eint->cur_mask[mask_offset] & BIT(offset))) { - writel_relaxed(BIT(offset), reg - - eint->regs->stat + - eint->regs->mask_set); - } - - dual_edge = eint->dual_edge[index]; - if (dual_edge) { - /* - * Clear soft-irq in case we raised it last - * time. - */ - writel(BIT(offset), reg - eint->regs->stat + - eint->regs->soft_clr); - - start_level = - eint->gpio_xlate->get_gpio_state(eint->pctl, - index); - } - - generic_handle_domain_irq(eint->domain, index); - - if (dual_edge) { - curr_level = mtk_eint_flip_edge(eint, index); + for (i = 0; i < eint->nbase; i++) { + for (j = 0; j < eint->base_pin_num[i]; j += 32) { + port = j >> 5; + status = readl(eint->base[i] + port * 4 + eint->regs->stat); + while (status) { + shift = __ffs(status); + status &= ~BIT(shift); + mask = BIT(shift); + eint_num = eint->pin_list[i][shift + j]; /* - * If level changed, we might lost one edge - * interrupt, raised it through soft-irq. + * If we get an interrupt on pin that was only required + * for wake (but no real interrupt requested), mask the + * interrupt (as would mtk_eint_resume do anyway later + * in the resume sequence). */ - if (start_level != curr_level) - writel(BIT(offset), reg - - eint->regs->stat + - eint->regs->soft_set); + if (eint->wake_mask[i][port] & mask && + !(eint->cur_mask[i][port] & mask)) { + reg = mtk_eint_get_offset(eint, eint_num, + eint->regs->mask_set); + writel_relaxed(mask, reg); + } + + dual_edge = eint->pins[eint_num].dual_edge; + if (dual_edge) { + /* + * Clear soft-irq in case we raised it last + * time. + */ + reg = mtk_eint_get_offset(eint, eint_num, + eint->regs->soft_clr); + writel(mask, reg); + + start_level = + eint->gpio_xlate->get_gpio_state(eint->pctl, + eint_num); + } + + generic_handle_domain_irq(eint->domain, eint_num); + + if (dual_edge) { + curr_level = mtk_eint_flip_edge(eint, eint_num); + + /* + * If level changed, we might lost one edge + * interrupt, raised it through soft-irq. + */ + if (start_level != curr_level) { + reg = mtk_eint_get_offset(eint, eint_num, + eint->regs->soft_set); + writel(mask, reg); + } + } + + if (eint->pins[eint_num].debounce) + mtk_eint_debounce_process(eint, eint_num); } - - if (index < eint->hw->db_cnt) - mtk_eint_debounce_process(eint, index); } } chained_irq_exit(chip, desc); @@ -423,6 +441,8 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num, int virq, eint_offset; unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask, dbnc; + unsigned int inst = eint->pins[eint_num].instance; + unsigned int idx = eint->pins[eint_num].index; struct irq_data *d; if (!eint->hw->db_time) @@ -432,8 +452,8 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num, eint_offset = (eint_num % 4) * 8; d = irq_get_irq_data(virq); - set_offset = (eint_num / 4) * 4 + eint->regs->dbnc_set; - clr_offset = (eint_num / 4) * 4 + eint->regs->dbnc_clr; + set_offset = (idx / 4) * 4 + eint->regs->dbnc_set; + clr_offset = (idx / 4) * 4 + eint->regs->dbnc_clr; if (!mtk_eint_can_en_debounce(eint, eint_num)) return -EINVAL; @@ -454,12 +474,12 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num, } clr_bit = 0xff << eint_offset; - writel(clr_bit, eint->base + clr_offset); + writel(clr_bit, eint->base[inst] + clr_offset); bit = ((dbnc << MTK_EINT_DBNC_SET_DBNC_BITS) | MTK_EINT_DBNC_SET_EN) << eint_offset; rst = MTK_EINT_DBNC_RST_BIT << eint_offset; - writel(rst | bit, eint->base + set_offset); + writel(rst | bit, eint->base[inst] + set_offset); /* * Delay a while (more than 2T) to wait for hw debounce counter reset @@ -487,32 +507,69 @@ EXPORT_SYMBOL_GPL(mtk_eint_find_irq); int mtk_eint_do_init(struct mtk_eint *eint) { - int i; + unsigned int size, i, port, inst = 0; + struct mtk_pinctrl *hw = (struct mtk_pinctrl *)eint->pctl; /* If clients don't assign a specific regs, let's use generic one */ if (!eint->regs) eint->regs = &mtk_generic_eint_regs; - eint->wake_mask = devm_kcalloc(eint->dev, eint->hw->ports, - sizeof(*eint->wake_mask), GFP_KERNEL); - if (!eint->wake_mask) + eint->base_pin_num = devm_kmalloc_array(eint->dev, eint->nbase, sizeof(u16), + GFP_KERNEL | __GFP_ZERO); + if (!eint->base_pin_num) return -ENOMEM; - eint->cur_mask = devm_kcalloc(eint->dev, eint->hw->ports, - sizeof(*eint->cur_mask), GFP_KERNEL); - if (!eint->cur_mask) - return -ENOMEM; + if (eint->nbase == 1) { + size = eint->hw->ap_num * sizeof(struct mtk_eint_pin); + eint->pins = devm_kmalloc(eint->dev, size, GFP_KERNEL); + if (!eint->pins) + goto err_pins; + + eint->base_pin_num[inst] = eint->hw->ap_num; + for (i = 0; i < eint->hw->ap_num; i++) { + eint->pins[i].instance = inst; + eint->pins[i].index = i; + eint->pins[i].debounce = (i < eint->hw->db_cnt) ? 1 : 0; + } + } - eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num, - sizeof(int), GFP_KERNEL); - if (!eint->dual_edge) - return -ENOMEM; + if (hw && hw->soc && hw->soc->eint_pin) { + eint->pins = hw->soc->eint_pin; + for (i = 0; i < eint->hw->ap_num; i++) { + inst = eint->pins[i].instance; + if (inst >= eint->nbase) + continue; + eint->base_pin_num[inst]++; + } + } + + eint->pin_list = devm_kmalloc(eint->dev, eint->nbase * sizeof(u16 *), GFP_KERNEL); + if (!eint->pin_list) + goto err_pin_list; + + eint->wake_mask = devm_kmalloc(eint->dev, eint->nbase * sizeof(u32 *), GFP_KERNEL); + if (!eint->wake_mask) + goto err_wake_mask; + + eint->cur_mask = devm_kmalloc(eint->dev, eint->nbase * sizeof(u32 *), GFP_KERNEL); + if (!eint->cur_mask) + goto err_cur_mask; + + for (i = 0; i < eint->nbase; i++) { + eint->pin_list[i] = devm_kzalloc(eint->dev, eint->base_pin_num[i] * sizeof(u16), + GFP_KERNEL); + port = DIV_ROUND_UP(eint->base_pin_num[i], 32); + eint->wake_mask[i] = devm_kzalloc(eint->dev, port * sizeof(u32), GFP_KERNEL); + eint->cur_mask[i] = devm_kzalloc(eint->dev, port * sizeof(u32), GFP_KERNEL); + if (!eint->pin_list[i] || !eint->wake_mask[i] || !eint->cur_mask[i]) + goto err_eint; + } eint->domain = irq_domain_add_linear(eint->dev->of_node, eint->hw->ap_num, &irq_domain_simple_ops, NULL); if (!eint->domain) - return -ENOMEM; + goto err_eint; if (eint->hw->db_time) { for (i = 0; i < MTK_EINT_DBNC_MAX; i++) @@ -523,8 +580,11 @@ int mtk_eint_do_init(struct mtk_eint *eint) mtk_eint_hw_init(eint); for (i = 0; i < eint->hw->ap_num; i++) { + inst = eint->pins[i].instance; + if (inst >= eint->nbase) + continue; + eint->pin_list[inst][eint->pins[i].index] = i; int virq = irq_create_mapping(eint->domain, i); - irq_set_chip_and_handler(virq, &mtk_eint_irq_chip, handle_level_irq); irq_set_chip_data(virq, eint); @@ -534,6 +594,27 @@ int mtk_eint_do_init(struct mtk_eint *eint) eint); return 0; + +err_eint: + for (i = 0; i < eint->nbase; i++) { + if (eint->cur_mask[i]) + devm_kfree(eint->dev, eint->cur_mask[i]); + if (eint->wake_mask[i]) + devm_kfree(eint->dev, eint->wake_mask[i]); + if (eint->pin_list[i]) + devm_kfree(eint->dev, eint->pin_list[i]); + } + devm_kfree(eint->dev, eint->cur_mask); +err_cur_mask: + devm_kfree(eint->dev, eint->wake_mask); +err_wake_mask: + devm_kfree(eint->dev, eint->pin_list); +err_pin_list: + if (eint->nbase == 1) + devm_kfree(eint->dev, eint->pins); +err_pins: + devm_kfree(eint->dev, eint->base_pin_num); + return -ENOMEM; } EXPORT_SYMBOL_GPL(mtk_eint_do_init); diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h index 6139b16cd225..f7f58cca0d5e 100644 --- a/drivers/pinctrl/mediatek/mtk-eint.h +++ b/drivers/pinctrl/mediatek/mtk-eint.h @@ -1,10 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright (C) 2014-2018 MediaTek Inc. + * Copyright (C) 2014-2025 MediaTek Inc. * * Author: Maoguang Meng * Sean Wang - * + * Hao Chang + * Qingliang Li */ #ifndef __MTK_EINT_H #define __MTK_EINT_H @@ -40,6 +41,14 @@ struct mtk_eint_hw { const unsigned int *db_time; }; +struct mtk_eint_pin { + u16 number; + u8 instance; + u8 index; + bool debounce; + bool dual_edge; +}; + extern const unsigned int debounce_time_mt2701[]; extern const unsigned int debounce_time_mt6765[]; extern const unsigned int debounce_time_mt6795[]; @@ -56,17 +65,21 @@ struct mtk_eint_xt { struct mtk_eint { struct device *dev; - void __iomem *base; + void __iomem **base; + u8 nbase; + u16 *base_pin_num; struct irq_domain *domain; int irq; int *dual_edge; - u32 *wake_mask; - u32 *cur_mask; + u16 **pin_list; + u32 **wake_mask; + u32 **cur_mask; /* Used to fit into various EINT device */ const struct mtk_eint_hw *hw; const struct mtk_eint_regs *regs; + struct mtk_eint_pin *pins; u16 num_db_time; /* Used to fit into various pinctrl device */ diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c index 00e95682b9f8..d1556b75d9ef 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "mtk-eint.h" @@ -367,7 +368,7 @@ static const struct mtk_eint_xt mtk_eint_xt = { int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - int ret; + int ret, i, j, count_reg_names; if (!IS_ENABLED(CONFIG_EINT_MTK)) return 0; @@ -379,10 +380,24 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev) if (!hw->eint) return -ENOMEM; - hw->eint->base = devm_platform_ioremap_resource_byname(pdev, "eint"); - if (IS_ERR(hw->eint->base)) { - ret = PTR_ERR(hw->eint->base); - goto err_free_eint; + count_reg_names = of_property_count_strings(np, "reg-names"); + if (count_reg_names < hw->soc->nbase_names) + return -EINVAL; + + hw->eint->nbase = count_reg_names - hw->soc->nbase_names; + hw->eint->base = devm_kmalloc_array(&pdev->dev, hw->eint->nbase, + sizeof(*hw->eint->base), GFP_KERNEL | __GFP_ZERO); + if (!hw->eint->base) { + ret = -ENOMEM; + goto err_free_base; + } + + for (i = hw->soc->nbase_names, j = 0; i < count_reg_names; i++, j++) { + hw->eint->base[j] = of_iomap(np, i); + if (IS_ERR(hw->eint->base[j])) { + ret = PTR_ERR(hw->eint->base[j]); + goto err_free_eint; + } } hw->eint->irq = irq_of_parse_and_map(np, 0); @@ -401,9 +416,19 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev) hw->eint->pctl = hw; hw->eint->gpio_xlate = &mtk_eint_xt; - return mtk_eint_do_init(hw->eint); + ret = mtk_eint_do_init(hw->eint); + if (ret) + goto err_free_eint; + + return 0; err_free_eint: + for (j = 0; j < hw->eint->nbase; j++) { + if (hw->eint->base[j]) + iounmap(hw->eint->base[j]); + } + devm_kfree(hw->dev, hw->eint->base); +err_free_base: devm_kfree(hw->dev, hw->eint); hw->eint = NULL; return ret; diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h index 9c271dc2b521..36d2898037dd 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h @@ -242,6 +242,7 @@ struct mtk_pin_soc { unsigned int nfuncs; const struct mtk_eint_regs *eint_regs; const struct mtk_eint_hw *eint_hw; + struct mtk_eint_pin *eint_pin; /* Specific parameters per SoC */ u8 gpio_m; diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.h b/drivers/pinctrl/mediatek/pinctrl-paris.h index 948ce126aa0c..d8c1822662fc 100644 --- a/drivers/pinctrl/mediatek/pinctrl-paris.h +++ b/drivers/pinctrl/mediatek/pinctrl-paris.h @@ -49,6 +49,13 @@ __VA_ARGS__, { } }, \ } +#define MTK_EINT_PIN(_number, _instance, _index, _debounce) { \ + .number = _number, \ + .instance = _instance, \ + .index = _index, \ + .debounce = _debounce, \ + } + #define PINCTRL_PIN_GROUP(_name_, id) \ { \ .grp = PINCTRL_PINGROUP(_name_,id##_pins, ARRAY_SIZE(id##_pins)), \ -- cgit v1.2.3-59-g8ed1b