xref: /OK3568_Linux_fs/u-boot/drivers/irq/virq.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2019 Rockchip Electronics Co., Ltd
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SPDX-License-Identifier:     GPL-2.0+
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <dm.h>
9*4882a593Smuzhiyun #include <fdtdec.h>
10*4882a593Smuzhiyun #include <malloc.h>
11*4882a593Smuzhiyun #include <asm/io.h>
12*4882a593Smuzhiyun #include <asm/u-boot-arm.h>
13*4882a593Smuzhiyun #include <irq-generic.h>
14*4882a593Smuzhiyun #include "irq-internal.h"
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun static LIST_HEAD(virq_desc_head);
19*4882a593Smuzhiyun static u32 virq_id = PLATFORM_MAX_IRQ;
20*4882a593Smuzhiyun 
virq_id_alloc(void)21*4882a593Smuzhiyun static u32 virq_id_alloc(void)
22*4882a593Smuzhiyun {
23*4882a593Smuzhiyun 	return ++virq_id;
24*4882a593Smuzhiyun }
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun struct virq_data {
27*4882a593Smuzhiyun 	int irq;
28*4882a593Smuzhiyun 	u32 flag;
29*4882a593Smuzhiyun 	u32 count;
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun 	void *data;
32*4882a593Smuzhiyun 	interrupt_handler_t *handle_irq;
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun /* The structure to maintail the irqchip and child virqs */
36*4882a593Smuzhiyun struct virq_desc {
37*4882a593Smuzhiyun 	struct virq_chip *chip;		/* irq chip */
38*4882a593Smuzhiyun 	struct virq_data *virqs;	/* child irq data list */
39*4882a593Smuzhiyun 	struct udevice *parent;		/* parent device */
40*4882a593Smuzhiyun 	int pirq;			/* parent irq */
41*4882a593Smuzhiyun 	int use_count;			/* enable count */
42*4882a593Smuzhiyun 	int irq_base;			/* child irq base */
43*4882a593Smuzhiyun 	int irq_end;			/* child irq end */
44*4882a593Smuzhiyun 	uint reg_stride;
45*4882a593Smuzhiyun 	uint unalign_reg_idx;
46*4882a593Smuzhiyun 	uint unalign_reg_stride;
47*4882a593Smuzhiyun 	uint *status_buf;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	struct list_head node;
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun 
find_virq_desc(int irq)52*4882a593Smuzhiyun static struct virq_desc *find_virq_desc(int irq)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun 	struct virq_desc *desc;
55*4882a593Smuzhiyun 	struct list_head *node;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	list_for_each(node, &virq_desc_head) {
58*4882a593Smuzhiyun 		desc = list_entry(node, struct virq_desc, node);
59*4882a593Smuzhiyun 		if (irq >= desc->irq_base && irq <= desc->irq_end)
60*4882a593Smuzhiyun 			return desc;
61*4882a593Smuzhiyun 	}
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	return NULL;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
find_virq_desc_by_pirq(int parent_irq)66*4882a593Smuzhiyun static struct virq_desc *find_virq_desc_by_pirq(int parent_irq)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	struct virq_desc *desc;
69*4882a593Smuzhiyun 	struct list_head *node;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	list_for_each(node, &virq_desc_head) {
72*4882a593Smuzhiyun 		desc = list_entry(node, struct virq_desc, node);
73*4882a593Smuzhiyun 		if (parent_irq == desc->pirq)
74*4882a593Smuzhiyun 			return desc;
75*4882a593Smuzhiyun 	}
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	return NULL;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun 
virq_to_irq(struct virq_chip * chip,int virq)80*4882a593Smuzhiyun int virq_to_irq(struct virq_chip *chip, int virq)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	struct virq_desc *desc;
83*4882a593Smuzhiyun 	struct list_head *node;
84*4882a593Smuzhiyun 	int irq;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	if (!chip)
87*4882a593Smuzhiyun 		return -EINVAL;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	list_for_each(node, &virq_desc_head) {
90*4882a593Smuzhiyun 		desc = list_entry(node, struct virq_desc, node);
91*4882a593Smuzhiyun 		if (desc->chip == chip) {
92*4882a593Smuzhiyun 			irq = desc->irq_base + virq;
93*4882a593Smuzhiyun 			if (irq >= desc->irq_base && irq <= desc->irq_end)
94*4882a593Smuzhiyun 				return irq;
95*4882a593Smuzhiyun 		}
96*4882a593Smuzhiyun 	}
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	return -ENONET;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
bad_virq(int irq)101*4882a593Smuzhiyun int bad_virq(int irq)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun 	return !find_virq_desc(irq);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
virqs_show(int pirq)106*4882a593Smuzhiyun void virqs_show(int pirq)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	struct virq_data *vdata;
109*4882a593Smuzhiyun 	struct virq_desc *desc;
110*4882a593Smuzhiyun 	struct udevice *dev;
111*4882a593Smuzhiyun 	int num;
112*4882a593Smuzhiyun 	int i;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	desc = find_virq_desc_by_pirq(pirq);
115*4882a593Smuzhiyun 	if (!desc)
116*4882a593Smuzhiyun 	       return;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	vdata = desc->virqs;
119*4882a593Smuzhiyun 	num = desc->irq_end - desc->irq_base;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	for (i = 0; i < num; i++) {
122*4882a593Smuzhiyun 		if (!vdata[i].handle_irq)
123*4882a593Smuzhiyun 			continue;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 		dev = (struct udevice *)vdata[i].data;
126*4882a593Smuzhiyun 		printf(" %3d    %d     0x%08lx    %-12s    |-- %-12s   %d\n",
127*4882a593Smuzhiyun 		       vdata[i].irq,
128*4882a593Smuzhiyun 		       vdata[i].flag & IRQ_FLG_ENABLE ? 1 : 0,
129*4882a593Smuzhiyun 		       (ulong)vdata[i].handle_irq, dev->driver->name, dev->name,
130*4882a593Smuzhiyun 		       vdata[i].count);
131*4882a593Smuzhiyun 	}
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun 
virq_install_handler(int irq,interrupt_handler_t * handler,void * data)134*4882a593Smuzhiyun int virq_install_handler(int irq, interrupt_handler_t *handler, void *data)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	struct virq_desc *desc;
137*4882a593Smuzhiyun 	int virq;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	if (!handler)
140*4882a593Smuzhiyun 		return -EINVAL;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	desc = find_virq_desc(irq);
143*4882a593Smuzhiyun 	if (!desc)
144*4882a593Smuzhiyun 		return -ENOENT;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	virq = irq - desc->irq_base;
147*4882a593Smuzhiyun 	if (desc->virqs[virq].handle_irq)
148*4882a593Smuzhiyun 		return -EBUSY;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	desc->virqs[virq].handle_irq = handler;
151*4882a593Smuzhiyun 	desc->virqs[virq].data = data;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	return 0;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
virq_free_handler(int irq)156*4882a593Smuzhiyun void virq_free_handler(int irq)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	struct virq_desc *desc;
159*4882a593Smuzhiyun 	int virq;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	desc = find_virq_desc(irq);
162*4882a593Smuzhiyun 	if (!desc)
163*4882a593Smuzhiyun 		return;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	virq = irq - desc->irq_base;
166*4882a593Smuzhiyun 	desc->virqs[virq].handle_irq = NULL;
167*4882a593Smuzhiyun 	desc->virqs[virq].data = NULL;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun 
reg_base_get(struct virq_desc * desc,uint reg_base,int idx)170*4882a593Smuzhiyun static uint reg_base_get(struct virq_desc *desc, uint reg_base, int idx)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	int reg_addr;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	if (idx <= desc->unalign_reg_idx) {
175*4882a593Smuzhiyun 		reg_addr = reg_base + (idx * desc->unalign_reg_stride);
176*4882a593Smuzhiyun 	} else {
177*4882a593Smuzhiyun 		reg_addr = reg_base +
178*4882a593Smuzhiyun 			   (desc->unalign_reg_idx * desc->unalign_reg_stride);
179*4882a593Smuzhiyun 		reg_addr += (idx - desc->unalign_reg_idx) * desc->reg_stride;
180*4882a593Smuzhiyun 	}
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	return reg_addr;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun 
virq_chip_generic_handler(int pirq,void * pdata)185*4882a593Smuzhiyun void virq_chip_generic_handler(int pirq, void *pdata)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun 	struct virq_chip *chip;
188*4882a593Smuzhiyun 	struct virq_desc *desc;
189*4882a593Smuzhiyun 	struct virq_data *vdata;
190*4882a593Smuzhiyun 	struct udevice *parent;
191*4882a593Smuzhiyun 	uint status_reg;
192*4882a593Smuzhiyun 	void *data;
193*4882a593Smuzhiyun 	int irq;
194*4882a593Smuzhiyun 	int ret;
195*4882a593Smuzhiyun 	int i;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	desc = find_virq_desc_by_pirq(pirq);
198*4882a593Smuzhiyun 	if (!desc)
199*4882a593Smuzhiyun 		return;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	chip = desc->chip;
202*4882a593Smuzhiyun 	vdata = desc->virqs;
203*4882a593Smuzhiyun 	parent = (struct udevice *)pdata;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	if (!chip || !vdata || !parent)
206*4882a593Smuzhiyun 		return;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	/* Read all status register */
209*4882a593Smuzhiyun 	for (i = 0; i < chip->num_regs; i++) {
210*4882a593Smuzhiyun 		status_reg = reg_base_get(desc, chip->status_base, i);
211*4882a593Smuzhiyun 		desc->status_buf[i] = chip->read(parent, status_reg);
212*4882a593Smuzhiyun 		if (desc->status_buf[i] < 0) {
213*4882a593Smuzhiyun 			printf("%s: Read status register 0x%x failed, ret=%d\n",
214*4882a593Smuzhiyun 			       __func__, status_reg, desc->status_buf[i]);
215*4882a593Smuzhiyun 		}
216*4882a593Smuzhiyun 	}
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	/* Handle all virq handler */
219*4882a593Smuzhiyun 	for (i = 0; i < chip->num_irqs; i++) {
220*4882a593Smuzhiyun 		if (desc->status_buf[chip->irqs[i].reg_offset] &
221*4882a593Smuzhiyun 		    chip->irqs[i].mask) {
222*4882a593Smuzhiyun 			irq = vdata[i].irq;
223*4882a593Smuzhiyun 			data = vdata[i].data;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 			if (vdata[i].handle_irq) {
226*4882a593Smuzhiyun 				vdata[i].count++;
227*4882a593Smuzhiyun 				vdata[i].handle_irq(irq, data);
228*4882a593Smuzhiyun 			}
229*4882a593Smuzhiyun 		}
230*4882a593Smuzhiyun 	}
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	/* Clear all status register */
233*4882a593Smuzhiyun 	for (i = 0; i < chip->num_regs; i++) {
234*4882a593Smuzhiyun 		status_reg = reg_base_get(desc, chip->status_base, i);
235*4882a593Smuzhiyun 		ret = chip->write(parent, status_reg, ~0U);
236*4882a593Smuzhiyun 		if (ret)
237*4882a593Smuzhiyun 			printf("%s: Clear status register 0x%x failed, ret=%d\n",
238*4882a593Smuzhiyun 			       __func__, status_reg, ret);
239*4882a593Smuzhiyun 	}
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun 
virq_add_chip(struct udevice * dev,struct virq_chip * chip,int irq)242*4882a593Smuzhiyun int virq_add_chip(struct udevice *dev, struct virq_chip *chip, int irq)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun 	struct virq_data *vdata;
245*4882a593Smuzhiyun 	struct virq_desc *desc;
246*4882a593Smuzhiyun 	uint *status_buf;
247*4882a593Smuzhiyun 	uint status_reg;
248*4882a593Smuzhiyun 	uint mask_reg;
249*4882a593Smuzhiyun 	int ret;
250*4882a593Smuzhiyun 	int i;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	if (irq < 0)
253*4882a593Smuzhiyun 		return -EINVAL;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	desc = (struct virq_desc *)malloc(sizeof(*desc));
256*4882a593Smuzhiyun 	if (!desc)
257*4882a593Smuzhiyun 		return -ENOMEM;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	vdata = (struct virq_data *)calloc(sizeof(*vdata), chip->num_irqs);
260*4882a593Smuzhiyun 	if (!vdata) {
261*4882a593Smuzhiyun 		ret = -ENOMEM;
262*4882a593Smuzhiyun 		goto free1;
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	status_buf = (uint *)calloc(sizeof(*status_buf), chip->num_irqs);
266*4882a593Smuzhiyun 	if (!status_buf) {
267*4882a593Smuzhiyun 		ret = -ENOMEM;
268*4882a593Smuzhiyun 		goto free2;
269*4882a593Smuzhiyun 	}
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	for (i = 0; i < chip->num_irqs; i++)
272*4882a593Smuzhiyun 		vdata[i].irq = virq_id_alloc();
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	desc->parent = dev;
275*4882a593Smuzhiyun 	desc->pirq = irq;
276*4882a593Smuzhiyun 	desc->chip = chip;
277*4882a593Smuzhiyun 	desc->virqs = vdata;
278*4882a593Smuzhiyun 	desc->use_count = 0;
279*4882a593Smuzhiyun 	desc->irq_base = vdata[0].irq;
280*4882a593Smuzhiyun 	desc->irq_end = vdata[chip->num_irqs - 1].irq;
281*4882a593Smuzhiyun 	desc->status_buf = status_buf;
282*4882a593Smuzhiyun 	desc->reg_stride = chip->irq_reg_stride ? : 1;
283*4882a593Smuzhiyun 	desc->unalign_reg_stride = chip->irq_unalign_reg_stride ? : 1;
284*4882a593Smuzhiyun 	desc->unalign_reg_idx = chip->irq_unalign_reg_stride ?
285*4882a593Smuzhiyun 					chip->irq_unalign_reg_idx : 0;
286*4882a593Smuzhiyun 	list_add_tail(&desc->node, &virq_desc_head);
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	/* Mask all register */
289*4882a593Smuzhiyun 	for (i = 0; i < chip->num_regs; i++) {
290*4882a593Smuzhiyun 		mask_reg = reg_base_get(desc, chip->mask_base, i);
291*4882a593Smuzhiyun 		ret = chip->write(dev, mask_reg, ~0U);
292*4882a593Smuzhiyun 		if (ret)
293*4882a593Smuzhiyun 			printf("%s: Set mask register 0x%x failed, ret=%d\n",
294*4882a593Smuzhiyun 			       __func__, mask_reg, ret);
295*4882a593Smuzhiyun 	}
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	/* Clear all status */
298*4882a593Smuzhiyun 	for (i = 0; i < chip->num_regs; i++) {
299*4882a593Smuzhiyun 		status_reg = reg_base_get(desc, chip->status_base, i);
300*4882a593Smuzhiyun 		ret = chip->write(dev, status_reg, ~0U);
301*4882a593Smuzhiyun 		if (ret)
302*4882a593Smuzhiyun 			printf("%s: Clear status register 0x%x failed, ret=%d\n",
303*4882a593Smuzhiyun 			       __func__, status_reg, ret);
304*4882a593Smuzhiyun 	}
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	/* Add parent irq into interrupt framework with generic virq handler */
307*4882a593Smuzhiyun 	irq_install_handler(irq, virq_chip_generic_handler, dev);
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	return irq_handler_disable(irq);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun free1:
312*4882a593Smuzhiyun 	free(desc);
313*4882a593Smuzhiyun free2:
314*4882a593Smuzhiyun 	free(status_buf);
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	return ret;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun 
virq_init(void)319*4882a593Smuzhiyun static int virq_init(void)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun 	INIT_LIST_HEAD(&virq_desc_head);
322*4882a593Smuzhiyun 	return 0;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun 
__virq_enable(int irq,int enable)325*4882a593Smuzhiyun static int __virq_enable(int irq, int enable)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun 	struct virq_chip *chip;
328*4882a593Smuzhiyun 	struct virq_desc *desc;
329*4882a593Smuzhiyun 	uint mask_reg, mask_val;
330*4882a593Smuzhiyun 	uint reg_val;
331*4882a593Smuzhiyun 	int virq;
332*4882a593Smuzhiyun 	int ret;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	desc = find_virq_desc(irq);
335*4882a593Smuzhiyun 	if (!desc) {
336*4882a593Smuzhiyun 		printf("%s: %s Invalid irq %d\n",
337*4882a593Smuzhiyun 		       __func__, enable ? "Enable" : "Disable", irq);
338*4882a593Smuzhiyun 		return -ENOENT;
339*4882a593Smuzhiyun 	}
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	chip = desc->chip;
342*4882a593Smuzhiyun 	if (!chip)
343*4882a593Smuzhiyun 		return -ENOENT;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	virq = irq - desc->irq_base;
346*4882a593Smuzhiyun 	mask_val = chip->irqs[virq].mask;
347*4882a593Smuzhiyun 	mask_reg = reg_base_get(desc, chip->mask_base,
348*4882a593Smuzhiyun 				chip->irqs[virq].reg_offset);
349*4882a593Smuzhiyun 	reg_val = chip->read(desc->parent, mask_reg);
350*4882a593Smuzhiyun 	if (enable)
351*4882a593Smuzhiyun 		reg_val &= ~mask_val;
352*4882a593Smuzhiyun 	else
353*4882a593Smuzhiyun 		reg_val |= mask_val;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	ret = chip->write(desc->parent, mask_reg, reg_val);
356*4882a593Smuzhiyun 	if (ret) {
357*4882a593Smuzhiyun 		printf("%s: Clear status register 0x%x failed, ret=%d\n",
358*4882a593Smuzhiyun 		       __func__, mask_reg, ret);
359*4882a593Smuzhiyun 		return ret;
360*4882a593Smuzhiyun 	}
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	if (enable)
363*4882a593Smuzhiyun 		desc->virqs[virq].flag |= IRQ_FLG_ENABLE;
364*4882a593Smuzhiyun 	else
365*4882a593Smuzhiyun 		desc->virqs[virq].flag &= ~IRQ_FLG_ENABLE;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	return 0;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun 
virq_enable(int irq)370*4882a593Smuzhiyun static int virq_enable(int irq)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun 	struct virq_desc *desc = find_virq_desc(irq);
373*4882a593Smuzhiyun 	int ret;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	if (bad_virq(irq))
376*4882a593Smuzhiyun 		return -EINVAL;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	ret = __virq_enable(irq, 1);
379*4882a593Smuzhiyun 	if (!ret) {
380*4882a593Smuzhiyun 		if (desc->use_count == 0)
381*4882a593Smuzhiyun 			irq_handler_enable(desc->pirq);
382*4882a593Smuzhiyun 		desc->use_count++;
383*4882a593Smuzhiyun 	}
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	return ret;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun 
virq_disable(int irq)388*4882a593Smuzhiyun static int virq_disable(int irq)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun 	struct virq_desc *desc = find_virq_desc(irq);
391*4882a593Smuzhiyun 	int ret;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	if (bad_virq(irq))
394*4882a593Smuzhiyun 		return -EINVAL;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	ret = __virq_enable(irq, 0);
397*4882a593Smuzhiyun 	if (!ret) {
398*4882a593Smuzhiyun 		if (desc->use_count <= 0)
399*4882a593Smuzhiyun 			return ret;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 		if (desc->use_count == 1)
402*4882a593Smuzhiyun 			irq_handler_disable(desc->pirq);
403*4882a593Smuzhiyun 		desc->use_count--;
404*4882a593Smuzhiyun 	}
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	return ret;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun struct irq_chip virq_generic_chip = {
410*4882a593Smuzhiyun 	.name		= "virq-irq-chip",
411*4882a593Smuzhiyun 	.irq_init	= virq_init,
412*4882a593Smuzhiyun 	.irq_enable	= virq_enable,
413*4882a593Smuzhiyun 	.irq_disable	= virq_disable,
414*4882a593Smuzhiyun };
415*4882a593Smuzhiyun 
arch_virq_get_irqchip(void)416*4882a593Smuzhiyun struct irq_chip *arch_virq_get_irqchip(void)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun 	return &virq_generic_chip;
419*4882a593Smuzhiyun }
420