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