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

gpio: vf610: add imx7ulp support

The Rapid General-Purpose Input and Output with 2 Ports (RGPIO2P)
on MX7ULP is similar to GPIO on Vibrid. But unlike Vibrid, the
RGPIO2P has an extra Port Data Direction Register (PDDR) used
to configure the individual port pins for input or output.

We introduce a bool have_paddr with fsl_gpio_soc_data data
to distinguish this differences. And we support getting the output
status by checking the GPIO direction in PDDR.

Cc: Alexandre Courbot <gnurou@gmail.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Stefan Agner <stefan@agner.ch>
Cc: Fugang Duan <fugang.duan@nxp.com>
Cc: Peter Chen <peter.chen@nxp.com>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Dong Aisheng and committed by
Linus Walleij
659d8a62 ca1f3ae3

+43 -2
+43 -2
drivers/gpio/gpio-vf610.c
··· 30 30 31 31 #define VF610_GPIO_PER_PORT 32 32 32 33 + struct fsl_gpio_soc_data { 34 + /* SoCs has a Port Data Direction Register (PDDR) */ 35 + bool have_paddr; 36 + }; 37 + 33 38 struct vf610_gpio_port { 34 39 struct gpio_chip gc; 35 40 void __iomem *base; 36 41 void __iomem *gpio_base; 42 + const struct fsl_gpio_soc_data *sdata; 37 43 u8 irqc[VF610_GPIO_PER_PORT]; 38 44 int irq; 39 45 }; ··· 49 43 #define GPIO_PCOR 0x08 50 44 #define GPIO_PTOR 0x0c 51 45 #define GPIO_PDIR 0x10 46 + #define GPIO_PDDR 0x14 52 47 53 48 #define PORT_PCR(n) ((n) * 0x4) 54 49 #define PORT_PCR_IRQC_OFFSET 16 ··· 68 61 69 62 static struct irq_chip vf610_gpio_irq_chip; 70 63 64 + static const struct fsl_gpio_soc_data imx_data = { 65 + .have_paddr = true, 66 + }; 67 + 71 68 static const struct of_device_id vf610_gpio_dt_ids[] = { 72 - { .compatible = "fsl,vf610-gpio" }, 69 + { .compatible = "fsl,vf610-gpio", .data = NULL, }, 70 + { .compatible = "fsl,imx7ulp-gpio", .data = &imx_data, }, 73 71 { /* sentinel */ } 74 72 }; 75 73 ··· 91 79 static int vf610_gpio_get(struct gpio_chip *gc, unsigned int gpio) 92 80 { 93 81 struct vf610_gpio_port *port = gpiochip_get_data(gc); 82 + unsigned long mask = BIT(gpio); 83 + void __iomem *addr; 94 84 95 - return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDIR) & BIT(gpio)); 85 + if (port->sdata && port->sdata->have_paddr) { 86 + mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR); 87 + addr = mask ? port->gpio_base + GPIO_PDOR : 88 + port->gpio_base + GPIO_PDIR; 89 + return !!(vf610_gpio_readl(addr) & BIT(gpio)); 90 + } else { 91 + return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDIR) 92 + & BIT(gpio)); 93 + } 96 94 } 97 95 98 96 static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) ··· 118 96 119 97 static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) 120 98 { 99 + struct vf610_gpio_port *port = gpiochip_get_data(chip); 100 + unsigned long mask = BIT(gpio); 101 + u32 val; 102 + 103 + if (port->sdata && port->sdata->have_paddr) { 104 + val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR); 105 + val &= ~mask; 106 + vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR); 107 + } 108 + 121 109 return pinctrl_gpio_direction_input(chip->base + gpio); 122 110 } 123 111 124 112 static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, 125 113 int value) 126 114 { 115 + struct vf610_gpio_port *port = gpiochip_get_data(chip); 116 + unsigned long mask = BIT(gpio); 117 + 118 + if (port->sdata && port->sdata->have_paddr) 119 + vf610_gpio_writel(mask, port->gpio_base + GPIO_PDDR); 120 + 127 121 vf610_gpio_set(chip, gpio, value); 128 122 129 123 return pinctrl_gpio_direction_output(chip->base + gpio); ··· 254 216 255 217 static int vf610_gpio_probe(struct platform_device *pdev) 256 218 { 219 + const struct of_device_id *of_id = of_match_device(vf610_gpio_dt_ids, 220 + &pdev->dev); 257 221 struct device *dev = &pdev->dev; 258 222 struct device_node *np = dev->of_node; 259 223 struct vf610_gpio_port *port; ··· 267 227 if (!port) 268 228 return -ENOMEM; 269 229 230 + port->sdata = of_id->data; 270 231 iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); 271 232 port->base = devm_ioremap_resource(dev, iores); 272 233 if (IS_ERR(port->base))