Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * wm8350-irq.c  --  IRQ support for Wolfson WM8350
0004  *
0005  * Copyright 2007, 2008, 2009 Wolfson Microelectronics PLC.
0006  *
0007  * Author: Liam Girdwood, Mark Brown
0008  */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/bug.h>
0013 #include <linux/device.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/irq.h>
0016 
0017 #include <linux/mfd/wm8350/core.h>
0018 #include <linux/mfd/wm8350/audio.h>
0019 #include <linux/mfd/wm8350/comparator.h>
0020 #include <linux/mfd/wm8350/gpio.h>
0021 #include <linux/mfd/wm8350/pmic.h>
0022 #include <linux/mfd/wm8350/rtc.h>
0023 #include <linux/mfd/wm8350/supply.h>
0024 #include <linux/mfd/wm8350/wdt.h>
0025 
0026 #define WM8350_INT_OFFSET_1                     0
0027 #define WM8350_INT_OFFSET_2                     1
0028 #define WM8350_POWER_UP_INT_OFFSET              2
0029 #define WM8350_UNDER_VOLTAGE_INT_OFFSET         3
0030 #define WM8350_OVER_CURRENT_INT_OFFSET          4
0031 #define WM8350_GPIO_INT_OFFSET                  5
0032 #define WM8350_COMPARATOR_INT_OFFSET            6
0033 
0034 struct wm8350_irq_data {
0035     int primary;
0036     int reg;
0037     int mask;
0038     int primary_only;
0039 };
0040 
0041 static struct wm8350_irq_data wm8350_irqs[] = {
0042     [WM8350_IRQ_OC_LS] = {
0043         .primary = WM8350_OC_INT,
0044         .reg = WM8350_OVER_CURRENT_INT_OFFSET,
0045         .mask = WM8350_OC_LS_EINT,
0046         .primary_only = 1,
0047     },
0048     [WM8350_IRQ_UV_DC1] = {
0049         .primary = WM8350_UV_INT,
0050         .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0051         .mask = WM8350_UV_DC1_EINT,
0052     },
0053     [WM8350_IRQ_UV_DC2] = {
0054         .primary = WM8350_UV_INT,
0055         .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0056         .mask = WM8350_UV_DC2_EINT,
0057     },
0058     [WM8350_IRQ_UV_DC3] = {
0059         .primary = WM8350_UV_INT,
0060         .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0061         .mask = WM8350_UV_DC3_EINT,
0062     },
0063     [WM8350_IRQ_UV_DC4] = {
0064         .primary = WM8350_UV_INT,
0065         .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0066         .mask = WM8350_UV_DC4_EINT,
0067     },
0068     [WM8350_IRQ_UV_DC5] = {
0069         .primary = WM8350_UV_INT,
0070         .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0071         .mask = WM8350_UV_DC5_EINT,
0072     },
0073     [WM8350_IRQ_UV_DC6] = {
0074         .primary = WM8350_UV_INT,
0075         .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0076         .mask = WM8350_UV_DC6_EINT,
0077     },
0078     [WM8350_IRQ_UV_LDO1] = {
0079         .primary = WM8350_UV_INT,
0080         .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0081         .mask = WM8350_UV_LDO1_EINT,
0082     },
0083     [WM8350_IRQ_UV_LDO2] = {
0084         .primary = WM8350_UV_INT,
0085         .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0086         .mask = WM8350_UV_LDO2_EINT,
0087     },
0088     [WM8350_IRQ_UV_LDO3] = {
0089         .primary = WM8350_UV_INT,
0090         .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0091         .mask = WM8350_UV_LDO3_EINT,
0092     },
0093     [WM8350_IRQ_UV_LDO4] = {
0094         .primary = WM8350_UV_INT,
0095         .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0096         .mask = WM8350_UV_LDO4_EINT,
0097     },
0098     [WM8350_IRQ_CHG_BAT_HOT] = {
0099         .primary = WM8350_CHG_INT,
0100         .reg = WM8350_INT_OFFSET_1,
0101         .mask = WM8350_CHG_BAT_HOT_EINT,
0102     },
0103     [WM8350_IRQ_CHG_BAT_COLD] = {
0104         .primary = WM8350_CHG_INT,
0105         .reg = WM8350_INT_OFFSET_1,
0106         .mask = WM8350_CHG_BAT_COLD_EINT,
0107     },
0108     [WM8350_IRQ_CHG_BAT_FAIL] = {
0109         .primary = WM8350_CHG_INT,
0110         .reg = WM8350_INT_OFFSET_1,
0111         .mask = WM8350_CHG_BAT_FAIL_EINT,
0112     },
0113     [WM8350_IRQ_CHG_TO] = {
0114         .primary = WM8350_CHG_INT,
0115         .reg = WM8350_INT_OFFSET_1,
0116         .mask = WM8350_CHG_TO_EINT,
0117     },
0118     [WM8350_IRQ_CHG_END] = {
0119         .primary = WM8350_CHG_INT,
0120         .reg = WM8350_INT_OFFSET_1,
0121         .mask = WM8350_CHG_END_EINT,
0122     },
0123     [WM8350_IRQ_CHG_START] = {
0124         .primary = WM8350_CHG_INT,
0125         .reg = WM8350_INT_OFFSET_1,
0126         .mask = WM8350_CHG_START_EINT,
0127     },
0128     [WM8350_IRQ_CHG_FAST_RDY] = {
0129         .primary = WM8350_CHG_INT,
0130         .reg = WM8350_INT_OFFSET_1,
0131         .mask = WM8350_CHG_FAST_RDY_EINT,
0132     },
0133     [WM8350_IRQ_CHG_VBATT_LT_3P9] = {
0134         .primary = WM8350_CHG_INT,
0135         .reg = WM8350_INT_OFFSET_1,
0136         .mask = WM8350_CHG_VBATT_LT_3P9_EINT,
0137     },
0138     [WM8350_IRQ_CHG_VBATT_LT_3P1] = {
0139         .primary = WM8350_CHG_INT,
0140         .reg = WM8350_INT_OFFSET_1,
0141         .mask = WM8350_CHG_VBATT_LT_3P1_EINT,
0142     },
0143     [WM8350_IRQ_CHG_VBATT_LT_2P85] = {
0144         .primary = WM8350_CHG_INT,
0145         .reg = WM8350_INT_OFFSET_1,
0146         .mask = WM8350_CHG_VBATT_LT_2P85_EINT,
0147     },
0148     [WM8350_IRQ_RTC_ALM] = {
0149         .primary = WM8350_RTC_INT,
0150         .reg = WM8350_INT_OFFSET_1,
0151         .mask = WM8350_RTC_ALM_EINT,
0152     },
0153     [WM8350_IRQ_RTC_SEC] = {
0154         .primary = WM8350_RTC_INT,
0155         .reg = WM8350_INT_OFFSET_1,
0156         .mask = WM8350_RTC_SEC_EINT,
0157     },
0158     [WM8350_IRQ_RTC_PER] = {
0159         .primary = WM8350_RTC_INT,
0160         .reg = WM8350_INT_OFFSET_1,
0161         .mask = WM8350_RTC_PER_EINT,
0162     },
0163     [WM8350_IRQ_CS1] = {
0164         .primary = WM8350_CS_INT,
0165         .reg = WM8350_INT_OFFSET_2,
0166         .mask = WM8350_CS1_EINT,
0167     },
0168     [WM8350_IRQ_CS2] = {
0169         .primary = WM8350_CS_INT,
0170         .reg = WM8350_INT_OFFSET_2,
0171         .mask = WM8350_CS2_EINT,
0172     },
0173     [WM8350_IRQ_SYS_HYST_COMP_FAIL] = {
0174         .primary = WM8350_SYS_INT,
0175         .reg = WM8350_INT_OFFSET_2,
0176         .mask = WM8350_SYS_HYST_COMP_FAIL_EINT,
0177     },
0178     [WM8350_IRQ_SYS_CHIP_GT115] = {
0179         .primary = WM8350_SYS_INT,
0180         .reg = WM8350_INT_OFFSET_2,
0181         .mask = WM8350_SYS_CHIP_GT115_EINT,
0182     },
0183     [WM8350_IRQ_SYS_CHIP_GT140] = {
0184         .primary = WM8350_SYS_INT,
0185         .reg = WM8350_INT_OFFSET_2,
0186         .mask = WM8350_SYS_CHIP_GT140_EINT,
0187     },
0188     [WM8350_IRQ_SYS_WDOG_TO] = {
0189         .primary = WM8350_SYS_INT,
0190         .reg = WM8350_INT_OFFSET_2,
0191         .mask = WM8350_SYS_WDOG_TO_EINT,
0192     },
0193     [WM8350_IRQ_AUXADC_DATARDY] = {
0194         .primary = WM8350_AUXADC_INT,
0195         .reg = WM8350_INT_OFFSET_2,
0196         .mask = WM8350_AUXADC_DATARDY_EINT,
0197     },
0198     [WM8350_IRQ_AUXADC_DCOMP4] = {
0199         .primary = WM8350_AUXADC_INT,
0200         .reg = WM8350_INT_OFFSET_2,
0201         .mask = WM8350_AUXADC_DCOMP4_EINT,
0202     },
0203     [WM8350_IRQ_AUXADC_DCOMP3] = {
0204         .primary = WM8350_AUXADC_INT,
0205         .reg = WM8350_INT_OFFSET_2,
0206         .mask = WM8350_AUXADC_DCOMP3_EINT,
0207     },
0208     [WM8350_IRQ_AUXADC_DCOMP2] = {
0209         .primary = WM8350_AUXADC_INT,
0210         .reg = WM8350_INT_OFFSET_2,
0211         .mask = WM8350_AUXADC_DCOMP2_EINT,
0212     },
0213     [WM8350_IRQ_AUXADC_DCOMP1] = {
0214         .primary = WM8350_AUXADC_INT,
0215         .reg = WM8350_INT_OFFSET_2,
0216         .mask = WM8350_AUXADC_DCOMP1_EINT,
0217     },
0218     [WM8350_IRQ_USB_LIMIT] = {
0219         .primary = WM8350_USB_INT,
0220         .reg = WM8350_INT_OFFSET_2,
0221         .mask = WM8350_USB_LIMIT_EINT,
0222         .primary_only = 1,
0223     },
0224     [WM8350_IRQ_WKUP_OFF_STATE] = {
0225         .primary = WM8350_WKUP_INT,
0226         .reg = WM8350_COMPARATOR_INT_OFFSET,
0227         .mask = WM8350_WKUP_OFF_STATE_EINT,
0228     },
0229     [WM8350_IRQ_WKUP_HIB_STATE] = {
0230         .primary = WM8350_WKUP_INT,
0231         .reg = WM8350_COMPARATOR_INT_OFFSET,
0232         .mask = WM8350_WKUP_HIB_STATE_EINT,
0233     },
0234     [WM8350_IRQ_WKUP_CONV_FAULT] = {
0235         .primary = WM8350_WKUP_INT,
0236         .reg = WM8350_COMPARATOR_INT_OFFSET,
0237         .mask = WM8350_WKUP_CONV_FAULT_EINT,
0238     },
0239     [WM8350_IRQ_WKUP_WDOG_RST] = {
0240         .primary = WM8350_WKUP_INT,
0241         .reg = WM8350_COMPARATOR_INT_OFFSET,
0242         .mask = WM8350_WKUP_WDOG_RST_EINT,
0243     },
0244     [WM8350_IRQ_WKUP_GP_PWR_ON] = {
0245         .primary = WM8350_WKUP_INT,
0246         .reg = WM8350_COMPARATOR_INT_OFFSET,
0247         .mask = WM8350_WKUP_GP_PWR_ON_EINT,
0248     },
0249     [WM8350_IRQ_WKUP_ONKEY] = {
0250         .primary = WM8350_WKUP_INT,
0251         .reg = WM8350_COMPARATOR_INT_OFFSET,
0252         .mask = WM8350_WKUP_ONKEY_EINT,
0253     },
0254     [WM8350_IRQ_WKUP_GP_WAKEUP] = {
0255         .primary = WM8350_WKUP_INT,
0256         .reg = WM8350_COMPARATOR_INT_OFFSET,
0257         .mask = WM8350_WKUP_GP_WAKEUP_EINT,
0258     },
0259     [WM8350_IRQ_CODEC_JCK_DET_L] = {
0260         .primary = WM8350_CODEC_INT,
0261         .reg = WM8350_COMPARATOR_INT_OFFSET,
0262         .mask = WM8350_CODEC_JCK_DET_L_EINT,
0263     },
0264     [WM8350_IRQ_CODEC_JCK_DET_R] = {
0265         .primary = WM8350_CODEC_INT,
0266         .reg = WM8350_COMPARATOR_INT_OFFSET,
0267         .mask = WM8350_CODEC_JCK_DET_R_EINT,
0268     },
0269     [WM8350_IRQ_CODEC_MICSCD] = {
0270         .primary = WM8350_CODEC_INT,
0271         .reg = WM8350_COMPARATOR_INT_OFFSET,
0272         .mask = WM8350_CODEC_MICSCD_EINT,
0273     },
0274     [WM8350_IRQ_CODEC_MICD] = {
0275         .primary = WM8350_CODEC_INT,
0276         .reg = WM8350_COMPARATOR_INT_OFFSET,
0277         .mask = WM8350_CODEC_MICD_EINT,
0278     },
0279     [WM8350_IRQ_EXT_USB_FB] = {
0280         .primary = WM8350_EXT_INT,
0281         .reg = WM8350_COMPARATOR_INT_OFFSET,
0282         .mask = WM8350_EXT_USB_FB_EINT,
0283     },
0284     [WM8350_IRQ_EXT_WALL_FB] = {
0285         .primary = WM8350_EXT_INT,
0286         .reg = WM8350_COMPARATOR_INT_OFFSET,
0287         .mask = WM8350_EXT_WALL_FB_EINT,
0288     },
0289     [WM8350_IRQ_EXT_BAT_FB] = {
0290         .primary = WM8350_EXT_INT,
0291         .reg = WM8350_COMPARATOR_INT_OFFSET,
0292         .mask = WM8350_EXT_BAT_FB_EINT,
0293     },
0294     [WM8350_IRQ_GPIO(0)] = {
0295         .primary = WM8350_GP_INT,
0296         .reg = WM8350_GPIO_INT_OFFSET,
0297         .mask = WM8350_GP0_EINT,
0298     },
0299     [WM8350_IRQ_GPIO(1)] = {
0300         .primary = WM8350_GP_INT,
0301         .reg = WM8350_GPIO_INT_OFFSET,
0302         .mask = WM8350_GP1_EINT,
0303     },
0304     [WM8350_IRQ_GPIO(2)] = {
0305         .primary = WM8350_GP_INT,
0306         .reg = WM8350_GPIO_INT_OFFSET,
0307         .mask = WM8350_GP2_EINT,
0308     },
0309     [WM8350_IRQ_GPIO(3)] = {
0310         .primary = WM8350_GP_INT,
0311         .reg = WM8350_GPIO_INT_OFFSET,
0312         .mask = WM8350_GP3_EINT,
0313     },
0314     [WM8350_IRQ_GPIO(4)] = {
0315         .primary = WM8350_GP_INT,
0316         .reg = WM8350_GPIO_INT_OFFSET,
0317         .mask = WM8350_GP4_EINT,
0318     },
0319     [WM8350_IRQ_GPIO(5)] = {
0320         .primary = WM8350_GP_INT,
0321         .reg = WM8350_GPIO_INT_OFFSET,
0322         .mask = WM8350_GP5_EINT,
0323     },
0324     [WM8350_IRQ_GPIO(6)] = {
0325         .primary = WM8350_GP_INT,
0326         .reg = WM8350_GPIO_INT_OFFSET,
0327         .mask = WM8350_GP6_EINT,
0328     },
0329     [WM8350_IRQ_GPIO(7)] = {
0330         .primary = WM8350_GP_INT,
0331         .reg = WM8350_GPIO_INT_OFFSET,
0332         .mask = WM8350_GP7_EINT,
0333     },
0334     [WM8350_IRQ_GPIO(8)] = {
0335         .primary = WM8350_GP_INT,
0336         .reg = WM8350_GPIO_INT_OFFSET,
0337         .mask = WM8350_GP8_EINT,
0338     },
0339     [WM8350_IRQ_GPIO(9)] = {
0340         .primary = WM8350_GP_INT,
0341         .reg = WM8350_GPIO_INT_OFFSET,
0342         .mask = WM8350_GP9_EINT,
0343     },
0344     [WM8350_IRQ_GPIO(10)] = {
0345         .primary = WM8350_GP_INT,
0346         .reg = WM8350_GPIO_INT_OFFSET,
0347         .mask = WM8350_GP10_EINT,
0348     },
0349     [WM8350_IRQ_GPIO(11)] = {
0350         .primary = WM8350_GP_INT,
0351         .reg = WM8350_GPIO_INT_OFFSET,
0352         .mask = WM8350_GP11_EINT,
0353     },
0354     [WM8350_IRQ_GPIO(12)] = {
0355         .primary = WM8350_GP_INT,
0356         .reg = WM8350_GPIO_INT_OFFSET,
0357         .mask = WM8350_GP12_EINT,
0358     },
0359 };
0360 
0361 static inline struct wm8350_irq_data *irq_to_wm8350_irq(struct wm8350 *wm8350,
0362                             int irq)
0363 {
0364     return &wm8350_irqs[irq - wm8350->irq_base];
0365 }
0366 
0367 /*
0368  * This is a threaded IRQ handler so can access I2C/SPI.  Since all
0369  * interrupts are clear on read the IRQ line will be reasserted and
0370  * the physical IRQ will be handled again if another interrupt is
0371  * asserted while we run - in the normal course of events this is a
0372  * rare occurrence so we save I2C/SPI reads.  We're also assuming that
0373  * it's rare to get lots of interrupts firing simultaneously so try to
0374  * minimise I/O.
0375  */
0376 static irqreturn_t wm8350_irq(int irq, void *irq_data)
0377 {
0378     struct wm8350 *wm8350 = irq_data;
0379     u16 level_one;
0380     u16 sub_reg[WM8350_NUM_IRQ_REGS];
0381     int read_done[WM8350_NUM_IRQ_REGS];
0382     struct wm8350_irq_data *data;
0383     int i;
0384 
0385     level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS)
0386         & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK);
0387 
0388     if (!level_one)
0389         return IRQ_NONE;
0390 
0391     memset(&read_done, 0, sizeof(read_done));
0392 
0393     for (i = 0; i < ARRAY_SIZE(wm8350_irqs); i++) {
0394         data = &wm8350_irqs[i];
0395 
0396         if (!(level_one & data->primary))
0397             continue;
0398 
0399         if (!read_done[data->reg]) {
0400             sub_reg[data->reg] =
0401                 wm8350_reg_read(wm8350, WM8350_INT_STATUS_1 +
0402                         data->reg);
0403             sub_reg[data->reg] &= ~wm8350->irq_masks[data->reg];
0404             read_done[data->reg] = 1;
0405         }
0406 
0407         if (sub_reg[data->reg] & data->mask)
0408             handle_nested_irq(wm8350->irq_base + i);
0409     }
0410 
0411     return IRQ_HANDLED;
0412 }
0413 
0414 static void wm8350_irq_lock(struct irq_data *data)
0415 {
0416     struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
0417 
0418     mutex_lock(&wm8350->irq_lock);
0419 }
0420 
0421 static void wm8350_irq_sync_unlock(struct irq_data *data)
0422 {
0423     struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
0424     int i;
0425 
0426     for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) {
0427         /* If there's been a change in the mask write it back
0428          * to the hardware. */
0429         WARN_ON(regmap_update_bits(wm8350->regmap,
0430                        WM8350_INT_STATUS_1_MASK + i,
0431                        0xffff, wm8350->irq_masks[i]));
0432     }
0433 
0434     mutex_unlock(&wm8350->irq_lock);
0435 }
0436 
0437 static void wm8350_irq_enable(struct irq_data *data)
0438 {
0439     struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
0440     struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350,
0441                                  data->irq);
0442 
0443     wm8350->irq_masks[irq_data->reg] &= ~irq_data->mask;
0444 }
0445 
0446 static void wm8350_irq_disable(struct irq_data *data)
0447 {
0448     struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
0449     struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350,
0450                                  data->irq);
0451 
0452     wm8350->irq_masks[irq_data->reg] |= irq_data->mask;
0453 }
0454 
0455 static struct irq_chip wm8350_irq_chip = {
0456     .name           = "wm8350",
0457     .irq_bus_lock       = wm8350_irq_lock,
0458     .irq_bus_sync_unlock    = wm8350_irq_sync_unlock,
0459     .irq_disable        = wm8350_irq_disable,
0460     .irq_enable     = wm8350_irq_enable,
0461 };
0462 
0463 int wm8350_irq_init(struct wm8350 *wm8350, int irq,
0464             struct wm8350_platform_data *pdata)
0465 {
0466     int ret, cur_irq, i;
0467     int flags = IRQF_ONESHOT;
0468     int irq_base = -1;
0469 
0470     if (!irq) {
0471         dev_warn(wm8350->dev, "No interrupt support, no core IRQ\n");
0472         return 0;
0473     }
0474 
0475     /* Mask top level interrupts */
0476     wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
0477 
0478     /* Mask all individual interrupts by default and cache the
0479      * masks.  We read the masks back since there are unwritable
0480      * bits in the mask registers. */
0481     for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) {
0482         wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK + i,
0483                  0xFFFF);
0484         wm8350->irq_masks[i] =
0485             wm8350_reg_read(wm8350,
0486                     WM8350_INT_STATUS_1_MASK + i);
0487     }
0488 
0489     mutex_init(&wm8350->irq_lock);
0490     wm8350->chip_irq = irq;
0491 
0492     if (pdata && pdata->irq_base > 0)
0493         irq_base = pdata->irq_base;
0494 
0495     wm8350->irq_base =
0496         irq_alloc_descs(irq_base, 0, ARRAY_SIZE(wm8350_irqs), 0);
0497     if (wm8350->irq_base < 0) {
0498         dev_warn(wm8350->dev, "Allocating irqs failed with %d\n",
0499             wm8350->irq_base);
0500         return 0;
0501     }
0502 
0503     if (pdata && pdata->irq_high) {
0504         flags |= IRQF_TRIGGER_HIGH;
0505 
0506         wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
0507                 WM8350_IRQ_POL);
0508     } else {
0509         flags |= IRQF_TRIGGER_LOW;
0510 
0511         wm8350_clear_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
0512                   WM8350_IRQ_POL);
0513     }
0514 
0515     /* Register with genirq */
0516     for (cur_irq = wm8350->irq_base;
0517          cur_irq < ARRAY_SIZE(wm8350_irqs) + wm8350->irq_base;
0518          cur_irq++) {
0519         irq_set_chip_data(cur_irq, wm8350);
0520         irq_set_chip_and_handler(cur_irq, &wm8350_irq_chip,
0521                      handle_edge_irq);
0522         irq_set_nested_thread(cur_irq, 1);
0523 
0524         irq_clear_status_flags(cur_irq, IRQ_NOREQUEST | IRQ_NOPROBE);
0525     }
0526 
0527     ret = request_threaded_irq(irq, NULL, wm8350_irq, flags,
0528                    "wm8350", wm8350);
0529     if (ret != 0)
0530         dev_err(wm8350->dev, "Failed to request IRQ: %d\n", ret);
0531 
0532     /* Allow interrupts to fire */
0533     wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0);
0534 
0535     return ret;
0536 }
0537 
0538 int wm8350_irq_exit(struct wm8350 *wm8350)
0539 {
0540     free_irq(wm8350->chip_irq, wm8350);
0541     return 0;
0542 }