1 // SPDX-License-Identifier: GPL-2.0
3 // Copyright (c) 2020 MediaTek Inc.
5 #include <linux/interrupt.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>
19 #define MTK_PMIC_REG_WIDTH 16
21 static const struct irq_top_t mt6357_ints
[] = {
32 static const struct irq_top_t mt6358_ints
[] = {
43 static const struct irq_top_t mt6359_ints
[] = {
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
,
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
,
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
,
75 static void pmic_irq_enable(struct irq_data
*data
)
77 unsigned int hwirq
= irqd_to_hwirq(data
);
78 struct mt6397_chip
*chip
= irq_data_get_irq_chip_data(data
);
79 struct pmic_irq_data
*irqd
= chip
->irq_data
;
81 irqd
->enable_hwirq
[hwirq
] = true;
84 static void pmic_irq_disable(struct irq_data
*data
)
86 unsigned int hwirq
= irqd_to_hwirq(data
);
87 struct mt6397_chip
*chip
= irq_data_get_irq_chip_data(data
);
88 struct pmic_irq_data
*irqd
= chip
->irq_data
;
90 irqd
->enable_hwirq
[hwirq
] = false;
93 static void pmic_irq_lock(struct irq_data
*data
)
95 struct mt6397_chip
*chip
= irq_data_get_irq_chip_data(data
);
97 mutex_lock(&chip
->irqlock
);
100 static void pmic_irq_sync_unlock(struct irq_data
*data
)
102 unsigned int i
, top_gp
, gp_offset
, en_reg
, int_regs
, shift
;
103 struct mt6397_chip
*chip
= irq_data_get_irq_chip_data(data
);
104 struct pmic_irq_data
*irqd
= chip
->irq_data
;
106 for (i
= 0; i
< irqd
->num_pmic_irqs
; i
++) {
107 if (irqd
->enable_hwirq
[i
] == irqd
->cache_hwirq
[i
])
110 /* Find out the IRQ group */
112 while ((top_gp
+ 1) < irqd
->num_top
&&
113 i
>= irqd
->pmic_ints
[top_gp
+ 1].hwirq_base
)
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
);
123 regmap_update_bits(chip
->regmap
, en_reg
, BIT(shift
),
124 irqd
->enable_hwirq
[i
] << shift
);
126 irqd
->cache_hwirq
[i
] = irqd
->enable_hwirq
[i
];
128 mutex_unlock(&chip
->irqlock
);
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
,
140 static void mt6358_irq_sp_handler(struct mt6397_chip
*chip
,
143 unsigned int irq_status
, sta_reg
, status
;
144 unsigned int hwirq
, virq
;
146 struct pmic_irq_data
*irqd
= chip
->irq_data
;
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
;
152 ret
= regmap_read(chip
->regmap
, sta_reg
, &irq_status
);
155 "Failed to read IRQ status, ret=%d\n", ret
);
166 hwirq
= irqd
->pmic_ints
[top_gp
].hwirq_base
+
167 MTK_PMIC_REG_WIDTH
* i
+ j
;
169 virq
= irq_find_mapping(chip
->irq_domain
, hwirq
);
171 handle_nested_irq(virq
);
176 regmap_write(chip
->regmap
, sta_reg
, irq_status
);
180 static irqreturn_t
mt6358_irq_handler(int irq
, void *data
)
182 struct mt6397_chip
*chip
= data
;
183 struct pmic_irq_data
*irqd
= chip
->irq_data
;
184 unsigned int bit
, i
, top_irq_status
= 0;
187 ret
= regmap_read(chip
->regmap
,
188 irqd
->top_int_status_reg
,
192 "Failed to read status from the device, ret=%d\n", ret
);
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
, i
);
200 top_irq_status
&= ~bit
;
209 static int pmic_irq_domain_map(struct irq_domain
*d
, unsigned int irq
,
212 struct mt6397_chip
*mt6397
= d
->host_data
;
214 irq_set_chip_data(irq
, mt6397
);
215 irq_set_chip_and_handler(irq
, &mt6358_irq_chip
, handle_level_irq
);
216 irq_set_nested_thread(irq
, 1);
217 irq_set_noprobe(irq
);
222 static const struct irq_domain_ops mt6358_irq_domain_ops
= {
223 .map
= pmic_irq_domain_map
,
224 .xlate
= irq_domain_xlate_twocell
,
227 int mt6358_irq_init(struct mt6397_chip
*chip
)
230 struct pmic_irq_data
*irqd
;
232 switch (chip
->chip_id
) {
234 chip
->irq_data
= &mt6357_irqd
;
239 chip
->irq_data
= &mt6358_irqd
;
243 chip
->irq_data
= &mt6359_irqd
;
247 dev_err(chip
->dev
, "unsupported chip: 0x%x\n", chip
->chip_id
);
251 mutex_init(&chip
->irqlock
);
252 irqd
= chip
->irq_data
;
253 irqd
->enable_hwirq
= devm_kcalloc(chip
->dev
,
255 sizeof(*irqd
->enable_hwirq
),
257 if (!irqd
->enable_hwirq
)
260 irqd
->cache_hwirq
= devm_kcalloc(chip
->dev
,
262 sizeof(*irqd
->cache_hwirq
),
264 if (!irqd
->cache_hwirq
)
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(chip
->regmap
,
271 irqd
->pmic_ints
[i
].en_reg
+
272 irqd
->pmic_ints
[i
].en_reg_shift
* j
, 0);
275 chip
->irq_domain
= irq_domain_add_linear(chip
->dev
->of_node
,
277 &mt6358_irq_domain_ops
, chip
);
278 if (!chip
->irq_domain
) {
279 dev_err(chip
->dev
, "Could not create IRQ domain\n");
283 ret
= devm_request_threaded_irq(chip
->dev
, chip
->irq
, NULL
,
284 mt6358_irq_handler
, IRQF_ONESHOT
,
285 mt6358_irq_chip
.name
, chip
);
287 dev_err(chip
->dev
, "Failed to register IRQ=%d, ret=%d\n",
292 enable_irq_wake(chip
->irq
);