1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2016 Nexell
4 * DeokJin, Lee <truevirtue@nexell.co.kr>
5 */
6
7#include <common.h>
8#include <dm.h>
9#include <errno.h>
10#include <malloc.h>
11#include <asm/global_data.h>
12#include <asm/io.h>
13#include <asm/gpio.h>
14
15DECLARE_GLOBAL_DATA_PTR;
16
17struct nx_gpio_regs {
18	u32	data;		/* Data register */
19	u32	outputenb;	/* Output Enable register */
20	u32	detmode[2];	/* Detect Mode Register */
21	u32	intenb;		/* Interrupt Enable Register */
22	u32	det;		/* Event Detect Register */
23	u32	pad;		/* Pad Status Register */
24};
25
26struct nx_alive_gpio_regs {
27	u32	pwrgate;	/* Power Gating Register */
28	u32	reserved0[28];	/* Reserved0 */
29	u32	outputenb_reset;/* Alive GPIO Output Enable Reset Register */
30	u32	outputenb;	/* Alive GPIO Output Enable Register */
31	u32	outputenb_read; /* Alive GPIO Output Read Register */
32	u32	reserved1[3];	/* Reserved1 */
33	u32	pad_reset;	/* Alive GPIO Output Reset Register */
34	u32	data;		/* Alive GPIO Output Register */
35	u32	pad_read;	/* Alive GPIO Pad Read Register */
36	u32	reserved2[33];	/* Reserved2 */
37	u32	pad;		/* Alive GPIO Input Value Register */
38};
39
40struct nx_gpio_plat {
41	void *regs;
42	int gpio_count;
43	const char *bank_name;
44};
45
46static int nx_alive_gpio_is_check(struct udevice *dev)
47{
48	struct nx_gpio_plat *plat = dev_get_plat(dev);
49	const char *bank_name = plat->bank_name;
50
51	if (!strcmp(bank_name, "gpio_alv"))
52		return 1;
53
54	return 0;
55}
56
57static int nx_alive_gpio_direction_input(struct udevice *dev, unsigned int pin)
58{
59	struct nx_gpio_plat *plat = dev_get_plat(dev);
60	struct nx_alive_gpio_regs *const regs = plat->regs;
61
62	setbits_le32(&regs->outputenb_reset, 1 << pin);
63
64	return 0;
65}
66
67static int nx_alive_gpio_direction_output(struct udevice *dev, unsigned int pin,
68					  int val)
69{
70	struct nx_gpio_plat *plat = dev_get_plat(dev);
71	struct nx_alive_gpio_regs *const regs = plat->regs;
72
73	if (val)
74		setbits_le32(&regs->data, 1 << pin);
75	else
76		setbits_le32(&regs->pad_reset, 1 << pin);
77
78	setbits_le32(&regs->outputenb, 1 << pin);
79
80	return 0;
81}
82
83static int nx_alive_gpio_get_value(struct udevice *dev, unsigned int pin)
84{
85	struct nx_gpio_plat *plat = dev_get_plat(dev);
86	struct nx_alive_gpio_regs *const regs = plat->regs;
87	unsigned int mask = 1UL << pin;
88	unsigned int value;
89
90	value = (readl(&regs->pad_read) & mask) >> pin;
91
92	return value;
93}
94
95static int nx_alive_gpio_set_value(struct udevice *dev, unsigned int pin,
96				   int val)
97{
98	struct nx_gpio_plat *plat = dev_get_plat(dev);
99	struct nx_alive_gpio_regs *const regs = plat->regs;
100
101	if (val)
102		setbits_le32(&regs->data, 1 << pin);
103	else
104		clrbits_le32(&regs->pad_reset, 1 << pin);
105
106	return 0;
107}
108
109static int nx_alive_gpio_get_function(struct udevice *dev, unsigned int pin)
110{
111	struct nx_gpio_plat *plat = dev_get_plat(dev);
112	struct nx_alive_gpio_regs *const regs = plat->regs;
113	unsigned int mask = (1UL << pin);
114	unsigned int output;
115
116	output = readl(&regs->outputenb_read) & mask;
117
118	if (output)
119		return GPIOF_OUTPUT;
120	else
121		return GPIOF_INPUT;
122}
123
124static int nx_gpio_direction_input(struct udevice *dev, unsigned int pin)
125{
126	struct nx_gpio_plat *plat = dev_get_plat(dev);
127	struct nx_gpio_regs *const regs = plat->regs;
128
129	if (nx_alive_gpio_is_check(dev))
130		return nx_alive_gpio_direction_input(dev, pin);
131
132	clrbits_le32(&regs->outputenb, 1 << pin);
133
134	return 0;
135}
136
137static int nx_gpio_direction_output(struct udevice *dev, unsigned int pin,
138				    int val)
139{
140	struct nx_gpio_plat *plat = dev_get_plat(dev);
141	struct nx_gpio_regs *const regs = plat->regs;
142
143	if (nx_alive_gpio_is_check(dev))
144		return nx_alive_gpio_direction_output(dev, pin, val);
145
146	if (val)
147		setbits_le32(&regs->data, 1 << pin);
148	else
149		clrbits_le32(&regs->data, 1 << pin);
150
151	setbits_le32(&regs->outputenb, 1 << pin);
152
153	return 0;
154}
155
156static int nx_gpio_get_value(struct udevice *dev, unsigned int pin)
157{
158	struct nx_gpio_plat *plat = dev_get_plat(dev);
159	struct nx_gpio_regs *const regs = plat->regs;
160	unsigned int mask = 1UL << pin;
161	unsigned int value;
162
163	if (nx_alive_gpio_is_check(dev))
164		return nx_alive_gpio_get_value(dev, pin);
165
166	value = (readl(&regs->pad) & mask) >> pin;
167
168	return value;
169}
170
171static int nx_gpio_set_value(struct udevice *dev, unsigned int pin, int val)
172{
173	struct nx_gpio_plat *plat = dev_get_plat(dev);
174	struct nx_gpio_regs *const regs = plat->regs;
175
176	if (nx_alive_gpio_is_check(dev))
177		return nx_alive_gpio_set_value(dev, pin, val);
178
179	if (val)
180		setbits_le32(&regs->data, 1 << pin);
181	else
182		clrbits_le32(&regs->data, 1 << pin);
183
184	return 0;
185}
186
187static int nx_gpio_get_function(struct udevice *dev, unsigned int pin)
188{
189	struct nx_gpio_plat *plat = dev_get_plat(dev);
190	struct nx_gpio_regs *const regs = plat->regs;
191	unsigned int mask = (1UL << pin);
192	unsigned int output;
193
194	if (nx_alive_gpio_is_check(dev))
195		return nx_alive_gpio_get_function(dev, pin);
196
197	output = readl(&regs->outputenb) & mask;
198
199	if (output)
200		return GPIOF_OUTPUT;
201	else
202		return GPIOF_INPUT;
203}
204
205static int nx_gpio_probe(struct udevice *dev)
206{
207	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
208	struct nx_gpio_plat *plat = dev_get_plat(dev);
209
210	uc_priv->gpio_count = plat->gpio_count;
211	uc_priv->bank_name = plat->bank_name;
212
213	return 0;
214}
215
216static int nx_gpio_of_to_plat(struct udevice *dev)
217{
218	struct nx_gpio_plat *plat = dev_get_plat(dev);
219
220	plat->regs = map_physmem(devfdt_get_addr(dev),
221				 sizeof(struct nx_gpio_regs),
222				 MAP_NOCACHE);
223	plat->gpio_count = dev_read_s32_default(dev, "nexell,gpio-bank-width",
224						32);
225	plat->bank_name = dev_read_string(dev, "gpio-bank-name");
226
227	return 0;
228}
229
230static const struct dm_gpio_ops nx_gpio_ops = {
231	.direction_input	= nx_gpio_direction_input,
232	.direction_output	= nx_gpio_direction_output,
233	.get_value		= nx_gpio_get_value,
234	.set_value		= nx_gpio_set_value,
235	.get_function		= nx_gpio_get_function,
236};
237
238static const struct udevice_id nx_gpio_ids[] = {
239	{ .compatible = "nexell,nexell-gpio" },
240	{ }
241};
242
243U_BOOT_DRIVER(nx_gpio) = {
244	.name		= "nx_gpio",
245	.id		= UCLASS_GPIO,
246	.of_match	= nx_gpio_ids,
247	.ops		= &nx_gpio_ops,
248	.of_to_plat = nx_gpio_of_to_plat,
249	.plat_auto	= sizeof(struct nx_gpio_plat),
250	.probe		= nx_gpio_probe,
251};
252