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 40 struct wm8350_irq_data { 41 int primary; 42 int reg; 43 int mask; 44 int primary_only; 45 }; 46 47 static 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 367 static 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 */ 382 static 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 420 static 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 427 static 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 if (wm8350->irq_masks[i] != 436 wm8350->reg_cache[WM8350_INT_STATUS_1_MASK + i]) 437 WARN_ON(wm8350_reg_write(wm8350, 438 WM8350_INT_STATUS_1_MASK + i, 439 wm8350->irq_masks[i])); 440 } 441 442 mutex_unlock(&wm8350->irq_lock); 443 } 444 445 static void wm8350_irq_enable(struct irq_data *data) 446 { 447 struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data); 448 struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, 449 data->irq); 450 451 wm8350->irq_masks[irq_data->reg] &= ~irq_data->mask; 452 } 453 454 static void wm8350_irq_disable(struct irq_data *data) 455 { 456 struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data); 457 struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, 458 data->irq); 459 460 wm8350->irq_masks[irq_data->reg] |= irq_data->mask; 461 } 462 463 static struct irq_chip wm8350_irq_chip = { 464 .name = "wm8350", 465 .irq_bus_lock = wm8350_irq_lock, 466 .irq_bus_sync_unlock = wm8350_irq_sync_unlock, 467 .irq_disable = wm8350_irq_disable, 468 .irq_enable = wm8350_irq_enable, 469 }; 470 471 int wm8350_irq_init(struct wm8350 *wm8350, int irq, 472 struct wm8350_platform_data *pdata) 473 { 474 int ret, cur_irq, i; 475 int flags = IRQF_ONESHOT; 476 int irq_base = -1; 477 478 if (!irq) { 479 dev_warn(wm8350->dev, "No interrupt support, no core IRQ\n"); 480 return 0; 481 } 482 483 /* Mask top level interrupts */ 484 wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF); 485 486 /* Mask all individual interrupts by default and cache the 487 * masks. We read the masks back since there are unwritable 488 * bits in the mask registers. */ 489 for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) { 490 wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK + i, 491 0xFFFF); 492 wm8350->irq_masks[i] = 493 wm8350_reg_read(wm8350, 494 WM8350_INT_STATUS_1_MASK + i); 495 } 496 497 mutex_init(&wm8350->irq_lock); 498 wm8350->chip_irq = irq; 499 500 if (pdata && pdata->irq_base > 0) 501 irq_base = pdata->irq_base; 502 503 wm8350->irq_base = irq_alloc_descs(irq_base, 0, ARRAY_SIZE(wm8350_irqs), 0); 504 if (wm8350->irq_base < 0) { 505 dev_warn(wm8350->dev, "Allocating irqs failed with %d\n", 506 wm8350->irq_base); 507 return 0; 508 } 509 510 if (pdata && pdata->irq_high) { 511 flags |= IRQF_TRIGGER_HIGH; 512 513 wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1, 514 WM8350_IRQ_POL); 515 } else { 516 flags |= IRQF_TRIGGER_LOW; 517 518 wm8350_clear_bits(wm8350, WM8350_SYSTEM_CONTROL_1, 519 WM8350_IRQ_POL); 520 } 521 522 /* Register with genirq */ 523 for (cur_irq = wm8350->irq_base; 524 cur_irq < ARRAY_SIZE(wm8350_irqs) + wm8350->irq_base; 525 cur_irq++) { 526 irq_set_chip_data(cur_irq, wm8350); 527 irq_set_chip_and_handler(cur_irq, &wm8350_irq_chip, 528 handle_edge_irq); 529 irq_set_nested_thread(cur_irq, 1); 530 531 /* ARM needs us to explicitly flag the IRQ as valid 532 * and will set them noprobe when we do so. */ 533 #ifdef CONFIG_ARM 534 set_irq_flags(cur_irq, IRQF_VALID); 535 #else 536 irq_set_noprobe(cur_irq); 537 #endif 538 } 539 540 ret = request_threaded_irq(irq, NULL, wm8350_irq, flags, 541 "wm8350", wm8350); 542 if (ret != 0) 543 dev_err(wm8350->dev, "Failed to request IRQ: %d\n", ret); 544 545 /* Allow interrupts to fire */ 546 wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0); 547 548 return ret; 549 } 550 551 int wm8350_irq_exit(struct wm8350 *wm8350) 552 { 553 free_irq(wm8350->chip_irq, wm8350); 554 return 0; 555 } 556