1 // SPDX-License-Identifier: GPL-2.0+
12 #include <asm/arch/imx-regs.h>
15 #include <dt-structs.h>
18 enum mxc_gpio_direction {
19 MXC_GPIO_DIRECTION_IN,
20 MXC_GPIO_DIRECTION_OUT,
23 #define GPIO_PER_BANK 32
25 struct mxc_gpio_plat {
26 #if CONFIG_IS_ENABLED(OF_PLATDATA)
27 /* Put this first since driver model will copy the data here */
28 struct dtd_gpio_mxc dtplat;
31 struct gpio_regs *regs;
34 struct mxc_bank_info {
35 struct gpio_regs *regs;
38 #if !CONFIG_IS_ENABLED(DM_GPIO)
39 #define GPIO_TO_PORT(n) ((n) / 32)
41 /* GPIO port description */
42 static unsigned long gpio_ports[] = {
43 [0] = GPIO1_BASE_ADDR,
44 [1] = GPIO2_BASE_ADDR,
45 [2] = GPIO3_BASE_ADDR,
46 #if defined(CONFIG_MX51) || \
47 defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
48 defined(CONFIG_MX7) || defined(CONFIG_IMX8M) || \
49 defined(CONFIG_ARCH_IMX8) || defined(CONFIG_IMXRT1050)
50 [3] = GPIO4_BASE_ADDR,
52 #if defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
53 defined(CONFIG_MX7) || defined(CONFIG_IMX8M) || \
54 defined(CONFIG_ARCH_IMX8) || defined(CONFIG_IMXRT1050)
55 [4] = GPIO5_BASE_ADDR,
56 #if !(defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL) || \
57 defined(CONFIG_IMX8M) || defined(CONFIG_IMXRT1050))
58 [5] = GPIO6_BASE_ADDR,
61 #if defined(CONFIG_MX53) || defined(CONFIG_MX6) || defined(CONFIG_MX7) || \
62 defined(CONFIG_ARCH_IMX8)
63 #if !(defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL))
64 [6] = GPIO7_BASE_ADDR,
67 #if defined(CONFIG_ARCH_IMX8)
68 [7] = GPIO8_BASE_ADDR,
72 static int mxc_gpio_direction(unsigned int gpio,
73 enum mxc_gpio_direction direction)
75 unsigned int port = GPIO_TO_PORT(gpio);
76 struct gpio_regs *regs;
79 if (port >= ARRAY_SIZE(gpio_ports))
84 regs = (struct gpio_regs *)gpio_ports[port];
86 l = readl(®s->gpio_dir);
89 case MXC_GPIO_DIRECTION_OUT:
92 case MXC_GPIO_DIRECTION_IN:
95 writel(l, ®s->gpio_dir);
100 int gpio_set_value(unsigned gpio, int value)
102 unsigned int port = GPIO_TO_PORT(gpio);
103 struct gpio_regs *regs;
106 if (port >= ARRAY_SIZE(gpio_ports))
111 regs = (struct gpio_regs *)gpio_ports[port];
113 l = readl(®s->gpio_dr);
118 writel(l, ®s->gpio_dr);
123 int gpio_get_value(unsigned gpio)
125 unsigned int port = GPIO_TO_PORT(gpio);
126 struct gpio_regs *regs;
129 if (port >= ARRAY_SIZE(gpio_ports))
134 regs = (struct gpio_regs *)gpio_ports[port];
136 if ((readl(®s->gpio_dir) >> gpio) & 0x01)
137 val = (readl(®s->gpio_dr) >> gpio) & 0x01;
139 val = (readl(®s->gpio_psr) >> gpio) & 0x01;
144 int gpio_request(unsigned gpio, const char *label)
146 unsigned int port = GPIO_TO_PORT(gpio);
147 if (port >= ARRAY_SIZE(gpio_ports))
152 int gpio_free(unsigned gpio)
157 int gpio_direction_input(unsigned gpio)
159 return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_IN);
162 int gpio_direction_output(unsigned gpio, int value)
164 int ret = gpio_set_value(gpio, value);
169 return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_OUT);
173 #if CONFIG_IS_ENABLED(DM_GPIO)
175 static int mxc_gpio_is_output(struct gpio_regs *regs, int offset)
179 val = readl(®s->gpio_dir);
181 return val & (1 << offset) ? 1 : 0;
184 static void mxc_gpio_bank_direction(struct gpio_regs *regs, int offset,
185 enum mxc_gpio_direction direction)
189 l = readl(®s->gpio_dir);
192 case MXC_GPIO_DIRECTION_OUT:
195 case MXC_GPIO_DIRECTION_IN:
198 writel(l, ®s->gpio_dir);
201 static void mxc_gpio_bank_set_value(struct gpio_regs *regs, int offset,
206 l = readl(®s->gpio_dr);
211 writel(l, ®s->gpio_dr);
214 static int mxc_gpio_bank_get_value(struct gpio_regs *regs, int offset)
216 if ((readl(®s->gpio_dir) >> offset) & 0x01)
217 return (readl(®s->gpio_dr) >> offset) & 0x01;
219 return (readl(®s->gpio_psr) >> offset) & 0x01;
222 /* set GPIO pin 'gpio' as an input */
223 static int mxc_gpio_direction_input(struct udevice *dev, unsigned offset)
225 struct mxc_bank_info *bank = dev_get_priv(dev);
227 /* Configure GPIO direction as input. */
228 mxc_gpio_bank_direction(bank->regs, offset, MXC_GPIO_DIRECTION_IN);
233 /* set GPIO pin 'gpio' as an output, with polarity 'value' */
234 static int mxc_gpio_direction_output(struct udevice *dev, unsigned offset,
237 struct mxc_bank_info *bank = dev_get_priv(dev);
239 /* Configure GPIO output value. */
240 mxc_gpio_bank_set_value(bank->regs, offset, value);
242 /* Configure GPIO direction as output. */
243 mxc_gpio_bank_direction(bank->regs, offset, MXC_GPIO_DIRECTION_OUT);
248 /* read GPIO IN value of pin 'gpio' */
249 static int mxc_gpio_get_value(struct udevice *dev, unsigned offset)
251 struct mxc_bank_info *bank = dev_get_priv(dev);
253 return mxc_gpio_bank_get_value(bank->regs, offset);
256 /* write GPIO OUT value to pin 'gpio' */
257 static int mxc_gpio_set_value(struct udevice *dev, unsigned offset,
260 struct mxc_bank_info *bank = dev_get_priv(dev);
262 mxc_gpio_bank_set_value(bank->regs, offset, value);
267 static int mxc_gpio_get_function(struct udevice *dev, unsigned offset)
269 struct mxc_bank_info *bank = dev_get_priv(dev);
271 /* GPIOF_FUNC is not implemented yet */
272 if (mxc_gpio_is_output(bank->regs, offset))
278 static const struct dm_gpio_ops gpio_mxc_ops = {
279 .direction_input = mxc_gpio_direction_input,
280 .direction_output = mxc_gpio_direction_output,
281 .get_value = mxc_gpio_get_value,
282 .set_value = mxc_gpio_set_value,
283 .get_function = mxc_gpio_get_function,
286 static int mxc_gpio_probe(struct udevice *dev)
288 struct mxc_bank_info *bank = dev_get_priv(dev);
289 struct mxc_gpio_plat *plat = dev_get_plat(dev);
290 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
294 #if CONFIG_IS_ENABLED(OF_PLATDATA)
295 struct dtd_gpio_mxc *dtplat = &plat->dtplat;
297 plat->regs = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
300 banknum = plat->bank_index;
301 if (IS_ENABLED(CONFIG_ARCH_IMX8))
302 sprintf(name, "GPIO%d_", banknum);
304 sprintf(name, "GPIO%d_", banknum + 1);
308 uc_priv->bank_name = str;
309 uc_priv->gpio_count = GPIO_PER_BANK;
310 bank->regs = plat->regs;
315 static int mxc_gpio_of_to_plat(struct udevice *dev)
317 struct mxc_gpio_plat *plat = dev_get_plat(dev);
318 if (!CONFIG_IS_ENABLED(OF_PLATDATA)) {
320 addr = dev_read_addr(dev);
321 if (addr == FDT_ADDR_T_NONE)
324 plat->regs = (struct gpio_regs *)addr;
326 plat->bank_index = dev_seq(dev);
331 static int mxc_gpio_bind(struct udevice *dev)
336 static const struct udevice_id mxc_gpio_ids[] = {
337 { .compatible = "fsl,imx35-gpio" },
341 U_BOOT_DRIVER(gpio_mxc) = {
344 .ops = &gpio_mxc_ops,
345 .probe = mxc_gpio_probe,
346 .of_to_plat = mxc_gpio_of_to_plat,
347 .plat_auto = sizeof(struct mxc_gpio_plat),
348 .priv_auto = sizeof(struct mxc_bank_info),
349 .of_match = mxc_gpio_ids,
350 .bind = mxc_gpio_bind,
353 DM_DRIVER_ALIAS(gpio_mxc, fsl_imx6q_gpio)
355 #if !CONFIG_IS_ENABLED(OF_CONTROL)
356 static const struct mxc_gpio_plat mxc_plat[] = {
357 { 0, (struct gpio_regs *)GPIO1_BASE_ADDR },
358 { 1, (struct gpio_regs *)GPIO2_BASE_ADDR },
359 { 2, (struct gpio_regs *)GPIO3_BASE_ADDR },
360 #if defined(CONFIG_MX51) || \
361 defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
362 defined(CONFIG_IMX8M) || defined(CONFIG_ARCH_IMX8)
363 { 3, (struct gpio_regs *)GPIO4_BASE_ADDR },
365 #if defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
366 defined(CONFIG_IMX8M) || defined(CONFIG_ARCH_IMX8)
367 { 4, (struct gpio_regs *)GPIO5_BASE_ADDR },
369 { 5, (struct gpio_regs *)GPIO6_BASE_ADDR },
372 #if defined(CONFIG_MX53) || defined(CONFIG_MX6) || defined(CONFIG_ARCH_IMX8)
373 { 6, (struct gpio_regs *)GPIO7_BASE_ADDR },
375 #if defined(CONFIG_ARCH_IMX8)
376 { 7, (struct gpio_regs *)GPIO8_BASE_ADDR },
380 U_BOOT_DRVINFOS(mxc_gpios) = {
381 { "gpio_mxc", &mxc_plat[0] },
382 { "gpio_mxc", &mxc_plat[1] },
383 { "gpio_mxc", &mxc_plat[2] },
384 #if defined(CONFIG_MX51) || \
385 defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
386 defined(CONFIG_IMX8M) || defined(CONFIG_ARCH_IMX8)
387 { "gpio_mxc", &mxc_plat[3] },
389 #if defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
390 defined(CONFIG_IMX8M) || defined(CONFIG_ARCH_IMX8)
391 { "gpio_mxc", &mxc_plat[4] },
393 { "gpio_mxc", &mxc_plat[5] },
396 #if defined(CONFIG_MX53) || defined(CONFIG_MX6) || defined(CONFIG_ARCH_IMX8)
397 { "gpio_mxc", &mxc_plat[6] },
399 #if defined(CONFIG_ARCH_IMX8)
400 { "gpio_mxc", &mxc_plat[7] },