diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-13 13:03:06 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-13 13:03:06 -0800 |
commit | 361c89a0da59c04b1d3d33568965fe426b0f18de (patch) | |
tree | d72c31f11bcd2a5fe743420ab486c24b78c7459d /drivers/gpio/gpio-mxc.c | |
parent | d0f3ad23cf4f4046e88eef92c608d43cad9e4f7e (diff) | |
parent | 83e1bcaf8cef26edaaf2a6098ef760f563683483 (diff) |
Merge tag 'pinctrl-v6.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl
Pull pin control updates from Linus Walleij:
"The two large chunks is the header clean-up from Andy and the Qualcomm
DT bindings clean-up from Krzysztof. Each which could give rise to
conflicts, but I haven't seen any.
The YAML conversions happening around the device tree is the biggest
item in the series and is the result of Rob Herrings ambition to
autovalidate these trees against strict schemas and it is paying off
in lots of bugs found and ever prettier device trees. Sooner or later
the transition will be complete, Krzysztof is fixing up all of the
Qualcomm stuff, which is pretty voluminous.
Core changes:
- minor but nice and important documentation clean-ups
New drivers:
- subdriver for the Qualcomm SDM670 SoC
- subdriver for the Intel Moorefield SoC
- trivial support for the NXP Freescale i.MXRT1170 SoC
Other changes and improvements
- major clean-up of the Qualcomm pin control device tree bindings by
Krzysztof
- major header clean-up by Andy
- some immutable irqchip clean-up for the Actions Semiconductor and
Nuvoton drivers
- GPIO helpers for The Cypress cy8c95x0 driver
- bias handling in the Mediatek MT7986 driver
- remove the unused pins-are-numbered concept that never flew"
* tag 'pinctrl-v6.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (231 commits)
pinctrl: thunderbay: fix possible memory leak in thunderbay_build_functions()
dt-bindings: pinctrl: st,stm32: Deprecate pins-are-numbered
dt-bindings: pinctrl: mediatek,mt65xx: Deprecate pins-are-numbered
pinctrl: stm32: Remove check for pins-are-numbered
pinctrl: mediatek: common: Remove check for pins-are-numbered
pinctrl: qcom: remove duplicate included header files
pinctrl: sunxi: d1: Add CAN bus pinmuxes
pinctrl: loongson2: Fix some const correctness
pinctrl: pinconf-generic: add missing of_node_put()
pinctrl: intel: Enumerate PWM device when community has a capability
pwm: lpss: Rename pwm_lpss_probe() --> devm_pwm_lpss_probe()
pwm: lpss: Allow other drivers to enable PWM LPSS
pwm: lpss: Include headers we are the direct user of
pwm: lpss: Rename MAX_PWMS --> LPSS_MAX_PWMS
pwm: Add a stub for devm_pwmchip_add()
pinctrl: k210: call of_node_put()
pinctrl: starfive: Use existing variable gpio
dt-bindings: pinctrl: semtech,sx150xq: fix match patterns for 16 GPIOs matching
pinconf-generic: fix style issues in pin_config_param doc
pinctrl: pinctrl-loongson2: fix Kconfig dependency
...
Diffstat (limited to 'drivers/gpio/gpio-mxc.c')
-rw-r--r-- | drivers/gpio/gpio-mxc.c | 92 |
1 files changed, 91 insertions, 1 deletions
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index c871602fc5ba..d5626c572d24 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -24,6 +24,12 @@ #include <linux/of_device.h> #include <linux/bug.h> +#define IMX_SCU_WAKEUP_OFF 0 +#define IMX_SCU_WAKEUP_LOW_LVL 4 +#define IMX_SCU_WAKEUP_FALL_EDGE 5 +#define IMX_SCU_WAKEUP_RISE_EDGE 6 +#define IMX_SCU_WAKEUP_HIGH_LVL 7 + /* device type dependent stuff */ struct mxc_gpio_hwdata { unsigned dr_reg; @@ -61,6 +67,9 @@ struct mxc_gpio_port { u32 both_edges; struct mxc_gpio_reg_saved gpio_saved_reg; bool power_off; + u32 wakeup_pads; + bool is_pad_wakeup; + u32 pad_type[32]; const struct mxc_gpio_hwdata *hwdata; }; @@ -130,6 +139,9 @@ static const struct of_device_id mxc_gpio_dt_ids[] = { { .compatible = "fsl,imx31-gpio", .data = &imx31_gpio_hwdata }, { .compatible = "fsl,imx35-gpio", .data = &imx35_gpio_hwdata }, { .compatible = "fsl,imx7d-gpio", .data = &imx35_gpio_hwdata }, + { .compatible = "fsl,imx8dxl-gpio", .data = &imx35_gpio_hwdata }, + { .compatible = "fsl,imx8qm-gpio", .data = &imx35_gpio_hwdata }, + { .compatible = "fsl,imx8qxp-gpio", .data = &imx35_gpio_hwdata }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mxc_gpio_dt_ids); @@ -203,6 +215,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) } writel(1 << gpio_idx, port->base + GPIO_ISR); + port->pad_type[gpio_idx] = type; return 0; } @@ -254,6 +267,9 @@ static void mx3_gpio_irq_handler(struct irq_desc *desc) struct mxc_gpio_port *port = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); + if (port->is_pad_wakeup) + return; + chained_irq_enter(chip, desc); irq_stat = readl(port->base + GPIO_ISR) & readl(port->base + GPIO_IMR); @@ -306,11 +322,13 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable) ret = enable_irq_wake(port->irq_high); else ret = enable_irq_wake(port->irq); + port->wakeup_pads |= (1 << gpio_idx); } else { if (port->irq_high && (gpio_idx >= 16)) ret = disable_irq_wake(port->irq_high); else ret = disable_irq_wake(port->irq); + port->wakeup_pads &= ~(1 << gpio_idx); } return ret; @@ -365,7 +383,6 @@ static int mxc_gpio_probe(struct platform_device *pdev) return -ENOMEM; port->dev = &pdev->dev; - port->hwdata = device_get_match_data(&pdev->dev); port->base = devm_platform_ioremap_resource(pdev, 0); @@ -498,6 +515,78 @@ static void mxc_gpio_restore_regs(struct mxc_gpio_port *port) writel(port->gpio_saved_reg.dr, port->base + GPIO_DR); } +static bool mxc_gpio_generic_config(struct mxc_gpio_port *port, + unsigned int offset, unsigned long conf) +{ + struct device_node *np = port->dev->of_node; + + if (of_device_is_compatible(np, "fsl,imx8dxl-gpio") || + of_device_is_compatible(np, "fsl,imx8qxp-gpio") || + of_device_is_compatible(np, "fsl,imx8qm-gpio")) + return (gpiochip_generic_config(&port->gc, offset, conf) == 0); + + return false; +} + +static bool mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable) +{ + unsigned long config; + bool ret = false; + int i, type; + + static const u32 pad_type_map[] = { + IMX_SCU_WAKEUP_OFF, /* 0 */ + IMX_SCU_WAKEUP_RISE_EDGE, /* IRQ_TYPE_EDGE_RISING */ + IMX_SCU_WAKEUP_FALL_EDGE, /* IRQ_TYPE_EDGE_FALLING */ + IMX_SCU_WAKEUP_FALL_EDGE, /* IRQ_TYPE_EDGE_BOTH */ + IMX_SCU_WAKEUP_HIGH_LVL, /* IRQ_TYPE_LEVEL_HIGH */ + IMX_SCU_WAKEUP_OFF, /* 5 */ + IMX_SCU_WAKEUP_OFF, /* 6 */ + IMX_SCU_WAKEUP_OFF, /* 7 */ + IMX_SCU_WAKEUP_LOW_LVL, /* IRQ_TYPE_LEVEL_LOW */ + }; + + for (i = 0; i < 32; i++) { + if ((port->wakeup_pads & (1 << i))) { + type = port->pad_type[i]; + if (enable) + config = pad_type_map[type]; + else + config = IMX_SCU_WAKEUP_OFF; + ret |= mxc_gpio_generic_config(port, i, config); + } + } + + return ret; +} + +static int __maybe_unused mxc_gpio_noirq_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mxc_gpio_port *port = platform_get_drvdata(pdev); + + if (port->wakeup_pads > 0) + port->is_pad_wakeup = mxc_gpio_set_pad_wakeup(port, true); + + return 0; +} + +static int __maybe_unused mxc_gpio_noirq_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mxc_gpio_port *port = platform_get_drvdata(pdev); + + if (port->wakeup_pads > 0) + mxc_gpio_set_pad_wakeup(port, false); + port->is_pad_wakeup = false; + + return 0; +} + +static const struct dev_pm_ops mxc_gpio_dev_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mxc_gpio_noirq_suspend, mxc_gpio_noirq_resume) +}; + static int mxc_gpio_syscore_suspend(void) { struct mxc_gpio_port *port; @@ -537,6 +626,7 @@ static struct platform_driver mxc_gpio_driver = { .name = "gpio-mxc", .of_match_table = mxc_gpio_dt_ids, .suppress_bind_attrs = true, + .pm = &mxc_gpio_dev_pm_ops, }, .probe = mxc_gpio_probe, }; |