1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2009
4 * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
5 *
6 * Copyright (C) 2011
7 * Stefano Babic, DENX Software Engineering, <sbabic@denx.de>
8 */
9#include <common.h>
10#include <errno.h>
11#include <dm.h>
12#include <malloc.h>
13#include <asm/arch/imx-regs.h>
14#include <asm/gpio.h>
15#include <asm/io.h>
16#include <dt-structs.h>
17#include <mapmem.h>
18
19enum mxc_gpio_direction {
20	MXC_GPIO_DIRECTION_IN,
21	MXC_GPIO_DIRECTION_OUT,
22};
23
24#define GPIO_PER_BANK			32
25
26struct mxc_gpio_plat {
27#if CONFIG_IS_ENABLED(OF_PLATDATA)
28	/* Put this first since driver model will copy the data here */
29	struct dtd_gpio_mxc dtplat;
30#endif
31	int bank_index;
32	struct gpio_regs *regs;
33};
34
35struct mxc_bank_info {
36	struct gpio_regs *regs;
37};
38
39#if !CONFIG_IS_ENABLED(DM_GPIO)
40#define GPIO_TO_PORT(n)		((n) / 32)
41
42/* GPIO port description */
43static unsigned long gpio_ports[] = {
44	[0] = GPIO1_BASE_ADDR,
45	[1] = GPIO2_BASE_ADDR,
46	[2] = GPIO3_BASE_ADDR,
47#if defined(CONFIG_MX51) || \
48		defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
49		defined(CONFIG_MX7) || defined(CONFIG_IMX8M) || \
50		defined(CONFIG_ARCH_IMX8) || defined(CONFIG_IMXRT1050)
51	[3] = GPIO4_BASE_ADDR,
52#endif
53#if defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
54		defined(CONFIG_MX7) || defined(CONFIG_IMX8M) || \
55		defined(CONFIG_ARCH_IMX8) || defined(CONFIG_IMXRT1050)
56	[4] = GPIO5_BASE_ADDR,
57#if !(defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL) || \
58		defined(CONFIG_IMX8M) || defined(CONFIG_IMXRT1050))
59	[5] = GPIO6_BASE_ADDR,
60#endif
61#endif
62#if defined(CONFIG_MX53) || defined(CONFIG_MX6) || defined(CONFIG_MX7) || \
63		defined(CONFIG_ARCH_IMX8)
64#if !(defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL))
65	[6] = GPIO7_BASE_ADDR,
66#endif
67#endif
68#if defined(CONFIG_ARCH_IMX8)
69	[7] = GPIO8_BASE_ADDR,
70#endif
71};
72
73static int mxc_gpio_direction(unsigned int gpio,
74	enum mxc_gpio_direction direction)
75{
76	unsigned int port = GPIO_TO_PORT(gpio);
77	struct gpio_regs *regs;
78	u32 l;
79
80	if (port >= ARRAY_SIZE(gpio_ports))
81		return -1;
82
83	gpio &= 0x1f;
84
85	regs = (struct gpio_regs *)gpio_ports[port];
86
87	l = readl(&regs->gpio_dir);
88
89	switch (direction) {
90	case MXC_GPIO_DIRECTION_OUT:
91		l |= 1 << gpio;
92		break;
93	case MXC_GPIO_DIRECTION_IN:
94		l &= ~(1 << gpio);
95	}
96	writel(l, &regs->gpio_dir);
97
98	return 0;
99}
100
101int gpio_set_value(unsigned gpio, int value)
102{
103	unsigned int port = GPIO_TO_PORT(gpio);
104	struct gpio_regs *regs;
105	u32 l;
106
107	if (port >= ARRAY_SIZE(gpio_ports))
108		return -1;
109
110	gpio &= 0x1f;
111
112	regs = (struct gpio_regs *)gpio_ports[port];
113
114	l = readl(&regs->gpio_dr);
115	if (value)
116		l |= 1 << gpio;
117	else
118		l &= ~(1 << gpio);
119	writel(l, &regs->gpio_dr);
120
121	return 0;
122}
123
124int gpio_get_value(unsigned gpio)
125{
126	unsigned int port = GPIO_TO_PORT(gpio);
127	struct gpio_regs *regs;
128	u32 val;
129
130	if (port >= ARRAY_SIZE(gpio_ports))
131		return -1;
132
133	gpio &= 0x1f;
134
135	regs = (struct gpio_regs *)gpio_ports[port];
136
137	val = (readl(&regs->gpio_psr) >> gpio) & 0x01;
138
139	return val;
140}
141
142int gpio_request(unsigned gpio, const char *label)
143{
144	unsigned int port = GPIO_TO_PORT(gpio);
145	if (port >= ARRAY_SIZE(gpio_ports))
146		return -1;
147	return 0;
148}
149
150int gpio_free(unsigned gpio)
151{
152	return 0;
153}
154
155int gpio_direction_input(unsigned gpio)
156{
157	return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_IN);
158}
159
160int gpio_direction_output(unsigned gpio, int value)
161{
162	int ret = gpio_set_value(gpio, value);
163
164	if (ret < 0)
165		return ret;
166
167	return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_OUT);
168}
169#endif
170
171#if CONFIG_IS_ENABLED(DM_GPIO)
172#include <fdtdec.h>
173static int mxc_gpio_is_output(struct gpio_regs *regs, int offset)
174{
175	u32 val;
176
177	val = readl(&regs->gpio_dir);
178
179	return val & (1 << offset) ? 1 : 0;
180}
181
182static void mxc_gpio_bank_direction(struct gpio_regs *regs, int offset,
183				    enum mxc_gpio_direction direction)
184{
185	u32 l;
186
187	l = readl(&regs->gpio_dir);
188
189	switch (direction) {
190	case MXC_GPIO_DIRECTION_OUT:
191		l |= 1 << offset;
192		break;
193	case MXC_GPIO_DIRECTION_IN:
194		l &= ~(1 << offset);
195	}
196	writel(l, &regs->gpio_dir);
197}
198
199static void mxc_gpio_bank_set_value(struct gpio_regs *regs, int offset,
200				    int value)
201{
202	u32 l;
203
204	l = readl(&regs->gpio_dr);
205	if (value)
206		l |= 1 << offset;
207	else
208		l &= ~(1 << offset);
209	writel(l, &regs->gpio_dr);
210}
211
212static int mxc_gpio_bank_get_value(struct gpio_regs *regs, int offset)
213{
214	return (readl(&regs->gpio_psr) >> offset) & 0x01;
215}
216
217/* set GPIO pin 'gpio' as an input */
218static int mxc_gpio_direction_input(struct udevice *dev, unsigned offset)
219{
220	struct mxc_bank_info *bank = dev_get_priv(dev);
221
222	/* Configure GPIO direction as input. */
223	mxc_gpio_bank_direction(bank->regs, offset, MXC_GPIO_DIRECTION_IN);
224
225	return 0;
226}
227
228/* set GPIO pin 'gpio' as an output, with polarity 'value' */
229static int mxc_gpio_direction_output(struct udevice *dev, unsigned offset,
230				       int value)
231{
232	struct mxc_bank_info *bank = dev_get_priv(dev);
233
234	/* Configure GPIO output value. */
235	mxc_gpio_bank_set_value(bank->regs, offset, value);
236
237	/* Configure GPIO direction as output. */
238	mxc_gpio_bank_direction(bank->regs, offset, MXC_GPIO_DIRECTION_OUT);
239
240	return 0;
241}
242
243/* read GPIO IN value of pin 'gpio' */
244static int mxc_gpio_get_value(struct udevice *dev, unsigned offset)
245{
246	struct mxc_bank_info *bank = dev_get_priv(dev);
247
248	return mxc_gpio_bank_get_value(bank->regs, offset);
249}
250
251/* write GPIO OUT value to pin 'gpio' */
252static int mxc_gpio_set_value(struct udevice *dev, unsigned offset,
253				 int value)
254{
255	struct mxc_bank_info *bank = dev_get_priv(dev);
256
257	mxc_gpio_bank_set_value(bank->regs, offset, value);
258
259	return 0;
260}
261
262static int mxc_gpio_get_function(struct udevice *dev, unsigned offset)
263{
264	struct mxc_bank_info *bank = dev_get_priv(dev);
265
266	/* GPIOF_FUNC is not implemented yet */
267	if (mxc_gpio_is_output(bank->regs, offset))
268		return GPIOF_OUTPUT;
269	else
270		return GPIOF_INPUT;
271}
272
273static const struct dm_gpio_ops gpio_mxc_ops = {
274	.direction_input	= mxc_gpio_direction_input,
275	.direction_output	= mxc_gpio_direction_output,
276	.get_value		= mxc_gpio_get_value,
277	.set_value		= mxc_gpio_set_value,
278	.get_function		= mxc_gpio_get_function,
279};
280
281static int mxc_gpio_probe(struct udevice *dev)
282{
283	struct mxc_bank_info *bank = dev_get_priv(dev);
284	struct mxc_gpio_plat *plat = dev_get_plat(dev);
285	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
286	int banknum;
287	char name[18], *str;
288
289#if CONFIG_IS_ENABLED(OF_PLATDATA)
290	struct dtd_gpio_mxc *dtplat = &plat->dtplat;
291
292	plat->regs = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
293#endif
294
295	banknum = plat->bank_index;
296	if (IS_ENABLED(CONFIG_ARCH_IMX8))
297		sprintf(name, "GPIO%d_", banknum);
298	else
299		sprintf(name, "GPIO%d_", banknum + 1);
300	str = strdup(name);
301	if (!str)
302		return -ENOMEM;
303	uc_priv->bank_name = str;
304	uc_priv->gpio_count = GPIO_PER_BANK;
305	bank->regs = plat->regs;
306
307	return 0;
308}
309
310static int mxc_gpio_of_to_plat(struct udevice *dev)
311{
312	struct mxc_gpio_plat *plat = dev_get_plat(dev);
313	if (!CONFIG_IS_ENABLED(OF_PLATDATA)) {
314		fdt_addr_t addr;
315		addr = dev_read_addr(dev);
316		if (addr == FDT_ADDR_T_NONE)
317			return -EINVAL;
318
319		plat->regs = (struct gpio_regs *)addr;
320	}
321	plat->bank_index = dev_seq(dev);
322
323	return 0;
324}
325
326static int mxc_gpio_bind(struct udevice *dev)
327{
328	return 0;
329}
330
331static const struct udevice_id mxc_gpio_ids[] = {
332	{ .compatible = "fsl,imx35-gpio" },
333	{ }
334};
335
336U_BOOT_DRIVER(gpio_mxc) = {
337	.name	= "gpio_mxc",
338	.id	= UCLASS_GPIO,
339	.ops	= &gpio_mxc_ops,
340	.probe	= mxc_gpio_probe,
341	.of_to_plat = mxc_gpio_of_to_plat,
342	.plat_auto	= sizeof(struct mxc_gpio_plat),
343	.priv_auto	= sizeof(struct mxc_bank_info),
344	.of_match = mxc_gpio_ids,
345	.bind	= mxc_gpio_bind,
346};
347
348DM_DRIVER_ALIAS(gpio_mxc, fsl_imx6q_gpio)
349
350#if !CONFIG_IS_ENABLED(OF_CONTROL)
351static 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_MX51) || \
356		defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
357		defined(CONFIG_IMX8M) || defined(CONFIG_ARCH_IMX8)
358	{ 3, (struct gpio_regs *)GPIO4_BASE_ADDR },
359#endif
360#if defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
361		defined(CONFIG_IMX8M) || defined(CONFIG_ARCH_IMX8)
362	{ 4, (struct gpio_regs *)GPIO5_BASE_ADDR },
363#ifndef CONFIG_IMX8M
364	{ 5, (struct gpio_regs *)GPIO6_BASE_ADDR },
365#endif
366#endif
367#if defined(CONFIG_MX53) || defined(CONFIG_MX6) || defined(CONFIG_ARCH_IMX8)
368	{ 6, (struct gpio_regs *)GPIO7_BASE_ADDR },
369#endif
370#if defined(CONFIG_ARCH_IMX8)
371	{ 7, (struct gpio_regs *)GPIO8_BASE_ADDR },
372#endif
373};
374
375U_BOOT_DRVINFOS(mxc_gpios) = {
376	{ "gpio_mxc", &mxc_plat[0] },
377	{ "gpio_mxc", &mxc_plat[1] },
378	{ "gpio_mxc", &mxc_plat[2] },
379#if defined(CONFIG_MX51) || \
380		defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
381		defined(CONFIG_IMX8M) || defined(CONFIG_ARCH_IMX8)
382	{ "gpio_mxc", &mxc_plat[3] },
383#endif
384#if defined(CONFIG_MX53) || defined(CONFIG_MX6) || \
385		defined(CONFIG_IMX8M) || defined(CONFIG_ARCH_IMX8)
386	{ "gpio_mxc", &mxc_plat[4] },
387#ifndef CONFIG_IMX8M
388	{ "gpio_mxc", &mxc_plat[5] },
389#endif
390#endif
391#if defined(CONFIG_MX53) || defined(CONFIG_MX6) || defined(CONFIG_ARCH_IMX8)
392	{ "gpio_mxc", &mxc_plat[6] },
393#endif
394#if defined(CONFIG_ARCH_IMX8)
395	{ "gpio_mxc", &mxc_plat[7] },
396#endif
397};
398#endif
399#endif
400