]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
6b6440de MV |
2 | /* |
3 | * Freescale i.MX28 GPIO control code | |
4 | * | |
5 | * Copyright (C) 2011 Marek Vasut <[email protected]> | |
6 | * on behalf of DENX Software Engineering GmbH | |
6b6440de MV |
7 | */ |
8 | ||
9 | #include <common.h> | |
f7ae49fc | 10 | #include <log.h> |
336d4615 | 11 | #include <malloc.h> |
cd93d625 | 12 | #include <linux/bitops.h> |
1221ce45 | 13 | #include <linux/errno.h> |
6b6440de MV |
14 | #include <asm/io.h> |
15 | #include <asm/arch/iomux.h> | |
16 | #include <asm/arch/imx-regs.h> | |
17 | ||
18 | #if defined(CONFIG_MX23) | |
19 | #define PINCTRL_BANKS 3 | |
20 | #define PINCTRL_DOUT(n) (0x0500 + ((n) * 0x10)) | |
21 | #define PINCTRL_DIN(n) (0x0600 + ((n) * 0x10)) | |
22 | #define PINCTRL_DOE(n) (0x0700 + ((n) * 0x10)) | |
23 | #define PINCTRL_PIN2IRQ(n) (0x0800 + ((n) * 0x10)) | |
24 | #define PINCTRL_IRQEN(n) (0x0900 + ((n) * 0x10)) | |
25 | #define PINCTRL_IRQSTAT(n) (0x0c00 + ((n) * 0x10)) | |
26 | #elif defined(CONFIG_MX28) | |
27 | #define PINCTRL_BANKS 5 | |
28 | #define PINCTRL_DOUT(n) (0x0700 + ((n) * 0x10)) | |
29 | #define PINCTRL_DIN(n) (0x0900 + ((n) * 0x10)) | |
30 | #define PINCTRL_DOE(n) (0x0b00 + ((n) * 0x10)) | |
31 | #define PINCTRL_PIN2IRQ(n) (0x1000 + ((n) * 0x10)) | |
32 | #define PINCTRL_IRQEN(n) (0x1100 + ((n) * 0x10)) | |
33 | #define PINCTRL_IRQSTAT(n) (0x1400 + ((n) * 0x10)) | |
34 | #else | |
35 | #error "Please select CONFIG_MX23 or CONFIG_MX28" | |
36 | #endif | |
37 | ||
38 | #define GPIO_INT_FALL_EDGE 0x0 | |
39 | #define GPIO_INT_LOW_LEV 0x1 | |
40 | #define GPIO_INT_RISE_EDGE 0x2 | |
41 | #define GPIO_INT_HIGH_LEV 0x3 | |
42 | #define GPIO_INT_LEV_MASK (1 << 0) | |
43 | #define GPIO_INT_POL_MASK (1 << 1) | |
44 | ||
45 | void mxs_gpio_init(void) | |
46 | { | |
47 | int i; | |
48 | ||
49 | for (i = 0; i < PINCTRL_BANKS; i++) { | |
50 | writel(0, MXS_PINCTRL_BASE + PINCTRL_PIN2IRQ(i)); | |
51 | writel(0, MXS_PINCTRL_BASE + PINCTRL_IRQEN(i)); | |
52 | /* Use SCT address here to clear the IRQSTAT bits */ | |
53 | writel(0xffffffff, MXS_PINCTRL_BASE + PINCTRL_IRQSTAT(i) + 8); | |
54 | } | |
55 | } | |
56 | ||
397af356 | 57 | #if !CONFIG_IS_ENABLED(DM_GPIO) |
365d6070 | 58 | int gpio_get_value(unsigned gpio) |
6b6440de | 59 | { |
365d6070 | 60 | uint32_t bank = PAD_BANK(gpio); |
6b6440de | 61 | uint32_t offset = PINCTRL_DIN(bank); |
ddcf13b1 OS |
62 | struct mxs_register_32 *reg = |
63 | (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset); | |
6b6440de | 64 | |
365d6070 | 65 | return (readl(®->reg) >> PAD_PIN(gpio)) & 1; |
6b6440de MV |
66 | } |
67 | ||
365d6070 | 68 | void gpio_set_value(unsigned gpio, int value) |
6b6440de | 69 | { |
365d6070 | 70 | uint32_t bank = PAD_BANK(gpio); |
6b6440de | 71 | uint32_t offset = PINCTRL_DOUT(bank); |
ddcf13b1 OS |
72 | struct mxs_register_32 *reg = |
73 | (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset); | |
6b6440de MV |
74 | |
75 | if (value) | |
365d6070 | 76 | writel(1 << PAD_PIN(gpio), ®->reg_set); |
6b6440de | 77 | else |
365d6070 | 78 | writel(1 << PAD_PIN(gpio), ®->reg_clr); |
6b6440de MV |
79 | } |
80 | ||
365d6070 | 81 | int gpio_direction_input(unsigned gpio) |
6b6440de | 82 | { |
365d6070 | 83 | uint32_t bank = PAD_BANK(gpio); |
6b6440de | 84 | uint32_t offset = PINCTRL_DOE(bank); |
ddcf13b1 OS |
85 | struct mxs_register_32 *reg = |
86 | (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset); | |
6b6440de | 87 | |
365d6070 | 88 | writel(1 << PAD_PIN(gpio), ®->reg_clr); |
6b6440de MV |
89 | |
90 | return 0; | |
91 | } | |
92 | ||
365d6070 | 93 | int gpio_direction_output(unsigned gpio, int value) |
6b6440de | 94 | { |
365d6070 | 95 | uint32_t bank = PAD_BANK(gpio); |
6b6440de | 96 | uint32_t offset = PINCTRL_DOE(bank); |
ddcf13b1 OS |
97 | struct mxs_register_32 *reg = |
98 | (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset); | |
6b6440de | 99 | |
365d6070 | 100 | gpio_set_value(gpio, value); |
6b6440de | 101 | |
ac135f66 MH |
102 | writel(1 << PAD_PIN(gpio), ®->reg_set); |
103 | ||
6b6440de MV |
104 | return 0; |
105 | } | |
106 | ||
365d6070 | 107 | int gpio_request(unsigned gpio, const char *label) |
6b6440de | 108 | { |
365d6070 JH |
109 | if (PAD_BANK(gpio) >= PINCTRL_BANKS) |
110 | return -1; | |
6b6440de MV |
111 | |
112 | return 0; | |
113 | } | |
114 | ||
365d6070 | 115 | int gpio_free(unsigned gpio) |
6b6440de | 116 | { |
365d6070 | 117 | return 0; |
6b6440de | 118 | } |
88f91d13 MR |
119 | |
120 | int name_to_gpio(const char *name) | |
121 | { | |
122 | unsigned bank, pin; | |
123 | char *end; | |
124 | ||
125 | bank = simple_strtoul(name, &end, 10); | |
126 | ||
127 | if (!*end || *end != ':') | |
128 | return bank; | |
129 | ||
130 | pin = simple_strtoul(end + 1, NULL, 10); | |
131 | ||
132 | return (bank << MXS_PAD_BANK_SHIFT) | (pin << MXS_PAD_PIN_SHIFT); | |
133 | } | |
bcee8d67 | 134 | #else /* DM_GPIO */ |
397af356 LM |
135 | #include <dm.h> |
136 | #include <asm/gpio.h> | |
c883d6a0 | 137 | #include <dt-structs.h> |
397af356 LM |
138 | #include <asm/arch/gpio.h> |
139 | #define MXS_MAX_GPIO_PER_BANK 32 | |
140 | ||
141 | DECLARE_GLOBAL_DATA_PTR; | |
142 | /* | |
143 | * According to i.MX28 Reference Manual: | |
144 | * 'i.MX28 Applications Processor Reference Manual, Rev. 1, 2010' | |
145 | * The i.MX28 has following number of GPIOs available: | |
146 | * Bank 0: 0-28 -> 29 PINS | |
147 | * Bank 1: 0-31 -> 32 PINS | |
148 | * Bank 2: 0-27 -> 28 PINS | |
149 | * Bank 3: 0-30 -> 31 PINS | |
150 | * Bank 4: 0-20 -> 21 PINS | |
151 | */ | |
152 | ||
8a8d24bd | 153 | struct mxs_gpio_plat { |
c883d6a0 | 154 | #if CONFIG_IS_ENABLED(OF_PLATDATA) |
df17cdc9 | 155 | struct dtd_fsl_imx23_gpio dtplat; |
c883d6a0 LM |
156 | #endif |
157 | unsigned int bank; | |
158 | int gpio_ranges; | |
159 | }; | |
160 | ||
397af356 LM |
161 | struct mxs_gpio_priv { |
162 | unsigned int bank; | |
163 | }; | |
164 | ||
165 | static int mxs_gpio_get_value(struct udevice *dev, unsigned offset) | |
166 | { | |
167 | struct mxs_gpio_priv *priv = dev_get_priv(dev); | |
168 | struct mxs_register_32 *reg = | |
169 | (struct mxs_register_32 *)(MXS_PINCTRL_BASE + | |
170 | PINCTRL_DIN(priv->bank)); | |
171 | ||
172 | return (readl(®->reg) >> offset) & 1; | |
173 | } | |
174 | ||
175 | static int mxs_gpio_set_value(struct udevice *dev, unsigned offset, | |
176 | int value) | |
177 | { | |
178 | struct mxs_gpio_priv *priv = dev_get_priv(dev); | |
179 | struct mxs_register_32 *reg = | |
180 | (struct mxs_register_32 *)(MXS_PINCTRL_BASE + | |
181 | PINCTRL_DOUT(priv->bank)); | |
182 | if (value) | |
183 | writel(BIT(offset), ®->reg_set); | |
184 | else | |
185 | writel(BIT(offset), ®->reg_clr); | |
186 | ||
187 | return 0; | |
188 | } | |
189 | ||
190 | static int mxs_gpio_direction_input(struct udevice *dev, unsigned offset) | |
191 | { | |
192 | struct mxs_gpio_priv *priv = dev_get_priv(dev); | |
193 | struct mxs_register_32 *reg = | |
194 | (struct mxs_register_32 *)(MXS_PINCTRL_BASE + | |
195 | PINCTRL_DOE(priv->bank)); | |
196 | ||
197 | writel(BIT(offset), ®->reg_clr); | |
198 | ||
199 | return 0; | |
200 | } | |
201 | ||
202 | static int mxs_gpio_direction_output(struct udevice *dev, unsigned offset, | |
203 | int value) | |
204 | { | |
205 | struct mxs_gpio_priv *priv = dev_get_priv(dev); | |
206 | struct mxs_register_32 *reg = | |
207 | (struct mxs_register_32 *)(MXS_PINCTRL_BASE + | |
208 | PINCTRL_DOE(priv->bank)); | |
209 | ||
210 | mxs_gpio_set_value(dev, offset, value); | |
211 | ||
212 | writel(BIT(offset), ®->reg_set); | |
213 | ||
214 | return 0; | |
215 | } | |
216 | ||
217 | static int mxs_gpio_get_function(struct udevice *dev, unsigned offset) | |
218 | { | |
219 | struct mxs_gpio_priv *priv = dev_get_priv(dev); | |
220 | struct mxs_register_32 *reg = | |
221 | (struct mxs_register_32 *)(MXS_PINCTRL_BASE + | |
222 | PINCTRL_DOE(priv->bank)); | |
223 | bool is_output = !!(readl(®->reg) >> offset); | |
224 | ||
225 | return is_output ? GPIOF_OUTPUT : GPIOF_INPUT; | |
226 | } | |
227 | ||
228 | static const struct dm_gpio_ops gpio_mxs_ops = { | |
229 | .direction_input = mxs_gpio_direction_input, | |
230 | .direction_output = mxs_gpio_direction_output, | |
231 | .get_value = mxs_gpio_get_value, | |
232 | .set_value = mxs_gpio_set_value, | |
233 | .get_function = mxs_gpio_get_function, | |
234 | }; | |
235 | ||
236 | static int mxs_gpio_probe(struct udevice *dev) | |
237 | { | |
8a8d24bd | 238 | struct mxs_gpio_plat *plat = dev_get_plat(dev); |
397af356 LM |
239 | struct mxs_gpio_priv *priv = dev_get_priv(dev); |
240 | struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); | |
397af356 | 241 | char name[16], *str; |
397af356 | 242 | |
c883d6a0 | 243 | #if CONFIG_IS_ENABLED(OF_PLATDATA) |
df17cdc9 | 244 | struct dtd_fsl_imx23_gpio *dtplat = &plat->dtplat; |
c883d6a0 LM |
245 | priv->bank = (unsigned int)dtplat->reg[0]; |
246 | uc_priv->gpio_count = dtplat->gpio_ranges[3]; | |
247 | #else | |
248 | priv->bank = (unsigned int)plat->bank; | |
249 | uc_priv->gpio_count = plat->gpio_ranges; | |
250 | #endif | |
397af356 LM |
251 | snprintf(name, sizeof(name), "GPIO%d_", priv->bank); |
252 | str = strdup(name); | |
253 | if (!str) | |
254 | return -ENOMEM; | |
255 | ||
256 | uc_priv->bank_name = str; | |
257 | ||
c883d6a0 LM |
258 | debug("%s: %s: %d pins base: 0x%x\n", __func__, uc_priv->bank_name, |
259 | uc_priv->gpio_count, priv->bank); | |
260 | ||
261 | return 0; | |
262 | } | |
263 | ||
264 | #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) | |
d1998a9f | 265 | static int mxs_of_to_plat(struct udevice *dev) |
c883d6a0 | 266 | { |
8a8d24bd | 267 | struct mxs_gpio_plat *plat = dev->plat; |
c883d6a0 LM |
268 | struct fdtdec_phandle_args args; |
269 | int node = dev_of_offset(dev); | |
270 | int ret; | |
271 | ||
2548493a | 272 | plat->bank = dev_read_addr(dev); |
c883d6a0 LM |
273 | if (plat->bank == FDT_ADDR_T_NONE) { |
274 | printf("%s: No 'reg' property defined!\n", __func__); | |
275 | return -EINVAL; | |
276 | } | |
277 | ||
397af356 LM |
278 | ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, node, "gpio-ranges", |
279 | NULL, 3, 0, &args); | |
280 | if (ret) | |
281 | printf("%s: 'gpio-ranges' not defined - using default!\n", | |
282 | __func__); | |
283 | ||
c883d6a0 | 284 | plat->gpio_ranges = ret == 0 ? args.args[2] : MXS_MAX_GPIO_PER_BANK; |
397af356 LM |
285 | |
286 | return 0; | |
287 | } | |
288 | ||
289 | static const struct udevice_id mxs_gpio_ids[] = { | |
290 | { .compatible = "fsl,imx23-gpio" }, | |
291 | { .compatible = "fsl,imx28-gpio" }, | |
292 | { } | |
293 | }; | |
c883d6a0 | 294 | #endif |
397af356 | 295 | |
e3e2470f | 296 | U_BOOT_DRIVER(fsl_imx23_gpio) = { |
c883d6a0 | 297 | .name = "fsl_imx23_gpio", |
397af356 LM |
298 | .id = UCLASS_GPIO, |
299 | .ops = &gpio_mxs_ops, | |
300 | .probe = mxs_gpio_probe, | |
41575d8e | 301 | .priv_auto = sizeof(struct mxs_gpio_priv), |
8a8d24bd | 302 | .plat_auto = sizeof(struct mxs_gpio_plat), |
c883d6a0 | 303 | #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) |
397af356 | 304 | .of_match = mxs_gpio_ids, |
d1998a9f | 305 | .of_to_plat = mxs_of_to_plat, |
c883d6a0 | 306 | #endif |
397af356 | 307 | }; |
addf358b WL |
308 | |
309 | U_BOOT_DRIVER_ALIAS(fsl_imx23_gpio, fsl_imx28_gpio) | |
bcee8d67 | 310 | #endif /* DM_GPIO */ |