diff options
Diffstat (limited to 'drivers/mfd/jz4740-adc.c')
-rw-r--r-- | drivers/mfd/jz4740-adc.c | 90 |
1 files changed, 28 insertions, 62 deletions
diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index a0bd0cf05af..21131c7b0f1 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c @@ -56,7 +56,7 @@ struct jz4740_adc { void __iomem *base; int irq; - int irq_base; + struct irq_chip_generic *gc; struct clk *clk; atomic_t clk_ref; @@ -64,63 +64,17 @@ struct jz4740_adc { spinlock_t lock; }; -static inline void jz4740_adc_irq_set_masked(struct jz4740_adc *adc, int irq, - bool masked) -{ - unsigned long flags; - uint8_t val; - - irq -= adc->irq_base; - - spin_lock_irqsave(&adc->lock, flags); - - val = readb(adc->base + JZ_REG_ADC_CTRL); - if (masked) - val |= BIT(irq); - else - val &= ~BIT(irq); - writeb(val, adc->base + JZ_REG_ADC_CTRL); - - spin_unlock_irqrestore(&adc->lock, flags); -} - -static void jz4740_adc_irq_mask(struct irq_data *data) -{ - struct jz4740_adc *adc = irq_data_get_irq_chip_data(data); - jz4740_adc_irq_set_masked(adc, data->irq, true); -} - -static void jz4740_adc_irq_unmask(struct irq_data *data) -{ - struct jz4740_adc *adc = irq_data_get_irq_chip_data(data); - jz4740_adc_irq_set_masked(adc, data->irq, false); -} - -static void jz4740_adc_irq_ack(struct irq_data *data) -{ - struct jz4740_adc *adc = irq_data_get_irq_chip_data(data); - unsigned int irq = data->irq - adc->irq_base; - writeb(BIT(irq), adc->base + JZ_REG_ADC_STATUS); -} - -static struct irq_chip jz4740_adc_irq_chip = { - .name = "jz4740-adc", - .irq_mask = jz4740_adc_irq_mask, - .irq_unmask = jz4740_adc_irq_unmask, - .irq_ack = jz4740_adc_irq_ack, -}; - static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc) { - struct jz4740_adc *adc = irq_desc_get_handler_data(desc); + struct irq_chip_generic *gc = irq_desc_get_handler_data(desc); uint8_t status; unsigned int i; - status = readb(adc->base + JZ_REG_ADC_STATUS); + status = readb(gc->reg_base + JZ_REG_ADC_STATUS); for (i = 0; i < 5; ++i) { if (status & BIT(i)) - generic_handle_irq(adc->irq_base + i); + generic_handle_irq(gc->irq_base + i); } } @@ -249,10 +203,12 @@ const struct mfd_cell jz4740_adc_cells[] = { static int __devinit jz4740_adc_probe(struct platform_device *pdev) { - int ret; + struct irq_chip_generic *gc; + struct irq_chip_type *ct; struct jz4740_adc *adc; struct resource *mem_base; - int irq; + int ret; + int irq_base; adc = kmalloc(sizeof(*adc), GFP_KERNEL); if (!adc) { @@ -267,9 +223,9 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev) goto err_free; } - adc->irq_base = platform_get_irq(pdev, 1); - if (adc->irq_base < 0) { - ret = adc->irq_base; + irq_base = platform_get_irq(pdev, 1); + if (irq_base < 0) { + ret = irq_base; dev_err(&pdev->dev, "Failed to get irq base: %d\n", ret); goto err_free; } @@ -309,20 +265,28 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, adc); - for (irq = adc->irq_base; irq < adc->irq_base + 5; ++irq) { - irq_set_chip_data(irq, adc); - irq_set_chip_and_handler(irq, &jz4740_adc_irq_chip, - handle_level_irq); - } + gc = irq_alloc_generic_chip("INTC", 1, irq_base, adc->base, + handle_level_irq); + + ct = gc->chip_types; + ct->regs.mask = JZ_REG_ADC_CTRL; + ct->regs.ack = JZ_REG_ADC_STATUS; + ct->chip.irq_mask = irq_gc_mask_set_bit; + ct->chip.irq_unmask = irq_gc_mask_clr_bit; + ct->chip.irq_ack = irq_gc_ack; + + irq_setup_generic_chip(gc, IRQ_MSK(5), 0, 0, IRQ_NOPROBE | IRQ_LEVEL); + + adc->gc = gc; - irq_set_handler_data(adc->irq, adc); + irq_set_handler_data(adc->irq, gc); irq_set_chained_handler(adc->irq, jz4740_adc_irq_demux); writeb(0x00, adc->base + JZ_REG_ADC_ENABLE); writeb(0xff, adc->base + JZ_REG_ADC_CTRL); ret = mfd_add_devices(&pdev->dev, 0, jz4740_adc_cells, - ARRAY_SIZE(jz4740_adc_cells), mem_base, adc->irq_base); + ARRAY_SIZE(jz4740_adc_cells), mem_base, irq_base); if (ret < 0) goto err_clk_put; @@ -347,6 +311,8 @@ static int __devexit jz4740_adc_remove(struct platform_device *pdev) mfd_remove_devices(&pdev->dev); + irq_remove_generic_chip(adc->gc, IRQ_MSK(5), IRQ_NOPROBE | IRQ_LEVEL, 0); + kfree(adc->gc); irq_set_handler_data(adc->irq, NULL); irq_set_chained_handler(adc->irq, NULL); |