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