Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: mvebu: add pwm support for Armada 8K/7K

Use the marvell,pwm-offset DT property to store the location of PWM
signal duration registers.

Since we have more than two GPIO chips per system, we can't use the
alias id to differentiate between them. Use the offset value for that.

Signed-off-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

authored by

Baruch Siach and committed by
Bartosz Golaszewski
85b7d8ab 94de03cc

+68 -33
+68 -33
drivers/gpio/gpio-mvebu.c
··· 70 70 */ 71 71 #define PWM_BLINK_ON_DURATION_OFF 0x0 72 72 #define PWM_BLINK_OFF_DURATION_OFF 0x4 73 + #define PWM_BLINK_COUNTER_B_OFF 0x8 73 74 75 + /* Armada 8k variant gpios register offsets */ 76 + #define AP80X_GPIO0_OFF_A8K 0x1040 77 + #define CP11X_GPIO0_OFF_A8K 0x100 78 + #define CP11X_GPIO1_OFF_A8K 0x140 74 79 75 80 /* The MV78200 has per-CPU registers for edge mask and level mask */ 76 81 #define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18) ··· 98 93 99 94 struct mvebu_pwm { 100 95 struct regmap *regs; 96 + u32 offset; 101 97 unsigned long clk_rate; 102 98 struct gpio_desc *gpiod; 103 99 struct pwm_chip chip; ··· 289 283 */ 290 284 static unsigned int mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm) 291 285 { 292 - return PWM_BLINK_ON_DURATION_OFF; 286 + return mvpwm->offset + PWM_BLINK_ON_DURATION_OFF; 293 287 } 294 288 295 289 static unsigned int mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm) 296 290 { 297 - return PWM_BLINK_OFF_DURATION_OFF; 291 + return mvpwm->offset + PWM_BLINK_OFF_DURATION_OFF; 298 292 } 299 293 300 294 /* ··· 787 781 struct device *dev = &pdev->dev; 788 782 struct mvebu_pwm *mvpwm; 789 783 void __iomem *base; 784 + u32 offset; 790 785 u32 set; 791 786 792 - if (!of_device_is_compatible(mvchip->chip.of_node, 793 - "marvell,armada-370-gpio")) 787 + if (of_device_is_compatible(mvchip->chip.of_node, 788 + "marvell,armada-370-gpio")) { 789 + /* 790 + * There are only two sets of PWM configuration registers for 791 + * all the GPIO lines on those SoCs which this driver reserves 792 + * for the first two GPIO chips. So if the resource is missing 793 + * we can't treat it as an error. 794 + */ 795 + if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm")) 796 + return 0; 797 + offset = 0; 798 + } else if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) { 799 + int ret = of_property_read_u32(dev->of_node, 800 + "marvell,pwm-offset", &offset); 801 + if (ret < 0) 802 + return 0; 803 + } else { 794 804 return 0; 795 - 796 - /* 797 - * There are only two sets of PWM configuration registers for 798 - * all the GPIO lines on those SoCs which this driver reserves 799 - * for the first two GPIO chips. So if the resource is missing 800 - * we can't treat it as an error. 801 - */ 802 - if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm")) 803 - return 0; 805 + } 804 806 805 807 if (IS_ERR(mvchip->clk)) 806 808 return PTR_ERR(mvchip->clk); 807 - 808 - /* 809 - * Use set A for lines of GPIO chip with id 0, B for GPIO chip 810 - * with id 1. Don't allow further GPIO chips to be used for PWM. 811 - */ 812 - if (id == 0) 813 - set = 0; 814 - else if (id == 1) 815 - set = U32_MAX; 816 - else 817 - return -EINVAL; 818 - regmap_write(mvchip->regs, 819 - GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set); 820 809 821 810 mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL); 822 811 if (!mvpwm) 823 812 return -ENOMEM; 824 813 mvchip->mvpwm = mvpwm; 825 814 mvpwm->mvchip = mvchip; 815 + mvpwm->offset = offset; 826 816 827 - base = devm_platform_ioremap_resource_byname(pdev, "pwm"); 828 - if (IS_ERR(base)) 829 - return PTR_ERR(base); 817 + if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) { 818 + mvpwm->regs = mvchip->regs; 830 819 831 - mvpwm->regs = devm_regmap_init_mmio(&pdev->dev, base, 832 - &mvebu_gpio_regmap_config); 833 - if (IS_ERR(mvpwm->regs)) 834 - return PTR_ERR(mvpwm->regs); 820 + switch (mvchip->offset) { 821 + case AP80X_GPIO0_OFF_A8K: 822 + case CP11X_GPIO0_OFF_A8K: 823 + /* Blink counter A */ 824 + set = 0; 825 + break; 826 + case CP11X_GPIO1_OFF_A8K: 827 + /* Blink counter B */ 828 + set = U32_MAX; 829 + mvpwm->offset += PWM_BLINK_COUNTER_B_OFF; 830 + break; 831 + default: 832 + return -EINVAL; 833 + } 834 + } else { 835 + base = devm_platform_ioremap_resource_byname(pdev, "pwm"); 836 + if (IS_ERR(base)) 837 + return PTR_ERR(base); 838 + 839 + mvpwm->regs = devm_regmap_init_mmio(&pdev->dev, base, 840 + &mvebu_gpio_regmap_config); 841 + if (IS_ERR(mvpwm->regs)) 842 + return PTR_ERR(mvpwm->regs); 843 + 844 + /* 845 + * Use set A for lines of GPIO chip with id 0, B for GPIO chip 846 + * with id 1. Don't allow further GPIO chips to be used for PWM. 847 + */ 848 + if (id == 0) 849 + set = 0; 850 + else if (id == 1) 851 + set = U32_MAX; 852 + else 853 + return -EINVAL; 854 + } 855 + 856 + regmap_write(mvchip->regs, 857 + GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set); 835 858 836 859 mvpwm->clk_rate = clk_get_rate(mvchip->clk); 837 860 if (!mvpwm->clk_rate) {