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