linux/drivers/mfd/wm8350-irq.c
<<
>>
Prefs
   1/*
   2 * wm8350-irq.c  --  IRQ support for Wolfson WM8350
   3 *
   4 * Copyright 2007, 2008, 2009 Wolfson Microelectronics PLC.
   5 *
   6 * Author: Liam Girdwood, Mark Brown
   7 *
   8 *  This program is free software; you can redistribute  it and/or modify it
   9 *  under  the terms of  the GNU General  Public License as published by the
  10 *  Free Software Foundation;  either version 2 of the  License, or (at your
  11 *  option) any later version.
  12 *
  13 */
  14
  15#include <linux/kernel.h>
  16#include <linux/module.h>
  17#include <linux/init.h>
  18#include <linux/bug.h>
  19#include <linux/device.h>
  20#include <linux/interrupt.h>
  21#include <linux/irq.h>
  22
  23#include <linux/mfd/wm8350/core.h>
  24#include <linux/mfd/wm8350/audio.h>
  25#include <linux/mfd/wm8350/comparator.h>
  26#include <linux/mfd/wm8350/gpio.h>
  27#include <linux/mfd/wm8350/pmic.h>
  28#include <linux/mfd/wm8350/rtc.h>
  29#include <linux/mfd/wm8350/supply.h>
  30#include <linux/mfd/wm8350/wdt.h>
  31
  32#define WM8350_INT_OFFSET_1                     0
  33#define WM8350_INT_OFFSET_2                     1
  34#define WM8350_POWER_UP_INT_OFFSET              2
  35#define WM8350_UNDER_VOLTAGE_INT_OFFSET         3
  36#define WM8350_OVER_CURRENT_INT_OFFSET          4
  37#define WM8350_GPIO_INT_OFFSET                  5
  38#define WM8350_COMPARATOR_INT_OFFSET            6
  39
  40struct wm8350_irq_data {
  41        int primary;
  42        int reg;
  43        int mask;
  44        int primary_only;
  45};
  46
  47static struct wm8350_irq_data wm8350_irqs[] = {
  48        [WM8350_IRQ_OC_LS] = {
  49                .primary = WM8350_OC_INT,
  50                .reg = WM8350_OVER_CURRENT_INT_OFFSET,
  51                .mask = WM8350_OC_LS_EINT,
  52                .primary_only = 1,
  53        },
  54        [WM8350_IRQ_UV_DC1] = {
  55                .primary = WM8350_UV_INT,
  56                .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
  57                .mask = WM8350_UV_DC1_EINT,
  58        },
  59        [WM8350_IRQ_UV_DC2] = {
  60                .primary = WM8350_UV_INT,
  61                .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
  62                .mask = WM8350_UV_DC2_EINT,
  63        },
  64        [WM8350_IRQ_UV_DC3] = {
  65                .primary = WM8350_UV_INT,
  66                .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
  67                .mask = WM8350_UV_DC3_EINT,
  68        },
  69        [WM8350_IRQ_UV_DC4] = {
  70                .primary = WM8350_UV_INT,
  71                .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
  72                .mask = WM8350_UV_DC4_EINT,
  73        },
  74        [WM8350_IRQ_UV_DC5] = {
  75                .primary = WM8350_UV_INT,
  76                .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
  77                .mask = WM8350_UV_DC5_EINT,
  78        },
  79        [WM8350_IRQ_UV_DC6] = {
  80                .primary = WM8350_UV_INT,
  81                .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
  82                .mask = WM8350_UV_DC6_EINT,
  83        },
  84        [WM8350_IRQ_UV_LDO1] = {
  85                .primary = WM8350_UV_INT,
  86                .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
  87                .mask = WM8350_UV_LDO1_EINT,
  88        },
  89        [WM8350_IRQ_UV_LDO2] = {
  90                .primary = WM8350_UV_INT,
  91                .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
  92                .mask = WM8350_UV_LDO2_EINT,
  93        },
  94        [WM8350_IRQ_UV_LDO3] = {
  95                .primary = WM8350_UV_INT,
  96                .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
  97                .mask = WM8350_UV_LDO3_EINT,
  98        },
  99        [WM8350_IRQ_UV_LDO4] = {
 100                .primary = WM8350_UV_INT,
 101                .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
 102                .mask = WM8350_UV_LDO4_EINT,
 103        },
 104        [WM8350_IRQ_CHG_BAT_HOT] = {
 105                .primary = WM8350_CHG_INT,
 106                .reg = WM8350_INT_OFFSET_1,
 107                .mask = WM8350_CHG_BAT_HOT_EINT,
 108        },
 109        [WM8350_IRQ_CHG_BAT_COLD] = {
 110                .primary = WM8350_CHG_INT,
 111                .reg = WM8350_INT_OFFSET_1,
 112                .mask = WM8350_CHG_BAT_COLD_EINT,
 113        },
 114        [WM8350_IRQ_CHG_BAT_FAIL] = {
 115                .primary = WM8350_CHG_INT,
 116                .reg = WM8350_INT_OFFSET_1,
 117                .mask = WM8350_CHG_BAT_FAIL_EINT,
 118        },
 119        [WM8350_IRQ_CHG_TO] = {
 120                .primary = WM8350_CHG_INT,
 121                .reg = WM8350_INT_OFFSET_1,
 122                .mask = WM8350_CHG_TO_EINT,
 123        },
 124        [WM8350_IRQ_CHG_END] = {
 125                .primary = WM8350_CHG_INT,
 126                .reg = WM8350_INT_OFFSET_1,
 127                .mask = WM8350_CHG_END_EINT,
 128        },
 129        [WM8350_IRQ_CHG_START] = {
 130                .primary = WM8350_CHG_INT,
 131                .reg = WM8350_INT_OFFSET_1,
 132                .mask = WM8350_CHG_START_EINT,
 133        },
 134        [WM8350_IRQ_CHG_FAST_RDY] = {
 135                .primary = WM8350_CHG_INT,
 136                .reg = WM8350_INT_OFFSET_1,
 137                .mask = WM8350_CHG_FAST_RDY_EINT,
 138        },
 139        [WM8350_IRQ_CHG_VBATT_LT_3P9] = {
 140                .primary = WM8350_CHG_INT,
 141                .reg = WM8350_INT_OFFSET_1,
 142                .mask = WM8350_CHG_VBATT_LT_3P9_EINT,
 143        },
 144        [WM8350_IRQ_CHG_VBATT_LT_3P1] = {
 145                .primary = WM8350_CHG_INT,
 146                .reg = WM8350_INT_OFFSET_1,
 147                .mask = WM8350_CHG_VBATT_LT_3P1_EINT,
 148        },
 149        [WM8350_IRQ_CHG_VBATT_LT_2P85] = {
 150                .primary = WM8350_CHG_INT,
 151                .reg = WM8350_INT_OFFSET_1,
 152                .mask = WM8350_CHG_VBATT_LT_2P85_EINT,
 153        },
 154        [WM8350_IRQ_RTC_ALM] = {
 155                .primary = WM8350_RTC_INT,
 156                .reg = WM8350_INT_OFFSET_1,
 157                .mask = WM8350_RTC_ALM_EINT,
 158        },
 159        [WM8350_IRQ_RTC_SEC] = {
 160                .primary = WM8350_RTC_INT,
 161                .reg = WM8350_INT_OFFSET_1,
 162                .mask = WM8350_RTC_SEC_EINT,
 163        },
 164        [WM8350_IRQ_RTC_PER] = {
 165                .primary = WM8350_RTC_INT,
 166                .reg = WM8350_INT_OFFSET_1,
 167                .mask = WM8350_RTC_PER_EINT,
 168        },
 169        [WM8350_IRQ_CS1] = {
 170                .primary = WM8350_CS_INT,
 171                .reg = WM8350_INT_OFFSET_2,
 172                .mask = WM8350_CS1_EINT,
 173        },
 174        [WM8350_IRQ_CS2] = {
 175                .primary = WM8350_CS_INT,
 176                .reg = WM8350_INT_OFFSET_2,
 177                .mask = WM8350_CS2_EINT,
 178        },
 179        [WM8350_IRQ_SYS_HYST_COMP_FAIL] = {
 180                .primary = WM8350_SYS_INT,
 181                .reg = WM8350_INT_OFFSET_2,
 182                .mask = WM8350_SYS_HYST_COMP_FAIL_EINT,
 183        },
 184        [WM8350_IRQ_SYS_CHIP_GT115] = {
 185                .primary = WM8350_SYS_INT,
 186                .reg = WM8350_INT_OFFSET_2,
 187                .mask = WM8350_SYS_CHIP_GT115_EINT,
 188        },
 189        [WM8350_IRQ_SYS_CHIP_GT140] = {
 190                .primary = WM8350_SYS_INT,
 191                .reg = WM8350_INT_OFFSET_2,
 192                .mask = WM8350_SYS_CHIP_GT140_EINT,
 193        },
 194        [WM8350_IRQ_SYS_WDOG_TO] = {
 195                .primary = WM8350_SYS_INT,
 196                .reg = WM8350_INT_OFFSET_2,
 197                .mask = WM8350_SYS_WDOG_TO_EINT,
 198        },
 199        [WM8350_IRQ_AUXADC_DATARDY] = {
 200                .primary = WM8350_AUXADC_INT,
 201                .reg = WM8350_INT_OFFSET_2,
 202                .mask = WM8350_AUXADC_DATARDY_EINT,
 203        },
 204        [WM8350_IRQ_AUXADC_DCOMP4] = {
 205                .primary = WM8350_AUXADC_INT,
 206                .reg = WM8350_INT_OFFSET_2,
 207                .mask = WM8350_AUXADC_DCOMP4_EINT,
 208        },
 209        [WM8350_IRQ_AUXADC_DCOMP3] = {
 210                .primary = WM8350_AUXADC_INT,
 211                .reg = WM8350_INT_OFFSET_2,
 212                .mask = WM8350_AUXADC_DCOMP3_EINT,
 213        },
 214        [WM8350_IRQ_AUXADC_DCOMP2] = {
 215                .primary = WM8350_AUXADC_INT,
 216                .reg = WM8350_INT_OFFSET_2,
 217                .mask = WM8350_AUXADC_DCOMP2_EINT,
 218        },
 219        [WM8350_IRQ_AUXADC_DCOMP1] = {
 220                .primary = WM8350_AUXADC_INT,
 221                .reg = WM8350_INT_OFFSET_2,
 222                .mask = WM8350_AUXADC_DCOMP1_EINT,
 223        },
 224        [WM8350_IRQ_USB_LIMIT] = {
 225                .primary = WM8350_USB_INT,
 226                .reg = WM8350_INT_OFFSET_2,
 227                .mask = WM8350_USB_LIMIT_EINT,
 228                .primary_only = 1,
 229        },
 230        [WM8350_IRQ_WKUP_OFF_STATE] = {
 231                .primary = WM8350_WKUP_INT,
 232                .reg = WM8350_COMPARATOR_INT_OFFSET,
 233                .mask = WM8350_WKUP_OFF_STATE_EINT,
 234        },
 235        [WM8350_IRQ_WKUP_HIB_STATE] = {
 236                .primary = WM8350_WKUP_INT,
 237                .reg = WM8350_COMPARATOR_INT_OFFSET,
 238                .mask = WM8350_WKUP_HIB_STATE_EINT,
 239        },
 240        [WM8350_IRQ_WKUP_CONV_FAULT] = {
 241                .primary = WM8350_WKUP_INT,
 242                .reg = WM8350_COMPARATOR_INT_OFFSET,
 243                .mask = WM8350_WKUP_CONV_FAULT_EINT,
 244        },
 245        [WM8350_IRQ_WKUP_WDOG_RST] = {
 246                .primary = WM8350_WKUP_INT,
 247                .reg = WM8350_COMPARATOR_INT_OFFSET,
 248                .mask = WM8350_WKUP_WDOG_RST_EINT,
 249        },
 250        [WM8350_IRQ_WKUP_GP_PWR_ON] = {
 251                .primary = WM8350_WKUP_INT,
 252                .reg = WM8350_COMPARATOR_INT_OFFSET,
 253                .mask = WM8350_WKUP_GP_PWR_ON_EINT,
 254        },
 255        [WM8350_IRQ_WKUP_ONKEY] = {
 256                .primary = WM8350_WKUP_INT,
 257                .reg = WM8350_COMPARATOR_INT_OFFSET,
 258                .mask = WM8350_WKUP_ONKEY_EINT,
 259        },
 260        [WM8350_IRQ_WKUP_GP_WAKEUP] = {
 261                .primary = WM8350_WKUP_INT,
 262                .reg = WM8350_COMPARATOR_INT_OFFSET,
 263                .mask = WM8350_WKUP_GP_WAKEUP_EINT,
 264        },
 265        [WM8350_IRQ_CODEC_JCK_DET_L] = {
 266                .primary = WM8350_CODEC_INT,
 267                .reg = WM8350_COMPARATOR_INT_OFFSET,
 268                .mask = WM8350_CODEC_JCK_DET_L_EINT,
 269        },
 270        [WM8350_IRQ_CODEC_JCK_DET_R] = {
 271                .primary = WM8350_CODEC_INT,
 272                .reg = WM8350_COMPARATOR_INT_OFFSET,
 273                .mask = WM8350_CODEC_JCK_DET_R_EINT,
 274        },
 275        [WM8350_IRQ_CODEC_MICSCD] = {
 276                .primary = WM8350_CODEC_INT,
 277                .reg = WM8350_COMPARATOR_INT_OFFSET,
 278                .mask = WM8350_CODEC_MICSCD_EINT,
 279        },
 280        [WM8350_IRQ_CODEC_MICD] = {
 281                .primary = WM8350_CODEC_INT,
 282                .reg = WM8350_COMPARATOR_INT_OFFSET,
 283                .mask = WM8350_CODEC_MICD_EINT,
 284        },
 285        [WM8350_IRQ_EXT_USB_FB] = {
 286                .primary = WM8350_EXT_INT,
 287                .reg = WM8350_COMPARATOR_INT_OFFSET,
 288                .mask = WM8350_EXT_USB_FB_EINT,
 289        },
 290        [WM8350_IRQ_EXT_WALL_FB] = {
 291                .primary = WM8350_EXT_INT,
 292                .reg = WM8350_COMPARATOR_INT_OFFSET,
 293                .mask = WM8350_EXT_WALL_FB_EINT,
 294        },
 295        [WM8350_IRQ_EXT_BAT_FB] = {
 296                .primary = WM8350_EXT_INT,
 297                .reg = WM8350_COMPARATOR_INT_OFFSET,
 298                .mask = WM8350_EXT_BAT_FB_EINT,
 299        },
 300        [WM8350_IRQ_GPIO(0)] = {
 301                .primary = WM8350_GP_INT,
 302                .reg = WM8350_GPIO_INT_OFFSET,
 303                .mask = WM8350_GP0_EINT,
 304        },
 305        [WM8350_IRQ_GPIO(1)] = {
 306                .primary = WM8350_GP_INT,
 307                .reg = WM8350_GPIO_INT_OFFSET,
 308                .mask = WM8350_GP1_EINT,
 309        },
 310        [WM8350_IRQ_GPIO(2)] = {
 311                .primary = WM8350_GP_INT,
 312                .reg = WM8350_GPIO_INT_OFFSET,
 313                .mask = WM8350_GP2_EINT,
 314        },
 315        [WM8350_IRQ_GPIO(3)] = {
 316                .primary = WM8350_GP_INT,
 317                .reg = WM8350_GPIO_INT_OFFSET,
 318                .mask = WM8350_GP3_EINT,
 319        },
 320        [WM8350_IRQ_GPIO(4)] = {
 321                .primary = WM8350_GP_INT,
 322                .reg = WM8350_GPIO_INT_OFFSET,
 323                .mask = WM8350_GP4_EINT,
 324        },
 325        [WM8350_IRQ_GPIO(5)] = {
 326                .primary = WM8350_GP_INT,
 327                .reg = WM8350_GPIO_INT_OFFSET,
 328                .mask = WM8350_GP5_EINT,
 329        },
 330        [WM8350_IRQ_GPIO(6)] = {
 331                .primary = WM8350_GP_INT,
 332                .reg = WM8350_GPIO_INT_OFFSET,
 333                .mask = WM8350_GP6_EINT,
 334        },
 335        [WM8350_IRQ_GPIO(7)] = {
 336                .primary = WM8350_GP_INT,
 337                .reg = WM8350_GPIO_INT_OFFSET,
 338                .mask = WM8350_GP7_EINT,
 339        },
 340        [WM8350_IRQ_GPIO(8)] = {
 341                .primary = WM8350_GP_INT,
 342                .reg = WM8350_GPIO_INT_OFFSET,
 343                .mask = WM8350_GP8_EINT,
 344        },
 345        [WM8350_IRQ_GPIO(9)] = {
 346                .primary = WM8350_GP_INT,
 347                .reg = WM8350_GPIO_INT_OFFSET,
 348                .mask = WM8350_GP9_EINT,
 349        },
 350        [WM8350_IRQ_GPIO(10)] = {
 351                .primary = WM8350_GP_INT,
 352                .reg = WM8350_GPIO_INT_OFFSET,
 353                .mask = WM8350_GP10_EINT,
 354        },
 355        [WM8350_IRQ_GPIO(11)] = {
 356                .primary = WM8350_GP_INT,
 357                .reg = WM8350_GPIO_INT_OFFSET,
 358                .mask = WM8350_GP11_EINT,
 359        },
 360        [WM8350_IRQ_GPIO(12)] = {
 361                .primary = WM8350_GP_INT,
 362                .reg = WM8350_GPIO_INT_OFFSET,
 363                .mask = WM8350_GP12_EINT,
 364        },
 365};
 366
 367static inline struct wm8350_irq_data *irq_to_wm8350_irq(struct wm8350 *wm8350,
 368                                                        int irq)
 369{
 370        return &wm8350_irqs[irq - wm8350->irq_base];
 371}
 372
 373/*
 374 * This is a threaded IRQ handler so can access I2C/SPI.  Since all
 375 * interrupts are clear on read the IRQ line will be reasserted and
 376 * the physical IRQ will be handled again if another interrupt is
 377 * asserted while we run - in the normal course of events this is a
 378 * rare occurrence so we save I2C/SPI reads.  We're also assuming that
 379 * it's rare to get lots of interrupts firing simultaneously so try to
 380 * minimise I/O.
 381 */
 382static irqreturn_t wm8350_irq(int irq, void *irq_data)
 383{
 384        struct wm8350 *wm8350 = irq_data;
 385        u16 level_one;
 386        u16 sub_reg[WM8350_NUM_IRQ_REGS];
 387        int read_done[WM8350_NUM_IRQ_REGS];
 388        struct wm8350_irq_data *data;
 389        int i;
 390
 391        level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS)
 392                & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK);
 393
 394        if (!level_one)
 395                return IRQ_NONE;
 396
 397        memset(&read_done, 0, sizeof(read_done));
 398
 399        for (i = 0; i < ARRAY_SIZE(wm8350_irqs); i++) {
 400                data = &wm8350_irqs[i];
 401
 402                if (!(level_one & data->primary))
 403                        continue;
 404
 405                if (!read_done[data->reg]) {
 406                        sub_reg[data->reg] =
 407                                wm8350_reg_read(wm8350, WM8350_INT_STATUS_1 +
 408                                                data->reg);
 409                        sub_reg[data->reg] &= ~wm8350->irq_masks[data->reg];
 410                        read_done[data->reg] = 1;
 411                }
 412
 413                if (sub_reg[data->reg] & data->mask)
 414                        handle_nested_irq(wm8350->irq_base + i);
 415        }
 416
 417        return IRQ_HANDLED;
 418}
 419
 420static void wm8350_irq_lock(struct irq_data *data)
 421{
 422        struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
 423
 424        mutex_lock(&wm8350->irq_lock);
 425}
 426
 427static void wm8350_irq_sync_unlock(struct irq_data *data)
 428{
 429        struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
 430        int i;
 431
 432        for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) {
 433                /* If there's been a change in the mask write it back
 434                 * to the hardware. */
 435                WARN_ON(regmap_update_bits(wm8350->regmap,
 436                                           WM8350_INT_STATUS_1_MASK + i,
 437                                           0xffff, wm8350->irq_masks[i]));
 438        }
 439
 440        mutex_unlock(&wm8350->irq_lock);
 441}
 442
 443static void wm8350_irq_enable(struct irq_data *data)
 444{
 445        struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
 446        struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350,
 447                                                             data->irq);
 448
 449        wm8350->irq_masks[irq_data->reg] &= ~irq_data->mask;
 450}
 451
 452static void wm8350_irq_disable(struct irq_data *data)
 453{
 454        struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
 455        struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350,
 456                                                             data->irq);
 457
 458        wm8350->irq_masks[irq_data->reg] |= irq_data->mask;
 459}
 460
 461static struct irq_chip wm8350_irq_chip = {
 462        .name                   = "wm8350",
 463        .irq_bus_lock           = wm8350_irq_lock,
 464        .irq_bus_sync_unlock    = wm8350_irq_sync_unlock,
 465        .irq_disable            = wm8350_irq_disable,
 466        .irq_enable             = wm8350_irq_enable,
 467};
 468
 469int wm8350_irq_init(struct wm8350 *wm8350, int irq,
 470                    struct wm8350_platform_data *pdata)
 471{
 472        int ret, cur_irq, i;
 473        int flags = IRQF_ONESHOT;
 474        int irq_base = -1;
 475
 476        if (!irq) {
 477                dev_warn(wm8350->dev, "No interrupt support, no core IRQ\n");
 478                return 0;
 479        }
 480
 481        /* Mask top level interrupts */
 482        wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
 483
 484        /* Mask all individual interrupts by default and cache the
 485         * masks.  We read the masks back since there are unwritable
 486         * bits in the mask registers. */
 487        for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) {
 488                wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK + i,
 489                                 0xFFFF);
 490                wm8350->irq_masks[i] =
 491                        wm8350_reg_read(wm8350,
 492                                        WM8350_INT_STATUS_1_MASK + i);
 493        }
 494
 495        mutex_init(&wm8350->irq_lock);
 496        wm8350->chip_irq = irq;
 497
 498        if (pdata && pdata->irq_base > 0)
 499                irq_base = pdata->irq_base;
 500
 501        wm8350->irq_base = irq_alloc_descs(irq_base, 0, ARRAY_SIZE(wm8350_irqs), 0);
 502        if (wm8350->irq_base < 0) {
 503                dev_warn(wm8350->dev, "Allocating irqs failed with %d\n",
 504                        wm8350->irq_base);
 505                return 0;
 506        }
 507
 508        if (pdata && pdata->irq_high) {
 509                flags |= IRQF_TRIGGER_HIGH;
 510
 511                wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
 512                                WM8350_IRQ_POL);
 513        } else {
 514                flags |= IRQF_TRIGGER_LOW;
 515
 516                wm8350_clear_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
 517                                  WM8350_IRQ_POL);
 518        }
 519
 520        /* Register with genirq */
 521        for (cur_irq = wm8350->irq_base;
 522             cur_irq < ARRAY_SIZE(wm8350_irqs) + wm8350->irq_base;
 523             cur_irq++) {
 524                irq_set_chip_data(cur_irq, wm8350);
 525                irq_set_chip_and_handler(cur_irq, &wm8350_irq_chip,
 526                                         handle_edge_irq);
 527                irq_set_nested_thread(cur_irq, 1);
 528
 529                /* ARM needs us to explicitly flag the IRQ as valid
 530                 * and will set them noprobe when we do so. */
 531#ifdef CONFIG_ARM
 532                set_irq_flags(cur_irq, IRQF_VALID);
 533#else
 534                irq_set_noprobe(cur_irq);
 535#endif
 536        }
 537
 538        ret = request_threaded_irq(irq, NULL, wm8350_irq, flags,
 539                                   "wm8350", wm8350);
 540        if (ret != 0)
 541                dev_err(wm8350->dev, "Failed to request IRQ: %d\n", ret);
 542
 543        /* Allow interrupts to fire */
 544        wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0);
 545
 546        return ret;
 547}
 548
 549int wm8350_irq_exit(struct wm8350 *wm8350)
 550{
 551        free_irq(wm8350->chip_irq, wm8350);
 552        return 0;
 553}
 554