xref: /rk3399_rockchip-uboot/drivers/gpio/mxc_gpio.c (revision 99c0ae16d8b2ebfb7381ba77d4e37e7bda734402)
1c4ea1424SStefano Babic /*
2c4ea1424SStefano Babic  * Copyright (C) 2009
3c4ea1424SStefano Babic  * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
4c4ea1424SStefano Babic  *
5d8e0ca85SStefano Babic  * Copyright (C) 2011
6d8e0ca85SStefano Babic  * Stefano Babic, DENX Software Engineering, <sbabic@denx.de>
7d8e0ca85SStefano Babic  *
81a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
9c4ea1424SStefano Babic  */
10c4ea1424SStefano Babic #include <common.h>
11441d0cffSSimon Glass #include <errno.h>
12441d0cffSSimon Glass #include <dm.h>
13441d0cffSSimon Glass #include <malloc.h>
14c4ea1424SStefano Babic #include <asm/arch/imx-regs.h>
15d8e0ca85SStefano Babic #include <asm/gpio.h>
16c4ea1424SStefano Babic #include <asm/io.h>
17c4ea1424SStefano Babic 
18d8e0ca85SStefano Babic enum mxc_gpio_direction {
19d8e0ca85SStefano Babic 	MXC_GPIO_DIRECTION_IN,
20d8e0ca85SStefano Babic 	MXC_GPIO_DIRECTION_OUT,
21d8e0ca85SStefano Babic };
22d8e0ca85SStefano Babic 
23441d0cffSSimon Glass #define GPIO_PER_BANK			32
24441d0cffSSimon Glass 
25441d0cffSSimon Glass struct mxc_gpio_plat {
26637a7693SPeng Fan 	int bank_index;
27441d0cffSSimon Glass 	struct gpio_regs *regs;
28441d0cffSSimon Glass };
29441d0cffSSimon Glass 
30441d0cffSSimon Glass struct mxc_bank_info {
31441d0cffSSimon Glass 	struct gpio_regs *regs;
32441d0cffSSimon Glass };
33441d0cffSSimon Glass 
34441d0cffSSimon Glass #ifndef CONFIG_DM_GPIO
358d28c211SVikram Narayanan #define GPIO_TO_PORT(n)		(n / 32)
36d8e0ca85SStefano Babic 
37c4ea1424SStefano Babic /* GPIO port description */
38c4ea1424SStefano Babic static unsigned long gpio_ports[] = {
39c4ea1424SStefano Babic 	[0] = GPIO1_BASE_ADDR,
40c4ea1424SStefano Babic 	[1] = GPIO2_BASE_ADDR,
41c4ea1424SStefano Babic 	[2] = GPIO3_BASE_ADDR,
42e71c39deStrem #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \
435ea6d7c8STroy Kisky 		defined(CONFIG_MX53) || defined(CONFIG_MX6)
44c4ea1424SStefano Babic 	[3] = GPIO4_BASE_ADDR,
45c4ea1424SStefano Babic #endif
465ea6d7c8STroy Kisky #if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6)
4701643ec1SLiu Hui-R64343 	[4] = GPIO5_BASE_ADDR,
4801643ec1SLiu Hui-R64343 	[5] = GPIO6_BASE_ADDR,
49e71c39deStrem #endif
505ea6d7c8STroy Kisky #if defined(CONFIG_MX53) || defined(CONFIG_MX6)
5101643ec1SLiu Hui-R64343 	[6] = GPIO7_BASE_ADDR,
5201643ec1SLiu Hui-R64343 #endif
53c4ea1424SStefano Babic };
54c4ea1424SStefano Babic 
55d8e0ca85SStefano Babic static int mxc_gpio_direction(unsigned int gpio,
56d8e0ca85SStefano Babic 	enum mxc_gpio_direction direction)
57c4ea1424SStefano Babic {
58be282554SVikram Narayanan 	unsigned int port = GPIO_TO_PORT(gpio);
59c4ea1424SStefano Babic 	struct gpio_regs *regs;
60c4ea1424SStefano Babic 	u32 l;
61c4ea1424SStefano Babic 
62c4ea1424SStefano Babic 	if (port >= ARRAY_SIZE(gpio_ports))
63365d6070SJoe Hershberger 		return -1;
64c4ea1424SStefano Babic 
65c4ea1424SStefano Babic 	gpio &= 0x1f;
66c4ea1424SStefano Babic 
67c4ea1424SStefano Babic 	regs = (struct gpio_regs *)gpio_ports[port];
68c4ea1424SStefano Babic 
69c4ea1424SStefano Babic 	l = readl(&regs->gpio_dir);
70c4ea1424SStefano Babic 
71c4ea1424SStefano Babic 	switch (direction) {
72c4ea1424SStefano Babic 	case MXC_GPIO_DIRECTION_OUT:
73c4ea1424SStefano Babic 		l |= 1 << gpio;
74c4ea1424SStefano Babic 		break;
75c4ea1424SStefano Babic 	case MXC_GPIO_DIRECTION_IN:
76c4ea1424SStefano Babic 		l &= ~(1 << gpio);
77c4ea1424SStefano Babic 	}
78c4ea1424SStefano Babic 	writel(l, &regs->gpio_dir);
79c4ea1424SStefano Babic 
80c4ea1424SStefano Babic 	return 0;
81c4ea1424SStefano Babic }
82c4ea1424SStefano Babic 
83365d6070SJoe Hershberger int gpio_set_value(unsigned gpio, int value)
84c4ea1424SStefano Babic {
85be282554SVikram Narayanan 	unsigned int port = GPIO_TO_PORT(gpio);
86c4ea1424SStefano Babic 	struct gpio_regs *regs;
87c4ea1424SStefano Babic 	u32 l;
88c4ea1424SStefano Babic 
89c4ea1424SStefano Babic 	if (port >= ARRAY_SIZE(gpio_ports))
90365d6070SJoe Hershberger 		return -1;
91c4ea1424SStefano Babic 
92c4ea1424SStefano Babic 	gpio &= 0x1f;
93c4ea1424SStefano Babic 
94c4ea1424SStefano Babic 	regs = (struct gpio_regs *)gpio_ports[port];
95c4ea1424SStefano Babic 
96c4ea1424SStefano Babic 	l = readl(&regs->gpio_dr);
97c4ea1424SStefano Babic 	if (value)
98c4ea1424SStefano Babic 		l |= 1 << gpio;
99c4ea1424SStefano Babic 	else
100c4ea1424SStefano Babic 		l &= ~(1 << gpio);
101c4ea1424SStefano Babic 	writel(l, &regs->gpio_dr);
102365d6070SJoe Hershberger 
103365d6070SJoe Hershberger 	return 0;
104c4ea1424SStefano Babic }
105c4ea1424SStefano Babic 
106365d6070SJoe Hershberger int gpio_get_value(unsigned gpio)
107c4ea1424SStefano Babic {
108be282554SVikram Narayanan 	unsigned int port = GPIO_TO_PORT(gpio);
109c4ea1424SStefano Babic 	struct gpio_regs *regs;
110365d6070SJoe Hershberger 	u32 val;
111c4ea1424SStefano Babic 
112c4ea1424SStefano Babic 	if (port >= ARRAY_SIZE(gpio_ports))
113365d6070SJoe Hershberger 		return -1;
114c4ea1424SStefano Babic 
115c4ea1424SStefano Babic 	gpio &= 0x1f;
116c4ea1424SStefano Babic 
117c4ea1424SStefano Babic 	regs = (struct gpio_regs *)gpio_ports[port];
118c4ea1424SStefano Babic 
1195dafa454SBenoît Thébaudeau 	val = (readl(&regs->gpio_psr) >> gpio) & 0x01;
120c4ea1424SStefano Babic 
121365d6070SJoe Hershberger 	return val;
122c4ea1424SStefano Babic }
123d8e0ca85SStefano Babic 
124365d6070SJoe Hershberger int gpio_request(unsigned gpio, const char *label)
125d8e0ca85SStefano Babic {
126be282554SVikram Narayanan 	unsigned int port = GPIO_TO_PORT(gpio);
127d8e0ca85SStefano Babic 	if (port >= ARRAY_SIZE(gpio_ports))
128365d6070SJoe Hershberger 		return -1;
129d8e0ca85SStefano Babic 	return 0;
130d8e0ca85SStefano Babic }
131d8e0ca85SStefano Babic 
132365d6070SJoe Hershberger int gpio_free(unsigned gpio)
133d8e0ca85SStefano Babic {
134365d6070SJoe Hershberger 	return 0;
135d8e0ca85SStefano Babic }
136d8e0ca85SStefano Babic 
137365d6070SJoe Hershberger int gpio_direction_input(unsigned gpio)
138d8e0ca85SStefano Babic {
139365d6070SJoe Hershberger 	return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_IN);
140d8e0ca85SStefano Babic }
141d8e0ca85SStefano Babic 
142365d6070SJoe Hershberger int gpio_direction_output(unsigned gpio, int value)
143d8e0ca85SStefano Babic {
14404c79cbdSDirk Behme 	int ret = gpio_set_value(gpio, value);
145d8e0ca85SStefano Babic 
146d8e0ca85SStefano Babic 	if (ret < 0)
147d8e0ca85SStefano Babic 		return ret;
148d8e0ca85SStefano Babic 
14904c79cbdSDirk Behme 	return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_OUT);
150d8e0ca85SStefano Babic }
151441d0cffSSimon Glass #endif
152441d0cffSSimon Glass 
153441d0cffSSimon Glass #ifdef CONFIG_DM_GPIO
154*99c0ae16SPeng Fan #include <fdtdec.h>
155*99c0ae16SPeng Fan DECLARE_GLOBAL_DATA_PTR;
156*99c0ae16SPeng Fan 
157441d0cffSSimon Glass static int mxc_gpio_is_output(struct gpio_regs *regs, int offset)
158441d0cffSSimon Glass {
159441d0cffSSimon Glass 	u32 val;
160441d0cffSSimon Glass 
161441d0cffSSimon Glass 	val = readl(&regs->gpio_dir);
162441d0cffSSimon Glass 
163441d0cffSSimon Glass 	return val & (1 << offset) ? 1 : 0;
164441d0cffSSimon Glass }
165441d0cffSSimon Glass 
166441d0cffSSimon Glass static void mxc_gpio_bank_direction(struct gpio_regs *regs, int offset,
167441d0cffSSimon Glass 				    enum mxc_gpio_direction direction)
168441d0cffSSimon Glass {
169441d0cffSSimon Glass 	u32 l;
170441d0cffSSimon Glass 
171441d0cffSSimon Glass 	l = readl(&regs->gpio_dir);
172441d0cffSSimon Glass 
173441d0cffSSimon Glass 	switch (direction) {
174441d0cffSSimon Glass 	case MXC_GPIO_DIRECTION_OUT:
175441d0cffSSimon Glass 		l |= 1 << offset;
176441d0cffSSimon Glass 		break;
177441d0cffSSimon Glass 	case MXC_GPIO_DIRECTION_IN:
178441d0cffSSimon Glass 		l &= ~(1 << offset);
179441d0cffSSimon Glass 	}
180441d0cffSSimon Glass 	writel(l, &regs->gpio_dir);
181441d0cffSSimon Glass }
182441d0cffSSimon Glass 
183441d0cffSSimon Glass static void mxc_gpio_bank_set_value(struct gpio_regs *regs, int offset,
184441d0cffSSimon Glass 				    int value)
185441d0cffSSimon Glass {
186441d0cffSSimon Glass 	u32 l;
187441d0cffSSimon Glass 
188441d0cffSSimon Glass 	l = readl(&regs->gpio_dr);
189441d0cffSSimon Glass 	if (value)
190441d0cffSSimon Glass 		l |= 1 << offset;
191441d0cffSSimon Glass 	else
192441d0cffSSimon Glass 		l &= ~(1 << offset);
193441d0cffSSimon Glass 	writel(l, &regs->gpio_dr);
194441d0cffSSimon Glass }
195441d0cffSSimon Glass 
196441d0cffSSimon Glass static int mxc_gpio_bank_get_value(struct gpio_regs *regs, int offset)
197441d0cffSSimon Glass {
198441d0cffSSimon Glass 	return (readl(&regs->gpio_psr) >> offset) & 0x01;
199441d0cffSSimon Glass }
200441d0cffSSimon Glass 
201441d0cffSSimon Glass /* set GPIO pin 'gpio' as an input */
202441d0cffSSimon Glass static int mxc_gpio_direction_input(struct udevice *dev, unsigned offset)
203441d0cffSSimon Glass {
204441d0cffSSimon Glass 	struct mxc_bank_info *bank = dev_get_priv(dev);
205441d0cffSSimon Glass 
206441d0cffSSimon Glass 	/* Configure GPIO direction as input. */
207441d0cffSSimon Glass 	mxc_gpio_bank_direction(bank->regs, offset, MXC_GPIO_DIRECTION_IN);
208441d0cffSSimon Glass 
209441d0cffSSimon Glass 	return 0;
210441d0cffSSimon Glass }
211441d0cffSSimon Glass 
212441d0cffSSimon Glass /* set GPIO pin 'gpio' as an output, with polarity 'value' */
213441d0cffSSimon Glass static int mxc_gpio_direction_output(struct udevice *dev, unsigned offset,
214441d0cffSSimon Glass 				       int value)
215441d0cffSSimon Glass {
216441d0cffSSimon Glass 	struct mxc_bank_info *bank = dev_get_priv(dev);
217441d0cffSSimon Glass 
218441d0cffSSimon Glass 	/* Configure GPIO output value. */
219441d0cffSSimon Glass 	mxc_gpio_bank_set_value(bank->regs, offset, value);
220441d0cffSSimon Glass 
221441d0cffSSimon Glass 	/* Configure GPIO direction as output. */
222441d0cffSSimon Glass 	mxc_gpio_bank_direction(bank->regs, offset, MXC_GPIO_DIRECTION_OUT);
223441d0cffSSimon Glass 
224441d0cffSSimon Glass 	return 0;
225441d0cffSSimon Glass }
226441d0cffSSimon Glass 
227441d0cffSSimon Glass /* read GPIO IN value of pin 'gpio' */
228441d0cffSSimon Glass static int mxc_gpio_get_value(struct udevice *dev, unsigned offset)
229441d0cffSSimon Glass {
230441d0cffSSimon Glass 	struct mxc_bank_info *bank = dev_get_priv(dev);
231441d0cffSSimon Glass 
232441d0cffSSimon Glass 	return mxc_gpio_bank_get_value(bank->regs, offset);
233441d0cffSSimon Glass }
234441d0cffSSimon Glass 
235441d0cffSSimon Glass /* write GPIO OUT value to pin 'gpio' */
236441d0cffSSimon Glass static int mxc_gpio_set_value(struct udevice *dev, unsigned offset,
237441d0cffSSimon Glass 				 int value)
238441d0cffSSimon Glass {
239441d0cffSSimon Glass 	struct mxc_bank_info *bank = dev_get_priv(dev);
240441d0cffSSimon Glass 
241441d0cffSSimon Glass 	mxc_gpio_bank_set_value(bank->regs, offset, value);
242441d0cffSSimon Glass 
243441d0cffSSimon Glass 	return 0;
244441d0cffSSimon Glass }
245441d0cffSSimon Glass 
246441d0cffSSimon Glass static int mxc_gpio_get_function(struct udevice *dev, unsigned offset)
247441d0cffSSimon Glass {
248441d0cffSSimon Glass 	struct mxc_bank_info *bank = dev_get_priv(dev);
249441d0cffSSimon Glass 
250441d0cffSSimon Glass 	/* GPIOF_FUNC is not implemented yet */
251441d0cffSSimon Glass 	if (mxc_gpio_is_output(bank->regs, offset))
252441d0cffSSimon Glass 		return GPIOF_OUTPUT;
253441d0cffSSimon Glass 	else
254441d0cffSSimon Glass 		return GPIOF_INPUT;
255441d0cffSSimon Glass }
256441d0cffSSimon Glass 
257441d0cffSSimon Glass static const struct dm_gpio_ops gpio_mxc_ops = {
258441d0cffSSimon Glass 	.direction_input	= mxc_gpio_direction_input,
259441d0cffSSimon Glass 	.direction_output	= mxc_gpio_direction_output,
260441d0cffSSimon Glass 	.get_value		= mxc_gpio_get_value,
261441d0cffSSimon Glass 	.set_value		= mxc_gpio_set_value,
262441d0cffSSimon Glass 	.get_function		= mxc_gpio_get_function,
263441d0cffSSimon Glass };
264441d0cffSSimon Glass 
265441d0cffSSimon Glass static int mxc_gpio_probe(struct udevice *dev)
266441d0cffSSimon Glass {
267441d0cffSSimon Glass 	struct mxc_bank_info *bank = dev_get_priv(dev);
268441d0cffSSimon Glass 	struct mxc_gpio_plat *plat = dev_get_platdata(dev);
269441d0cffSSimon Glass 	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
270441d0cffSSimon Glass 	int banknum;
271441d0cffSSimon Glass 	char name[18], *str;
272441d0cffSSimon Glass 
273637a7693SPeng Fan 	banknum = plat->bank_index;
274441d0cffSSimon Glass 	sprintf(name, "GPIO%d_", banknum + 1);
275441d0cffSSimon Glass 	str = strdup(name);
276441d0cffSSimon Glass 	if (!str)
277441d0cffSSimon Glass 		return -ENOMEM;
278441d0cffSSimon Glass 	uc_priv->bank_name = str;
279441d0cffSSimon Glass 	uc_priv->gpio_count = GPIO_PER_BANK;
280441d0cffSSimon Glass 	bank->regs = plat->regs;
281441d0cffSSimon Glass 
282441d0cffSSimon Glass 	return 0;
283441d0cffSSimon Glass }
284441d0cffSSimon Glass 
285*99c0ae16SPeng Fan static int mxc_gpio_bind(struct udevice *dev)
286*99c0ae16SPeng Fan {
287*99c0ae16SPeng Fan 	struct mxc_gpio_plat *plat = dev->platdata;
288*99c0ae16SPeng Fan 	fdt_addr_t addr;
289*99c0ae16SPeng Fan 
290*99c0ae16SPeng Fan 	/*
291*99c0ae16SPeng Fan 	 * If platdata already exsits, directly return.
292*99c0ae16SPeng Fan 	 * Actually only when DT is not supported, platdata
293*99c0ae16SPeng Fan 	 * is statically initialized in U_BOOT_DEVICES.Here
294*99c0ae16SPeng Fan 	 * will return.
295*99c0ae16SPeng Fan 	 */
296*99c0ae16SPeng Fan 	if (plat)
297*99c0ae16SPeng Fan 		return 0;
298*99c0ae16SPeng Fan 
299*99c0ae16SPeng Fan 	addr = dev_get_addr(dev);
300*99c0ae16SPeng Fan 	if (addr == FDT_ADDR_T_NONE)
301*99c0ae16SPeng Fan 		return -ENODEV;
302*99c0ae16SPeng Fan 
303*99c0ae16SPeng Fan 	/*
304*99c0ae16SPeng Fan 	 * TODO:
305*99c0ae16SPeng Fan 	 * When every board is converted to driver model and DT is supported,
306*99c0ae16SPeng Fan 	 * this can be done by auto-alloc feature, but not using calloc
307*99c0ae16SPeng Fan 	 * to alloc memory for platdata.
308*99c0ae16SPeng Fan 	 */
309*99c0ae16SPeng Fan 	plat = calloc(1, sizeof(*plat));
310*99c0ae16SPeng Fan 	if (!plat)
311*99c0ae16SPeng Fan 		return -ENOMEM;
312*99c0ae16SPeng Fan 
313*99c0ae16SPeng Fan 	plat->regs = (struct gpio_regs *)addr;
314*99c0ae16SPeng Fan 	plat->bank_index = dev->req_seq;
315*99c0ae16SPeng Fan 	dev->platdata = plat;
316*99c0ae16SPeng Fan 
317*99c0ae16SPeng Fan 	return 0;
318*99c0ae16SPeng Fan }
319*99c0ae16SPeng Fan 
320*99c0ae16SPeng Fan static const struct udevice_id mxc_gpio_ids[] = {
321*99c0ae16SPeng Fan 	{ .compatible = "fsl,imx35-gpio" },
322*99c0ae16SPeng Fan 	{ }
323*99c0ae16SPeng Fan };
324*99c0ae16SPeng Fan 
325441d0cffSSimon Glass U_BOOT_DRIVER(gpio_mxc) = {
326441d0cffSSimon Glass 	.name	= "gpio_mxc",
327441d0cffSSimon Glass 	.id	= UCLASS_GPIO,
328441d0cffSSimon Glass 	.ops	= &gpio_mxc_ops,
329441d0cffSSimon Glass 	.probe	= mxc_gpio_probe,
330441d0cffSSimon Glass 	.priv_auto_alloc_size = sizeof(struct mxc_bank_info),
331*99c0ae16SPeng Fan 	.of_match = mxc_gpio_ids,
332*99c0ae16SPeng Fan 	.bind	= mxc_gpio_bind,
333*99c0ae16SPeng Fan };
334*99c0ae16SPeng Fan 
335*99c0ae16SPeng Fan #ifndef CONFIG_OF_CONTROL
336*99c0ae16SPeng Fan static const struct mxc_gpio_plat mxc_plat[] = {
337*99c0ae16SPeng Fan 	{ 0, (struct gpio_regs *)GPIO1_BASE_ADDR },
338*99c0ae16SPeng Fan 	{ 1, (struct gpio_regs *)GPIO2_BASE_ADDR },
339*99c0ae16SPeng Fan 	{ 2, (struct gpio_regs *)GPIO3_BASE_ADDR },
340*99c0ae16SPeng Fan #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \
341*99c0ae16SPeng Fan 		defined(CONFIG_MX53) || defined(CONFIG_MX6)
342*99c0ae16SPeng Fan 	{ 3, (struct gpio_regs *)GPIO4_BASE_ADDR },
343*99c0ae16SPeng Fan #endif
344*99c0ae16SPeng Fan #if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6)
345*99c0ae16SPeng Fan 	{ 4, (struct gpio_regs *)GPIO5_BASE_ADDR },
346*99c0ae16SPeng Fan 	{ 5, (struct gpio_regs *)GPIO6_BASE_ADDR },
347*99c0ae16SPeng Fan #endif
348*99c0ae16SPeng Fan #if defined(CONFIG_MX53) || defined(CONFIG_MX6)
349*99c0ae16SPeng Fan 	{ 6, (struct gpio_regs *)GPIO7_BASE_ADDR },
350*99c0ae16SPeng Fan #endif
351441d0cffSSimon Glass };
352441d0cffSSimon Glass 
353441d0cffSSimon Glass U_BOOT_DEVICES(mxc_gpios) = {
354441d0cffSSimon Glass 	{ "gpio_mxc", &mxc_plat[0] },
355441d0cffSSimon Glass 	{ "gpio_mxc", &mxc_plat[1] },
356441d0cffSSimon Glass 	{ "gpio_mxc", &mxc_plat[2] },
357441d0cffSSimon Glass #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \
358441d0cffSSimon Glass 		defined(CONFIG_MX53) || defined(CONFIG_MX6)
359441d0cffSSimon Glass 	{ "gpio_mxc", &mxc_plat[3] },
360441d0cffSSimon Glass #endif
361441d0cffSSimon Glass #if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6)
362441d0cffSSimon Glass 	{ "gpio_mxc", &mxc_plat[4] },
363441d0cffSSimon Glass 	{ "gpio_mxc", &mxc_plat[5] },
364441d0cffSSimon Glass #endif
365441d0cffSSimon Glass #if defined(CONFIG_MX53) || defined(CONFIG_MX6)
366441d0cffSSimon Glass 	{ "gpio_mxc", &mxc_plat[6] },
367441d0cffSSimon Glass #endif
368441d0cffSSimon Glass };
369441d0cffSSimon Glass #endif
370*99c0ae16SPeng Fan #endif
371