Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Renesas RZ/G2L IRQC Driver
  4 *
  5 * Copyright (C) 2022 Renesas Electronics Corporation.
  6 *
  7 * Author: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
  8 */
  9
 10#include <linux/bitfield.h>
 11#include <linux/clk.h>
 12#include <linux/err.h>
 13#include <linux/io.h>
 14#include <linux/irqchip.h>
 15#include <linux/irqdomain.h>
 16#include <linux/of_address.h>
 17#include <linux/of_platform.h>
 18#include <linux/pm_runtime.h>
 19#include <linux/reset.h>
 20#include <linux/spinlock.h>
 21
 22#define IRQC_IRQ_START			1
 23#define IRQC_IRQ_COUNT			8
 24#define IRQC_TINT_START			(IRQC_IRQ_START + IRQC_IRQ_COUNT)
 25#define IRQC_TINT_COUNT			32
 26#define IRQC_NUM_IRQ			(IRQC_TINT_START + IRQC_TINT_COUNT)
 27
 28#define ISCR				0x10
 29#define IITSR				0x14
 30#define TSCR				0x20
 31#define TITSR0				0x24
 32#define TITSR1				0x28
 33#define TITSR0_MAX_INT			16
 34#define TITSEL_WIDTH			0x2
 35#define TSSR(n)				(0x30 + ((n) * 4))
 36#define TIEN				BIT(7)
 37#define TSSEL_SHIFT(n)			(8 * (n))
 38#define TSSEL_MASK			GENMASK(7, 0)
 39#define IRQ_MASK			0x3
 40
 41#define TSSR_OFFSET(n)			((n) % 4)
 42#define TSSR_INDEX(n)			((n) / 4)
 43
 44#define TITSR_TITSEL_EDGE_RISING	0
 45#define TITSR_TITSEL_EDGE_FALLING	1
 46#define TITSR_TITSEL_LEVEL_HIGH		2
 47#define TITSR_TITSEL_LEVEL_LOW		3
 48
 49#define IITSR_IITSEL(n, sense)		((sense) << ((n) * 2))
 50#define IITSR_IITSEL_LEVEL_LOW		0
 51#define IITSR_IITSEL_EDGE_FALLING	1
 52#define IITSR_IITSEL_EDGE_RISING	2
 53#define IITSR_IITSEL_EDGE_BOTH		3
 54#define IITSR_IITSEL_MASK(n)		IITSR_IITSEL((n), 3)
 55
 56#define TINT_EXTRACT_HWIRQ(x)           FIELD_GET(GENMASK(15, 0), (x))
 57#define TINT_EXTRACT_GPIOINT(x)         FIELD_GET(GENMASK(31, 16), (x))
 58
 59struct rzg2l_irqc_priv {
 60	void __iomem *base;
 61	struct irq_fwspec fwspec[IRQC_NUM_IRQ];
 62	raw_spinlock_t lock;
 63};
 64
 65static struct rzg2l_irqc_priv *irq_data_to_priv(struct irq_data *data)
 66{
 67	return data->domain->host_data;
 68}
 69
 70static void rzg2l_irq_eoi(struct irq_data *d)
 71{
 72	unsigned int hw_irq = irqd_to_hwirq(d) - IRQC_IRQ_START;
 73	struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
 74	u32 bit = BIT(hw_irq);
 75	u32 reg;
 76
 77	reg = readl_relaxed(priv->base + ISCR);
 78	if (reg & bit)
 79		writel_relaxed(reg & ~bit, priv->base + ISCR);
 80}
 81
 82static void rzg2l_tint_eoi(struct irq_data *d)
 83{
 84	unsigned int hw_irq = irqd_to_hwirq(d) - IRQC_TINT_START;
 85	struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
 86	u32 bit = BIT(hw_irq);
 87	u32 reg;
 88
 89	reg = readl_relaxed(priv->base + TSCR);
 90	if (reg & bit)
 91		writel_relaxed(reg & ~bit, priv->base + TSCR);
 92}
 93
 94static void rzg2l_irqc_eoi(struct irq_data *d)
 95{
 96	struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
 97	unsigned int hw_irq = irqd_to_hwirq(d);
 98
 99	raw_spin_lock(&priv->lock);
100	if (hw_irq >= IRQC_IRQ_START && hw_irq <= IRQC_IRQ_COUNT)
101		rzg2l_irq_eoi(d);
102	else if (hw_irq >= IRQC_TINT_START && hw_irq < IRQC_NUM_IRQ)
103		rzg2l_tint_eoi(d);
104	raw_spin_unlock(&priv->lock);
105	irq_chip_eoi_parent(d);
106}
107
108static void rzg2l_irqc_irq_disable(struct irq_data *d)
109{
110	unsigned int hw_irq = irqd_to_hwirq(d);
111
112	if (hw_irq >= IRQC_TINT_START && hw_irq < IRQC_NUM_IRQ) {
113		struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
114		u32 offset = hw_irq - IRQC_TINT_START;
115		u32 tssr_offset = TSSR_OFFSET(offset);
116		u8 tssr_index = TSSR_INDEX(offset);
117		u32 reg;
118
119		raw_spin_lock(&priv->lock);
120		reg = readl_relaxed(priv->base + TSSR(tssr_index));
121		reg &= ~(TSSEL_MASK << tssr_offset);
122		writel_relaxed(reg, priv->base + TSSR(tssr_index));
123		raw_spin_unlock(&priv->lock);
124	}
125	irq_chip_disable_parent(d);
126}
127
128static void rzg2l_irqc_irq_enable(struct irq_data *d)
129{
130	unsigned int hw_irq = irqd_to_hwirq(d);
131
132	if (hw_irq >= IRQC_TINT_START && hw_irq < IRQC_NUM_IRQ) {
133		struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
134		unsigned long tint = (uintptr_t)d->chip_data;
135		u32 offset = hw_irq - IRQC_TINT_START;
136		u32 tssr_offset = TSSR_OFFSET(offset);
137		u8 tssr_index = TSSR_INDEX(offset);
138		u32 reg;
139
140		raw_spin_lock(&priv->lock);
141		reg = readl_relaxed(priv->base + TSSR(tssr_index));
142		reg |= (TIEN | tint) << TSSEL_SHIFT(tssr_offset);
143		writel_relaxed(reg, priv->base + TSSR(tssr_index));
144		raw_spin_unlock(&priv->lock);
145	}
146	irq_chip_enable_parent(d);
147}
148
149static int rzg2l_irq_set_type(struct irq_data *d, unsigned int type)
150{
151	unsigned int hw_irq = irqd_to_hwirq(d) - IRQC_IRQ_START;
152	struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
153	u16 sense, tmp;
154
155	switch (type & IRQ_TYPE_SENSE_MASK) {
156	case IRQ_TYPE_LEVEL_LOW:
157		sense = IITSR_IITSEL_LEVEL_LOW;
158		break;
159
160	case IRQ_TYPE_EDGE_FALLING:
161		sense = IITSR_IITSEL_EDGE_FALLING;
162		break;
163
164	case IRQ_TYPE_EDGE_RISING:
165		sense = IITSR_IITSEL_EDGE_RISING;
166		break;
167
168	case IRQ_TYPE_EDGE_BOTH:
169		sense = IITSR_IITSEL_EDGE_BOTH;
170		break;
171
172	default:
173		return -EINVAL;
174	}
175
176	raw_spin_lock(&priv->lock);
177	tmp = readl_relaxed(priv->base + IITSR);
178	tmp &= ~IITSR_IITSEL_MASK(hw_irq);
179	tmp |= IITSR_IITSEL(hw_irq, sense);
180	writel_relaxed(tmp, priv->base + IITSR);
181	raw_spin_unlock(&priv->lock);
182
183	return 0;
184}
185
186static int rzg2l_tint_set_edge(struct irq_data *d, unsigned int type)
187{
188	struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
189	unsigned int hwirq = irqd_to_hwirq(d);
190	u32 titseln = hwirq - IRQC_TINT_START;
191	u32 offset;
192	u8 sense;
193	u32 reg;
194
195	switch (type & IRQ_TYPE_SENSE_MASK) {
196	case IRQ_TYPE_EDGE_RISING:
197		sense = TITSR_TITSEL_EDGE_RISING;
198		break;
199
200	case IRQ_TYPE_EDGE_FALLING:
201		sense = TITSR_TITSEL_EDGE_FALLING;
202		break;
203
204	default:
205		return -EINVAL;
206	}
207
208	offset = TITSR0;
209	if (titseln >= TITSR0_MAX_INT) {
210		titseln -= TITSR0_MAX_INT;
211		offset = TITSR1;
212	}
213
214	raw_spin_lock(&priv->lock);
215	reg = readl_relaxed(priv->base + offset);
216	reg &= ~(IRQ_MASK << (titseln * TITSEL_WIDTH));
217	reg |= sense << (titseln * TITSEL_WIDTH);
218	writel_relaxed(reg, priv->base + offset);
219	raw_spin_unlock(&priv->lock);
220
221	return 0;
222}
223
224static int rzg2l_irqc_set_type(struct irq_data *d, unsigned int type)
225{
226	unsigned int hw_irq = irqd_to_hwirq(d);
227	int ret = -EINVAL;
228
229	if (hw_irq >= IRQC_IRQ_START && hw_irq <= IRQC_IRQ_COUNT)
230		ret = rzg2l_irq_set_type(d, type);
231	else if (hw_irq >= IRQC_TINT_START && hw_irq < IRQC_NUM_IRQ)
232		ret = rzg2l_tint_set_edge(d, type);
233	if (ret)
234		return ret;
235
236	return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
237}
238
239static const struct irq_chip irqc_chip = {
240	.name			= "rzg2l-irqc",
241	.irq_eoi		= rzg2l_irqc_eoi,
242	.irq_mask		= irq_chip_mask_parent,
243	.irq_unmask		= irq_chip_unmask_parent,
244	.irq_disable		= rzg2l_irqc_irq_disable,
245	.irq_enable		= rzg2l_irqc_irq_enable,
246	.irq_get_irqchip_state	= irq_chip_get_parent_state,
247	.irq_set_irqchip_state	= irq_chip_set_parent_state,
248	.irq_retrigger		= irq_chip_retrigger_hierarchy,
249	.irq_set_type		= rzg2l_irqc_set_type,
250	.flags			= IRQCHIP_MASK_ON_SUSPEND |
251				  IRQCHIP_SET_TYPE_MASKED |
252				  IRQCHIP_SKIP_SET_WAKE,
253};
254
255static int rzg2l_irqc_alloc(struct irq_domain *domain, unsigned int virq,
256			    unsigned int nr_irqs, void *arg)
257{
258	struct rzg2l_irqc_priv *priv = domain->host_data;
259	unsigned long tint = 0;
260	irq_hw_number_t hwirq;
261	unsigned int type;
262	int ret;
263
264	ret = irq_domain_translate_twocell(domain, arg, &hwirq, &type);
265	if (ret)
266		return ret;
267
268	/*
269	 * For TINT interrupts ie where pinctrl driver is child of irqc domain
270	 * the hwirq and TINT are encoded in fwspec->param[0].
271	 * hwirq for TINT range from 9-40, hwirq is embedded 0-15 bits and TINT
272	 * from 16-31 bits. TINT from the pinctrl driver needs to be programmed
273	 * in IRQC registers to enable a given gpio pin as interrupt.
274	 */
275	if (hwirq > IRQC_IRQ_COUNT) {
276		tint = TINT_EXTRACT_GPIOINT(hwirq);
277		hwirq = TINT_EXTRACT_HWIRQ(hwirq);
278
279		if (hwirq < IRQC_TINT_START)
280			return -EINVAL;
281	}
282
283	if (hwirq > (IRQC_NUM_IRQ - 1))
284		return -EINVAL;
285
286	ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &irqc_chip,
287					    (void *)(uintptr_t)tint);
288	if (ret)
289		return ret;
290
291	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &priv->fwspec[hwirq]);
292}
293
294static const struct irq_domain_ops rzg2l_irqc_domain_ops = {
295	.alloc = rzg2l_irqc_alloc,
296	.free = irq_domain_free_irqs_common,
297	.translate = irq_domain_translate_twocell,
298};
299
300static int rzg2l_irqc_parse_interrupts(struct rzg2l_irqc_priv *priv,
301				       struct device_node *np)
302{
303	struct of_phandle_args map;
304	unsigned int i;
305	int ret;
306
307	for (i = 0; i < IRQC_NUM_IRQ; i++) {
308		ret = of_irq_parse_one(np, i, &map);
309		if (ret)
310			return ret;
311		of_phandle_args_to_fwspec(np, map.args, map.args_count,
312					  &priv->fwspec[i]);
313	}
314
315	return 0;
316}
317
318static int rzg2l_irqc_init(struct device_node *node, struct device_node *parent)
319{
320	struct irq_domain *irq_domain, *parent_domain;
321	struct platform_device *pdev;
322	struct reset_control *resetn;
323	struct rzg2l_irqc_priv *priv;
324	int ret;
325
326	pdev = of_find_device_by_node(node);
327	if (!pdev)
328		return -ENODEV;
329
330	parent_domain = irq_find_host(parent);
331	if (!parent_domain) {
332		dev_err(&pdev->dev, "cannot find parent domain\n");
333		return -ENODEV;
334	}
335
336	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
337	if (!priv)
338		return -ENOMEM;
339
340	priv->base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL);
341	if (IS_ERR(priv->base))
342		return PTR_ERR(priv->base);
343
344	ret = rzg2l_irqc_parse_interrupts(priv, node);
345	if (ret) {
346		dev_err(&pdev->dev, "cannot parse interrupts: %d\n", ret);
347		return ret;
348	}
349
350	resetn = devm_reset_control_get_exclusive(&pdev->dev, NULL);
351	if (IS_ERR(resetn))
352		return PTR_ERR(resetn);
353
354	ret = reset_control_deassert(resetn);
355	if (ret) {
356		dev_err(&pdev->dev, "failed to deassert resetn pin, %d\n", ret);
357		return ret;
358	}
359
360	pm_runtime_enable(&pdev->dev);
361	ret = pm_runtime_resume_and_get(&pdev->dev);
362	if (ret < 0) {
363		dev_err(&pdev->dev, "pm_runtime_resume_and_get failed: %d\n", ret);
364		goto pm_disable;
365	}
366
367	raw_spin_lock_init(&priv->lock);
368
369	irq_domain = irq_domain_add_hierarchy(parent_domain, 0, IRQC_NUM_IRQ,
370					      node, &rzg2l_irqc_domain_ops,
371					      priv);
372	if (!irq_domain) {
373		dev_err(&pdev->dev, "failed to add irq domain\n");
374		ret = -ENOMEM;
375		goto pm_put;
376	}
377
378	return 0;
379
380pm_put:
381	pm_runtime_put(&pdev->dev);
382pm_disable:
383	pm_runtime_disable(&pdev->dev);
384	reset_control_assert(resetn);
385	return ret;
386}
387
388IRQCHIP_PLATFORM_DRIVER_BEGIN(rzg2l_irqc)
389IRQCHIP_MATCH("renesas,rzg2l-irqc", rzg2l_irqc_init)
390IRQCHIP_PLATFORM_DRIVER_END(rzg2l_irqc)
391MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>");
392MODULE_DESCRIPTION("Renesas RZ/G2L IRQC Driver");
393MODULE_LICENSE("GPL");