xref: /openbmc/linux/drivers/gpio/gpio-aspeed-sgpio.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1f8b410e3SLinus Walleij // SPDX-License-Identifier: GPL-2.0-or-later
2f8b410e3SLinus Walleij /*
3f8b410e3SLinus Walleij  * Copyright 2019 American Megatrends International LLC.
4f8b410e3SLinus Walleij  *
5f8b410e3SLinus Walleij  * Author: Karthikeyan Mani <karthikeyanm@amiindia.co.in>
6f8b410e3SLinus Walleij  */
7f8b410e3SLinus Walleij 
8f8b410e3SLinus Walleij #include <linux/bitfield.h>
9f8b410e3SLinus Walleij #include <linux/clk.h>
10f8b410e3SLinus Walleij #include <linux/gpio/driver.h>
11f8b410e3SLinus Walleij #include <linux/hashtable.h>
12f8b410e3SLinus Walleij #include <linux/init.h>
13f8b410e3SLinus Walleij #include <linux/io.h>
14f8b410e3SLinus Walleij #include <linux/kernel.h>
15f8b410e3SLinus Walleij #include <linux/module.h>
16f8b410e3SLinus Walleij #include <linux/platform_device.h>
17*c5dcf768SLinus Walleij #include <linux/seq_file.h>
18f8b410e3SLinus Walleij #include <linux/spinlock.h>
19f8b410e3SLinus Walleij #include <linux/string.h>
20f8b410e3SLinus Walleij 
21f8b410e3SLinus Walleij #define ASPEED_SGPIO_CTRL		0x54
22f8b410e3SLinus Walleij 
23f8b410e3SLinus Walleij #define ASPEED_SGPIO_CLK_DIV_MASK	GENMASK(31, 16)
24f8b410e3SLinus Walleij #define ASPEED_SGPIO_ENABLE		BIT(0)
25e1f85d25SSteven Lee #define ASPEED_SGPIO_PINS_SHIFT		6
26e1f85d25SSteven Lee 
27e1f85d25SSteven Lee struct aspeed_sgpio_pdata {
28e1f85d25SSteven Lee 	const u32 pin_mask;
29e1f85d25SSteven Lee };
30f8b410e3SLinus Walleij 
31f8b410e3SLinus Walleij struct aspeed_sgpio {
32f8b410e3SLinus Walleij 	struct gpio_chip chip;
33*c5dcf768SLinus Walleij 	struct device *dev;
34f8b410e3SLinus Walleij 	struct clk *pclk;
35ab39d698SIwona Winiarska 	raw_spinlock_t lock;
36f8b410e3SLinus Walleij 	void __iomem *base;
37f8b410e3SLinus Walleij 	int irq;
38f8b410e3SLinus Walleij };
39f8b410e3SLinus Walleij 
40f8b410e3SLinus Walleij struct aspeed_sgpio_bank {
418a3581c6SSteven Lee 	u16    val_regs;
428a3581c6SSteven Lee 	u16    rdata_reg;
438a3581c6SSteven Lee 	u16    irq_regs;
448a3581c6SSteven Lee 	u16    tolerance_regs;
45f8b410e3SLinus Walleij 	const char  names[4][3];
46f8b410e3SLinus Walleij };
47f8b410e3SLinus Walleij 
48f8b410e3SLinus Walleij /*
49f8b410e3SLinus Walleij  * Note: The "value" register returns the input value when the GPIO is
50f8b410e3SLinus Walleij  *	 configured as an input.
51f8b410e3SLinus Walleij  *
52f8b410e3SLinus Walleij  *	 The "rdata" register returns the output value when the GPIO is
53f8b410e3SLinus Walleij  *	 configured as an output.
54f8b410e3SLinus Walleij  */
55f8b410e3SLinus Walleij static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = {
56f8b410e3SLinus Walleij 	{
57f8b410e3SLinus Walleij 		.val_regs = 0x0000,
58f8b410e3SLinus Walleij 		.rdata_reg = 0x0070,
59f8b410e3SLinus Walleij 		.irq_regs = 0x0004,
608a3581c6SSteven Lee 		.tolerance_regs = 0x0018,
61f8b410e3SLinus Walleij 		.names = { "A", "B", "C", "D" },
62f8b410e3SLinus Walleij 	},
63f8b410e3SLinus Walleij 	{
64f8b410e3SLinus Walleij 		.val_regs = 0x001C,
65f8b410e3SLinus Walleij 		.rdata_reg = 0x0074,
66f8b410e3SLinus Walleij 		.irq_regs = 0x0020,
678a3581c6SSteven Lee 		.tolerance_regs = 0x0034,
68f8b410e3SLinus Walleij 		.names = { "E", "F", "G", "H" },
69f8b410e3SLinus Walleij 	},
70f8b410e3SLinus Walleij 	{
71f8b410e3SLinus Walleij 		.val_regs = 0x0038,
72f8b410e3SLinus Walleij 		.rdata_reg = 0x0078,
73f8b410e3SLinus Walleij 		.irq_regs = 0x003C,
748a3581c6SSteven Lee 		.tolerance_regs = 0x0050,
75e1f85d25SSteven Lee 		.names = { "I", "J", "K", "L" },
76e1f85d25SSteven Lee 	},
77e1f85d25SSteven Lee 	{
78e1f85d25SSteven Lee 		.val_regs = 0x0090,
79e1f85d25SSteven Lee 		.rdata_reg = 0x007C,
80e1f85d25SSteven Lee 		.irq_regs = 0x0094,
818a3581c6SSteven Lee 		.tolerance_regs = 0x00A8,
82e1f85d25SSteven Lee 		.names = { "M", "N", "O", "P" },
83f8b410e3SLinus Walleij 	},
84f8b410e3SLinus Walleij };
85f8b410e3SLinus Walleij 
86f8b410e3SLinus Walleij enum aspeed_sgpio_reg {
87f8b410e3SLinus Walleij 	reg_val,
88f8b410e3SLinus Walleij 	reg_rdata,
89f8b410e3SLinus Walleij 	reg_irq_enable,
90f8b410e3SLinus Walleij 	reg_irq_type0,
91f8b410e3SLinus Walleij 	reg_irq_type1,
92f8b410e3SLinus Walleij 	reg_irq_type2,
93f8b410e3SLinus Walleij 	reg_irq_status,
948a3581c6SSteven Lee 	reg_tolerance,
95f8b410e3SLinus Walleij };
96f8b410e3SLinus Walleij 
97f8b410e3SLinus Walleij #define GPIO_VAL_VALUE      0x00
98f8b410e3SLinus Walleij #define GPIO_IRQ_ENABLE     0x00
99f8b410e3SLinus Walleij #define GPIO_IRQ_TYPE0      0x04
100f8b410e3SLinus Walleij #define GPIO_IRQ_TYPE1      0x08
101f8b410e3SLinus Walleij #define GPIO_IRQ_TYPE2      0x0C
102f8b410e3SLinus Walleij #define GPIO_IRQ_STATUS     0x10
103f8b410e3SLinus Walleij 
bank_reg(struct aspeed_sgpio * gpio,const struct aspeed_sgpio_bank * bank,const enum aspeed_sgpio_reg reg)104f8b410e3SLinus Walleij static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
105f8b410e3SLinus Walleij 				     const struct aspeed_sgpio_bank *bank,
106f8b410e3SLinus Walleij 				     const enum aspeed_sgpio_reg reg)
107f8b410e3SLinus Walleij {
108f8b410e3SLinus Walleij 	switch (reg) {
109f8b410e3SLinus Walleij 	case reg_val:
110f8b410e3SLinus Walleij 		return gpio->base + bank->val_regs + GPIO_VAL_VALUE;
111f8b410e3SLinus Walleij 	case reg_rdata:
112f8b410e3SLinus Walleij 		return gpio->base + bank->rdata_reg;
113f8b410e3SLinus Walleij 	case reg_irq_enable:
114f8b410e3SLinus Walleij 		return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE;
115f8b410e3SLinus Walleij 	case reg_irq_type0:
116f8b410e3SLinus Walleij 		return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0;
117f8b410e3SLinus Walleij 	case reg_irq_type1:
118f8b410e3SLinus Walleij 		return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1;
119f8b410e3SLinus Walleij 	case reg_irq_type2:
120f8b410e3SLinus Walleij 		return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2;
121f8b410e3SLinus Walleij 	case reg_irq_status:
122f8b410e3SLinus Walleij 		return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS;
1238a3581c6SSteven Lee 	case reg_tolerance:
1248a3581c6SSteven Lee 		return gpio->base + bank->tolerance_regs;
125f8b410e3SLinus Walleij 	default:
126f8b410e3SLinus Walleij 		/* acturally if code runs to here, it's an error case */
12711e299deSArnd Bergmann 		BUG();
128f8b410e3SLinus Walleij 	}
129f8b410e3SLinus Walleij }
130f8b410e3SLinus Walleij 
131e1f85d25SSteven Lee #define GPIO_BANK(x)    ((x) >> 6)
132e1f85d25SSteven Lee #define GPIO_OFFSET(x)  ((x) & GENMASK(5, 0))
133e1f85d25SSteven Lee #define GPIO_BIT(x)     BIT(GPIO_OFFSET(x) >> 1)
134f8b410e3SLinus Walleij 
to_bank(unsigned int offset)135f8b410e3SLinus Walleij static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
136f8b410e3SLinus Walleij {
137ac67b07eSJeremy Kerr 	unsigned int bank;
138ac67b07eSJeremy Kerr 
139ac67b07eSJeremy Kerr 	bank = GPIO_BANK(offset);
140f8b410e3SLinus Walleij 
141f8b410e3SLinus Walleij 	WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
142f8b410e3SLinus Walleij 	return &aspeed_sgpio_banks[bank];
143f8b410e3SLinus Walleij }
144f8b410e3SLinus Walleij 
aspeed_sgpio_init_valid_mask(struct gpio_chip * gc,unsigned long * valid_mask,unsigned int ngpios)145ac67b07eSJeremy Kerr static int aspeed_sgpio_init_valid_mask(struct gpio_chip *gc,
146ac67b07eSJeremy Kerr 		unsigned long *valid_mask, unsigned int ngpios)
147ac67b07eSJeremy Kerr {
148e1f85d25SSteven Lee 	bitmap_set(valid_mask, 0, ngpios);
149ac67b07eSJeremy Kerr 	return 0;
150ac67b07eSJeremy Kerr }
151ac67b07eSJeremy Kerr 
aspeed_sgpio_irq_init_valid_mask(struct gpio_chip * gc,unsigned long * valid_mask,unsigned int ngpios)152ac67b07eSJeremy Kerr static void aspeed_sgpio_irq_init_valid_mask(struct gpio_chip *gc,
153ac67b07eSJeremy Kerr 		unsigned long *valid_mask, unsigned int ngpios)
154ac67b07eSJeremy Kerr {
155e1f85d25SSteven Lee 	unsigned int i;
156ac67b07eSJeremy Kerr 
157e1f85d25SSteven Lee 	/* input GPIOs are even bits */
158e1f85d25SSteven Lee 	for (i = 0; i < ngpios; i++) {
159e1f85d25SSteven Lee 		if (i % 2)
160e1f85d25SSteven Lee 			clear_bit(i, valid_mask);
161e1f85d25SSteven Lee 	}
162ac67b07eSJeremy Kerr }
163ac67b07eSJeremy Kerr 
aspeed_sgpio_is_input(unsigned int offset)164ac67b07eSJeremy Kerr static bool aspeed_sgpio_is_input(unsigned int offset)
165ac67b07eSJeremy Kerr {
166e1f85d25SSteven Lee 	return !(offset % 2);
167ac67b07eSJeremy Kerr }
168ac67b07eSJeremy Kerr 
aspeed_sgpio_get(struct gpio_chip * gc,unsigned int offset)169f8b410e3SLinus Walleij static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
170f8b410e3SLinus Walleij {
171f8b410e3SLinus Walleij 	struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
172f8b410e3SLinus Walleij 	const struct aspeed_sgpio_bank *bank = to_bank(offset);
173f8b410e3SLinus Walleij 	unsigned long flags;
174f8b410e3SLinus Walleij 	enum aspeed_sgpio_reg reg;
175f8b410e3SLinus Walleij 	int rc = 0;
176f8b410e3SLinus Walleij 
177ab39d698SIwona Winiarska 	raw_spin_lock_irqsave(&gpio->lock, flags);
178f8b410e3SLinus Walleij 
179ac67b07eSJeremy Kerr 	reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata;
180f8b410e3SLinus Walleij 	rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
181f8b410e3SLinus Walleij 
182ab39d698SIwona Winiarska 	raw_spin_unlock_irqrestore(&gpio->lock, flags);
183f8b410e3SLinus Walleij 
184f8b410e3SLinus Walleij 	return rc;
185f8b410e3SLinus Walleij }
186f8b410e3SLinus Walleij 
sgpio_set_value(struct gpio_chip * gc,unsigned int offset,int val)187ac67b07eSJeremy Kerr static int sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
188f8b410e3SLinus Walleij {
189f8b410e3SLinus Walleij 	struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
190f8b410e3SLinus Walleij 	const struct aspeed_sgpio_bank *bank = to_bank(offset);
191ac67b07eSJeremy Kerr 	void __iomem *addr_r, *addr_w;
192f8b410e3SLinus Walleij 	u32 reg = 0;
193f8b410e3SLinus Walleij 
194ac67b07eSJeremy Kerr 	if (aspeed_sgpio_is_input(offset))
195ac67b07eSJeremy Kerr 		return -EINVAL;
196ac67b07eSJeremy Kerr 
197ac67b07eSJeremy Kerr 	/* Since this is an output, read the cached value from rdata, then
198ac67b07eSJeremy Kerr 	 * update val. */
199ac67b07eSJeremy Kerr 	addr_r = bank_reg(gpio, bank, reg_rdata);
200ac67b07eSJeremy Kerr 	addr_w = bank_reg(gpio, bank, reg_val);
201ac67b07eSJeremy Kerr 
202ac67b07eSJeremy Kerr 	reg = ioread32(addr_r);
203f8b410e3SLinus Walleij 
204f8b410e3SLinus Walleij 	if (val)
205f8b410e3SLinus Walleij 		reg |= GPIO_BIT(offset);
206f8b410e3SLinus Walleij 	else
207f8b410e3SLinus Walleij 		reg &= ~GPIO_BIT(offset);
208f8b410e3SLinus Walleij 
209ac67b07eSJeremy Kerr 	iowrite32(reg, addr_w);
210ac67b07eSJeremy Kerr 
211ac67b07eSJeremy Kerr 	return 0;
212f8b410e3SLinus Walleij }
213f8b410e3SLinus Walleij 
aspeed_sgpio_set(struct gpio_chip * gc,unsigned int offset,int val)214f8b410e3SLinus Walleij static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
215f8b410e3SLinus Walleij {
216f8b410e3SLinus Walleij 	struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
217f8b410e3SLinus Walleij 	unsigned long flags;
218f8b410e3SLinus Walleij 
219ab39d698SIwona Winiarska 	raw_spin_lock_irqsave(&gpio->lock, flags);
220f8b410e3SLinus Walleij 
221f8b410e3SLinus Walleij 	sgpio_set_value(gc, offset, val);
222f8b410e3SLinus Walleij 
223ab39d698SIwona Winiarska 	raw_spin_unlock_irqrestore(&gpio->lock, flags);
224f8b410e3SLinus Walleij }
225f8b410e3SLinus Walleij 
aspeed_sgpio_dir_in(struct gpio_chip * gc,unsigned int offset)226f8b410e3SLinus Walleij static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset)
227f8b410e3SLinus Walleij {
228ac67b07eSJeremy Kerr 	return aspeed_sgpio_is_input(offset) ? 0 : -EINVAL;
229f8b410e3SLinus Walleij }
230f8b410e3SLinus Walleij 
aspeed_sgpio_dir_out(struct gpio_chip * gc,unsigned int offset,int val)231f8b410e3SLinus Walleij static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
232f8b410e3SLinus Walleij {
233f8b410e3SLinus Walleij 	struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
234f8b410e3SLinus Walleij 	unsigned long flags;
235ac67b07eSJeremy Kerr 	int rc;
236ac67b07eSJeremy Kerr 
237ac67b07eSJeremy Kerr 	/* No special action is required for setting the direction; we'll
238ac67b07eSJeremy Kerr 	 * error-out in sgpio_set_value if this isn't an output GPIO */
239f8b410e3SLinus Walleij 
240ab39d698SIwona Winiarska 	raw_spin_lock_irqsave(&gpio->lock, flags);
241ac67b07eSJeremy Kerr 	rc = sgpio_set_value(gc, offset, val);
242ab39d698SIwona Winiarska 	raw_spin_unlock_irqrestore(&gpio->lock, flags);
243f8b410e3SLinus Walleij 
244ac67b07eSJeremy Kerr 	return rc;
245f8b410e3SLinus Walleij }
246f8b410e3SLinus Walleij 
aspeed_sgpio_get_direction(struct gpio_chip * gc,unsigned int offset)247f8b410e3SLinus Walleij static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
248f8b410e3SLinus Walleij {
249ac67b07eSJeremy Kerr 	return !!aspeed_sgpio_is_input(offset);
250f8b410e3SLinus Walleij }
251f8b410e3SLinus Walleij 
irqd_to_aspeed_sgpio_data(struct irq_data * d,struct aspeed_sgpio ** gpio,const struct aspeed_sgpio_bank ** bank,u32 * bit,int * offset)252f8b410e3SLinus Walleij static void irqd_to_aspeed_sgpio_data(struct irq_data *d,
253f8b410e3SLinus Walleij 					struct aspeed_sgpio **gpio,
254f8b410e3SLinus Walleij 					const struct aspeed_sgpio_bank **bank,
255f8b410e3SLinus Walleij 					u32 *bit, int *offset)
256f8b410e3SLinus Walleij {
257f8b410e3SLinus Walleij 	struct aspeed_sgpio *internal;
258f8b410e3SLinus Walleij 
259f8b410e3SLinus Walleij 	*offset = irqd_to_hwirq(d);
260f8b410e3SLinus Walleij 	internal = irq_data_get_irq_chip_data(d);
261f8b410e3SLinus Walleij 	WARN_ON(!internal);
262f8b410e3SLinus Walleij 
263f8b410e3SLinus Walleij 	*gpio = internal;
264f8b410e3SLinus Walleij 	*bank = to_bank(*offset);
265f8b410e3SLinus Walleij 	*bit = GPIO_BIT(*offset);
266f8b410e3SLinus Walleij }
267f8b410e3SLinus Walleij 
aspeed_sgpio_irq_ack(struct irq_data * d)268f8b410e3SLinus Walleij static void aspeed_sgpio_irq_ack(struct irq_data *d)
269f8b410e3SLinus Walleij {
270f8b410e3SLinus Walleij 	const struct aspeed_sgpio_bank *bank;
271f8b410e3SLinus Walleij 	struct aspeed_sgpio *gpio;
272f8b410e3SLinus Walleij 	unsigned long flags;
273f8b410e3SLinus Walleij 	void __iomem *status_addr;
274f8b410e3SLinus Walleij 	int offset;
275f8b410e3SLinus Walleij 	u32 bit;
276f8b410e3SLinus Walleij 
277f8b410e3SLinus Walleij 	irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
278f8b410e3SLinus Walleij 
279f8b410e3SLinus Walleij 	status_addr = bank_reg(gpio, bank, reg_irq_status);
280f8b410e3SLinus Walleij 
281ab39d698SIwona Winiarska 	raw_spin_lock_irqsave(&gpio->lock, flags);
282f8b410e3SLinus Walleij 
283f8b410e3SLinus Walleij 	iowrite32(bit, status_addr);
284f8b410e3SLinus Walleij 
285ab39d698SIwona Winiarska 	raw_spin_unlock_irqrestore(&gpio->lock, flags);
286f8b410e3SLinus Walleij }
287f8b410e3SLinus Walleij 
aspeed_sgpio_irq_set_mask(struct irq_data * d,bool set)288f8b410e3SLinus Walleij static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
289f8b410e3SLinus Walleij {
290f8b410e3SLinus Walleij 	const struct aspeed_sgpio_bank *bank;
291f8b410e3SLinus Walleij 	struct aspeed_sgpio *gpio;
292f8b410e3SLinus Walleij 	unsigned long flags;
293f8b410e3SLinus Walleij 	u32 reg, bit;
294f8b410e3SLinus Walleij 	void __iomem *addr;
295f8b410e3SLinus Walleij 	int offset;
296f8b410e3SLinus Walleij 
297f8b410e3SLinus Walleij 	irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
298f8b410e3SLinus Walleij 	addr = bank_reg(gpio, bank, reg_irq_enable);
299f8b410e3SLinus Walleij 
300*c5dcf768SLinus Walleij 	/* Unmasking the IRQ */
301*c5dcf768SLinus Walleij 	if (set)
302*c5dcf768SLinus Walleij 		gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d));
303*c5dcf768SLinus Walleij 
304ab39d698SIwona Winiarska 	raw_spin_lock_irqsave(&gpio->lock, flags);
305f8b410e3SLinus Walleij 
306f8b410e3SLinus Walleij 	reg = ioread32(addr);
307f8b410e3SLinus Walleij 	if (set)
308f8b410e3SLinus Walleij 		reg |= bit;
309f8b410e3SLinus Walleij 	else
310f8b410e3SLinus Walleij 		reg &= ~bit;
311f8b410e3SLinus Walleij 
312f8b410e3SLinus Walleij 	iowrite32(reg, addr);
313f8b410e3SLinus Walleij 
314ab39d698SIwona Winiarska 	raw_spin_unlock_irqrestore(&gpio->lock, flags);
315*c5dcf768SLinus Walleij 
316*c5dcf768SLinus Walleij 	/* Masking the IRQ */
317*c5dcf768SLinus Walleij 	if (!set)
318*c5dcf768SLinus Walleij 		gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d));
319*c5dcf768SLinus Walleij 
320*c5dcf768SLinus Walleij 
321f8b410e3SLinus Walleij }
322f8b410e3SLinus Walleij 
aspeed_sgpio_irq_mask(struct irq_data * d)323f8b410e3SLinus Walleij static void aspeed_sgpio_irq_mask(struct irq_data *d)
324f8b410e3SLinus Walleij {
325f8b410e3SLinus Walleij 	aspeed_sgpio_irq_set_mask(d, false);
326f8b410e3SLinus Walleij }
327f8b410e3SLinus Walleij 
aspeed_sgpio_irq_unmask(struct irq_data * d)328f8b410e3SLinus Walleij static void aspeed_sgpio_irq_unmask(struct irq_data *d)
329f8b410e3SLinus Walleij {
330f8b410e3SLinus Walleij 	aspeed_sgpio_irq_set_mask(d, true);
331f8b410e3SLinus Walleij }
332f8b410e3SLinus Walleij 
aspeed_sgpio_set_type(struct irq_data * d,unsigned int type)333f8b410e3SLinus Walleij static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
334f8b410e3SLinus Walleij {
335f8b410e3SLinus Walleij 	u32 type0 = 0;
336f8b410e3SLinus Walleij 	u32 type1 = 0;
337f8b410e3SLinus Walleij 	u32 type2 = 0;
338f8b410e3SLinus Walleij 	u32 bit, reg;
339f8b410e3SLinus Walleij 	const struct aspeed_sgpio_bank *bank;
340f8b410e3SLinus Walleij 	irq_flow_handler_t handler;
341f8b410e3SLinus Walleij 	struct aspeed_sgpio *gpio;
342f8b410e3SLinus Walleij 	unsigned long flags;
343f8b410e3SLinus Walleij 	void __iomem *addr;
344f8b410e3SLinus Walleij 	int offset;
345f8b410e3SLinus Walleij 
346f8b410e3SLinus Walleij 	irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
347f8b410e3SLinus Walleij 
348f8b410e3SLinus Walleij 	switch (type & IRQ_TYPE_SENSE_MASK) {
349f8b410e3SLinus Walleij 	case IRQ_TYPE_EDGE_BOTH:
350f8b410e3SLinus Walleij 		type2 |= bit;
351df561f66SGustavo A. R. Silva 		fallthrough;
352f8b410e3SLinus Walleij 	case IRQ_TYPE_EDGE_RISING:
353f8b410e3SLinus Walleij 		type0 |= bit;
354df561f66SGustavo A. R. Silva 		fallthrough;
355f8b410e3SLinus Walleij 	case IRQ_TYPE_EDGE_FALLING:
356f8b410e3SLinus Walleij 		handler = handle_edge_irq;
357f8b410e3SLinus Walleij 		break;
358f8b410e3SLinus Walleij 	case IRQ_TYPE_LEVEL_HIGH:
359f8b410e3SLinus Walleij 		type0 |= bit;
360df561f66SGustavo A. R. Silva 		fallthrough;
361f8b410e3SLinus Walleij 	case IRQ_TYPE_LEVEL_LOW:
362f8b410e3SLinus Walleij 		type1 |= bit;
363f8b410e3SLinus Walleij 		handler = handle_level_irq;
364f8b410e3SLinus Walleij 		break;
365f8b410e3SLinus Walleij 	default:
366f8b410e3SLinus Walleij 		return -EINVAL;
367f8b410e3SLinus Walleij 	}
368f8b410e3SLinus Walleij 
369ab39d698SIwona Winiarska 	raw_spin_lock_irqsave(&gpio->lock, flags);
370f8b410e3SLinus Walleij 
371f8b410e3SLinus Walleij 	addr = bank_reg(gpio, bank, reg_irq_type0);
372f8b410e3SLinus Walleij 	reg = ioread32(addr);
373f8b410e3SLinus Walleij 	reg = (reg & ~bit) | type0;
374f8b410e3SLinus Walleij 	iowrite32(reg, addr);
375f8b410e3SLinus Walleij 
376f8b410e3SLinus Walleij 	addr = bank_reg(gpio, bank, reg_irq_type1);
377f8b410e3SLinus Walleij 	reg = ioread32(addr);
378f8b410e3SLinus Walleij 	reg = (reg & ~bit) | type1;
379f8b410e3SLinus Walleij 	iowrite32(reg, addr);
380f8b410e3SLinus Walleij 
381f8b410e3SLinus Walleij 	addr = bank_reg(gpio, bank, reg_irq_type2);
382f8b410e3SLinus Walleij 	reg = ioread32(addr);
383f8b410e3SLinus Walleij 	reg = (reg & ~bit) | type2;
384f8b410e3SLinus Walleij 	iowrite32(reg, addr);
385f8b410e3SLinus Walleij 
386ab39d698SIwona Winiarska 	raw_spin_unlock_irqrestore(&gpio->lock, flags);
387f8b410e3SLinus Walleij 
388f8b410e3SLinus Walleij 	irq_set_handler_locked(d, handler);
389f8b410e3SLinus Walleij 
390f8b410e3SLinus Walleij 	return 0;
391f8b410e3SLinus Walleij }
392f8b410e3SLinus Walleij 
aspeed_sgpio_irq_handler(struct irq_desc * desc)393f8b410e3SLinus Walleij static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
394f8b410e3SLinus Walleij {
395f8b410e3SLinus Walleij 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
396f8b410e3SLinus Walleij 	struct irq_chip *ic = irq_desc_get_chip(desc);
397f8b410e3SLinus Walleij 	struct aspeed_sgpio *data = gpiochip_get_data(gc);
398dbd1c54fSMarc Zyngier 	unsigned int i, p;
399f8b410e3SLinus Walleij 	unsigned long reg;
400f8b410e3SLinus Walleij 
401f8b410e3SLinus Walleij 	chained_irq_enter(ic, desc);
402f8b410e3SLinus Walleij 
403f8b410e3SLinus Walleij 	for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
404f8b410e3SLinus Walleij 		const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i];
405f8b410e3SLinus Walleij 
406f8b410e3SLinus Walleij 		reg = ioread32(bank_reg(data, bank, reg_irq_status));
407f8b410e3SLinus Walleij 
408dbd1c54fSMarc Zyngier 		for_each_set_bit(p, &reg, 32)
409e5a7431fSSteven Lee 			generic_handle_domain_irq(gc->irq.domain, (i * 32 + p) * 2);
410f8b410e3SLinus Walleij 	}
411f8b410e3SLinus Walleij 
412f8b410e3SLinus Walleij 	chained_irq_exit(ic, desc);
413f8b410e3SLinus Walleij }
414f8b410e3SLinus Walleij 
aspeed_sgpio_irq_print_chip(struct irq_data * d,struct seq_file * p)415*c5dcf768SLinus Walleij static void aspeed_sgpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
416*c5dcf768SLinus Walleij {
417*c5dcf768SLinus Walleij 	const struct aspeed_sgpio_bank *bank;
418*c5dcf768SLinus Walleij 	struct aspeed_sgpio *gpio;
419*c5dcf768SLinus Walleij 	u32 bit;
420*c5dcf768SLinus Walleij 	int offset;
421*c5dcf768SLinus Walleij 
422*c5dcf768SLinus Walleij 	irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
423*c5dcf768SLinus Walleij 	seq_printf(p, dev_name(gpio->dev));
424*c5dcf768SLinus Walleij }
425*c5dcf768SLinus Walleij 
426*c5dcf768SLinus Walleij static const struct irq_chip aspeed_sgpio_irq_chip = {
427*c5dcf768SLinus Walleij 	.irq_ack = aspeed_sgpio_irq_ack,
428*c5dcf768SLinus Walleij 	.irq_mask = aspeed_sgpio_irq_mask,
429*c5dcf768SLinus Walleij 	.irq_unmask = aspeed_sgpio_irq_unmask,
430*c5dcf768SLinus Walleij 	.irq_set_type = aspeed_sgpio_set_type,
431*c5dcf768SLinus Walleij 	.irq_print_chip = aspeed_sgpio_irq_print_chip,
432*c5dcf768SLinus Walleij 	.flags = IRQCHIP_IMMUTABLE,
433*c5dcf768SLinus Walleij 	GPIOCHIP_IRQ_RESOURCE_HELPERS,
434*c5dcf768SLinus Walleij };
435*c5dcf768SLinus Walleij 
aspeed_sgpio_setup_irqs(struct aspeed_sgpio * gpio,struct platform_device * pdev)436f8b410e3SLinus Walleij static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
437f8b410e3SLinus Walleij 				   struct platform_device *pdev)
438f8b410e3SLinus Walleij {
439f8b410e3SLinus Walleij 	int rc, i;
440f8b410e3SLinus Walleij 	const struct aspeed_sgpio_bank *bank;
441f8b410e3SLinus Walleij 	struct gpio_irq_chip *irq;
442f8b410e3SLinus Walleij 
443f8b410e3SLinus Walleij 	rc = platform_get_irq(pdev, 0);
444f8b410e3SLinus Walleij 	if (rc < 0)
445f8b410e3SLinus Walleij 		return rc;
446f8b410e3SLinus Walleij 
447f8b410e3SLinus Walleij 	gpio->irq = rc;
448f8b410e3SLinus Walleij 
4490d311d8bSSachin agarwal 	/* Disable IRQ and clear Interrupt status registers for all SGPIO Pins. */
450f8b410e3SLinus Walleij 	for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
451f8b410e3SLinus Walleij 		bank =  &aspeed_sgpio_banks[i];
452f8b410e3SLinus Walleij 		/* disable irq enable bits */
453f8b410e3SLinus Walleij 		iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable));
454f8b410e3SLinus Walleij 		/* clear status bits */
455f8b410e3SLinus Walleij 		iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status));
456f8b410e3SLinus Walleij 	}
457f8b410e3SLinus Walleij 
458f8b410e3SLinus Walleij 	irq = &gpio->chip.irq;
459*c5dcf768SLinus Walleij 	gpio_irq_chip_set_chip(irq, &aspeed_sgpio_irq_chip);
460ac67b07eSJeremy Kerr 	irq->init_valid_mask = aspeed_sgpio_irq_init_valid_mask;
461f8b410e3SLinus Walleij 	irq->handler = handle_bad_irq;
462f8b410e3SLinus Walleij 	irq->default_type = IRQ_TYPE_NONE;
463f8b410e3SLinus Walleij 	irq->parent_handler = aspeed_sgpio_irq_handler;
464f8b410e3SLinus Walleij 	irq->parent_handler_data = gpio;
465f8b410e3SLinus Walleij 	irq->parents = &gpio->irq;
466f8b410e3SLinus Walleij 	irq->num_parents = 1;
467f8b410e3SLinus Walleij 
468bf0d394eSJeremy Kerr 	/* Apply default IRQ settings */
469f8b410e3SLinus Walleij 	for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
470f8b410e3SLinus Walleij 		bank = &aspeed_sgpio_banks[i];
471f8b410e3SLinus Walleij 		/* set falling or level-low irq */
472f8b410e3SLinus Walleij 		iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
473f8b410e3SLinus Walleij 		/* trigger type is edge */
474f8b410e3SLinus Walleij 		iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1));
475bf0d394eSJeremy Kerr 		/* single edge trigger */
476bf0d394eSJeremy Kerr 		iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2));
477f8b410e3SLinus Walleij 	}
478f8b410e3SLinus Walleij 
479f8b410e3SLinus Walleij 	return 0;
480f8b410e3SLinus Walleij }
481f8b410e3SLinus Walleij 
482e1f85d25SSteven Lee static const struct aspeed_sgpio_pdata ast2400_sgpio_pdata = {
483e1f85d25SSteven Lee 	.pin_mask = GENMASK(9, 6),
484e1f85d25SSteven Lee };
485e1f85d25SSteven Lee 
aspeed_sgpio_reset_tolerance(struct gpio_chip * chip,unsigned int offset,bool enable)4868a3581c6SSteven Lee static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip,
4878a3581c6SSteven Lee 					unsigned int offset, bool enable)
4888a3581c6SSteven Lee {
4898a3581c6SSteven Lee 	struct aspeed_sgpio *gpio = gpiochip_get_data(chip);
4908a3581c6SSteven Lee 	unsigned long flags;
4918a3581c6SSteven Lee 	void __iomem *reg;
4928a3581c6SSteven Lee 	u32 val;
4938a3581c6SSteven Lee 
4948a3581c6SSteven Lee 	reg = bank_reg(gpio, to_bank(offset), reg_tolerance);
4958a3581c6SSteven Lee 
496ab39d698SIwona Winiarska 	raw_spin_lock_irqsave(&gpio->lock, flags);
4978a3581c6SSteven Lee 
4988a3581c6SSteven Lee 	val = readl(reg);
4998a3581c6SSteven Lee 
5008a3581c6SSteven Lee 	if (enable)
5018a3581c6SSteven Lee 		val |= GPIO_BIT(offset);
5028a3581c6SSteven Lee 	else
5038a3581c6SSteven Lee 		val &= ~GPIO_BIT(offset);
5048a3581c6SSteven Lee 
5058a3581c6SSteven Lee 	writel(val, reg);
5068a3581c6SSteven Lee 
507ab39d698SIwona Winiarska 	raw_spin_unlock_irqrestore(&gpio->lock, flags);
5088a3581c6SSteven Lee 
5098a3581c6SSteven Lee 	return 0;
5108a3581c6SSteven Lee }
5118a3581c6SSteven Lee 
aspeed_sgpio_set_config(struct gpio_chip * chip,unsigned int offset,unsigned long config)5128a3581c6SSteven Lee static int aspeed_sgpio_set_config(struct gpio_chip *chip, unsigned int offset,
5138a3581c6SSteven Lee 				   unsigned long config)
5148a3581c6SSteven Lee {
5158a3581c6SSteven Lee 	unsigned long param = pinconf_to_config_param(config);
5168a3581c6SSteven Lee 	u32 arg = pinconf_to_config_argument(config);
5178a3581c6SSteven Lee 
5188a3581c6SSteven Lee 	if (param == PIN_CONFIG_PERSIST_STATE)
5198a3581c6SSteven Lee 		return aspeed_sgpio_reset_tolerance(chip, offset, arg);
5208a3581c6SSteven Lee 
5218a3581c6SSteven Lee 	return -ENOTSUPP;
5228a3581c6SSteven Lee }
5238a3581c6SSteven Lee 
524e1f85d25SSteven Lee static const struct aspeed_sgpio_pdata ast2600_sgpiom_pdata = {
525e1f85d25SSteven Lee 	.pin_mask = GENMASK(10, 6),
526e1f85d25SSteven Lee };
527e1f85d25SSteven Lee 
528f8b410e3SLinus Walleij static const struct of_device_id aspeed_sgpio_of_table[] = {
529e1f85d25SSteven Lee 	{ .compatible = "aspeed,ast2400-sgpio", .data = &ast2400_sgpio_pdata, },
530e1f85d25SSteven Lee 	{ .compatible = "aspeed,ast2500-sgpio", .data = &ast2400_sgpio_pdata, },
531e1f85d25SSteven Lee 	{ .compatible = "aspeed,ast2600-sgpiom", .data = &ast2600_sgpiom_pdata, },
532f8b410e3SLinus Walleij 	{}
533f8b410e3SLinus Walleij };
534f8b410e3SLinus Walleij 
535f8b410e3SLinus Walleij MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
536f8b410e3SLinus Walleij 
aspeed_sgpio_probe(struct platform_device * pdev)537f8b410e3SLinus Walleij static int __init aspeed_sgpio_probe(struct platform_device *pdev)
538f8b410e3SLinus Walleij {
539e1f85d25SSteven Lee 	u32 nr_gpios, sgpio_freq, sgpio_clk_div, gpio_cnt_regval, pin_mask;
540e1f85d25SSteven Lee 	const struct aspeed_sgpio_pdata *pdata;
541f8b410e3SLinus Walleij 	struct aspeed_sgpio *gpio;
542f8b410e3SLinus Walleij 	unsigned long apb_freq;
543e1f85d25SSteven Lee 	int rc;
544f8b410e3SLinus Walleij 
545f8b410e3SLinus Walleij 	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
546f8b410e3SLinus Walleij 	if (!gpio)
547f8b410e3SLinus Walleij 		return -ENOMEM;
548f8b410e3SLinus Walleij 
549f8b410e3SLinus Walleij 	gpio->base = devm_platform_ioremap_resource(pdev, 0);
550f8b410e3SLinus Walleij 	if (IS_ERR(gpio->base))
551f8b410e3SLinus Walleij 		return PTR_ERR(gpio->base);
552f8b410e3SLinus Walleij 
553*c5dcf768SLinus Walleij 	gpio->dev = &pdev->dev;
554*c5dcf768SLinus Walleij 
555e1f85d25SSteven Lee 	pdata = device_get_match_data(&pdev->dev);
556e1f85d25SSteven Lee 	if (!pdata)
557e1f85d25SSteven Lee 		return -EINVAL;
558e1f85d25SSteven Lee 
559e1f85d25SSteven Lee 	pin_mask = pdata->pin_mask;
560e1f85d25SSteven Lee 
5611f857b67SSteven Lee 	rc = device_property_read_u32(&pdev->dev, "ngpios", &nr_gpios);
562f8b410e3SLinus Walleij 	if (rc < 0) {
563f8b410e3SLinus Walleij 		dev_err(&pdev->dev, "Could not read ngpios property\n");
564f8b410e3SLinus Walleij 		return -EINVAL;
565f43837f4SSteven Lee 	} else if (nr_gpios % 8) {
566f43837f4SSteven Lee 		dev_err(&pdev->dev, "Number of GPIOs not multiple of 8: %d\n",
567f43837f4SSteven Lee 			nr_gpios);
568f8b410e3SLinus Walleij 		return -EINVAL;
569f8b410e3SLinus Walleij 	}
570f8b410e3SLinus Walleij 
5711f857b67SSteven Lee 	rc = device_property_read_u32(&pdev->dev, "bus-frequency", &sgpio_freq);
572f8b410e3SLinus Walleij 	if (rc < 0) {
573f8b410e3SLinus Walleij 		dev_err(&pdev->dev, "Could not read bus-frequency property\n");
574f8b410e3SLinus Walleij 		return -EINVAL;
575f8b410e3SLinus Walleij 	}
576f8b410e3SLinus Walleij 
577f8b410e3SLinus Walleij 	gpio->pclk = devm_clk_get(&pdev->dev, NULL);
578f8b410e3SLinus Walleij 	if (IS_ERR(gpio->pclk)) {
579f8b410e3SLinus Walleij 		dev_err(&pdev->dev, "devm_clk_get failed\n");
580f8b410e3SLinus Walleij 		return PTR_ERR(gpio->pclk);
581f8b410e3SLinus Walleij 	}
582f8b410e3SLinus Walleij 
583f8b410e3SLinus Walleij 	apb_freq = clk_get_rate(gpio->pclk);
584f8b410e3SLinus Walleij 
585f8b410e3SLinus Walleij 	/*
586f8b410e3SLinus Walleij 	 * From the datasheet,
587f8b410e3SLinus Walleij 	 *	SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1)
588f8b410e3SLinus Walleij 	 *	period = 2 * (GPIO254[31:16] + 1) / PCLK
589f8b410e3SLinus Walleij 	 *	frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK)
590f8b410e3SLinus Walleij 	 *	frequency = PCLK / (2 * (GPIO254[31:16] + 1))
591f8b410e3SLinus Walleij 	 *	frequency * 2 * (GPIO254[31:16] + 1) = PCLK
592f8b410e3SLinus Walleij 	 *	GPIO254[31:16] = PCLK / (frequency * 2) - 1
593f8b410e3SLinus Walleij 	 */
594f8b410e3SLinus Walleij 	if (sgpio_freq == 0)
595f8b410e3SLinus Walleij 		return -EINVAL;
596f8b410e3SLinus Walleij 
597f8b410e3SLinus Walleij 	sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1;
598f8b410e3SLinus Walleij 
599f8b410e3SLinus Walleij 	if (sgpio_clk_div > (1 << 16) - 1)
600f8b410e3SLinus Walleij 		return -EINVAL;
601f8b410e3SLinus Walleij 
602e1f85d25SSteven Lee 	gpio_cnt_regval = ((nr_gpios / 8) << ASPEED_SGPIO_PINS_SHIFT) & pin_mask;
603e1f85d25SSteven Lee 	iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | gpio_cnt_regval |
604e1f85d25SSteven Lee 		  ASPEED_SGPIO_ENABLE, gpio->base + ASPEED_SGPIO_CTRL);
605f8b410e3SLinus Walleij 
606ab39d698SIwona Winiarska 	raw_spin_lock_init(&gpio->lock);
607f8b410e3SLinus Walleij 
608f8b410e3SLinus Walleij 	gpio->chip.parent = &pdev->dev;
609e1f85d25SSteven Lee 	gpio->chip.ngpio = nr_gpios * 2;
610ac67b07eSJeremy Kerr 	gpio->chip.init_valid_mask = aspeed_sgpio_init_valid_mask;
611f8b410e3SLinus Walleij 	gpio->chip.direction_input = aspeed_sgpio_dir_in;
612f8b410e3SLinus Walleij 	gpio->chip.direction_output = aspeed_sgpio_dir_out;
613f8b410e3SLinus Walleij 	gpio->chip.get_direction = aspeed_sgpio_get_direction;
614f8b410e3SLinus Walleij 	gpio->chip.request = NULL;
615f8b410e3SLinus Walleij 	gpio->chip.free = NULL;
616f8b410e3SLinus Walleij 	gpio->chip.get = aspeed_sgpio_get;
617f8b410e3SLinus Walleij 	gpio->chip.set = aspeed_sgpio_set;
6188a3581c6SSteven Lee 	gpio->chip.set_config = aspeed_sgpio_set_config;
619f8b410e3SLinus Walleij 	gpio->chip.label = dev_name(&pdev->dev);
620f8b410e3SLinus Walleij 	gpio->chip.base = -1;
621f8b410e3SLinus Walleij 
622f8b410e3SLinus Walleij 	aspeed_sgpio_setup_irqs(gpio, pdev);
623f8b410e3SLinus Walleij 
624f8b410e3SLinus Walleij 	rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
625f8b410e3SLinus Walleij 	if (rc < 0)
626f8b410e3SLinus Walleij 		return rc;
627f8b410e3SLinus Walleij 
628f8b410e3SLinus Walleij 	return 0;
629f8b410e3SLinus Walleij }
630f8b410e3SLinus Walleij 
631f8b410e3SLinus Walleij static struct platform_driver aspeed_sgpio_driver = {
632f8b410e3SLinus Walleij 	.driver = {
633f8b410e3SLinus Walleij 		.name = KBUILD_MODNAME,
634f8b410e3SLinus Walleij 		.of_match_table = aspeed_sgpio_of_table,
635f8b410e3SLinus Walleij 	},
636f8b410e3SLinus Walleij };
637f8b410e3SLinus Walleij 
638f8b410e3SLinus Walleij module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe);
639f8b410e3SLinus Walleij MODULE_DESCRIPTION("Aspeed Serial GPIO Driver");
640