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 a0bd0cf05af3..21131c7b0f1e 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c | |||
| @@ -56,7 +56,7 @@ struct jz4740_adc { | |||
| 56 | void __iomem *base; | 56 | void __iomem *base; |
| 57 | 57 | ||
| 58 | int irq; | 58 | int irq; |
| 59 | int irq_base; | 59 | struct irq_chip_generic *gc; |
| 60 | 60 | ||
| 61 | struct clk *clk; | 61 | struct clk *clk; |
| 62 | atomic_t clk_ref; | 62 | atomic_t clk_ref; |
| @@ -64,63 +64,17 @@ struct jz4740_adc { | |||
| 64 | spinlock_t lock; | 64 | spinlock_t lock; |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | static inline void jz4740_adc_irq_set_masked(struct jz4740_adc *adc, int irq, | ||
| 68 | bool masked) | ||
| 69 | { | ||
| 70 | unsigned long flags; | ||
| 71 | uint8_t val; | ||
| 72 | |||
| 73 | irq -= adc->irq_base; | ||
| 74 | |||
| 75 | spin_lock_irqsave(&adc->lock, flags); | ||
| 76 | |||
| 77 | val = readb(adc->base + JZ_REG_ADC_CTRL); | ||
| 78 | if (masked) | ||
| 79 | val |= BIT(irq); | ||
| 80 | else | ||
| 81 | val &= ~BIT(irq); | ||
| 82 | writeb(val, adc->base + JZ_REG_ADC_CTRL); | ||
| 83 | |||
| 84 | spin_unlock_irqrestore(&adc->lock, flags); | ||
| 85 | } | ||
| 86 | |||
| 87 | static void jz4740_adc_irq_mask(struct irq_data *data) | ||
| 88 | { | ||
| 89 | struct jz4740_adc *adc = irq_data_get_irq_chip_data(data); | ||
| 90 | jz4740_adc_irq_set_masked(adc, data->irq, true); | ||
| 91 | } | ||
| 92 | |||
| 93 | static void jz4740_adc_irq_unmask(struct irq_data *data) | ||
| 94 | { | ||
| 95 | struct jz4740_adc *adc = irq_data_get_irq_chip_data(data); | ||
| 96 | jz4740_adc_irq_set_masked(adc, data->irq, false); | ||
| 97 | } | ||
| 98 | |||
| 99 | static void jz4740_adc_irq_ack(struct irq_data *data) | ||
| 100 | { | ||
| 101 | struct jz4740_adc *adc = irq_data_get_irq_chip_data(data); | ||
| 102 | unsigned int irq = data->irq - adc->irq_base; | ||
| 103 | writeb(BIT(irq), adc->base + JZ_REG_ADC_STATUS); | ||
| 104 | } | ||
| 105 | |||
| 106 | static struct irq_chip jz4740_adc_irq_chip = { | ||
| 107 | .name = "jz4740-adc", | ||
| 108 | .irq_mask = jz4740_adc_irq_mask, | ||
| 109 | .irq_unmask = jz4740_adc_irq_unmask, | ||
| 110 | .irq_ack = jz4740_adc_irq_ack, | ||
| 111 | }; | ||
| 112 | |||
| 113 | static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc) | 67 | static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc) |
| 114 | { | 68 | { |
| 115 | struct jz4740_adc *adc = irq_desc_get_handler_data(desc); | 69 | struct irq_chip_generic *gc = irq_desc_get_handler_data(desc); |
| 116 | uint8_t status; | 70 | uint8_t status; |
| 117 | unsigned int i; | 71 | unsigned int i; |
| 118 | 72 | ||
| 119 | status = readb(adc->base + JZ_REG_ADC_STATUS); | 73 | status = readb(gc->reg_base + JZ_REG_ADC_STATUS); |
| 120 | 74 | ||
| 121 | for (i = 0; i < 5; ++i) { | 75 | for (i = 0; i < 5; ++i) { |
| 122 | if (status & BIT(i)) | 76 | if (status & BIT(i)) |
| 123 | generic_handle_irq(adc->irq_base + i); | 77 | generic_handle_irq(gc->irq_base + i); |
| 124 | } | 78 | } |
| 125 | } | 79 | } |
| 126 | 80 | ||
| @@ -249,10 +203,12 @@ const struct mfd_cell jz4740_adc_cells[] = { | |||
| 249 | 203 | ||
| 250 | static int __devinit jz4740_adc_probe(struct platform_device *pdev) | 204 | static int __devinit jz4740_adc_probe(struct platform_device *pdev) |
| 251 | { | 205 | { |
| 252 | int ret; | 206 | struct irq_chip_generic *gc; |
| 207 | struct irq_chip_type *ct; | ||
| 253 | struct jz4740_adc *adc; | 208 | struct jz4740_adc *adc; |
| 254 | struct resource *mem_base; | 209 | struct resource *mem_base; |
| 255 | int irq; | 210 | int ret; |
| 211 | int irq_base; | ||
| 256 | 212 | ||
| 257 | adc = kmalloc(sizeof(*adc), GFP_KERNEL); | 213 | adc = kmalloc(sizeof(*adc), GFP_KERNEL); |
| 258 | if (!adc) { | 214 | if (!adc) { |
| @@ -267,9 +223,9 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev) | |||
| 267 | goto err_free; | 223 | goto err_free; |
| 268 | } | 224 | } |
| 269 | 225 | ||
| 270 | adc->irq_base = platform_get_irq(pdev, 1); | 226 | irq_base = platform_get_irq(pdev, 1); |
| 271 | if (adc->irq_base < 0) { | 227 | if (irq_base < 0) { |
| 272 | ret = adc->irq_base; | 228 | ret = irq_base; |
| 273 | dev_err(&pdev->dev, "Failed to get irq base: %d\n", ret); | 229 | dev_err(&pdev->dev, "Failed to get irq base: %d\n", ret); |
| 274 | goto err_free; | 230 | goto err_free; |
| 275 | } | 231 | } |
| @@ -309,20 +265,28 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev) | |||
| 309 | 265 | ||
| 310 | platform_set_drvdata(pdev, adc); | 266 | platform_set_drvdata(pdev, adc); |
| 311 | 267 | ||
| 312 | for (irq = adc->irq_base; irq < adc->irq_base + 5; ++irq) { | 268 | gc = irq_alloc_generic_chip("INTC", 1, irq_base, adc->base, |
| 313 | irq_set_chip_data(irq, adc); | 269 | handle_level_irq); |
| 314 | irq_set_chip_and_handler(irq, &jz4740_adc_irq_chip, | 270 | |
| 315 | handle_level_irq); | 271 | ct = gc->chip_types; |
| 316 | } | 272 | ct->regs.mask = JZ_REG_ADC_CTRL; |
| 273 | ct->regs.ack = JZ_REG_ADC_STATUS; | ||
| 274 | ct->chip.irq_mask = irq_gc_mask_set_bit; | ||
| 275 | ct->chip.irq_unmask = irq_gc_mask_clr_bit; | ||
| 276 | ct->chip.irq_ack = irq_gc_ack; | ||
| 277 | |||
| 278 | irq_setup_generic_chip(gc, IRQ_MSK(5), 0, 0, IRQ_NOPROBE | IRQ_LEVEL); | ||
| 279 | |||
| 280 | adc->gc = gc; | ||
| 317 | 281 | ||
| 318 | irq_set_handler_data(adc->irq, adc); | 282 | irq_set_handler_data(adc->irq, gc); |
| 319 | irq_set_chained_handler(adc->irq, jz4740_adc_irq_demux); | 283 | irq_set_chained_handler(adc->irq, jz4740_adc_irq_demux); |
| 320 | 284 | ||
| 321 | writeb(0x00, adc->base + JZ_REG_ADC_ENABLE); | 285 | writeb(0x00, adc->base + JZ_REG_ADC_ENABLE); |
| 322 | writeb(0xff, adc->base + JZ_REG_ADC_CTRL); | 286 | writeb(0xff, adc->base + JZ_REG_ADC_CTRL); |
| 323 | 287 | ||
| 324 | ret = mfd_add_devices(&pdev->dev, 0, jz4740_adc_cells, | 288 | ret = mfd_add_devices(&pdev->dev, 0, jz4740_adc_cells, |
| 325 | ARRAY_SIZE(jz4740_adc_cells), mem_base, adc->irq_base); | 289 | ARRAY_SIZE(jz4740_adc_cells), mem_base, irq_base); |
| 326 | if (ret < 0) | 290 | if (ret < 0) |
| 327 | goto err_clk_put; | 291 | goto err_clk_put; |
| 328 | 292 | ||
| @@ -347,6 +311,8 @@ static int __devexit jz4740_adc_remove(struct platform_device *pdev) | |||
| 347 | 311 | ||
| 348 | mfd_remove_devices(&pdev->dev); | 312 | mfd_remove_devices(&pdev->dev); |
| 349 | 313 | ||
| 314 | irq_remove_generic_chip(adc->gc, IRQ_MSK(5), IRQ_NOPROBE | IRQ_LEVEL, 0); | ||
| 315 | kfree(adc->gc); | ||
| 350 | irq_set_handler_data(adc->irq, NULL); | 316 | irq_set_handler_data(adc->irq, NULL); |
| 351 | irq_set_chained_handler(adc->irq, NULL); | 317 | irq_set_chained_handler(adc->irq, NULL); |
| 352 | 318 | ||
