xref: /openbmc/u-boot/drivers/gpio/aspeed_gpio.c (revision 32bb51fc)
1 /*
2  * ast_gpio.c - GPIO driver for the Aspeed SoC
3  *
4  * Copyright (C) ASPEED Technology Inc.
5  * Ryan Chen <ryan_chen@aspeedtech.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  */
12 #include <common.h>
13 #include <asm/io.h>
14 #include <asm/gpio.h>
15 
16 #include <config.h>
17 #include <common.h>
18 #include <clk.h>
19 #include <dm.h>
20 #include <asm/io.h>
21 #include <linux/sizes.h>
22 
23 struct aspeed_gpio_priv {
24 	void *regs;
25 };
26 
27 struct aspeed_gpio_bank {
28 	uint16_t	val_regs;	/* +0: Rd: read input value, Wr: set write latch
29 					 * +4: Rd/Wr: Direction (0=in, 1=out)
30 					 */
31 	uint16_t	rdata_reg;	/*     Rd: read write latch, Wr: <none>  */
32 	uint16_t	irq_regs;
33 	uint16_t	debounce_regs;
34 	uint16_t	tolerance_regs;
35 	uint16_t	cmdsrc_regs;
36 	const char	names[4][3];
37 };
38 
39 static const struct aspeed_gpio_bank aspeed_gpio_banks[] = {
40 	{
41 		.val_regs = 0x0000,
42 		.rdata_reg = 0x00c0,
43 		.irq_regs = 0x0008,
44 		.debounce_regs = 0x0040,
45 		.tolerance_regs = 0x001c,
46 		.cmdsrc_regs = 0x0060,
47 		.names = { "A", "B", "C", "D" },
48 	},
49 	{
50 		.val_regs = 0x0020,
51 		.rdata_reg = 0x00c4,
52 		.irq_regs = 0x0028,
53 		.debounce_regs = 0x0048,
54 		.tolerance_regs = 0x003c,
55 		.cmdsrc_regs = 0x0068,
56 		.names = { "E", "F", "G", "H" },
57 	},
58 	{
59 		.val_regs = 0x0070,
60 		.rdata_reg = 0x00c8,
61 		.irq_regs = 0x0098,
62 		.debounce_regs = 0x00b0,
63 		.tolerance_regs = 0x00ac,
64 		.cmdsrc_regs = 0x0090,
65 		.names = { "I", "J", "K", "L" },
66 	},
67 	{
68 		.val_regs = 0x0078,
69 		.rdata_reg = 0x00cc,
70 		.irq_regs = 0x00e8,
71 		.debounce_regs = 0x0100,
72 		.tolerance_regs = 0x00fc,
73 		.cmdsrc_regs = 0x00e0,
74 		.names = { "M", "N", "O", "P" },
75 	},
76 	{
77 		.val_regs = 0x0080,
78 		.rdata_reg = 0x00d0,
79 		.irq_regs = 0x0118,
80 		.debounce_regs = 0x0130,
81 		.tolerance_regs = 0x012c,
82 		.cmdsrc_regs = 0x0110,
83 		.names = { "Q", "R", "S", "T" },
84 	},
85 	{
86 		.val_regs = 0x0088,
87 		.rdata_reg = 0x00d4,
88 		.irq_regs = 0x0148,
89 		.debounce_regs = 0x0160,
90 		.tolerance_regs = 0x015c,
91 		.cmdsrc_regs = 0x0140,
92 		.names = { "U", "V", "W", "X" },
93 	},
94 	{
95 		.val_regs = 0x01E0,
96 		.rdata_reg = 0x00d8,
97 		.irq_regs = 0x0178,
98 		.debounce_regs = 0x0190,
99 		.tolerance_regs = 0x018c,
100 		.cmdsrc_regs = 0x0170,
101 		.names = { "Y", "Z", "AA", "AB" },
102 	},
103 	{
104 		.val_regs = 0x01e8,
105 		.rdata_reg = 0x00dc,
106 		.irq_regs = 0x01a8,
107 		.debounce_regs = 0x01c0,
108 		.tolerance_regs = 0x01bc,
109 		.cmdsrc_regs = 0x01a0,
110 		.names = { "AC", "", "", "" },
111 	},
112 };
113 
114 enum aspeed_gpio_reg {
115 	reg_val,
116 	reg_rdata,
117 	reg_dir,
118 	reg_irq_enable,
119 	reg_irq_type0,
120 	reg_irq_type1,
121 	reg_irq_type2,
122 	reg_irq_status,
123 	reg_debounce_sel1,
124 	reg_debounce_sel2,
125 	reg_tolerance,
126 	reg_cmdsrc0,
127 	reg_cmdsrc1,
128 };
129 
130 #define GPIO_VAL_VALUE	0x00
131 #define GPIO_VAL_DIR	0x04
132 
133 #define GPIO_IRQ_ENABLE	0x00
134 #define GPIO_IRQ_TYPE0	0x04
135 #define GPIO_IRQ_TYPE1	0x08
136 #define GPIO_IRQ_TYPE2	0x0c
137 #define GPIO_IRQ_STATUS	0x10
138 
139 #define GPIO_DEBOUNCE_SEL1 0x00
140 #define GPIO_DEBOUNCE_SEL2 0x04
141 
142 #define GPIO_CMDSRC_0	0x00
143 #define GPIO_CMDSRC_1	0x04
144 #define  GPIO_CMDSRC_ARM		0
145 #define  GPIO_CMDSRC_LPC		1
146 #define  GPIO_CMDSRC_COLDFIRE		2
147 #define  GPIO_CMDSRC_RESERVED		3
148 
149 /* This will be resolved at compile time */
150 static inline void __iomem *bank_reg(struct aspeed_gpio_priv *gpio,
151 				     const struct aspeed_gpio_bank *bank,
152 				     const enum aspeed_gpio_reg reg)
153 {
154 	switch (reg) {
155 	case reg_val:
156 		return gpio->regs + bank->val_regs + GPIO_VAL_VALUE;
157 	case reg_rdata:
158 		return gpio->regs + bank->rdata_reg;
159 	case reg_dir:
160 		return gpio->regs + bank->val_regs + GPIO_VAL_DIR;
161 	case reg_irq_enable:
162 		return gpio->regs + bank->irq_regs + GPIO_IRQ_ENABLE;
163 	case reg_irq_type0:
164 		return gpio->regs + bank->irq_regs + GPIO_IRQ_TYPE0;
165 	case reg_irq_type1:
166 		return gpio->regs + bank->irq_regs + GPIO_IRQ_TYPE1;
167 	case reg_irq_type2:
168 		return gpio->regs + bank->irq_regs + GPIO_IRQ_TYPE2;
169 	case reg_irq_status:
170 		return gpio->regs + bank->irq_regs + GPIO_IRQ_STATUS;
171 	case reg_debounce_sel1:
172 		return gpio->regs + bank->debounce_regs + GPIO_DEBOUNCE_SEL1;
173 	case reg_debounce_sel2:
174 		return gpio->regs + bank->debounce_regs + GPIO_DEBOUNCE_SEL2;
175 	case reg_tolerance:
176 		return gpio->regs + bank->tolerance_regs;
177 	case reg_cmdsrc0:
178 		return gpio->regs + bank->cmdsrc_regs + GPIO_CMDSRC_0;
179 	case reg_cmdsrc1:
180 		return gpio->regs + bank->cmdsrc_regs + GPIO_CMDSRC_1;
181 	}
182 	BUG();
183 }
184 
185 #define GPIO_BANK(x)	((x) >> 5)
186 #define GPIO_OFFSET(x)	((x) & 0x1f)
187 #define GPIO_BIT(x)	BIT(GPIO_OFFSET(x))
188 
189 static const struct aspeed_gpio_bank *to_bank(unsigned int offset)
190 {
191 	unsigned int bank = GPIO_BANK(offset);
192 
193 	WARN_ON(bank >= ARRAY_SIZE(aspeed_gpio_banks));
194 	return &aspeed_gpio_banks[bank];
195 }
196 
197 static int
198 aspeed_gpio_direction_input(struct udevice *dev, unsigned offset)
199 {
200 	struct aspeed_gpio_priv *priv = dev_get_priv(dev);
201 	const struct aspeed_gpio_bank *bank = to_bank(offset);
202 	u32 dir = readl(bank_reg(priv, bank, reg_dir));
203 
204 	dir &= ~GPIO_BIT(offset);
205 	writel(dir, bank_reg(priv, bank, reg_dir));
206 
207 	return 0;
208 }
209 
210 static int
211 aspeed_gpio_direction_output(struct udevice *dev, unsigned offset,
212 									int value)
213 {
214 	struct aspeed_gpio_priv *priv = dev_get_priv(dev);
215 	const struct aspeed_gpio_bank *bank = to_bank(offset);
216 	u32 dir = readl(bank_reg(priv, bank, reg_dir));
217 	u32 output = readl(bank_reg(priv, bank, reg_val));
218 
219 	dir |= GPIO_BIT(offset);
220 	writel(dir, bank_reg(priv, bank, reg_dir));
221 
222 	if(value)
223 		output |= GPIO_BIT(offset);
224 	else
225 		output &= ~GPIO_BIT(offset);
226 
227 	writel(output, bank_reg(priv, bank, reg_val));
228 
229 	return 0;
230 }
231 
232 
233 static int aspeed_gpio_get_value(struct udevice *dev, unsigned offset)
234 {
235 	struct aspeed_gpio_priv *priv = dev_get_priv(dev);
236 	const struct aspeed_gpio_bank *bank = to_bank(offset);
237 
238 	return !!(readl(bank_reg(priv, bank, reg_val)) & GPIO_BIT(offset));
239 }
240 
241 static int aspeed_gpio_set_value(struct udevice *dev, unsigned offset,
242                                   int value)
243 {
244 
245 	struct aspeed_gpio_priv *priv = dev_get_priv(dev);
246 	const struct aspeed_gpio_bank *bank = to_bank(offset);
247 	u32 data = readl(bank_reg(priv, bank, reg_val));
248 
249 	if (value)
250 		data |= GPIO_BIT(offset);
251 	else
252 		data &= ~GPIO_BIT(offset);
253 
254 	writel(data, bank_reg(priv, bank, reg_val));
255 
256 	return 0;
257 }
258 
259 static int aspeed_gpio_get_function(struct udevice *dev, unsigned offset)
260 {
261 	struct aspeed_gpio_priv *priv = dev_get_priv(dev);
262 	const struct aspeed_gpio_bank *bank = to_bank(offset);
263 
264 	if(readl(bank_reg(priv, bank, reg_dir)) & GPIO_BIT(offset))
265 		return GPIOF_OUTPUT;
266 	else
267 		return GPIOF_INPUT;
268 }
269 
270 static const struct dm_gpio_ops gpio_aspeed_ops = {
271 	.direction_input		= aspeed_gpio_direction_input,
272 	.direction_output		= aspeed_gpio_direction_output,
273 	.get_value				= aspeed_gpio_get_value,
274 	.set_value				= aspeed_gpio_set_value,
275 	.get_function			= aspeed_gpio_get_function,
276 };
277 
278 static int aspeed_gpio_probe(struct udevice *dev)
279 {
280 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
281 	struct aspeed_gpio_priv *priv = dev_get_priv(dev);
282 	ulong driver_data = dev_get_driver_data(dev);
283 
284 	uc_priv->bank_name = dev->name;
285     uc_priv->gpio_count = driver_data;
286 
287 	priv->regs = devfdt_get_addr_ptr(dev);
288 
289     return 0;
290 }
291 
292 static const struct udevice_id aspeed_gpio_ids[] = {
293 	{ .compatible = "aspeed,ast2500-gpio",	.data = 232 },
294 	{ .compatible = "aspeed,ast2600-gpio",	.data = 208 },
295 	{ }
296 };
297 
298 U_BOOT_DRIVER(gpio_aspeed) = {
299     .name   = "gpio_aspeed",
300     .id     = UCLASS_GPIO,
301     .of_match = aspeed_gpio_ids,
302     .ops    = &gpio_aspeed_ops,
303     .probe  = aspeed_gpio_probe,
304     .priv_auto_alloc_size = sizeof(struct aspeed_gpio_priv),
305 };
306