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, ®, 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