diff options
Diffstat (limited to 'drivers/gpio/gpio-mxc.c')
-rw-r--r-- | drivers/gpio/gpio-mxc.c | 89 |
1 files changed, 45 insertions, 44 deletions
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index fae1a30f8ae6..433cbadc3a4c 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -7,6 +7,7 @@ // Authors: Daniel Mack, Juergen Beisert. // Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/init.h> @@ -22,6 +23,7 @@ #include <linux/spinlock.h> #include <linux/syscore_ops.h> #include <linux/gpio/driver.h> +#include <linux/gpio/generic.h> #include <linux/of.h> #include <linux/bug.h> @@ -64,7 +66,7 @@ struct mxc_gpio_port { int irq_high; void (*mx_irq_handler)(struct irq_desc *desc); struct irq_domain *domain; - struct gpio_chip gc; + struct gpio_generic_chip gen_gc; struct device *dev; u32 both_edges; struct mxc_gpio_reg_saved gpio_saved_reg; @@ -161,7 +163,6 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct mxc_gpio_port *port = gc->private; - unsigned long flags; u32 bit, val; u32 gpio_idx = d->hwirq; int edge; @@ -179,7 +180,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) if (GPIO_EDGE_SEL >= 0) { edge = GPIO_INT_BOTH_EDGES; } else { - val = port->gc.get(&port->gc, gpio_idx); + val = port->gen_gc.gc.get(&port->gen_gc.gc, gpio_idx); if (val) { edge = GPIO_INT_LOW_LEV; pr_debug("mxc: set GPIO %d to low trigger\n", gpio_idx); @@ -200,41 +201,38 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) return -EINVAL; } - raw_spin_lock_irqsave(&port->gc.bgpio_lock, flags); + scoped_guard(gpio_generic_lock_irqsave, &port->gen_gc) { + if (GPIO_EDGE_SEL >= 0) { + val = readl(port->base + GPIO_EDGE_SEL); + if (edge == GPIO_INT_BOTH_EDGES) + writel(val | (1 << gpio_idx), + port->base + GPIO_EDGE_SEL); + else + writel(val & ~(1 << gpio_idx), + port->base + GPIO_EDGE_SEL); + } - if (GPIO_EDGE_SEL >= 0) { - val = readl(port->base + GPIO_EDGE_SEL); - if (edge == GPIO_INT_BOTH_EDGES) - writel(val | (1 << gpio_idx), - port->base + GPIO_EDGE_SEL); - else - writel(val & ~(1 << gpio_idx), - port->base + GPIO_EDGE_SEL); - } + if (edge != GPIO_INT_BOTH_EDGES) { + reg += GPIO_ICR1 + ((gpio_idx & 0x10) >> 2); /* lower or upper register */ + bit = gpio_idx & 0xf; + val = readl(reg) & ~(0x3 << (bit << 1)); + writel(val | (edge << (bit << 1)), reg); + } - if (edge != GPIO_INT_BOTH_EDGES) { - reg += GPIO_ICR1 + ((gpio_idx & 0x10) >> 2); /* lower or upper register */ - bit = gpio_idx & 0xf; - val = readl(reg) & ~(0x3 << (bit << 1)); - writel(val | (edge << (bit << 1)), reg); + writel(1 << gpio_idx, port->base + GPIO_ISR); + port->pad_type[gpio_idx] = type; } - writel(1 << gpio_idx, port->base + GPIO_ISR); - port->pad_type[gpio_idx] = type; - - raw_spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); - - return port->gc.direction_input(&port->gc, gpio_idx); + return port->gen_gc.gc.direction_input(&port->gen_gc.gc, gpio_idx); } static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) { void __iomem *reg = port->base; - unsigned long flags; u32 bit, val; int edge; - raw_spin_lock_irqsave(&port->gc.bgpio_lock, flags); + guard(gpio_generic_lock_irqsave)(&port->gen_gc); reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ bit = gpio & 0xf; @@ -250,12 +248,9 @@ static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) } else { pr_err("mxc: invalid configuration for GPIO %d: %x\n", gpio, edge); - goto unlock; + return; } writel(val | (edge << (bit << 1)), reg); - -unlock: - raw_spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); } /* handle 32 interrupts in one status register */ @@ -420,6 +415,7 @@ static void mxc_update_irq_chained_handler(struct mxc_gpio_port *port, bool enab static int mxc_gpio_probe(struct platform_device *pdev) { + struct gpio_generic_chip_config config = { }; struct device_node *np = pdev->dev.of_node; struct mxc_gpio_port *port; int irq_count; @@ -479,27 +475,31 @@ static int mxc_gpio_probe(struct platform_device *pdev) port->mx_irq_handler = mx3_gpio_irq_handler; mxc_update_irq_chained_handler(port, true); - err = bgpio_init(&port->gc, &pdev->dev, 4, - port->base + GPIO_PSR, - port->base + GPIO_DR, NULL, - port->base + GPIO_GDIR, NULL, - BGPIOF_READ_OUTPUT_REG_SET); + + config.dev = &pdev->dev; + config.sz = 4; + config.dat = port->base + GPIO_PSR; + config.set = port->base + GPIO_DR; + config.dirout = port->base + GPIO_GDIR; + config.flags = BGPIOF_READ_OUTPUT_REG_SET; + + err = gpio_generic_chip_init(&port->gen_gc, &config); if (err) goto out_bgio; - port->gc.request = mxc_gpio_request; - port->gc.free = mxc_gpio_free; - port->gc.to_irq = mxc_gpio_to_irq; + port->gen_gc.gc.request = mxc_gpio_request; + port->gen_gc.gc.free = mxc_gpio_free; + port->gen_gc.gc.to_irq = mxc_gpio_to_irq; /* * Driver is DT-only, so a fixed base needs only be maintained for legacy * userspace with sysfs interface. */ if (IS_ENABLED(CONFIG_GPIO_SYSFS)) - port->gc.base = of_alias_get_id(np, "gpio") * 32; + port->gen_gc.gc.base = of_alias_get_id(np, "gpio") * 32; else /* silence boot time warning */ - port->gc.base = -1; + port->gen_gc.gc.base = -1; - err = devm_gpiochip_add_data(&pdev->dev, &port->gc, port); + err = devm_gpiochip_add_data(&pdev->dev, &port->gen_gc.gc, port); if (err) goto out_bgio; @@ -509,8 +509,8 @@ static int mxc_gpio_probe(struct platform_device *pdev) goto out_bgio; } - port->domain = irq_domain_create_legacy(of_fwnode_handle(np), 32, irq_base, 0, - &irq_domain_simple_ops, NULL); + port->domain = irq_domain_create_legacy(dev_fwnode(&pdev->dev), 32, irq_base, 0, + &irq_domain_simple_ops, NULL); if (!port->domain) { err = -ENODEV; goto out_bgio; @@ -573,7 +573,8 @@ static bool mxc_gpio_generic_config(struct mxc_gpio_port *port, 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 (gpiochip_generic_config(&port->gen_gc.gc, + offset, conf) == 0); return false; } |