File Index
Files and directories
Sign in
FILE

mt6397-irq.c

File preview with syntax highlighting.

linux-6.19.14/drivers/mfd/mt6397-irq.c C
  1// SPDX-License-Identifier: GPL-2.0
  2//
  3// Copyright (c) 2019 MediaTek Inc.
  4
  5#include <linux/interrupt.h>
  6#include <linux/irq.h>
  7#include <linux/irqdomain.h>
  8#include <linux/module.h>
  9#include <linux/platform_device.h>
 10#include <linux/regmap.h>
 11#include <linux/suspend.h>
 12#include <linux/mfd/mt6323/core.h>
 13#include <linux/mfd/mt6323/registers.h>
 14#include <linux/mfd/mt6328/core.h>
 15#include <linux/mfd/mt6328/registers.h>
 16#include <linux/mfd/mt6331/core.h>
 17#include <linux/mfd/mt6331/registers.h>
 18#include <linux/mfd/mt6397/core.h>
 19#include <linux/mfd/mt6397/registers.h>
 20
 21static void mt6397_irq_lock(struct irq_data *data)
 22{
 23	struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);
 24
 25	mutex_lock(&mt6397->irqlock);
 26}
 27
 28static void mt6397_irq_sync_unlock(struct irq_data *data)
 29{
 30	struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);
 31
 32	regmap_write(mt6397->regmap, mt6397->int_con[0],
 33		     mt6397->irq_masks_cur[0]);
 34	regmap_write(mt6397->regmap, mt6397->int_con[1],
 35		     mt6397->irq_masks_cur[1]);
 36	if (mt6397->int_con[2])
 37		regmap_write(mt6397->regmap, mt6397->int_con[2],
 38			     mt6397->irq_masks_cur[2]);
 39
 40	mutex_unlock(&mt6397->irqlock);
 41}
 42
 43static void mt6397_irq_disable(struct irq_data *data)
 44{
 45	struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);
 46	int shift = data->hwirq & 0xf;
 47	int reg = data->hwirq >> 4;
 48
 49	mt6397->irq_masks_cur[reg] &= ~BIT(shift);
 50}
 51
 52static void mt6397_irq_enable(struct irq_data *data)
 53{
 54	struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);
 55	int shift = data->hwirq & 0xf;
 56	int reg = data->hwirq >> 4;
 57
 58	mt6397->irq_masks_cur[reg] |= BIT(shift);
 59}
 60
 61static int mt6397_irq_set_wake(struct irq_data *irq_data, unsigned int on)
 62{
 63	struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(irq_data);
 64	int shift = irq_data->hwirq & 0xf;
 65	int reg = irq_data->hwirq >> 4;
 66
 67	if (on)
 68		mt6397->wake_mask[reg] |= BIT(shift);
 69	else
 70		mt6397->wake_mask[reg] &= ~BIT(shift);
 71
 72	return 0;
 73}
 74
 75static struct irq_chip mt6397_irq_chip = {
 76	.name = "mt6397-irq",
 77	.irq_bus_lock = mt6397_irq_lock,
 78	.irq_bus_sync_unlock = mt6397_irq_sync_unlock,
 79	.irq_enable = mt6397_irq_enable,
 80	.irq_disable = mt6397_irq_disable,
 81	.irq_set_wake = pm_sleep_ptr(mt6397_irq_set_wake),
 82};
 83
 84static void mt6397_irq_handle_reg(struct mt6397_chip *mt6397, int reg,
 85				  int irqbase)
 86{
 87	unsigned int status = 0;
 88	int i, irq, ret;
 89
 90	ret = regmap_read(mt6397->regmap, reg, &status);
 91	if (ret) {
 92		dev_err(mt6397->dev, "Failed to read irq status: %d\n", ret);
 93		return;
 94	}
 95
 96	for (i = 0; i < 16; i++) {
 97		if (status & BIT(i)) {
 98			irq = irq_find_mapping(mt6397->irq_domain, irqbase + i);
 99			if (irq)
100				handle_nested_irq(irq);
101		}
102	}
103
104	regmap_write(mt6397->regmap, reg, status);
105}
106
107static irqreturn_t mt6397_irq_thread(int irq, void *data)
108{
109	struct mt6397_chip *mt6397 = data;
110
111	mt6397_irq_handle_reg(mt6397, mt6397->int_status[0], 0);
112	mt6397_irq_handle_reg(mt6397, mt6397->int_status[1], 16);
113	if (mt6397->int_status[2])
114		mt6397_irq_handle_reg(mt6397, mt6397->int_status[2], 32);
115
116	return IRQ_HANDLED;
117}
118
119static int mt6397_irq_domain_map(struct irq_domain *d, unsigned int irq,
120				 irq_hw_number_t hw)
121{
122	struct mt6397_chip *mt6397 = d->host_data;
123
124	irq_set_chip_data(irq, mt6397);
125	irq_set_chip_and_handler(irq, &mt6397_irq_chip, handle_level_irq);
126	irq_set_nested_thread(irq, 1);
127	irq_set_noprobe(irq);
128
129	return 0;
130}
131
132static const struct irq_domain_ops mt6397_irq_domain_ops = {
133	.map = mt6397_irq_domain_map,
134};
135
136static int mt6397_irq_pm_notifier(struct notifier_block *notifier,
137				  unsigned long pm_event, void *unused)
138{
139	struct mt6397_chip *chip =
140		container_of(notifier, struct mt6397_chip, pm_nb);
141
142	switch (pm_event) {
143	case PM_SUSPEND_PREPARE:
144		regmap_write(chip->regmap,
145			     chip->int_con[0], chip->wake_mask[0]);
146		regmap_write(chip->regmap,
147			     chip->int_con[1], chip->wake_mask[1]);
148		if (chip->int_con[2])
149			regmap_write(chip->regmap,
150				     chip->int_con[2], chip->wake_mask[2]);
151		enable_irq_wake(chip->irq);
152		break;
153
154	case PM_POST_SUSPEND:
155		regmap_write(chip->regmap,
156			     chip->int_con[0], chip->irq_masks_cur[0]);
157		regmap_write(chip->regmap,
158			     chip->int_con[1], chip->irq_masks_cur[1]);
159		if (chip->int_con[2])
160			regmap_write(chip->regmap,
161				     chip->int_con[2], chip->irq_masks_cur[2]);
162		disable_irq_wake(chip->irq);
163		break;
164
165	default:
166		break;
167	}
168
169	return NOTIFY_DONE;
170}
171
172int mt6397_irq_init(struct mt6397_chip *chip)
173{
174	int ret;
175
176	mutex_init(&chip->irqlock);
177
178	switch (chip->chip_id) {
179	case MT6323_CHIP_ID:
180		chip->int_con[0] = MT6323_INT_CON0;
181		chip->int_con[1] = MT6323_INT_CON1;
182		chip->int_status[0] = MT6323_INT_STATUS0;
183		chip->int_status[1] = MT6323_INT_STATUS1;
184		break;
185	case MT6328_CHIP_ID:
186		chip->int_con[0] = MT6328_INT_CON0;
187		chip->int_con[1] = MT6328_INT_CON1;
188		chip->int_con[2] = MT6328_INT_CON2;
189		chip->int_status[0] = MT6328_INT_STATUS0;
190		chip->int_status[1] = MT6328_INT_STATUS1;
191		chip->int_status[2] = MT6328_INT_STATUS2;
192		break;
193	case MT6331_CHIP_ID:
194		chip->int_con[0] = MT6331_INT_CON0;
195		chip->int_con[1] = MT6331_INT_CON1;
196		chip->int_status[0] = MT6331_INT_STATUS_CON0;
197		chip->int_status[1] = MT6331_INT_STATUS_CON1;
198		break;
199	case MT6391_CHIP_ID:
200	case MT6397_CHIP_ID:
201		chip->int_con[0] = MT6397_INT_CON0;
202		chip->int_con[1] = MT6397_INT_CON1;
203		chip->int_status[0] = MT6397_INT_STATUS0;
204		chip->int_status[1] = MT6397_INT_STATUS1;
205		break;
206
207	default:
208		dev_err(chip->dev, "unsupported chip: 0x%x\n", chip->chip_id);
209		return -ENODEV;
210	}
211
212	/* Mask all interrupt sources */
213	regmap_write(chip->regmap, chip->int_con[0], 0x0);
214	regmap_write(chip->regmap, chip->int_con[1], 0x0);
215	if (chip->int_con[2])
216		regmap_write(chip->regmap, chip->int_con[2], 0x0);
217
218	chip->pm_nb.notifier_call = mt6397_irq_pm_notifier;
219	chip->irq_domain = irq_domain_create_linear(dev_fwnode(chip->dev), MT6397_IRQ_NR,
220						    &mt6397_irq_domain_ops, chip);
221	if (!chip->irq_domain) {
222		dev_err(chip->dev, "could not create irq domain\n");
223		return -ENOMEM;
224	}
225
226	ret = devm_request_threaded_irq(chip->dev, chip->irq, NULL,
227					mt6397_irq_thread, IRQF_ONESHOT,
228					"mt6397-pmic", chip);
229	if (ret) {
230		dev_err(chip->dev, "failed to register irq=%d; err: %d\n",
231			chip->irq, ret);
232		irq_domain_remove(chip->irq_domain);
233		return ret;
234	}
235
236	register_pm_notifier(&chip->pm_nb);
237	return 0;
238}
~/ Read-only file preview.