1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* Copyright (c) 2020 HiSilicon Limited. */ |
3 | #include <linux/gpio/driver.h> |
4 | #include <linux/module.h> |
5 | #include <linux/mod_devicetable.h> |
6 | #include <linux/platform_device.h> |
7 | #include <linux/property.h> |
8 | |
9 | #define HISI_GPIO_SWPORT_DR_SET_WX 0x000 |
10 | #define HISI_GPIO_SWPORT_DR_CLR_WX 0x004 |
11 | #define HISI_GPIO_SWPORT_DDR_SET_WX 0x010 |
12 | #define HISI_GPIO_SWPORT_DDR_CLR_WX 0x014 |
13 | #define HISI_GPIO_SWPORT_DDR_ST_WX 0x018 |
14 | #define HISI_GPIO_INTEN_SET_WX 0x020 |
15 | #define HISI_GPIO_INTEN_CLR_WX 0x024 |
16 | #define HISI_GPIO_INTMASK_SET_WX 0x030 |
17 | #define HISI_GPIO_INTMASK_CLR_WX 0x034 |
18 | #define HISI_GPIO_INTTYPE_EDGE_SET_WX 0x040 |
19 | #define HISI_GPIO_INTTYPE_EDGE_CLR_WX 0x044 |
20 | #define HISI_GPIO_INT_POLARITY_SET_WX 0x050 |
21 | #define HISI_GPIO_INT_POLARITY_CLR_WX 0x054 |
22 | #define HISI_GPIO_DEBOUNCE_SET_WX 0x060 |
23 | #define HISI_GPIO_DEBOUNCE_CLR_WX 0x064 |
24 | #define HISI_GPIO_INTSTATUS_WX 0x070 |
25 | #define HISI_GPIO_PORTA_EOI_WX 0x078 |
26 | #define HISI_GPIO_EXT_PORT_WX 0x080 |
27 | #define HISI_GPIO_INTCOMB_MASK_WX 0x0a0 |
28 | #define HISI_GPIO_INT_DEDGE_SET 0x0b0 |
29 | #define HISI_GPIO_INT_DEDGE_CLR 0x0b4 |
30 | #define HISI_GPIO_INT_DEDGE_ST 0x0b8 |
31 | |
32 | #define HISI_GPIO_LINE_NUM_MAX 32 |
33 | #define HISI_GPIO_DRIVER_NAME "gpio-hisi" |
34 | |
35 | struct hisi_gpio { |
36 | struct gpio_chip chip; |
37 | struct device *dev; |
38 | void __iomem *reg_base; |
39 | unsigned int line_num; |
40 | int irq; |
41 | }; |
42 | |
43 | static inline u32 hisi_gpio_read_reg(struct gpio_chip *chip, |
44 | unsigned int off) |
45 | { |
46 | struct hisi_gpio *hisi_gpio = |
47 | container_of(chip, struct hisi_gpio, chip); |
48 | void __iomem *reg = hisi_gpio->reg_base + off; |
49 | |
50 | return readl(addr: reg); |
51 | } |
52 | |
53 | static inline void hisi_gpio_write_reg(struct gpio_chip *chip, |
54 | unsigned int off, u32 val) |
55 | { |
56 | struct hisi_gpio *hisi_gpio = |
57 | container_of(chip, struct hisi_gpio, chip); |
58 | void __iomem *reg = hisi_gpio->reg_base + off; |
59 | |
60 | writel(val, addr: reg); |
61 | } |
62 | |
63 | static void hisi_gpio_set_debounce(struct gpio_chip *chip, unsigned int off, |
64 | u32 debounce) |
65 | { |
66 | if (debounce) |
67 | hisi_gpio_write_reg(chip, HISI_GPIO_DEBOUNCE_SET_WX, BIT(off)); |
68 | else |
69 | hisi_gpio_write_reg(chip, HISI_GPIO_DEBOUNCE_CLR_WX, BIT(off)); |
70 | } |
71 | |
72 | static int hisi_gpio_set_config(struct gpio_chip *chip, unsigned int offset, |
73 | unsigned long config) |
74 | { |
75 | u32 config_para = pinconf_to_config_param(config); |
76 | u32 config_arg; |
77 | |
78 | switch (config_para) { |
79 | case PIN_CONFIG_INPUT_DEBOUNCE: |
80 | config_arg = pinconf_to_config_argument(config); |
81 | hisi_gpio_set_debounce(chip, off: offset, debounce: config_arg); |
82 | break; |
83 | default: |
84 | return -ENOTSUPP; |
85 | } |
86 | |
87 | return 0; |
88 | } |
89 | |
90 | static void hisi_gpio_set_ack(struct irq_data *d) |
91 | { |
92 | struct gpio_chip *chip = irq_data_get_irq_chip_data(d); |
93 | |
94 | hisi_gpio_write_reg(chip, HISI_GPIO_PORTA_EOI_WX, BIT(irqd_to_hwirq(d))); |
95 | } |
96 | |
97 | static void hisi_gpio_irq_set_mask(struct irq_data *d) |
98 | { |
99 | struct gpio_chip *chip = irq_data_get_irq_chip_data(d); |
100 | |
101 | hisi_gpio_write_reg(chip, HISI_GPIO_INTMASK_SET_WX, BIT(irqd_to_hwirq(d))); |
102 | gpiochip_disable_irq(gc: chip, offset: irqd_to_hwirq(d)); |
103 | } |
104 | |
105 | static void hisi_gpio_irq_clr_mask(struct irq_data *d) |
106 | { |
107 | struct gpio_chip *chip = irq_data_get_irq_chip_data(d); |
108 | |
109 | gpiochip_enable_irq(gc: chip, offset: irqd_to_hwirq(d)); |
110 | hisi_gpio_write_reg(chip, HISI_GPIO_INTMASK_CLR_WX, BIT(irqd_to_hwirq(d))); |
111 | } |
112 | |
113 | static int hisi_gpio_irq_set_type(struct irq_data *d, u32 type) |
114 | { |
115 | struct gpio_chip *chip = irq_data_get_irq_chip_data(d); |
116 | unsigned int mask = BIT(irqd_to_hwirq(d)); |
117 | |
118 | switch (type) { |
119 | case IRQ_TYPE_EDGE_BOTH: |
120 | hisi_gpio_write_reg(chip, HISI_GPIO_INT_DEDGE_SET, val: mask); |
121 | break; |
122 | case IRQ_TYPE_EDGE_RISING: |
123 | hisi_gpio_write_reg(chip, HISI_GPIO_INTTYPE_EDGE_SET_WX, val: mask); |
124 | hisi_gpio_write_reg(chip, HISI_GPIO_INT_POLARITY_SET_WX, val: mask); |
125 | break; |
126 | case IRQ_TYPE_EDGE_FALLING: |
127 | hisi_gpio_write_reg(chip, HISI_GPIO_INTTYPE_EDGE_SET_WX, val: mask); |
128 | hisi_gpio_write_reg(chip, HISI_GPIO_INT_POLARITY_CLR_WX, val: mask); |
129 | break; |
130 | case IRQ_TYPE_LEVEL_HIGH: |
131 | hisi_gpio_write_reg(chip, HISI_GPIO_INTTYPE_EDGE_CLR_WX, val: mask); |
132 | hisi_gpio_write_reg(chip, HISI_GPIO_INT_POLARITY_SET_WX, val: mask); |
133 | break; |
134 | case IRQ_TYPE_LEVEL_LOW: |
135 | hisi_gpio_write_reg(chip, HISI_GPIO_INTTYPE_EDGE_CLR_WX, val: mask); |
136 | hisi_gpio_write_reg(chip, HISI_GPIO_INT_POLARITY_CLR_WX, val: mask); |
137 | break; |
138 | default: |
139 | return -EINVAL; |
140 | } |
141 | |
142 | /* |
143 | * The dual-edge interrupt and other interrupt's registers do not |
144 | * take effect at the same time. The registers of the two-edge |
145 | * interrupts have higher priorities, the configuration of |
146 | * the dual-edge interrupts must be disabled before the configuration |
147 | * of other kind of interrupts. |
148 | */ |
149 | if (type != IRQ_TYPE_EDGE_BOTH) { |
150 | unsigned int both = hisi_gpio_read_reg(chip, HISI_GPIO_INT_DEDGE_ST); |
151 | |
152 | if (both & mask) |
153 | hisi_gpio_write_reg(chip, HISI_GPIO_INT_DEDGE_CLR, val: mask); |
154 | } |
155 | |
156 | if (type & IRQ_TYPE_LEVEL_MASK) |
157 | irq_set_handler_locked(data: d, handler: handle_level_irq); |
158 | else if (type & IRQ_TYPE_EDGE_BOTH) |
159 | irq_set_handler_locked(data: d, handler: handle_edge_irq); |
160 | |
161 | return 0; |
162 | } |
163 | |
164 | static void hisi_gpio_irq_enable(struct irq_data *d) |
165 | { |
166 | struct gpio_chip *chip = irq_data_get_irq_chip_data(d); |
167 | |
168 | hisi_gpio_irq_clr_mask(d); |
169 | hisi_gpio_write_reg(chip, HISI_GPIO_INTEN_SET_WX, BIT(irqd_to_hwirq(d))); |
170 | } |
171 | |
172 | static void hisi_gpio_irq_disable(struct irq_data *d) |
173 | { |
174 | struct gpio_chip *chip = irq_data_get_irq_chip_data(d); |
175 | |
176 | hisi_gpio_irq_set_mask(d); |
177 | hisi_gpio_write_reg(chip, HISI_GPIO_INTEN_CLR_WX, BIT(irqd_to_hwirq(d))); |
178 | } |
179 | |
180 | static void hisi_gpio_irq_handler(struct irq_desc *desc) |
181 | { |
182 | struct hisi_gpio *hisi_gpio = irq_desc_get_handler_data(desc); |
183 | unsigned long irq_msk = hisi_gpio_read_reg(chip: &hisi_gpio->chip, |
184 | HISI_GPIO_INTSTATUS_WX); |
185 | struct irq_chip *irq_c = irq_desc_get_chip(desc); |
186 | int hwirq; |
187 | |
188 | chained_irq_enter(chip: irq_c, desc); |
189 | for_each_set_bit(hwirq, &irq_msk, HISI_GPIO_LINE_NUM_MAX) |
190 | generic_handle_domain_irq(domain: hisi_gpio->chip.irq.domain, |
191 | hwirq); |
192 | chained_irq_exit(chip: irq_c, desc); |
193 | } |
194 | |
195 | static const struct irq_chip hisi_gpio_irq_chip = { |
196 | .name = "HISI-GPIO" , |
197 | .irq_ack = hisi_gpio_set_ack, |
198 | .irq_mask = hisi_gpio_irq_set_mask, |
199 | .irq_unmask = hisi_gpio_irq_clr_mask, |
200 | .irq_set_type = hisi_gpio_irq_set_type, |
201 | .irq_enable = hisi_gpio_irq_enable, |
202 | .irq_disable = hisi_gpio_irq_disable, |
203 | .flags = IRQCHIP_IMMUTABLE, |
204 | GPIOCHIP_IRQ_RESOURCE_HELPERS, |
205 | }; |
206 | |
207 | static void hisi_gpio_init_irq(struct hisi_gpio *hisi_gpio) |
208 | { |
209 | struct gpio_chip *chip = &hisi_gpio->chip; |
210 | struct gpio_irq_chip *girq_chip = &chip->irq; |
211 | |
212 | gpio_irq_chip_set_chip(girq: girq_chip, chip: &hisi_gpio_irq_chip); |
213 | girq_chip->default_type = IRQ_TYPE_NONE; |
214 | girq_chip->num_parents = 1; |
215 | girq_chip->parents = &hisi_gpio->irq; |
216 | girq_chip->parent_handler = hisi_gpio_irq_handler; |
217 | girq_chip->parent_handler_data = hisi_gpio; |
218 | |
219 | /* Clear Mask of GPIO controller combine IRQ */ |
220 | hisi_gpio_write_reg(chip, HISI_GPIO_INTCOMB_MASK_WX, val: 1); |
221 | } |
222 | |
223 | static const struct acpi_device_id hisi_gpio_acpi_match[] = { |
224 | {"HISI0184" , 0}, |
225 | {} |
226 | }; |
227 | MODULE_DEVICE_TABLE(acpi, hisi_gpio_acpi_match); |
228 | |
229 | static const struct of_device_id hisi_gpio_dts_match[] = { |
230 | { .compatible = "hisilicon,ascend910-gpio" , }, |
231 | { } |
232 | }; |
233 | MODULE_DEVICE_TABLE(of, hisi_gpio_dts_match); |
234 | |
235 | static void hisi_gpio_get_pdata(struct device *dev, |
236 | struct hisi_gpio *hisi_gpio) |
237 | { |
238 | struct platform_device *pdev = to_platform_device(dev); |
239 | struct fwnode_handle *fwnode; |
240 | int idx = 0; |
241 | |
242 | device_for_each_child_node(dev, fwnode) { |
243 | /* Cycle for once, no need for an array to save line_num */ |
244 | if (fwnode_property_read_u32(fwnode, propname: "ngpios" , |
245 | val: &hisi_gpio->line_num)) { |
246 | dev_err(dev, |
247 | "failed to get number of lines for port%d and use default value instead\n" , |
248 | idx); |
249 | hisi_gpio->line_num = HISI_GPIO_LINE_NUM_MAX; |
250 | } |
251 | |
252 | if (WARN_ON(hisi_gpio->line_num > HISI_GPIO_LINE_NUM_MAX)) |
253 | hisi_gpio->line_num = HISI_GPIO_LINE_NUM_MAX; |
254 | |
255 | hisi_gpio->irq = platform_get_irq(pdev, idx); |
256 | |
257 | dev_info(dev, |
258 | "get hisi_gpio[%d] with %u lines\n" , idx, |
259 | hisi_gpio->line_num); |
260 | |
261 | idx++; |
262 | } |
263 | } |
264 | |
265 | static int hisi_gpio_probe(struct platform_device *pdev) |
266 | { |
267 | struct device *dev = &pdev->dev; |
268 | struct hisi_gpio *hisi_gpio; |
269 | int port_num; |
270 | int ret; |
271 | |
272 | /* |
273 | * One GPIO controller own one port currently, |
274 | * if we get more from ACPI table, return error. |
275 | */ |
276 | port_num = device_get_child_node_count(dev); |
277 | if (WARN_ON(port_num != 1)) |
278 | return -ENODEV; |
279 | |
280 | hisi_gpio = devm_kzalloc(dev, size: sizeof(*hisi_gpio), GFP_KERNEL); |
281 | if (!hisi_gpio) |
282 | return -ENOMEM; |
283 | |
284 | hisi_gpio->reg_base = devm_platform_ioremap_resource(pdev, index: 0); |
285 | if (IS_ERR(ptr: hisi_gpio->reg_base)) |
286 | return PTR_ERR(ptr: hisi_gpio->reg_base); |
287 | |
288 | hisi_gpio_get_pdata(dev, hisi_gpio); |
289 | |
290 | hisi_gpio->dev = dev; |
291 | |
292 | ret = bgpio_init(gc: &hisi_gpio->chip, dev: hisi_gpio->dev, sz: 0x4, |
293 | dat: hisi_gpio->reg_base + HISI_GPIO_EXT_PORT_WX, |
294 | set: hisi_gpio->reg_base + HISI_GPIO_SWPORT_DR_SET_WX, |
295 | clr: hisi_gpio->reg_base + HISI_GPIO_SWPORT_DR_CLR_WX, |
296 | dirout: hisi_gpio->reg_base + HISI_GPIO_SWPORT_DDR_SET_WX, |
297 | dirin: hisi_gpio->reg_base + HISI_GPIO_SWPORT_DDR_CLR_WX, |
298 | BGPIOF_NO_SET_ON_INPUT); |
299 | if (ret) { |
300 | dev_err(dev, "failed to init, ret = %d\n" , ret); |
301 | return ret; |
302 | } |
303 | |
304 | hisi_gpio->chip.set_config = hisi_gpio_set_config; |
305 | hisi_gpio->chip.ngpio = hisi_gpio->line_num; |
306 | hisi_gpio->chip.bgpio_dir_unreadable = 1; |
307 | hisi_gpio->chip.base = -1; |
308 | |
309 | if (hisi_gpio->irq > 0) |
310 | hisi_gpio_init_irq(hisi_gpio); |
311 | |
312 | ret = devm_gpiochip_add_data(dev, &hisi_gpio->chip, hisi_gpio); |
313 | if (ret) { |
314 | dev_err(dev, "failed to register gpiochip, ret = %d\n" , ret); |
315 | return ret; |
316 | } |
317 | |
318 | return 0; |
319 | } |
320 | |
321 | static struct platform_driver hisi_gpio_driver = { |
322 | .driver = { |
323 | .name = HISI_GPIO_DRIVER_NAME, |
324 | .acpi_match_table = hisi_gpio_acpi_match, |
325 | .of_match_table = hisi_gpio_dts_match, |
326 | }, |
327 | .probe = hisi_gpio_probe, |
328 | }; |
329 | |
330 | module_platform_driver(hisi_gpio_driver); |
331 | |
332 | MODULE_LICENSE("GPL" ); |
333 | MODULE_AUTHOR("Luo Jiaxing <luojiaxing@huawei.com>" ); |
334 | MODULE_DESCRIPTION("HiSilicon GPIO controller driver" ); |
335 | MODULE_ALIAS("platform:" HISI_GPIO_DRIVER_NAME); |
336 | |