Prepare v2024.10
[platform/kernel/u-boot.git] / drivers / gpio / imx_rgpio2p.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2016 Freescale Semiconductor, Inc.
4  *
5  * RGPIO2P driver for the Freescale i.MX7ULP.
6  */
7
8 #include <dm.h>
9 #include <errno.h>
10 #include <fdtdec.h>
11 #include <asm/gpio.h>
12 #include <asm/io.h>
13 #include <dm/device-internal.h>
14 #include <malloc.h>
15
16 enum imx_rgpio2p_direction {
17         IMX_RGPIO2P_DIRECTION_IN,
18         IMX_RGPIO2P_DIRECTION_OUT,
19 };
20
21 #define GPIO_PER_BANK                   32
22
23 struct imx_rgpio2p_soc_data {
24         bool have_dual_base;
25 };
26
27 #define IMX8ULP_GPIO_BASE_OFF   0x40
28
29 struct imx_rgpio2p_data {
30         struct gpio_regs *regs;
31 };
32
33 struct imx_rgpio2p_plat {
34         int bank_index;
35         struct gpio_regs *regs;
36 };
37
38 static int imx_rgpio2p_is_output(struct gpio_regs *regs, int offset)
39 {
40         u32 val;
41
42         val = readl(&regs->gpio_pddr);
43
44         return val & (1 << offset) ? 1 : 0;
45 }
46
47 static int imx_rgpio2p_bank_get_direction(struct gpio_regs *regs, int offset)
48 {
49         if ((readl(&regs->gpio_pddr) >> offset) & 0x01)
50                 return IMX_RGPIO2P_DIRECTION_OUT;
51
52         return IMX_RGPIO2P_DIRECTION_IN;
53 }
54
55 static void imx_rgpio2p_bank_direction(struct gpio_regs *regs, int offset,
56                                     enum imx_rgpio2p_direction direction)
57 {
58         u32 l;
59
60         l = readl(&regs->gpio_pddr);
61
62         switch (direction) {
63         case IMX_RGPIO2P_DIRECTION_OUT:
64                 l |= 1 << offset;
65                 break;
66         case IMX_RGPIO2P_DIRECTION_IN:
67                 l &= ~(1 << offset);
68         }
69         writel(l, &regs->gpio_pddr);
70 }
71
72 static void imx_rgpio2p_bank_set_value(struct gpio_regs *regs, int offset,
73                                     int value)
74 {
75         if (value)
76                 writel((1 << offset), &regs->gpio_psor);
77         else
78                 writel((1 << offset), &regs->gpio_pcor);
79 }
80
81 static int imx_rgpio2p_bank_get_value(struct gpio_regs *regs, int offset)
82 {
83         if (imx_rgpio2p_bank_get_direction(regs, offset) ==
84             IMX_RGPIO2P_DIRECTION_IN)
85                 return (readl(&regs->gpio_pdir) >> offset) & 0x01;
86
87         return (readl(&regs->gpio_pdor) >> offset) & 0x01;
88 }
89
90 static int  imx_rgpio2p_direction_input(struct udevice *dev, unsigned offset)
91 {
92         struct imx_rgpio2p_data *bank = dev_get_priv(dev);
93
94         /* Configure GPIO direction as input. */
95         imx_rgpio2p_bank_direction(bank->regs, offset, IMX_RGPIO2P_DIRECTION_IN);
96
97         return 0;
98 }
99
100 static int imx_rgpio2p_direction_output(struct udevice *dev, unsigned offset,
101                                        int value)
102 {
103         struct imx_rgpio2p_data *bank = dev_get_priv(dev);
104
105         /* Configure GPIO output value. */
106         imx_rgpio2p_bank_set_value(bank->regs, offset, value);
107
108         /* Configure GPIO direction as output. */
109         imx_rgpio2p_bank_direction(bank->regs, offset, IMX_RGPIO2P_DIRECTION_OUT);
110
111         return 0;
112 }
113
114 static int imx_rgpio2p_get_value(struct udevice *dev, unsigned offset)
115 {
116         struct imx_rgpio2p_data *bank = dev_get_priv(dev);
117
118         return imx_rgpio2p_bank_get_value(bank->regs, offset);
119 }
120
121 static int imx_rgpio2p_set_value(struct udevice *dev, unsigned offset,
122                                  int value)
123 {
124         struct imx_rgpio2p_data *bank = dev_get_priv(dev);
125
126         imx_rgpio2p_bank_set_value(bank->regs, offset, value);
127
128         return 0;
129 }
130
131 static int imx_rgpio2p_get_function(struct udevice *dev, unsigned offset)
132 {
133         struct imx_rgpio2p_data *bank = dev_get_priv(dev);
134
135         /* GPIOF_FUNC is not implemented yet */
136         if (imx_rgpio2p_is_output(bank->regs, offset))
137                 return GPIOF_OUTPUT;
138         else
139                 return GPIOF_INPUT;
140 }
141
142 static const struct dm_gpio_ops imx_rgpio2p_ops = {
143         .direction_input        = imx_rgpio2p_direction_input,
144         .direction_output       = imx_rgpio2p_direction_output,
145         .get_value              = imx_rgpio2p_get_value,
146         .set_value              = imx_rgpio2p_set_value,
147         .get_function           = imx_rgpio2p_get_function,
148 };
149
150 static int imx_rgpio2p_probe(struct udevice *dev)
151 {
152         struct imx_rgpio2p_data *bank = dev_get_priv(dev);
153         struct imx_rgpio2p_plat *plat = dev_get_plat(dev);
154         struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
155         int banknum;
156         char name[18], *str;
157
158         banknum = plat->bank_index;
159         sprintf(name, "GPIO%d_", banknum + 1);
160         str = strdup(name);
161         if (!str)
162                 return -ENOMEM;
163         uc_priv->bank_name = str;
164         uc_priv->gpio_count = GPIO_PER_BANK;
165         bank->regs = plat->regs;
166
167         return 0;
168 }
169
170 static int imx_rgpio2p_bind(struct udevice *dev)
171 {
172         struct imx_rgpio2p_plat *plat = dev_get_plat(dev);
173         struct imx_rgpio2p_soc_data *data =
174                 (struct imx_rgpio2p_soc_data *)dev_get_driver_data(dev);
175         bool dual_base = data->have_dual_base;
176         fdt_addr_t addr;
177
178         /*
179          * If plat already exsits, directly return.
180          * Actually only when DT is not supported, plat
181          * is statically initialized in U_BOOT_DRVINFOS.Here
182          * will return.
183          */
184         if (plat)
185                 return 0;
186
187         /*
188          * Handle legacy compatible combinations which used two reg values
189          * for the i.MX8ULP and i.MX93.
190          */
191         if (device_is_compatible(dev, "fsl,imx7ulp-gpio") &&
192             (device_is_compatible(dev, "fsl,imx93-gpio") ||
193             (device_is_compatible(dev, "fsl,imx8ulp-gpio"))))
194                 dual_base = true;
195
196         if (dual_base) {
197                 addr = devfdt_get_addr_index(dev, 1);
198                 if (addr == FDT_ADDR_T_NONE)
199                         return -EINVAL;
200         } else {
201                 addr = devfdt_get_addr_index(dev, 0);
202                 if (addr == FDT_ADDR_T_NONE)
203                         return -EINVAL;
204
205                 addr += IMX8ULP_GPIO_BASE_OFF;
206         }
207
208         /*
209          * TODO:
210          * When every board is converted to driver model and DT is supported,
211          * this can be done by auto-alloc feature, but not using calloc
212          * to alloc memory for plat.
213          *
214          * For example imx_rgpio2p_plat uses platform data rather than device
215          * tree.
216          *
217          * NOTE: DO NOT COPY this code if you are using device tree.
218          */
219         plat = calloc(1, sizeof(*plat));
220         if (!plat)
221                 return -ENOMEM;
222
223         plat->regs = (struct gpio_regs *)addr;
224         plat->bank_index = dev_seq(dev);
225         dev_set_plat(dev, plat);
226
227         return 0;
228 }
229
230 static struct imx_rgpio2p_soc_data imx7ulp_data = {
231         .have_dual_base = true,
232 };
233
234 static struct imx_rgpio2p_soc_data imx8ulp_data = {
235         .have_dual_base = false,
236 };
237
238 static const struct udevice_id imx_rgpio2p_ids[] = {
239         { .compatible = "fsl,imx7ulp-gpio", .data = (ulong)&imx7ulp_data },
240         { .compatible = "fsl,imx8ulp-gpio", .data = (ulong)&imx8ulp_data },
241         { }
242 };
243
244 U_BOOT_DRIVER(imx_rgpio2p) = {
245         .name   = "imx_rgpio2p",
246         .id     = UCLASS_GPIO,
247         .ops    = &imx_rgpio2p_ops,
248         .probe  = imx_rgpio2p_probe,
249         .priv_auto      = sizeof(struct imx_rgpio2p_plat),
250         .of_match = imx_rgpio2p_ids,
251         .bind   = imx_rgpio2p_bind,
252 };
253
254 #if !CONFIG_IS_ENABLED(OF_CONTROL)
255 static const struct imx_rgpio2p_plat imx_plat[] = {
256         { 0, (struct gpio_regs *)RGPIO2P_GPIO1_BASE_ADDR },
257         { 1, (struct gpio_regs *)RGPIO2P_GPIO2_BASE_ADDR },
258         { 2, (struct gpio_regs *)RGPIO2P_GPIO3_BASE_ADDR },
259         { 3, (struct gpio_regs *)RGPIO2P_GPIO4_BASE_ADDR },
260         { 4, (struct gpio_regs *)RGPIO2P_GPIO5_BASE_ADDR },
261         { 5, (struct gpio_regs *)RGPIO2P_GPIO6_BASE_ADDR },
262 };
263
264 U_BOOT_DRVINFOS(imx_rgpio2ps) = {
265         { "imx_rgpio2p", &imx_plat[0] },
266         { "imx_rgpio2p", &imx_plat[1] },
267         { "imx_rgpio2p", &imx_plat[2] },
268         { "imx_rgpio2p", &imx_plat[3] },
269         { "imx_rgpio2p", &imx_plat[4] },
270         { "imx_rgpio2p", &imx_plat[5] },
271 };
272 #endif