blob: 3094f1c804a47d7c8f2791bd8f14a53f452a761c [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Marek Vasut6b6440d2011-11-08 23:18:13 +00002/*
3 * Freescale i.MX28 GPIO control code
4 *
5 * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
6 * on behalf of DENX Software Engineering GmbH
Marek Vasut6b6440d2011-11-08 23:18:13 +00007 */
8
9#include <common.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060010#include <log.h>
Simon Glass336d4612020-02-03 07:36:16 -070011#include <malloc.h>
Masahiro Yamada1221ce42016-09-21 11:28:55 +090012#include <linux/errno.h>
Marek Vasut6b6440d2011-11-08 23:18:13 +000013#include <asm/io.h>
14#include <asm/arch/iomux.h>
15#include <asm/arch/imx-regs.h>
16
17#if defined(CONFIG_MX23)
18#define PINCTRL_BANKS 3
19#define PINCTRL_DOUT(n) (0x0500 + ((n) * 0x10))
20#define PINCTRL_DIN(n) (0x0600 + ((n) * 0x10))
21#define PINCTRL_DOE(n) (0x0700 + ((n) * 0x10))
22#define PINCTRL_PIN2IRQ(n) (0x0800 + ((n) * 0x10))
23#define PINCTRL_IRQEN(n) (0x0900 + ((n) * 0x10))
24#define PINCTRL_IRQSTAT(n) (0x0c00 + ((n) * 0x10))
25#elif defined(CONFIG_MX28)
26#define PINCTRL_BANKS 5
27#define PINCTRL_DOUT(n) (0x0700 + ((n) * 0x10))
28#define PINCTRL_DIN(n) (0x0900 + ((n) * 0x10))
29#define PINCTRL_DOE(n) (0x0b00 + ((n) * 0x10))
30#define PINCTRL_PIN2IRQ(n) (0x1000 + ((n) * 0x10))
31#define PINCTRL_IRQEN(n) (0x1100 + ((n) * 0x10))
32#define PINCTRL_IRQSTAT(n) (0x1400 + ((n) * 0x10))
33#else
34#error "Please select CONFIG_MX23 or CONFIG_MX28"
35#endif
36
37#define GPIO_INT_FALL_EDGE 0x0
38#define GPIO_INT_LOW_LEV 0x1
39#define GPIO_INT_RISE_EDGE 0x2
40#define GPIO_INT_HIGH_LEV 0x3
41#define GPIO_INT_LEV_MASK (1 << 0)
42#define GPIO_INT_POL_MASK (1 << 1)
43
44void mxs_gpio_init(void)
45{
46 int i;
47
48 for (i = 0; i < PINCTRL_BANKS; i++) {
49 writel(0, MXS_PINCTRL_BASE + PINCTRL_PIN2IRQ(i));
50 writel(0, MXS_PINCTRL_BASE + PINCTRL_IRQEN(i));
51 /* Use SCT address here to clear the IRQSTAT bits */
52 writel(0xffffffff, MXS_PINCTRL_BASE + PINCTRL_IRQSTAT(i) + 8);
53 }
54}
55
Lukasz Majewski397af352019-06-19 17:31:05 +020056#if !CONFIG_IS_ENABLED(DM_GPIO)
Joe Hershberger365d6072011-11-11 15:55:36 -060057int gpio_get_value(unsigned gpio)
Marek Vasut6b6440d2011-11-08 23:18:13 +000058{
Joe Hershberger365d6072011-11-11 15:55:36 -060059 uint32_t bank = PAD_BANK(gpio);
Marek Vasut6b6440d2011-11-08 23:18:13 +000060 uint32_t offset = PINCTRL_DIN(bank);
Otavio Salvadorddcf13b2012-08-05 09:05:30 +000061 struct mxs_register_32 *reg =
62 (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset);
Marek Vasut6b6440d2011-11-08 23:18:13 +000063
Joe Hershberger365d6072011-11-11 15:55:36 -060064 return (readl(&reg->reg) >> PAD_PIN(gpio)) & 1;
Marek Vasut6b6440d2011-11-08 23:18:13 +000065}
66
Joe Hershberger365d6072011-11-11 15:55:36 -060067void gpio_set_value(unsigned gpio, int value)
Marek Vasut6b6440d2011-11-08 23:18:13 +000068{
Joe Hershberger365d6072011-11-11 15:55:36 -060069 uint32_t bank = PAD_BANK(gpio);
Marek Vasut6b6440d2011-11-08 23:18:13 +000070 uint32_t offset = PINCTRL_DOUT(bank);
Otavio Salvadorddcf13b2012-08-05 09:05:30 +000071 struct mxs_register_32 *reg =
72 (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset);
Marek Vasut6b6440d2011-11-08 23:18:13 +000073
74 if (value)
Joe Hershberger365d6072011-11-11 15:55:36 -060075 writel(1 << PAD_PIN(gpio), &reg->reg_set);
Marek Vasut6b6440d2011-11-08 23:18:13 +000076 else
Joe Hershberger365d6072011-11-11 15:55:36 -060077 writel(1 << PAD_PIN(gpio), &reg->reg_clr);
Marek Vasut6b6440d2011-11-08 23:18:13 +000078}
79
Joe Hershberger365d6072011-11-11 15:55:36 -060080int gpio_direction_input(unsigned gpio)
Marek Vasut6b6440d2011-11-08 23:18:13 +000081{
Joe Hershberger365d6072011-11-11 15:55:36 -060082 uint32_t bank = PAD_BANK(gpio);
Marek Vasut6b6440d2011-11-08 23:18:13 +000083 uint32_t offset = PINCTRL_DOE(bank);
Otavio Salvadorddcf13b2012-08-05 09:05:30 +000084 struct mxs_register_32 *reg =
85 (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset);
Marek Vasut6b6440d2011-11-08 23:18:13 +000086
Joe Hershberger365d6072011-11-11 15:55:36 -060087 writel(1 << PAD_PIN(gpio), &reg->reg_clr);
Marek Vasut6b6440d2011-11-08 23:18:13 +000088
89 return 0;
90}
91
Joe Hershberger365d6072011-11-11 15:55:36 -060092int gpio_direction_output(unsigned gpio, int value)
Marek Vasut6b6440d2011-11-08 23:18:13 +000093{
Joe Hershberger365d6072011-11-11 15:55:36 -060094 uint32_t bank = PAD_BANK(gpio);
Marek Vasut6b6440d2011-11-08 23:18:13 +000095 uint32_t offset = PINCTRL_DOE(bank);
Otavio Salvadorddcf13b2012-08-05 09:05:30 +000096 struct mxs_register_32 *reg =
97 (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset);
Marek Vasut6b6440d2011-11-08 23:18:13 +000098
Joe Hershberger365d6072011-11-11 15:55:36 -060099 gpio_set_value(gpio, value);
Marek Vasut6b6440d2011-11-08 23:18:13 +0000100
Michael Heimpoldac135f62013-11-03 22:59:26 +0100101 writel(1 << PAD_PIN(gpio), &reg->reg_set);
102
Marek Vasut6b6440d2011-11-08 23:18:13 +0000103 return 0;
104}
105
Joe Hershberger365d6072011-11-11 15:55:36 -0600106int gpio_request(unsigned gpio, const char *label)
Marek Vasut6b6440d2011-11-08 23:18:13 +0000107{
Joe Hershberger365d6072011-11-11 15:55:36 -0600108 if (PAD_BANK(gpio) >= PINCTRL_BANKS)
109 return -1;
Marek Vasut6b6440d2011-11-08 23:18:13 +0000110
111 return 0;
112}
113
Joe Hershberger365d6072011-11-11 15:55:36 -0600114int gpio_free(unsigned gpio)
Marek Vasut6b6440d2011-11-08 23:18:13 +0000115{
Joe Hershberger365d6072011-11-11 15:55:36 -0600116 return 0;
Marek Vasut6b6440d2011-11-08 23:18:13 +0000117}
Måns Rullgård88f91d12015-12-15 22:27:57 +0000118
119int name_to_gpio(const char *name)
120{
121 unsigned bank, pin;
122 char *end;
123
124 bank = simple_strtoul(name, &end, 10);
125
126 if (!*end || *end != ':')
127 return bank;
128
129 pin = simple_strtoul(end + 1, NULL, 10);
130
131 return (bank << MXS_PAD_BANK_SHIFT) | (pin << MXS_PAD_PIN_SHIFT);
132}
Simon Glassbcee8d62019-12-06 21:41:35 -0700133#else /* DM_GPIO */
Lukasz Majewski397af352019-06-19 17:31:05 +0200134#include <dm.h>
135#include <asm/gpio.h>
Lukasz Majewskic883d6a2019-09-05 09:55:01 +0200136#include <dt-structs.h>
Lukasz Majewski397af352019-06-19 17:31:05 +0200137#include <asm/arch/gpio.h>
138#define MXS_MAX_GPIO_PER_BANK 32
139
Lukasz Majewskic883d6a2019-09-05 09:55:01 +0200140#ifdef CONFIG_MX28
141#define dtd_fsl_imx_gpio dtd_fsl_imx28_gpio
142#else /* CONFIG_MX23 */
143#define dtd_fsl_imx_gpio dtd_fsl_imx23_gpio
144#endif
145
Lukasz Majewski397af352019-06-19 17:31:05 +0200146DECLARE_GLOBAL_DATA_PTR;
147/*
148 * According to i.MX28 Reference Manual:
149 * 'i.MX28 Applications Processor Reference Manual, Rev. 1, 2010'
150 * The i.MX28 has following number of GPIOs available:
151 * Bank 0: 0-28 -> 29 PINS
152 * Bank 1: 0-31 -> 32 PINS
153 * Bank 2: 0-27 -> 28 PINS
154 * Bank 3: 0-30 -> 31 PINS
155 * Bank 4: 0-20 -> 21 PINS
156 */
157
Lukasz Majewskic883d6a2019-09-05 09:55:01 +0200158struct mxs_gpio_platdata {
159#if CONFIG_IS_ENABLED(OF_PLATDATA)
160 struct dtd_fsl_imx_gpio dtplat;
161#endif
162 unsigned int bank;
163 int gpio_ranges;
164};
165
Lukasz Majewski397af352019-06-19 17:31:05 +0200166struct mxs_gpio_priv {
167 unsigned int bank;
168};
169
170static int mxs_gpio_get_value(struct udevice *dev, unsigned offset)
171{
172 struct mxs_gpio_priv *priv = dev_get_priv(dev);
173 struct mxs_register_32 *reg =
174 (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
175 PINCTRL_DIN(priv->bank));
176
177 return (readl(&reg->reg) >> offset) & 1;
178}
179
180static int mxs_gpio_set_value(struct udevice *dev, unsigned offset,
181 int value)
182{
183 struct mxs_gpio_priv *priv = dev_get_priv(dev);
184 struct mxs_register_32 *reg =
185 (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
186 PINCTRL_DOUT(priv->bank));
187 if (value)
188 writel(BIT(offset), &reg->reg_set);
189 else
190 writel(BIT(offset), &reg->reg_clr);
191
192 return 0;
193}
194
195static int mxs_gpio_direction_input(struct udevice *dev, unsigned offset)
196{
197 struct mxs_gpio_priv *priv = dev_get_priv(dev);
198 struct mxs_register_32 *reg =
199 (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
200 PINCTRL_DOE(priv->bank));
201
202 writel(BIT(offset), &reg->reg_clr);
203
204 return 0;
205}
206
207static int mxs_gpio_direction_output(struct udevice *dev, unsigned offset,
208 int value)
209{
210 struct mxs_gpio_priv *priv = dev_get_priv(dev);
211 struct mxs_register_32 *reg =
212 (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
213 PINCTRL_DOE(priv->bank));
214
215 mxs_gpio_set_value(dev, offset, value);
216
217 writel(BIT(offset), &reg->reg_set);
218
219 return 0;
220}
221
222static int mxs_gpio_get_function(struct udevice *dev, unsigned offset)
223{
224 struct mxs_gpio_priv *priv = dev_get_priv(dev);
225 struct mxs_register_32 *reg =
226 (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
227 PINCTRL_DOE(priv->bank));
228 bool is_output = !!(readl(&reg->reg) >> offset);
229
230 return is_output ? GPIOF_OUTPUT : GPIOF_INPUT;
231}
232
233static const struct dm_gpio_ops gpio_mxs_ops = {
234 .direction_input = mxs_gpio_direction_input,
235 .direction_output = mxs_gpio_direction_output,
236 .get_value = mxs_gpio_get_value,
237 .set_value = mxs_gpio_set_value,
238 .get_function = mxs_gpio_get_function,
239};
240
241static int mxs_gpio_probe(struct udevice *dev)
242{
Lukasz Majewskic883d6a2019-09-05 09:55:01 +0200243 struct mxs_gpio_platdata *plat = dev_get_platdata(dev);
Lukasz Majewski397af352019-06-19 17:31:05 +0200244 struct mxs_gpio_priv *priv = dev_get_priv(dev);
245 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Lukasz Majewski397af352019-06-19 17:31:05 +0200246 char name[16], *str;
Lukasz Majewski397af352019-06-19 17:31:05 +0200247
Lukasz Majewskic883d6a2019-09-05 09:55:01 +0200248#if CONFIG_IS_ENABLED(OF_PLATDATA)
249 struct dtd_fsl_imx_gpio *dtplat = &plat->dtplat;
250 priv->bank = (unsigned int)dtplat->reg[0];
251 uc_priv->gpio_count = dtplat->gpio_ranges[3];
252#else
253 priv->bank = (unsigned int)plat->bank;
254 uc_priv->gpio_count = plat->gpio_ranges;
255#endif
Lukasz Majewski397af352019-06-19 17:31:05 +0200256 snprintf(name, sizeof(name), "GPIO%d_", priv->bank);
257 str = strdup(name);
258 if (!str)
259 return -ENOMEM;
260
261 uc_priv->bank_name = str;
262
Lukasz Majewskic883d6a2019-09-05 09:55:01 +0200263 debug("%s: %s: %d pins base: 0x%x\n", __func__, uc_priv->bank_name,
264 uc_priv->gpio_count, priv->bank);
265
266 return 0;
267}
268
269#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
270static int mxs_ofdata_to_platdata(struct udevice *dev)
271{
272 struct mxs_gpio_platdata *plat = dev->platdata;
273 struct fdtdec_phandle_args args;
274 int node = dev_of_offset(dev);
275 int ret;
276
277 plat->bank = devfdt_get_addr(dev);
278 if (plat->bank == FDT_ADDR_T_NONE) {
279 printf("%s: No 'reg' property defined!\n", __func__);
280 return -EINVAL;
281 }
282
Lukasz Majewski397af352019-06-19 17:31:05 +0200283 ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, node, "gpio-ranges",
284 NULL, 3, 0, &args);
285 if (ret)
286 printf("%s: 'gpio-ranges' not defined - using default!\n",
287 __func__);
288
Lukasz Majewskic883d6a2019-09-05 09:55:01 +0200289 plat->gpio_ranges = ret == 0 ? args.args[2] : MXS_MAX_GPIO_PER_BANK;
Lukasz Majewski397af352019-06-19 17:31:05 +0200290
291 return 0;
292}
293
294static const struct udevice_id mxs_gpio_ids[] = {
295 { .compatible = "fsl,imx23-gpio" },
296 { .compatible = "fsl,imx28-gpio" },
297 { }
298};
Lukasz Majewskic883d6a2019-09-05 09:55:01 +0200299#endif
Lukasz Majewski397af352019-06-19 17:31:05 +0200300
301U_BOOT_DRIVER(gpio_mxs) = {
Lukasz Majewskic883d6a2019-09-05 09:55:01 +0200302#ifdef CONFIG_MX28
303 .name = "fsl_imx28_gpio",
304#else /* CONFIG_MX23 */
305 .name = "fsl_imx23_gpio",
306#endif
Lukasz Majewski397af352019-06-19 17:31:05 +0200307 .id = UCLASS_GPIO,
308 .ops = &gpio_mxs_ops,
309 .probe = mxs_gpio_probe,
310 .priv_auto_alloc_size = sizeof(struct mxs_gpio_priv),
Lukasz Majewskic883d6a2019-09-05 09:55:01 +0200311 .platdata_auto_alloc_size = sizeof(struct mxs_gpio_platdata),
312#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
Lukasz Majewski397af352019-06-19 17:31:05 +0200313 .of_match = mxs_gpio_ids,
Lukasz Majewskic883d6a2019-09-05 09:55:01 +0200314 .ofdata_to_platdata = mxs_ofdata_to_platdata,
315#endif
Lukasz Majewski397af352019-06-19 17:31:05 +0200316};
Simon Glassbcee8d62019-12-06 21:41:35 -0700317#endif /* DM_GPIO */