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