File Index
Files and directories
Sign in
FILE

hi6421v600-irq.c

File preview with syntax highlighting.

linux-6.19.14/drivers/misc/hi6421v600-irq.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Device driver for irqs in HISI PMIC IC
  4 *
  5 * Copyright (c) 2013 Linaro Ltd.
  6 * Copyright (c) 2011 Hisilicon.
  7 * Copyright (c) 2020-2021 Huawei Technologies Co., Ltd.
  8 */
  9
 10#include <linux/bitops.h>
 11#include <linux/interrupt.h>
 12#include <linux/irq.h>
 13#include <linux/module.h>
 14#include <linux/platform_device.h>
 15#include <linux/slab.h>
 16#include <linux/irqdomain.h>
 17#include <linux/regmap.h>
 18
 19struct hi6421v600_irq {
 20	struct device		*dev;
 21	struct irq_domain	*domain;
 22	int			irq;
 23	unsigned int		*irqs;
 24	struct regmap		*regmap;
 25
 26	/* Protect IRQ mask changes */
 27	spinlock_t		lock;
 28};
 29
 30enum hi6421v600_irq_list {
 31	OTMP = 0,
 32	VBUS_CONNECT,
 33	VBUS_DISCONNECT,
 34	ALARMON_R,
 35	HOLD_6S,
 36	HOLD_1S,
 37	POWERKEY_UP,
 38	POWERKEY_DOWN,
 39	OCP_SCP_R,
 40	COUL_R,
 41	SIM0_HPD_R,
 42	SIM0_HPD_F,
 43	SIM1_HPD_R,
 44	SIM1_HPD_F,
 45
 46	PMIC_IRQ_LIST_MAX
 47};
 48
 49#define HISI_IRQ_BANK_SIZE		2
 50
 51/*
 52 * IRQ number for the power key button and mask for both UP and DOWN IRQs
 53 */
 54#define HISI_POWERKEY_IRQ_NUM		0
 55#define HISI_IRQ_POWERKEY_UP_DOWN	(BIT(POWERKEY_DOWN) | BIT(POWERKEY_UP))
 56
 57/*
 58 * Registers for IRQ address and IRQ mask bits
 59 *
 60 * Please notice that we need to regmap a larger region, as other
 61 * registers are used by the irqs.
 62 * See drivers/irq/hi6421-irq.c.
 63 */
 64#define SOC_PMIC_IRQ_MASK_0_ADDR	0x0202
 65#define SOC_PMIC_IRQ0_ADDR		0x0212
 66
 67/*
 68 * The IRQs are mapped as:
 69 *
 70 *	======================  =============   ============	=====
 71 *	IRQ			MASK REGISTER	IRQ REGISTER	BIT
 72 *	======================  =============   ============	=====
 73 *	OTMP			0x0202		0x212		bit 0
 74 *	VBUS_CONNECT		0x0202		0x212		bit 1
 75 *	VBUS_DISCONNECT		0x0202		0x212		bit 2
 76 *	ALARMON_R		0x0202		0x212		bit 3
 77 *	HOLD_6S			0x0202		0x212		bit 4
 78 *	HOLD_1S			0x0202		0x212		bit 5
 79 *	POWERKEY_UP		0x0202		0x212		bit 6
 80 *	POWERKEY_DOWN		0x0202		0x212		bit 7
 81 *
 82 *	OCP_SCP_R		0x0203		0x213		bit 0
 83 *	COUL_R			0x0203		0x213		bit 1
 84 *	SIM0_HPD_R		0x0203		0x213		bit 2
 85 *	SIM0_HPD_F		0x0203		0x213		bit 3
 86 *	SIM1_HPD_R		0x0203		0x213		bit 4
 87 *	SIM1_HPD_F		0x0203		0x213		bit 5
 88 *	======================  =============   ============	=====
 89 *
 90 * Each mask register contains 8 bits. The ancillary macros below
 91 * convert a number from 0 to 14 into a register address and a bit mask
 92 */
 93#define HISI_IRQ_MASK_REG(irq_data)	(SOC_PMIC_IRQ_MASK_0_ADDR + \
 94					 (irqd_to_hwirq(irq_data) / BITS_PER_BYTE))
 95#define HISI_IRQ_MASK_BIT(irq_data)	BIT(irqd_to_hwirq(irq_data) & (BITS_PER_BYTE - 1))
 96#define HISI_8BITS_MASK			0xff
 97
 98static irqreturn_t hi6421v600_irq_handler(int irq, void *__priv)
 99{
100	struct hi6421v600_irq *priv = __priv;
101	unsigned long pending;
102	unsigned int in;
103	int i, offset;
104
105	for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
106		regmap_read(priv->regmap, SOC_PMIC_IRQ0_ADDR + i, &in);
107
108		/* Mark pending IRQs as handled */
109		regmap_write(priv->regmap, SOC_PMIC_IRQ0_ADDR + i, in);
110
111		pending = in & HISI_8BITS_MASK;
112
113		if (i == HISI_POWERKEY_IRQ_NUM &&
114		    (pending & HISI_IRQ_POWERKEY_UP_DOWN) == HISI_IRQ_POWERKEY_UP_DOWN) {
115			/*
116			 * If both powerkey down and up IRQs are received,
117			 * handle them at the right order
118			 */
119			generic_handle_irq_safe(priv->irqs[POWERKEY_DOWN]);
120			generic_handle_irq_safe(priv->irqs[POWERKEY_UP]);
121			pending &= ~HISI_IRQ_POWERKEY_UP_DOWN;
122		}
123
124		if (!pending)
125			continue;
126
127		for_each_set_bit(offset, &pending, BITS_PER_BYTE) {
128			generic_handle_irq_safe(priv->irqs[offset + i * BITS_PER_BYTE]);
129		}
130	}
131
132	return IRQ_HANDLED;
133}
134
135static void hi6421v600_irq_mask(struct irq_data *d)
136{
137	struct hi6421v600_irq *priv = irq_data_get_irq_chip_data(d);
138	unsigned long flags;
139	unsigned int data;
140	u32 offset;
141
142	offset = HISI_IRQ_MASK_REG(d);
143
144	spin_lock_irqsave(&priv->lock, flags);
145
146	regmap_read(priv->regmap, offset, &data);
147	data |= HISI_IRQ_MASK_BIT(d);
148	regmap_write(priv->regmap, offset, data);
149
150	spin_unlock_irqrestore(&priv->lock, flags);
151}
152
153static void hi6421v600_irq_unmask(struct irq_data *d)
154{
155	struct hi6421v600_irq *priv = irq_data_get_irq_chip_data(d);
156	u32 data, offset;
157	unsigned long flags;
158
159	offset = HISI_IRQ_MASK_REG(d);
160
161	spin_lock_irqsave(&priv->lock, flags);
162
163	regmap_read(priv->regmap, offset, &data);
164	data &= ~HISI_IRQ_MASK_BIT(d);
165	regmap_write(priv->regmap, offset, data);
166
167	spin_unlock_irqrestore(&priv->lock, flags);
168}
169
170static struct irq_chip hi6421v600_pmu_irqchip = {
171	.name		= "hi6421v600-irq",
172	.irq_mask	= hi6421v600_irq_mask,
173	.irq_unmask	= hi6421v600_irq_unmask,
174	.irq_disable	= hi6421v600_irq_mask,
175	.irq_enable	= hi6421v600_irq_unmask,
176};
177
178static int hi6421v600_irq_map(struct irq_domain *d, unsigned int virq,
179			      irq_hw_number_t hw)
180{
181	struct hi6421v600_irq *priv = d->host_data;
182
183	irq_set_chip_and_handler_name(virq, &hi6421v600_pmu_irqchip,
184				      handle_simple_irq, "hi6421v600");
185	irq_set_chip_data(virq, priv);
186	irq_set_irq_type(virq, IRQ_TYPE_NONE);
187
188	return 0;
189}
190
191static const struct irq_domain_ops hi6421v600_domain_ops = {
192	.map	= hi6421v600_irq_map,
193	.xlate	= irq_domain_xlate_twocell,
194};
195
196static void hi6421v600_irq_init(struct hi6421v600_irq *priv)
197{
198	int i;
199	unsigned int pending;
200
201	/* Mask all IRQs */
202	for (i = 0; i < HISI_IRQ_BANK_SIZE; i++)
203		regmap_write(priv->regmap, SOC_PMIC_IRQ_MASK_0_ADDR + i,
204			     HISI_8BITS_MASK);
205
206	/* Mark all IRQs as handled */
207	for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
208		regmap_read(priv->regmap, SOC_PMIC_IRQ0_ADDR + i, &pending);
209		regmap_write(priv->regmap, SOC_PMIC_IRQ0_ADDR + i,
210			     HISI_8BITS_MASK);
211	}
212}
213
214static int hi6421v600_irq_probe(struct platform_device *pdev)
215{
216	struct device *pmic_dev = pdev->dev.parent;
217	struct platform_device *pmic_pdev;
218	struct device *dev = &pdev->dev;
219	struct hi6421v600_irq *priv;
220	struct regmap *regmap;
221	unsigned int virq;
222	int i, ret;
223
224	/*
225	 * This driver is meant to be called by hi6421-spmi-core,
226	 * which should first set drvdata. If this doesn't happen, hit
227	 * a warn on and return.
228	 */
229	regmap = dev_get_drvdata(pmic_dev);
230	if (WARN_ON(!regmap))
231		return -ENODEV;
232
233	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
234	if (!priv)
235		return -ENOMEM;
236
237	priv->dev = dev;
238	priv->regmap = regmap;
239
240	spin_lock_init(&priv->lock);
241
242	pmic_pdev = container_of(pmic_dev, struct platform_device, dev);
243
244	priv->irq = platform_get_irq(pmic_pdev, 0);
245	if (priv->irq < 0)
246		return priv->irq;
247
248	platform_set_drvdata(pdev, priv);
249
250	hi6421v600_irq_init(priv);
251
252	priv->irqs = devm_kzalloc(dev, PMIC_IRQ_LIST_MAX * sizeof(int), GFP_KERNEL);
253	if (!priv->irqs)
254		return -ENOMEM;
255
256	priv->domain = irq_domain_create_simple(dev_fwnode(pmic_dev), PMIC_IRQ_LIST_MAX, 0,
257						&hi6421v600_domain_ops, priv);
258	if (!priv->domain) {
259		dev_err(dev, "Failed to create IRQ domain\n");
260		return -ENODEV;
261	}
262
263	for (i = 0; i < PMIC_IRQ_LIST_MAX; i++) {
264		virq = irq_create_mapping(priv->domain, i);
265		if (!virq) {
266			dev_err(dev, "Failed to map H/W IRQ\n");
267			return -ENODEV;
268		}
269		priv->irqs[i] = virq;
270	}
271
272	ret = devm_request_threaded_irq(dev,
273					priv->irq, hi6421v600_irq_handler,
274					NULL,
275					IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
276					"pmic", priv);
277	if (ret < 0) {
278		dev_err(dev, "Failed to start IRQ handling thread: error %d\n",
279			ret);
280		return ret;
281	}
282
283	return 0;
284}
285
286static const struct platform_device_id hi6421v600_irq_table[] = {
287	{ .name = "hi6421v600-irq" },
288	{},
289};
290MODULE_DEVICE_TABLE(platform, hi6421v600_irq_table);
291
292static struct platform_driver hi6421v600_irq_driver = {
293	.id_table = hi6421v600_irq_table,
294	.driver = {
295		.name = "hi6421v600-irq",
296	},
297	.probe	= hi6421v600_irq_probe,
298};
299module_platform_driver(hi6421v600_irq_driver);
300
301MODULE_DESCRIPTION("HiSilicon Hi6421v600 IRQ driver");
302MODULE_LICENSE("GPL v2");
~/ Read-only file preview.