diff options
-rw-r--r-- | drivers/gpio/gpio-mvebu.c | 155 |
1 files changed, 110 insertions, 45 deletions
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 1c1549db5623..aeb3cb9dc340 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -89,8 +89,16 @@ #define MVEBU_GPIO_SOC_VARIANT_ARMADAXP 0x3 #define MVEBU_GPIO_SOC_VARIANT_A8K 0x4 +#define MVEBU_PWM_SOC_VARIANT_ARMADA370 1 +#define MVEBU_PWM_SOC_VARIANT_A8K 2 + #define MVEBU_MAX_GPIO_PER_BANK 32 +struct mvebu_gpio_soc_variant { + int gpio; + int pwm; +}; + struct mvebu_pwm { struct regmap *regs; u32 offset; @@ -773,43 +781,82 @@ static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip) } static int mvebu_pwm_probe(struct platform_device *pdev, + const struct mvebu_gpio_soc_variant *soc_variant, struct mvebu_gpio_chip *mvchip, int id) { struct device *dev = &pdev->dev; struct mvebu_pwm *mvpwm; + struct regmap *regs; void __iomem *base; - u32 set; + u32 set, offset; - if (!of_device_is_compatible(mvchip->chip.of_node, - "marvell,armada-370-gpio")) + if (!soc_variant->pwm) return 0; - /* - * There are only two sets of PWM configuration registers for - * all the GPIO lines on those SoCs which this driver reserves - * for the first two GPIO chips. So if the resource is missing - * we can't treat it as an error. - */ - if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm")) - return 0; + switch (soc_variant->pwm) { + case MVEBU_PWM_SOC_VARIANT_ARMADA370: + /* + * There are only two sets of PWM configuration registers for + * all the GPIO lines on those SoCs which this driver reserves + * for the first two GPIO chips. So if the resource is missing + * we can't treat it as an error. + */ + if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm")) + return 0; - if (IS_ERR(mvchip->clk)) - return PTR_ERR(mvchip->clk); + if (IS_ERR(mvchip->clk)) + return PTR_ERR(mvchip->clk); - /* - * Use set A for lines of GPIO chip with id 0, B for GPIO chip - * with id 1. Don't allow further GPIO chips to be used for PWM. - */ - if (id == 0) - set = 0; - else if (id == 1) - set = U32_MAX; - else - return -EINVAL; + base = devm_platform_ioremap_resource_byname(pdev, "pwm"); + if (IS_ERR(base)) + return PTR_ERR(base); - regmap_write(mvchip->regs, - GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set); + regs = devm_regmap_init_mmio(&pdev->dev, base, + &mvebu_gpio_regmap_config); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + /* + * Use set A for lines of GPIO chip with id 0, B for GPIO chip + * with id 1. Don't allow further GPIO chips to be used for PWM. + */ + if (id == 0) + set = 0; + else if (id == 1) + set = U32_MAX; + else + return -EINVAL; + + offset = 0; + break; + + case MVEBU_PWM_SOC_VARIANT_A8K: + /* + * If there is no clock, this is an older DT, so avoid + * registering the PWM. + */ + if (IS_ERR(mvchip->clk)) + return 0; + + regs = mvchip->regs; + switch (id) { + case 1: + offset = 0x1f0; + set = 0; + break; + case 2: + offset = 0x1f8; + set = U32_MAX; + break; + default: + return -EINVAL; + } + break; + + default: + return -EINVAL; + } mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL); if (!mvpwm) @@ -817,15 +864,11 @@ static int mvebu_pwm_probe(struct platform_device *pdev, mvchip->mvpwm = mvpwm; mvpwm->mvchip = mvchip; + mvpwm->regs = regs; + mvpwm->offset = offset; - base = devm_platform_ioremap_resource_byname(pdev, "pwm"); - if (IS_ERR(base)) - return PTR_ERR(base); - - mvpwm->regs = devm_regmap_init_mmio(&pdev->dev, base, - &mvebu_gpio_regmap_config); - if (IS_ERR(mvpwm->regs)) - return PTR_ERR(mvpwm->regs); + regmap_write(mvchip->regs, + GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set); mvpwm->clk_rate = clk_get_rate(mvchip->clk); if (!mvpwm->clk_rate) { @@ -902,26 +945,48 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) #define mvebu_gpio_dbg_show NULL #endif +static const struct mvebu_gpio_soc_variant mvebu_gpio_orion_variant = { + .gpio = MVEBU_GPIO_SOC_VARIANT_ORION, +}; + +static const struct mvebu_gpio_soc_variant mvebu_gpio_mv78200_variant = { + .gpio = MVEBU_GPIO_SOC_VARIANT_MV78200, +}; + +static const struct mvebu_gpio_soc_variant mvebu_gpio_armadaxp_variant = { + .gpio = MVEBU_GPIO_SOC_VARIANT_ARMADAXP, +}; + +static const struct mvebu_gpio_soc_variant mvebu_gpio_armada370_variant = { + .gpio = MVEBU_GPIO_SOC_VARIANT_ORION, + .pwm = MVEBU_PWM_SOC_VARIANT_ARMADA370, +}; + +static const struct mvebu_gpio_soc_variant mvebu_gpio_a8k_variant = { + .gpio = MVEBU_GPIO_SOC_VARIANT_A8K, + .pwm = MVEBU_PWM_SOC_VARIANT_A8K, +}; + static const struct of_device_id mvebu_gpio_of_match[] = { { .compatible = "marvell,orion-gpio", - .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, + .data = &mvebu_gpio_orion_variant, }, { .compatible = "marvell,mv78200-gpio", - .data = (void *) MVEBU_GPIO_SOC_VARIANT_MV78200, + .data = &mvebu_gpio_mv78200_variant, }, { .compatible = "marvell,armadaxp-gpio", - .data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP, + .data = &mvebu_gpio_armadaxp_variant, }, { .compatible = "marvell,armada-370-gpio", - .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, + .data = &mvebu_gpio_armada370_variant, }, { .compatible = "marvell,armada-8k-gpio", - .data = (void *) MVEBU_GPIO_SOC_VARIANT_A8K, + .data = &mvebu_gpio_a8k_variant, }, { /* sentinel */ @@ -1086,6 +1151,7 @@ static int mvebu_gpio_probe_syscon(struct platform_device *pdev, static int mvebu_gpio_probe(struct platform_device *pdev) { + const struct mvebu_gpio_soc_variant *soc_variant; struct mvebu_gpio_chip *mvchip; const struct of_device_id *match; struct device_node *np = pdev->dev.of_node; @@ -1093,15 +1159,14 @@ static int mvebu_gpio_probe(struct platform_device *pdev) struct irq_chip_type *ct; unsigned int ngpios; bool have_irqs; - int soc_variant; int i, cpu, id; int err; match = of_match_device(mvebu_gpio_of_match, &pdev->dev); if (match) - soc_variant = (unsigned long) match->data; + soc_variant = match->data; else - soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION; + soc_variant = &mvebu_gpio_orion_variant; /* Some gpio controllers do not provide irq support */ err = platform_irq_count(pdev); @@ -1136,7 +1201,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) if (!IS_ERR(mvchip->clk)) clk_prepare_enable(mvchip->clk); - mvchip->soc_variant = soc_variant; + mvchip->soc_variant = soc_variant->gpio; mvchip->chip.label = dev_name(&pdev->dev); mvchip->chip.parent = &pdev->dev; mvchip->chip.request = gpiochip_generic_request; @@ -1154,7 +1219,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->chip.of_node = np; mvchip->chip.dbg_show = mvebu_gpio_dbg_show; - if (soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) + if (soc_variant->gpio == MVEBU_GPIO_SOC_VARIANT_A8K) err = mvebu_gpio_probe_syscon(pdev, mvchip); else err = mvebu_gpio_probe_raw(pdev, mvchip); @@ -1165,7 +1230,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) /* * Mask and clear GPIO interrupts. */ - switch (soc_variant) { + switch (soc_variant->gpio) { case MVEBU_GPIO_SOC_VARIANT_ORION: case MVEBU_GPIO_SOC_VARIANT_A8K: regmap_write(mvchip->regs, @@ -1205,7 +1270,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) /* Some MVEBU SoCs have simple PWM support for GPIO lines */ if (IS_ENABLED(CONFIG_PWM)) { - err = mvebu_pwm_probe(pdev, mvchip, id); + err = mvebu_pwm_probe(pdev, soc_variant, mvchip, id); if (err) return err; } |