]> git.ipfire.org Git - thirdparty/u-boot.git/blame - drivers/gpio/imx_rgpio2p.c
Revert "Merge patch series "arm: dts: am62-beagleplay: Fix Beagleplay Ethernet""
[thirdparty/u-boot.git] / drivers / gpio / imx_rgpio2p.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
d665eb61
PF
2/*
3 * Copyright 2016 Freescale Semiconductor, Inc.
4 *
5 * RGPIO2P driver for the Freescale i.MX7ULP.
d665eb61
PF
6 */
7
d678a59d 8#include <common.h>
d665eb61
PF
9#include <dm.h>
10#include <errno.h>
11#include <fdtdec.h>
12#include <asm/gpio.h>
13#include <asm/io.h>
0fd3d911 14#include <dm/device-internal.h>
d665eb61
PF
15#include <malloc.h>
16
d665eb61
PF
17enum imx_rgpio2p_direction {
18 IMX_RGPIO2P_DIRECTION_IN,
19 IMX_RGPIO2P_DIRECTION_OUT,
20};
21
22#define GPIO_PER_BANK 32
23
51cfa66f
PF
24struct imx_rgpio2p_soc_data {
25 bool have_dual_base;
26};
27
28#define IMX8ULP_GPIO_BASE_OFF 0x40
29
d665eb61
PF
30struct imx_rgpio2p_data {
31 struct gpio_regs *regs;
32};
33
34struct imx_rgpio2p_plat {
35 int bank_index;
36 struct gpio_regs *regs;
37};
38
39static 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
0539d16d
CF
48static 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
d665eb61
PF
56static 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
73static 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
82static int imx_rgpio2p_bank_get_value(struct gpio_regs *regs, int offset)
83{
0539d16d
CF
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;
d665eb61
PF
89}
90
91static 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
101static 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
115static 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
122static 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
132static 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
143static 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
151static int imx_rgpio2p_probe(struct udevice *dev)
152{
153 struct imx_rgpio2p_data *bank = dev_get_priv(dev);
c69cda25 154 struct imx_rgpio2p_plat *plat = dev_get_plat(dev);
d665eb61
PF
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
171static int imx_rgpio2p_bind(struct udevice *dev)
172{
0fd3d911 173 struct imx_rgpio2p_plat *plat = dev_get_plat(dev);
51cfa66f
PF
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;
d665eb61
PF
177 fdt_addr_t addr;
178
179 /*
caa4daa2
SG
180 * If plat already exsits, directly return.
181 * Actually only when DT is not supported, plat
20e442ab 182 * is statically initialized in U_BOOT_DRVINFOS.Here
d665eb61
PF
183 * will return.
184 */
185 if (plat)
186 return 0;
187
51cfa66f
PF
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 }
d665eb61
PF
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
caa4daa2 213 * to alloc memory for plat.
4d686041
SG
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.
d665eb61
PF
219 */
220 plat = calloc(1, sizeof(*plat));
221 if (!plat)
222 return -ENOMEM;
223
224 plat->regs = (struct gpio_regs *)addr;
fb0ea6a7 225 plat->bank_index = dev_seq(dev);
0fd3d911 226 dev_set_plat(dev, plat);
d665eb61
PF
227
228 return 0;
229}
230
51cfa66f
PF
231static struct imx_rgpio2p_soc_data imx7ulp_data = {
232 .have_dual_base = true,
233};
234
235static struct imx_rgpio2p_soc_data imx8ulp_data = {
236 .have_dual_base = false,
237};
d665eb61
PF
238
239static const struct udevice_id imx_rgpio2p_ids[] = {
51cfa66f
PF
240 { .compatible = "fsl,imx7ulp-gpio", .data = (ulong)&imx7ulp_data },
241 { .compatible = "fsl,imx8ulp-gpio", .data = (ulong)&imx8ulp_data },
d665eb61
PF
242 { }
243};
244
245U_BOOT_DRIVER(imx_rgpio2p) = {
246 .name = "imx_rgpio2p",
247 .id = UCLASS_GPIO,
248 .ops = &imx_rgpio2p_ops,
249 .probe = imx_rgpio2p_probe,
41575d8e 250 .priv_auto = sizeof(struct imx_rgpio2p_plat),
d665eb61
PF
251 .of_match = imx_rgpio2p_ids,
252 .bind = imx_rgpio2p_bind,
253};
254
255#if !CONFIG_IS_ENABLED(OF_CONTROL)
256static 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
20e442ab 265U_BOOT_DRVINFOS(imx_rgpio2ps) = {
d665eb61
PF
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