1 // SPDX-License-Identifier: GPL-2.0+
4 * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
7 * Stefano Babic, DENX Software Engineering, <sbabic@denx.de>
13 #include <asm/arch/imx-regs.h>
17 enum mxc_gpio_direction
{
18 MXC_GPIO_DIRECTION_IN
,
19 MXC_GPIO_DIRECTION_OUT
,
22 #define GPIO_PER_BANK 32
24 struct mxc_gpio_plat
{
26 struct gpio_regs
*regs
;
29 struct mxc_bank_info
{
30 struct gpio_regs
*regs
;
33 #if !CONFIG_IS_ENABLED(DM_GPIO)
34 #define GPIO_TO_PORT(n) ((n) / 32)
36 /* GPIO port description */
37 static unsigned long gpio_ports
[] = {
38 [0] = GPIO1_BASE_ADDR
,
39 [1] = GPIO2_BASE_ADDR
,
40 [2] = GPIO3_BASE_ADDR
,
41 #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \
42 defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
43 defined(CONFIG_MX7) || defined(CONFIG_IMX8M) || \
44 defined(CONFIG_ARCH_IMX8) || defined(CONFIG_IMXRT1050)
45 [3] = GPIO4_BASE_ADDR
,
47 #if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
48 defined(CONFIG_MX7) || defined(CONFIG_IMX8M) || \
49 defined(CONFIG_ARCH_IMX8) || defined(CONFIG_IMXRT1050)
50 [4] = GPIO5_BASE_ADDR
,
51 #if !(defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL) || \
52 defined(CONFIG_IMX8M) || defined(CONFIG_IMXRT1050))
53 [5] = GPIO6_BASE_ADDR
,
56 #if defined(CONFIG_MX53) || defined(CONFIG_MX6) || defined(CONFIG_MX7) || \
57 defined(CONFIG_ARCH_IMX8)
58 #if !(defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL))
59 [6] = GPIO7_BASE_ADDR
,
62 #if defined(CONFIG_ARCH_IMX8)
63 [7] = GPIO8_BASE_ADDR
,
67 static int mxc_gpio_direction(unsigned int gpio
,
68 enum mxc_gpio_direction direction
)
70 unsigned int port
= GPIO_TO_PORT(gpio
);
71 struct gpio_regs
*regs
;
74 if (port
>= ARRAY_SIZE(gpio_ports
))
79 regs
= (struct gpio_regs
*)gpio_ports
[port
];
81 l
= readl(®s
->gpio_dir
);
84 case MXC_GPIO_DIRECTION_OUT
:
87 case MXC_GPIO_DIRECTION_IN
:
90 writel(l
, ®s
->gpio_dir
);
95 int gpio_set_value(unsigned gpio
, int value
)
97 unsigned int port
= GPIO_TO_PORT(gpio
);
98 struct gpio_regs
*regs
;
101 if (port
>= ARRAY_SIZE(gpio_ports
))
106 regs
= (struct gpio_regs
*)gpio_ports
[port
];
108 l
= readl(®s
->gpio_dr
);
113 writel(l
, ®s
->gpio_dr
);
118 int gpio_get_value(unsigned gpio
)
120 unsigned int port
= GPIO_TO_PORT(gpio
);
121 struct gpio_regs
*regs
;
124 if (port
>= ARRAY_SIZE(gpio_ports
))
129 regs
= (struct gpio_regs
*)gpio_ports
[port
];
131 val
= (readl(®s
->gpio_psr
) >> gpio
) & 0x01;
136 int gpio_request(unsigned gpio
, const char *label
)
138 unsigned int port
= GPIO_TO_PORT(gpio
);
139 if (port
>= ARRAY_SIZE(gpio_ports
))
144 int gpio_free(unsigned gpio
)
149 int gpio_direction_input(unsigned gpio
)
151 return mxc_gpio_direction(gpio
, MXC_GPIO_DIRECTION_IN
);
154 int gpio_direction_output(unsigned gpio
, int value
)
156 int ret
= gpio_set_value(gpio
, value
);
161 return mxc_gpio_direction(gpio
, MXC_GPIO_DIRECTION_OUT
);
165 #if CONFIG_IS_ENABLED(DM_GPIO)
167 static int mxc_gpio_is_output(struct gpio_regs
*regs
, int offset
)
171 val
= readl(®s
->gpio_dir
);
173 return val
& (1 << offset
) ? 1 : 0;
176 static void mxc_gpio_bank_direction(struct gpio_regs
*regs
, int offset
,
177 enum mxc_gpio_direction direction
)
181 l
= readl(®s
->gpio_dir
);
184 case MXC_GPIO_DIRECTION_OUT
:
187 case MXC_GPIO_DIRECTION_IN
:
190 writel(l
, ®s
->gpio_dir
);
193 static void mxc_gpio_bank_set_value(struct gpio_regs
*regs
, int offset
,
198 l
= readl(®s
->gpio_dr
);
203 writel(l
, ®s
->gpio_dr
);
206 static int mxc_gpio_bank_get_value(struct gpio_regs
*regs
, int offset
)
208 return (readl(®s
->gpio_psr
) >> offset
) & 0x01;
211 /* set GPIO pin 'gpio' as an input */
212 static int mxc_gpio_direction_input(struct udevice
*dev
, unsigned offset
)
214 struct mxc_bank_info
*bank
= dev_get_priv(dev
);
216 /* Configure GPIO direction as input. */
217 mxc_gpio_bank_direction(bank
->regs
, offset
, MXC_GPIO_DIRECTION_IN
);
222 /* set GPIO pin 'gpio' as an output, with polarity 'value' */
223 static int mxc_gpio_direction_output(struct udevice
*dev
, unsigned offset
,
226 struct mxc_bank_info
*bank
= dev_get_priv(dev
);
228 /* Configure GPIO output value. */
229 mxc_gpio_bank_set_value(bank
->regs
, offset
, value
);
231 /* Configure GPIO direction as output. */
232 mxc_gpio_bank_direction(bank
->regs
, offset
, MXC_GPIO_DIRECTION_OUT
);
237 /* read GPIO IN value of pin 'gpio' */
238 static int mxc_gpio_get_value(struct udevice
*dev
, unsigned offset
)
240 struct mxc_bank_info
*bank
= dev_get_priv(dev
);
242 return mxc_gpio_bank_get_value(bank
->regs
, offset
);
245 /* write GPIO OUT value to pin 'gpio' */
246 static int mxc_gpio_set_value(struct udevice
*dev
, unsigned offset
,
249 struct mxc_bank_info
*bank
= dev_get_priv(dev
);
251 mxc_gpio_bank_set_value(bank
->regs
, offset
, value
);
256 static int mxc_gpio_get_function(struct udevice
*dev
, unsigned offset
)
258 struct mxc_bank_info
*bank
= dev_get_priv(dev
);
260 /* GPIOF_FUNC is not implemented yet */
261 if (mxc_gpio_is_output(bank
->regs
, offset
))
267 static const struct dm_gpio_ops gpio_mxc_ops
= {
268 .direction_input
= mxc_gpio_direction_input
,
269 .direction_output
= mxc_gpio_direction_output
,
270 .get_value
= mxc_gpio_get_value
,
271 .set_value
= mxc_gpio_set_value
,
272 .get_function
= mxc_gpio_get_function
,
275 static int mxc_gpio_probe(struct udevice
*dev
)
277 struct mxc_bank_info
*bank
= dev_get_priv(dev
);
278 struct mxc_gpio_plat
*plat
= dev_get_platdata(dev
);
279 struct gpio_dev_priv
*uc_priv
= dev_get_uclass_priv(dev
);
283 banknum
= plat
->bank_index
;
284 sprintf(name
, "GPIO%d_", banknum
+ 1);
288 uc_priv
->bank_name
= str
;
289 uc_priv
->gpio_count
= GPIO_PER_BANK
;
290 bank
->regs
= plat
->regs
;
295 static int mxc_gpio_bind(struct udevice
*dev
)
297 struct mxc_gpio_plat
*plat
= dev
->platdata
;
301 * If platdata already exsits, directly return.
302 * Actually only when DT is not supported, platdata
303 * is statically initialized in U_BOOT_DEVICES.Here
309 addr
= devfdt_get_addr(dev
);
310 if (addr
== FDT_ADDR_T_NONE
)
315 * When every board is converted to driver model and DT is supported,
316 * this can be done by auto-alloc feature, but not using calloc
317 * to alloc memory for platdata.
319 * For example mxc_plat below uses platform data rather than device
322 * NOTE: DO NOT COPY this code if you are using device tree.
324 plat
= calloc(1, sizeof(*plat
));
328 plat
->regs
= (struct gpio_regs
*)addr
;
329 plat
->bank_index
= dev
->req_seq
;
330 dev
->platdata
= plat
;
335 static const struct udevice_id mxc_gpio_ids
[] = {
336 { .compatible
= "fsl,imx35-gpio" },
340 U_BOOT_DRIVER(gpio_mxc
) = {
343 .ops
= &gpio_mxc_ops
,
344 .probe
= mxc_gpio_probe
,
345 .priv_auto_alloc_size
= sizeof(struct mxc_bank_info
),
346 .of_match
= mxc_gpio_ids
,
347 .bind
= mxc_gpio_bind
,
350 #if !CONFIG_IS_ENABLED(OF_CONTROL)
351 static const struct mxc_gpio_plat mxc_plat
[] = {
352 { 0, (struct gpio_regs
*)GPIO1_BASE_ADDR
},
353 { 1, (struct gpio_regs
*)GPIO2_BASE_ADDR
},
354 { 2, (struct gpio_regs
*)GPIO3_BASE_ADDR
},
355 #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \
356 defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
357 defined(CONFIG_IMX8M) || defined(CONFIG_ARCH_IMX8)
358 { 3, (struct gpio_regs
*)GPIO4_BASE_ADDR
},
360 #if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
361 defined(CONFIG_IMX8M) || defined(CONFIG_ARCH_IMX8)
362 { 4, (struct gpio_regs
*)GPIO5_BASE_ADDR
},
364 { 5, (struct gpio_regs
*)GPIO6_BASE_ADDR
},
367 #if defined(CONFIG_MX53) || defined(CONFIG_MX6) || defined(CONFIG_ARCH_IMX8)
368 { 6, (struct gpio_regs
*)GPIO7_BASE_ADDR
},
370 #if defined(CONFIG_ARCH_IMX8)
371 { 7, (struct gpio_regs
*)GPIO8_BASE_ADDR
},
375 U_BOOT_DEVICES(mxc_gpios
) = {
376 { "gpio_mxc", &mxc_plat
[0] },
377 { "gpio_mxc", &mxc_plat
[1] },
378 { "gpio_mxc", &mxc_plat
[2] },
379 #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \
380 defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
381 defined(CONFIG_IMX8M) || defined(CONFIG_ARCH_IMX8)
382 { "gpio_mxc", &mxc_plat
[3] },
384 #if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
385 defined(CONFIG_IMX8M) || defined(CONFIG_ARCH_IMX8)
386 { "gpio_mxc", &mxc_plat
[4] },
388 { "gpio_mxc", &mxc_plat
[5] },
391 #if defined(CONFIG_MX53) || defined(CONFIG_MX6) || defined(CONFIG_ARCH_IMX8)
392 { "gpio_mxc", &mxc_plat
[6] },
394 #if defined(CONFIG_ARCH_IMX8)
395 { "gpio_mxc", &mxc_plat
[7] },