diff options
Diffstat (limited to 'drivers/gpio/gpio-mvebu.c')
| -rw-r--r-- | drivers/gpio/gpio-mvebu.c | 144 |
1 files changed, 65 insertions, 79 deletions
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 4c1f9e1091b7..22c36b79e249 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * GPIO driver for Marvell SoCs * @@ -7,10 +8,6 @@ * Andrew Lunn <andrew@lunn.ch> * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * This driver is a fairly straightforward GPIO driver for the * complete family of Marvell EBU SoC platforms (Orion, Dove, * Kirkwood, Discovery, Armada 370/XP). The only complexity of this @@ -45,12 +42,14 @@ #include <linux/irqchip/chained_irq.h> #include <linux/irqdomain.h> #include <linux/mfd/syscon.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/pwm.h> #include <linux/regmap.h> #include <linux/slab.h> +#include <linux/string_choices.h> /* * GPIO unit register offsets. @@ -101,7 +100,6 @@ struct mvebu_pwm { u32 offset; unsigned long clk_rate; struct gpio_desc *gpiod; - struct pwm_chip chip; spinlock_t lock; struct mvebu_gpio_chip *mvchip; @@ -300,12 +298,12 @@ static unsigned int mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm) /* * Functions implementing the gpio_chip methods */ -static void mvebu_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) +static int mvebu_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) { struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); - regmap_update_bits(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, - BIT(pin), value ? BIT(pin) : 0); + return regmap_update_bits(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, + BIT(pin), value ? BIT(pin) : 0); } static int mvebu_gpio_get(struct gpio_chip *chip, unsigned int pin) @@ -348,7 +346,7 @@ static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned int pin) * Check with the pinctrl driver whether this pin is usable as * an input GPIO */ - ret = pinctrl_gpio_direction_input(chip->base + pin); + ret = pinctrl_gpio_direction_input(chip, pin); if (ret) return ret; @@ -368,7 +366,7 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned int pin, * Check with the pinctrl driver whether this pin is usable as * an output GPIO */ - ret = pinctrl_gpio_direction_output(chip->base + pin); + ret = pinctrl_gpio_direction_output(chip, pin); if (ret) return ret; @@ -410,9 +408,8 @@ static void mvebu_gpio_irq_ack(struct irq_data *d) struct mvebu_gpio_chip *mvchip = gc->private; u32 mask = d->mask; - irq_gc_lock(gc); + guard(raw_spinlock)(&gc->lock); mvebu_gpio_write_edge_cause(mvchip, ~mask); - irq_gc_unlock(gc); } static void mvebu_gpio_edge_irq_mask(struct irq_data *d) @@ -422,10 +419,9 @@ static void mvebu_gpio_edge_irq_mask(struct irq_data *d) struct irq_chip_type *ct = irq_data_get_chip_type(d); u32 mask = d->mask; - irq_gc_lock(gc); + guard(raw_spinlock)(&gc->lock); ct->mask_cache_priv &= ~mask; mvebu_gpio_write_edge_mask(mvchip, ct->mask_cache_priv); - irq_gc_unlock(gc); } static void mvebu_gpio_edge_irq_unmask(struct irq_data *d) @@ -435,11 +431,10 @@ static void mvebu_gpio_edge_irq_unmask(struct irq_data *d) struct irq_chip_type *ct = irq_data_get_chip_type(d); u32 mask = d->mask; - irq_gc_lock(gc); + guard(raw_spinlock)(&gc->lock); mvebu_gpio_write_edge_cause(mvchip, ~mask); ct->mask_cache_priv |= mask; mvebu_gpio_write_edge_mask(mvchip, ct->mask_cache_priv); - irq_gc_unlock(gc); } static void mvebu_gpio_level_irq_mask(struct irq_data *d) @@ -449,10 +444,9 @@ static void mvebu_gpio_level_irq_mask(struct irq_data *d) struct irq_chip_type *ct = irq_data_get_chip_type(d); u32 mask = d->mask; - irq_gc_lock(gc); + guard(raw_spinlock)(&gc->lock); ct->mask_cache_priv &= ~mask; mvebu_gpio_write_level_mask(mvchip, ct->mask_cache_priv); - irq_gc_unlock(gc); } static void mvebu_gpio_level_irq_unmask(struct irq_data *d) @@ -462,10 +456,9 @@ static void mvebu_gpio_level_irq_unmask(struct irq_data *d) struct irq_chip_type *ct = irq_data_get_chip_type(d); u32 mask = d->mask; - irq_gc_lock(gc); + guard(raw_spinlock)(&gc->lock); ct->mask_cache_priv |= mask; mvebu_gpio_write_level_mask(mvchip, ct->mask_cache_priv); - irq_gc_unlock(gc); } /***************************************************************************** @@ -580,11 +573,10 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc) for (i = 0; i < mvchip->chip.ngpio; i++) { int irq; - irq = irq_find_mapping(mvchip->domain, i); - if (!(cause & BIT(i))) continue; + irq = irq_find_mapping(mvchip->domain, i); type = irq_get_trigger_type(irq); if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { /* Swap polarity (race with GPIO line) */ @@ -609,7 +601,6 @@ static const struct regmap_config mvebu_gpio_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .fast_io = true, }; /* @@ -617,7 +608,7 @@ static const struct regmap_config mvebu_gpio_regmap_config = { */ static struct mvebu_pwm *to_mvebu_pwm(struct pwm_chip *chip) { - return container_of(chip, struct mvebu_pwm, chip); + return pwmchip_get_drvdata(chip); } static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) @@ -660,9 +651,10 @@ static void mvebu_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) spin_unlock_irqrestore(&mvpwm->lock, flags); } -static void mvebu_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) { +static int mvebu_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) +{ struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); struct mvebu_gpio_chip *mvchip = mvpwm->mvchip; @@ -696,6 +688,8 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip, state->enabled = false; spin_unlock_irqrestore(&mvpwm->lock, flags); + + return 0; } static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, @@ -707,6 +701,9 @@ static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, unsigned long flags; unsigned int on, off; + if (state->polarity != PWM_POLARITY_NORMAL) + return -EINVAL; + val = (unsigned long long) mvpwm->clk_rate * state->duty_cycle; do_div(val, NSEC_PER_SEC); if (val > UINT_MAX + 1ULL) @@ -753,7 +750,6 @@ static const struct pwm_ops mvebu_pwm_ops = { .free = mvebu_pwm_free, .get_state = mvebu_pwm_get_state, .apply = mvebu_pwm_apply, - .owner = THIS_MODULE, }; static void __maybe_unused mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip) @@ -786,12 +782,17 @@ static int mvebu_pwm_probe(struct platform_device *pdev, { struct device *dev = &pdev->dev; struct mvebu_pwm *mvpwm; + struct pwm_chip *chip; void __iomem *base; u32 offset; u32 set; - if (of_device_is_compatible(mvchip->chip.of_node, - "marvell,armada-370-gpio")) { + if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) { + int ret = device_property_read_u32(dev, "marvell,pwm-offset", + &offset); + if (ret < 0) + return 0; + } else { /* * There are only two sets of PWM configuration registers for * all the GPIO lines on those SoCs which this driver reserves @@ -801,21 +802,16 @@ static int mvebu_pwm_probe(struct platform_device *pdev, if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm")) return 0; offset = 0; - } else if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) { - int ret = of_property_read_u32(dev->of_node, - "marvell,pwm-offset", &offset); - if (ret < 0) - return 0; - } else { - return 0; } if (IS_ERR(mvchip->clk)) return PTR_ERR(mvchip->clk); - mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL); - if (!mvpwm) - return -ENOMEM; + chip = devm_pwmchip_alloc(dev, mvchip->chip.ngpio, sizeof(*mvpwm)); + if (IS_ERR(chip)) + return PTR_ERR(chip); + mvpwm = to_mvebu_pwm(chip); + mvchip->mvpwm = mvpwm; mvpwm->mvchip = mvchip; mvpwm->offset = offset; @@ -868,20 +864,11 @@ static int mvebu_pwm_probe(struct platform_device *pdev, return -EINVAL; } - mvpwm->chip.dev = dev; - mvpwm->chip.ops = &mvebu_pwm_ops; - mvpwm->chip.npwm = mvchip->chip.ngpio; - /* - * There may already be some PWM allocated, so we can't force - * mvpwm->chip.base to a fixed point like mvchip->chip.base. - * So, we let pwmchip_add() do the numbering and take the next free - * region. - */ - mvpwm->chip.base = -1; + chip->ops = &mvebu_pwm_ops; spin_lock_init(&mvpwm->lock); - return pwmchip_add(&mvpwm->chip); + return devm_pwmchip_add(dev, chip); } #ifdef CONFIG_DEBUG_FS @@ -910,18 +897,18 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) msk = BIT(i); is_out = !(io_conf & msk); - seq_printf(s, " gpio-%-3d (%-20.20s)", chip->base + i, label); + seq_printf(s, " gpio-%-3d (%-20.20s)", i, label); if (is_out) { seq_printf(s, " out %s %s\n", - out & msk ? "hi" : "lo", + str_hi_lo(out & msk), blink & msk ? "(blink )" : ""); continue; } seq_printf(s, " in %s (act %s) - IRQ", - (data_in ^ in_pol) & msk ? "hi" : "lo", - in_pol & msk ? "lo" : "hi"); + str_hi_lo((data_in ^ in_pol) & msk), + str_lo_hi(in_pol & msk)); if (!((edg_msk | lvl_msk) & msk)) { seq_puts(s, " disabled\n"); continue; @@ -1009,7 +996,7 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state) BUG(); } - if (IS_ENABLED(CONFIG_PWM)) + if (IS_REACHABLE(CONFIG_PWM)) mvebu_pwm_suspend(mvchip); return 0; @@ -1061,7 +1048,7 @@ static int mvebu_gpio_resume(struct platform_device *pdev) BUG(); } - if (IS_ENABLED(CONFIG_PWM)) + if (IS_REACHABLE(CONFIG_PWM)) mvebu_pwm_resume(mvchip); return 0; @@ -1113,16 +1100,22 @@ static int mvebu_gpio_probe_syscon(struct platform_device *pdev, if (IS_ERR(mvchip->regs)) return PTR_ERR(mvchip->regs); - if (of_property_read_u32(pdev->dev.of_node, "offset", &mvchip->offset)) + if (device_property_read_u32(&pdev->dev, "offset", &mvchip->offset)) return -EINVAL; return 0; } +static void mvebu_gpio_remove_irq_domain(void *data) +{ + struct irq_domain *domain = data; + + irq_domain_remove(domain); +} + static int mvebu_gpio_probe(struct platform_device *pdev) { struct mvebu_gpio_chip *mvchip; - const struct of_device_id *match; struct device_node *np = pdev->dev.of_node; struct irq_chip_generic *gc; struct irq_chip_type *ct; @@ -1132,11 +1125,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) int i, cpu, id; int err; - match = of_match_device(mvebu_gpio_of_match, &pdev->dev); - if (match) - soc_variant = (unsigned long) match->data; - else - soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION; + soc_variant = (unsigned long)device_get_match_data(&pdev->dev); /* Some gpio controllers do not provide irq support */ err = platform_irq_count(pdev); @@ -1152,7 +1141,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mvchip); - if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) { + if (device_property_read_u32(&pdev->dev, "ngpios", &ngpios)) { dev_err(&pdev->dev, "Missing ngpios OF property\n"); return -ENODEV; } @@ -1235,7 +1224,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) devm_gpiochip_add_data(&pdev->dev, &mvchip->chip, mvchip); /* Some MVEBU SoCs have simple PWM support for GPIO lines */ - if (IS_ENABLED(CONFIG_PWM)) { + if (IS_REACHABLE(CONFIG_PWM)) { err = mvebu_pwm_probe(pdev, mvchip, id); if (err) return err; @@ -1245,22 +1234,26 @@ static int mvebu_gpio_probe(struct platform_device *pdev) if (!have_irqs) return 0; - mvchip->domain = - irq_domain_add_linear(np, ngpios, &irq_generic_chip_ops, NULL); + mvchip->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), ngpios, + &irq_generic_chip_ops, NULL); if (!mvchip->domain) { dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n", mvchip->chip.label); - err = -ENODEV; - goto err_pwm; + return -ENODEV; } + err = devm_add_action_or_reset(&pdev->dev, mvebu_gpio_remove_irq_domain, + mvchip->domain); + if (err) + return err; + err = irq_alloc_domain_generic_chips( mvchip->domain, ngpios, 2, np->name, handle_level_irq, IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, 0); if (err) { dev_err(&pdev->dev, "couldn't allocate irq chips %s (DT).\n", mvchip->chip.label); - goto err_domain; + return err; } /* @@ -1300,13 +1293,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev) } return 0; - -err_domain: - irq_domain_remove(mvchip->domain); -err_pwm: - pwmchip_remove(&mvchip->mvpwm->chip); - - return err; } static struct platform_driver mvebu_gpio_driver = { |
