1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // Copyright (c) 2020 MediaTek Inc. |
4 | |
5 | #include <linux/interrupt.h> |
6 | #include <linux/irq.h> |
7 | #include <linux/irqdomain.h> |
8 | #include <linux/mfd/mt6357/core.h> |
9 | #include <linux/mfd/mt6357/registers.h> |
10 | #include <linux/mfd/mt6358/core.h> |
11 | #include <linux/mfd/mt6358/registers.h> |
12 | #include <linux/mfd/mt6359/core.h> |
13 | #include <linux/mfd/mt6359/registers.h> |
14 | #include <linux/mfd/mt6397/core.h> |
15 | #include <linux/module.h> |
16 | #include <linux/platform_device.h> |
17 | #include <linux/regmap.h> |
18 | |
19 | #define MTK_PMIC_REG_WIDTH 16 |
20 | |
21 | static const struct irq_top_t mt6357_ints[] = { |
22 | MT6357_TOP_GEN(BUCK), |
23 | MT6357_TOP_GEN(LDO), |
24 | MT6357_TOP_GEN(PSC), |
25 | MT6357_TOP_GEN(SCK), |
26 | MT6357_TOP_GEN(BM), |
27 | MT6357_TOP_GEN(HK), |
28 | MT6357_TOP_GEN(AUD), |
29 | MT6357_TOP_GEN(MISC), |
30 | }; |
31 | |
32 | static const struct irq_top_t mt6358_ints[] = { |
33 | MT6358_TOP_GEN(BUCK), |
34 | MT6358_TOP_GEN(LDO), |
35 | MT6358_TOP_GEN(PSC), |
36 | MT6358_TOP_GEN(SCK), |
37 | MT6358_TOP_GEN(BM), |
38 | MT6358_TOP_GEN(HK), |
39 | MT6358_TOP_GEN(AUD), |
40 | MT6358_TOP_GEN(MISC), |
41 | }; |
42 | |
43 | static const struct irq_top_t mt6359_ints[] = { |
44 | MT6359_TOP_GEN(BUCK), |
45 | MT6359_TOP_GEN(LDO), |
46 | MT6359_TOP_GEN(PSC), |
47 | MT6359_TOP_GEN(SCK), |
48 | MT6359_TOP_GEN(BM), |
49 | MT6359_TOP_GEN(HK), |
50 | MT6359_TOP_GEN(AUD), |
51 | MT6359_TOP_GEN(MISC), |
52 | }; |
53 | |
54 | static struct pmic_irq_data mt6357_irqd = { |
55 | .num_top = ARRAY_SIZE(mt6357_ints), |
56 | .num_pmic_irqs = MT6357_IRQ_NR, |
57 | .top_int_status_reg = MT6357_TOP_INT_STATUS0, |
58 | .pmic_ints = mt6357_ints, |
59 | }; |
60 | |
61 | static struct pmic_irq_data mt6358_irqd = { |
62 | .num_top = ARRAY_SIZE(mt6358_ints), |
63 | .num_pmic_irqs = MT6358_IRQ_NR, |
64 | .top_int_status_reg = MT6358_TOP_INT_STATUS0, |
65 | .pmic_ints = mt6358_ints, |
66 | }; |
67 | |
68 | static struct pmic_irq_data mt6359_irqd = { |
69 | .num_top = ARRAY_SIZE(mt6359_ints), |
70 | .num_pmic_irqs = MT6359_IRQ_NR, |
71 | .top_int_status_reg = MT6359_TOP_INT_STATUS0, |
72 | .pmic_ints = mt6359_ints, |
73 | }; |
74 | |
75 | static void pmic_irq_enable(struct irq_data *data) |
76 | { |
77 | unsigned int hwirq = irqd_to_hwirq(d: data); |
78 | struct mt6397_chip *chip = irq_data_get_irq_chip_data(d: data); |
79 | struct pmic_irq_data *irqd = chip->irq_data; |
80 | |
81 | irqd->enable_hwirq[hwirq] = true; |
82 | } |
83 | |
84 | static void pmic_irq_disable(struct irq_data *data) |
85 | { |
86 | unsigned int hwirq = irqd_to_hwirq(d: data); |
87 | struct mt6397_chip *chip = irq_data_get_irq_chip_data(d: data); |
88 | struct pmic_irq_data *irqd = chip->irq_data; |
89 | |
90 | irqd->enable_hwirq[hwirq] = false; |
91 | } |
92 | |
93 | static void pmic_irq_lock(struct irq_data *data) |
94 | { |
95 | struct mt6397_chip *chip = irq_data_get_irq_chip_data(d: data); |
96 | |
97 | mutex_lock(&chip->irqlock); |
98 | } |
99 | |
100 | static void pmic_irq_sync_unlock(struct irq_data *data) |
101 | { |
102 | unsigned int i, top_gp, gp_offset, en_reg, int_regs, shift; |
103 | struct mt6397_chip *chip = irq_data_get_irq_chip_data(d: data); |
104 | struct pmic_irq_data *irqd = chip->irq_data; |
105 | |
106 | for (i = 0; i < irqd->num_pmic_irqs; i++) { |
107 | if (irqd->enable_hwirq[i] == irqd->cache_hwirq[i]) |
108 | continue; |
109 | |
110 | /* Find out the IRQ group */ |
111 | top_gp = 0; |
112 | while ((top_gp + 1) < irqd->num_top && |
113 | i >= irqd->pmic_ints[top_gp + 1].hwirq_base) |
114 | top_gp++; |
115 | |
116 | /* Find the IRQ registers */ |
117 | gp_offset = i - irqd->pmic_ints[top_gp].hwirq_base; |
118 | int_regs = gp_offset / MTK_PMIC_REG_WIDTH; |
119 | shift = gp_offset % MTK_PMIC_REG_WIDTH; |
120 | en_reg = irqd->pmic_ints[top_gp].en_reg + |
121 | (irqd->pmic_ints[top_gp].en_reg_shift * int_regs); |
122 | |
123 | regmap_update_bits(map: chip->regmap, reg: en_reg, BIT(shift), |
124 | val: irqd->enable_hwirq[i] << shift); |
125 | |
126 | irqd->cache_hwirq[i] = irqd->enable_hwirq[i]; |
127 | } |
128 | mutex_unlock(lock: &chip->irqlock); |
129 | } |
130 | |
131 | static struct irq_chip mt6358_irq_chip = { |
132 | .name = "mt6358-irq" , |
133 | .flags = IRQCHIP_SKIP_SET_WAKE, |
134 | .irq_enable = pmic_irq_enable, |
135 | .irq_disable = pmic_irq_disable, |
136 | .irq_bus_lock = pmic_irq_lock, |
137 | .irq_bus_sync_unlock = pmic_irq_sync_unlock, |
138 | }; |
139 | |
140 | static void mt6358_irq_sp_handler(struct mt6397_chip *chip, |
141 | unsigned int top_gp) |
142 | { |
143 | unsigned int irq_status, sta_reg, status; |
144 | unsigned int hwirq, virq; |
145 | int i, j, ret; |
146 | struct pmic_irq_data *irqd = chip->irq_data; |
147 | |
148 | for (i = 0; i < irqd->pmic_ints[top_gp].num_int_regs; i++) { |
149 | sta_reg = irqd->pmic_ints[top_gp].sta_reg + |
150 | irqd->pmic_ints[top_gp].sta_reg_shift * i; |
151 | |
152 | ret = regmap_read(map: chip->regmap, reg: sta_reg, val: &irq_status); |
153 | if (ret) { |
154 | dev_err(chip->dev, |
155 | "Failed to read IRQ status, ret=%d\n" , ret); |
156 | return; |
157 | } |
158 | |
159 | if (!irq_status) |
160 | continue; |
161 | |
162 | status = irq_status; |
163 | do { |
164 | j = __ffs(status); |
165 | |
166 | hwirq = irqd->pmic_ints[top_gp].hwirq_base + |
167 | MTK_PMIC_REG_WIDTH * i + j; |
168 | |
169 | virq = irq_find_mapping(domain: chip->irq_domain, hwirq); |
170 | if (virq) |
171 | handle_nested_irq(irq: virq); |
172 | |
173 | status &= ~BIT(j); |
174 | } while (status); |
175 | |
176 | regmap_write(map: chip->regmap, reg: sta_reg, val: irq_status); |
177 | } |
178 | } |
179 | |
180 | static irqreturn_t mt6358_irq_handler(int irq, void *data) |
181 | { |
182 | struct mt6397_chip *chip = data; |
183 | struct pmic_irq_data *irqd = chip->irq_data; |
184 | unsigned int bit, i, top_irq_status = 0; |
185 | int ret; |
186 | |
187 | ret = regmap_read(map: chip->regmap, |
188 | reg: irqd->top_int_status_reg, |
189 | val: &top_irq_status); |
190 | if (ret) { |
191 | dev_err(chip->dev, |
192 | "Failed to read status from the device, ret=%d\n" , ret); |
193 | return IRQ_NONE; |
194 | } |
195 | |
196 | for (i = 0; i < irqd->num_top; i++) { |
197 | bit = BIT(irqd->pmic_ints[i].top_offset); |
198 | if (top_irq_status & bit) { |
199 | mt6358_irq_sp_handler(chip, top_gp: i); |
200 | top_irq_status &= ~bit; |
201 | if (!top_irq_status) |
202 | break; |
203 | } |
204 | } |
205 | |
206 | return IRQ_HANDLED; |
207 | } |
208 | |
209 | static int pmic_irq_domain_map(struct irq_domain *d, unsigned int irq, |
210 | irq_hw_number_t hw) |
211 | { |
212 | struct mt6397_chip *mt6397 = d->host_data; |
213 | |
214 | irq_set_chip_data(irq, data: mt6397); |
215 | irq_set_chip_and_handler(irq, chip: &mt6358_irq_chip, handle: handle_level_irq); |
216 | irq_set_nested_thread(irq, nest: 1); |
217 | irq_set_noprobe(irq); |
218 | |
219 | return 0; |
220 | } |
221 | |
222 | static const struct irq_domain_ops mt6358_irq_domain_ops = { |
223 | .map = pmic_irq_domain_map, |
224 | .xlate = irq_domain_xlate_twocell, |
225 | }; |
226 | |
227 | int mt6358_irq_init(struct mt6397_chip *chip) |
228 | { |
229 | int i, j, ret; |
230 | struct pmic_irq_data *irqd; |
231 | |
232 | switch (chip->chip_id) { |
233 | case MT6357_CHIP_ID: |
234 | chip->irq_data = &mt6357_irqd; |
235 | break; |
236 | |
237 | case MT6358_CHIP_ID: |
238 | case MT6366_CHIP_ID: |
239 | chip->irq_data = &mt6358_irqd; |
240 | break; |
241 | |
242 | case MT6359_CHIP_ID: |
243 | chip->irq_data = &mt6359_irqd; |
244 | break; |
245 | |
246 | default: |
247 | dev_err(chip->dev, "unsupported chip: 0x%x\n" , chip->chip_id); |
248 | return -ENODEV; |
249 | } |
250 | |
251 | mutex_init(&chip->irqlock); |
252 | irqd = chip->irq_data; |
253 | irqd->enable_hwirq = devm_kcalloc(dev: chip->dev, |
254 | n: irqd->num_pmic_irqs, |
255 | size: sizeof(*irqd->enable_hwirq), |
256 | GFP_KERNEL); |
257 | if (!irqd->enable_hwirq) |
258 | return -ENOMEM; |
259 | |
260 | irqd->cache_hwirq = devm_kcalloc(dev: chip->dev, |
261 | n: irqd->num_pmic_irqs, |
262 | size: sizeof(*irqd->cache_hwirq), |
263 | GFP_KERNEL); |
264 | if (!irqd->cache_hwirq) |
265 | return -ENOMEM; |
266 | |
267 | /* Disable all interrupts for initializing */ |
268 | for (i = 0; i < irqd->num_top; i++) { |
269 | for (j = 0; j < irqd->pmic_ints[i].num_int_regs; j++) |
270 | regmap_write(map: chip->regmap, |
271 | reg: irqd->pmic_ints[i].en_reg + |
272 | irqd->pmic_ints[i].en_reg_shift * j, val: 0); |
273 | } |
274 | |
275 | chip->irq_domain = irq_domain_add_linear(of_node: chip->dev->of_node, |
276 | size: irqd->num_pmic_irqs, |
277 | ops: &mt6358_irq_domain_ops, host_data: chip); |
278 | if (!chip->irq_domain) { |
279 | dev_err(chip->dev, "Could not create IRQ domain\n" ); |
280 | return -ENODEV; |
281 | } |
282 | |
283 | ret = devm_request_threaded_irq(dev: chip->dev, irq: chip->irq, NULL, |
284 | thread_fn: mt6358_irq_handler, IRQF_ONESHOT, |
285 | devname: mt6358_irq_chip.name, dev_id: chip); |
286 | if (ret) { |
287 | dev_err(chip->dev, "Failed to register IRQ=%d, ret=%d\n" , |
288 | chip->irq, ret); |
289 | return ret; |
290 | } |
291 | |
292 | enable_irq_wake(irq: chip->irq); |
293 | return ret; |
294 | } |
295 | |