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/workqueue.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_NUM_IRQ_REGS 7 33 34 #define WM8350_INT_OFFSET_1 0 35 #define WM8350_INT_OFFSET_2 1 36 #define WM8350_POWER_UP_INT_OFFSET 2 37 #define WM8350_UNDER_VOLTAGE_INT_OFFSET 3 38 #define WM8350_OVER_CURRENT_INT_OFFSET 4 39 #define WM8350_GPIO_INT_OFFSET 5 40 #define WM8350_COMPARATOR_INT_OFFSET 6 41 42 struct wm8350_irq_data { 43 int primary; 44 int reg; 45 int mask; 46 int primary_only; 47 }; 48 49 static struct wm8350_irq_data wm8350_irqs[] = { 50 [WM8350_IRQ_OC_LS] = { 51 .primary = WM8350_OC_INT, 52 .reg = WM8350_OVER_CURRENT_INT_OFFSET, 53 .mask = WM8350_OC_LS_EINT, 54 .primary_only = 1, 55 }, 56 [WM8350_IRQ_UV_DC1] = { 57 .primary = WM8350_UV_INT, 58 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, 59 .mask = WM8350_UV_DC1_EINT, 60 }, 61 [WM8350_IRQ_UV_DC2] = { 62 .primary = WM8350_UV_INT, 63 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, 64 .mask = WM8350_UV_DC2_EINT, 65 }, 66 [WM8350_IRQ_UV_DC3] = { 67 .primary = WM8350_UV_INT, 68 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, 69 .mask = WM8350_UV_DC3_EINT, 70 }, 71 [WM8350_IRQ_UV_DC4] = { 72 .primary = WM8350_UV_INT, 73 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, 74 .mask = WM8350_UV_DC4_EINT, 75 }, 76 [WM8350_IRQ_UV_DC5] = { 77 .primary = WM8350_UV_INT, 78 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, 79 .mask = WM8350_UV_DC5_EINT, 80 }, 81 [WM8350_IRQ_UV_DC6] = { 82 .primary = WM8350_UV_INT, 83 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, 84 .mask = WM8350_UV_DC6_EINT, 85 }, 86 [WM8350_IRQ_UV_LDO1] = { 87 .primary = WM8350_UV_INT, 88 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, 89 .mask = WM8350_UV_LDO1_EINT, 90 }, 91 [WM8350_IRQ_UV_LDO2] = { 92 .primary = WM8350_UV_INT, 93 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, 94 .mask = WM8350_UV_LDO2_EINT, 95 }, 96 [WM8350_IRQ_UV_LDO3] = { 97 .primary = WM8350_UV_INT, 98 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, 99 .mask = WM8350_UV_LDO3_EINT, 100 }, 101 [WM8350_IRQ_UV_LDO4] = { 102 .primary = WM8350_UV_INT, 103 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET, 104 .mask = WM8350_UV_LDO4_EINT, 105 }, 106 [WM8350_IRQ_CHG_BAT_HOT] = { 107 .primary = WM8350_CHG_INT, 108 .reg = WM8350_INT_OFFSET_1, 109 .mask = WM8350_CHG_BAT_HOT_EINT, 110 }, 111 [WM8350_IRQ_CHG_BAT_COLD] = { 112 .primary = WM8350_CHG_INT, 113 .reg = WM8350_INT_OFFSET_1, 114 .mask = WM8350_CHG_BAT_COLD_EINT, 115 }, 116 [WM8350_IRQ_CHG_BAT_FAIL] = { 117 .primary = WM8350_CHG_INT, 118 .reg = WM8350_INT_OFFSET_1, 119 .mask = WM8350_CHG_BAT_FAIL_EINT, 120 }, 121 [WM8350_IRQ_CHG_TO] = { 122 .primary = WM8350_CHG_INT, 123 .reg = WM8350_INT_OFFSET_1, 124 .mask = WM8350_CHG_TO_EINT, 125 }, 126 [WM8350_IRQ_CHG_END] = { 127 .primary = WM8350_CHG_INT, 128 .reg = WM8350_INT_OFFSET_1, 129 .mask = WM8350_CHG_END_EINT, 130 }, 131 [WM8350_IRQ_CHG_START] = { 132 .primary = WM8350_CHG_INT, 133 .reg = WM8350_INT_OFFSET_1, 134 .mask = WM8350_CHG_START_EINT, 135 }, 136 [WM8350_IRQ_CHG_FAST_RDY] = { 137 .primary = WM8350_CHG_INT, 138 .reg = WM8350_INT_OFFSET_1, 139 .mask = WM8350_CHG_FAST_RDY_EINT, 140 }, 141 [WM8350_IRQ_CHG_VBATT_LT_3P9] = { 142 .primary = WM8350_CHG_INT, 143 .reg = WM8350_INT_OFFSET_1, 144 .mask = WM8350_CHG_VBATT_LT_3P9_EINT, 145 }, 146 [WM8350_IRQ_CHG_VBATT_LT_3P1] = { 147 .primary = WM8350_CHG_INT, 148 .reg = WM8350_INT_OFFSET_1, 149 .mask = WM8350_CHG_VBATT_LT_3P1_EINT, 150 }, 151 [WM8350_IRQ_CHG_VBATT_LT_2P85] = { 152 .primary = WM8350_CHG_INT, 153 .reg = WM8350_INT_OFFSET_1, 154 .mask = WM8350_CHG_VBATT_LT_2P85_EINT, 155 }, 156 [WM8350_IRQ_RTC_ALM] = { 157 .primary = WM8350_RTC_INT, 158 .reg = WM8350_INT_OFFSET_1, 159 .mask = WM8350_RTC_ALM_EINT, 160 }, 161 [WM8350_IRQ_RTC_SEC] = { 162 .primary = WM8350_RTC_INT, 163 .reg = WM8350_INT_OFFSET_1, 164 .mask = WM8350_RTC_SEC_EINT, 165 }, 166 [WM8350_IRQ_RTC_PER] = { 167 .primary = WM8350_RTC_INT, 168 .reg = WM8350_INT_OFFSET_1, 169 .mask = WM8350_RTC_PER_EINT, 170 }, 171 [WM8350_IRQ_CS1] = { 172 .primary = WM8350_CS_INT, 173 .reg = WM8350_INT_OFFSET_2, 174 .mask = WM8350_CS1_EINT, 175 }, 176 [WM8350_IRQ_CS2] = { 177 .primary = WM8350_CS_INT, 178 .reg = WM8350_INT_OFFSET_2, 179 .mask = WM8350_CS2_EINT, 180 }, 181 [WM8350_IRQ_SYS_HYST_COMP_FAIL] = { 182 .primary = WM8350_SYS_INT, 183 .reg = WM8350_INT_OFFSET_2, 184 .mask = WM8350_SYS_HYST_COMP_FAIL_EINT, 185 }, 186 [WM8350_IRQ_SYS_CHIP_GT115] = { 187 .primary = WM8350_SYS_INT, 188 .reg = WM8350_INT_OFFSET_2, 189 .mask = WM8350_SYS_CHIP_GT115_EINT, 190 }, 191 [WM8350_IRQ_SYS_CHIP_GT140] = { 192 .primary = WM8350_SYS_INT, 193 .reg = WM8350_INT_OFFSET_2, 194 .mask = WM8350_SYS_CHIP_GT140_EINT, 195 }, 196 [WM8350_IRQ_SYS_WDOG_TO] = { 197 .primary = WM8350_SYS_INT, 198 .reg = WM8350_INT_OFFSET_2, 199 .mask = WM8350_SYS_WDOG_TO_EINT, 200 }, 201 [WM8350_IRQ_AUXADC_DATARDY] = { 202 .primary = WM8350_AUXADC_INT, 203 .reg = WM8350_INT_OFFSET_2, 204 .mask = WM8350_AUXADC_DATARDY_EINT, 205 }, 206 [WM8350_IRQ_AUXADC_DCOMP4] = { 207 .primary = WM8350_AUXADC_INT, 208 .reg = WM8350_INT_OFFSET_2, 209 .mask = WM8350_AUXADC_DCOMP4_EINT, 210 }, 211 [WM8350_IRQ_AUXADC_DCOMP3] = { 212 .primary = WM8350_AUXADC_INT, 213 .reg = WM8350_INT_OFFSET_2, 214 .mask = WM8350_AUXADC_DCOMP3_EINT, 215 }, 216 [WM8350_IRQ_AUXADC_DCOMP2] = { 217 .primary = WM8350_AUXADC_INT, 218 .reg = WM8350_INT_OFFSET_2, 219 .mask = WM8350_AUXADC_DCOMP2_EINT, 220 }, 221 [WM8350_IRQ_AUXADC_DCOMP1] = { 222 .primary = WM8350_AUXADC_INT, 223 .reg = WM8350_INT_OFFSET_2, 224 .mask = WM8350_AUXADC_DCOMP1_EINT, 225 }, 226 [WM8350_IRQ_USB_LIMIT] = { 227 .primary = WM8350_USB_INT, 228 .reg = WM8350_INT_OFFSET_2, 229 .mask = WM8350_USB_LIMIT_EINT, 230 .primary_only = 1, 231 }, 232 [WM8350_IRQ_WKUP_OFF_STATE] = { 233 .primary = WM8350_WKUP_INT, 234 .reg = WM8350_COMPARATOR_INT_OFFSET, 235 .mask = WM8350_WKUP_OFF_STATE_EINT, 236 }, 237 [WM8350_IRQ_WKUP_HIB_STATE] = { 238 .primary = WM8350_WKUP_INT, 239 .reg = WM8350_COMPARATOR_INT_OFFSET, 240 .mask = WM8350_WKUP_HIB_STATE_EINT, 241 }, 242 [WM8350_IRQ_WKUP_CONV_FAULT] = { 243 .primary = WM8350_WKUP_INT, 244 .reg = WM8350_COMPARATOR_INT_OFFSET, 245 .mask = WM8350_WKUP_CONV_FAULT_EINT, 246 }, 247 [WM8350_IRQ_WKUP_WDOG_RST] = { 248 .primary = WM8350_WKUP_INT, 249 .reg = WM8350_COMPARATOR_INT_OFFSET, 250 .mask = WM8350_WKUP_WDOG_RST_EINT, 251 }, 252 [WM8350_IRQ_WKUP_GP_PWR_ON] = { 253 .primary = WM8350_WKUP_INT, 254 .reg = WM8350_COMPARATOR_INT_OFFSET, 255 .mask = WM8350_WKUP_GP_PWR_ON_EINT, 256 }, 257 [WM8350_IRQ_WKUP_ONKEY] = { 258 .primary = WM8350_WKUP_INT, 259 .reg = WM8350_COMPARATOR_INT_OFFSET, 260 .mask = WM8350_WKUP_ONKEY_EINT, 261 }, 262 [WM8350_IRQ_WKUP_GP_WAKEUP] = { 263 .primary = WM8350_WKUP_INT, 264 .reg = WM8350_COMPARATOR_INT_OFFSET, 265 .mask = WM8350_WKUP_GP_WAKEUP_EINT, 266 }, 267 [WM8350_IRQ_CODEC_JCK_DET_L] = { 268 .primary = WM8350_CODEC_INT, 269 .reg = WM8350_COMPARATOR_INT_OFFSET, 270 .mask = WM8350_CODEC_JCK_DET_L_EINT, 271 }, 272 [WM8350_IRQ_CODEC_JCK_DET_R] = { 273 .primary = WM8350_CODEC_INT, 274 .reg = WM8350_COMPARATOR_INT_OFFSET, 275 .mask = WM8350_CODEC_JCK_DET_R_EINT, 276 }, 277 [WM8350_IRQ_CODEC_MICSCD] = { 278 .primary = WM8350_CODEC_INT, 279 .reg = WM8350_COMPARATOR_INT_OFFSET, 280 .mask = WM8350_CODEC_MICSCD_EINT, 281 }, 282 [WM8350_IRQ_CODEC_MICD] = { 283 .primary = WM8350_CODEC_INT, 284 .reg = WM8350_COMPARATOR_INT_OFFSET, 285 .mask = WM8350_CODEC_MICD_EINT, 286 }, 287 [WM8350_IRQ_EXT_USB_FB] = { 288 .primary = WM8350_EXT_INT, 289 .reg = WM8350_COMPARATOR_INT_OFFSET, 290 .mask = WM8350_EXT_USB_FB_EINT, 291 }, 292 [WM8350_IRQ_EXT_WALL_FB] = { 293 .primary = WM8350_EXT_INT, 294 .reg = WM8350_COMPARATOR_INT_OFFSET, 295 .mask = WM8350_EXT_WALL_FB_EINT, 296 }, 297 [WM8350_IRQ_EXT_BAT_FB] = { 298 .primary = WM8350_EXT_INT, 299 .reg = WM8350_COMPARATOR_INT_OFFSET, 300 .mask = WM8350_EXT_BAT_FB_EINT, 301 }, 302 [WM8350_IRQ_GPIO(0)] = { 303 .primary = WM8350_GP_INT, 304 .reg = WM8350_GPIO_INT_OFFSET, 305 .mask = WM8350_GP0_EINT, 306 }, 307 [WM8350_IRQ_GPIO(1)] = { 308 .primary = WM8350_GP_INT, 309 .reg = WM8350_GPIO_INT_OFFSET, 310 .mask = WM8350_GP1_EINT, 311 }, 312 [WM8350_IRQ_GPIO(2)] = { 313 .primary = WM8350_GP_INT, 314 .reg = WM8350_GPIO_INT_OFFSET, 315 .mask = WM8350_GP2_EINT, 316 }, 317 [WM8350_IRQ_GPIO(3)] = { 318 .primary = WM8350_GP_INT, 319 .reg = WM8350_GPIO_INT_OFFSET, 320 .mask = WM8350_GP3_EINT, 321 }, 322 [WM8350_IRQ_GPIO(4)] = { 323 .primary = WM8350_GP_INT, 324 .reg = WM8350_GPIO_INT_OFFSET, 325 .mask = WM8350_GP4_EINT, 326 }, 327 [WM8350_IRQ_GPIO(5)] = { 328 .primary = WM8350_GP_INT, 329 .reg = WM8350_GPIO_INT_OFFSET, 330 .mask = WM8350_GP5_EINT, 331 }, 332 [WM8350_IRQ_GPIO(6)] = { 333 .primary = WM8350_GP_INT, 334 .reg = WM8350_GPIO_INT_OFFSET, 335 .mask = WM8350_GP6_EINT, 336 }, 337 [WM8350_IRQ_GPIO(7)] = { 338 .primary = WM8350_GP_INT, 339 .reg = WM8350_GPIO_INT_OFFSET, 340 .mask = WM8350_GP7_EINT, 341 }, 342 [WM8350_IRQ_GPIO(8)] = { 343 .primary = WM8350_GP_INT, 344 .reg = WM8350_GPIO_INT_OFFSET, 345 .mask = WM8350_GP8_EINT, 346 }, 347 [WM8350_IRQ_GPIO(9)] = { 348 .primary = WM8350_GP_INT, 349 .reg = WM8350_GPIO_INT_OFFSET, 350 .mask = WM8350_GP9_EINT, 351 }, 352 [WM8350_IRQ_GPIO(10)] = { 353 .primary = WM8350_GP_INT, 354 .reg = WM8350_GPIO_INT_OFFSET, 355 .mask = WM8350_GP10_EINT, 356 }, 357 [WM8350_IRQ_GPIO(11)] = { 358 .primary = WM8350_GP_INT, 359 .reg = WM8350_GPIO_INT_OFFSET, 360 .mask = WM8350_GP11_EINT, 361 }, 362 [WM8350_IRQ_GPIO(12)] = { 363 .primary = WM8350_GP_INT, 364 .reg = WM8350_GPIO_INT_OFFSET, 365 .mask = WM8350_GP12_EINT, 366 }, 367 }; 368 369 static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq) 370 { 371 mutex_lock(&wm8350->irq_mutex); 372 373 if (wm8350->irq[irq].handler) 374 wm8350->irq[irq].handler(irq, wm8350->irq[irq].data); 375 else { 376 dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n", 377 irq); 378 wm8350_mask_irq(wm8350, irq); 379 } 380 381 mutex_unlock(&wm8350->irq_mutex); 382 } 383 384 /* 385 * This is a threaded IRQ handler so can access I2C/SPI. Since all 386 * interrupts are clear on read the IRQ line will be reasserted and 387 * the physical IRQ will be handled again if another interrupt is 388 * asserted while we run - in the normal course of events this is a 389 * rare occurrence so we save I2C/SPI reads. 390 */ 391 static irqreturn_t wm8350_irq(int irq, void *irq_data) 392 { 393 struct wm8350 *wm8350 = irq_data; 394 u16 level_one; 395 u16 sub_reg[WM8350_NUM_IRQ_REGS]; 396 int read_done[WM8350_NUM_IRQ_REGS]; 397 struct wm8350_irq_data *data; 398 int i; 399 400 /* TODO: Use block reads to improve performance? */ 401 level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS) 402 & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK); 403 404 if (!level_one) 405 return IRQ_NONE; 406 407 memset(&read_done, 0, sizeof(read_done)); 408 409 for (i = 0; i < ARRAY_SIZE(wm8350_irqs); i++) { 410 data = &wm8350_irqs[i]; 411 412 if (!(level_one & data->primary)) 413 continue; 414 415 if (!read_done[data->reg]) { 416 sub_reg[data->reg] = 417 wm8350_reg_read(wm8350, WM8350_INT_STATUS_1 + 418 data->reg); 419 sub_reg[data->reg] &= 420 ~wm8350_reg_read(wm8350, 421 WM8350_INT_STATUS_1_MASK + 422 data->reg); 423 read_done[data->reg] = 1; 424 } 425 426 if (sub_reg[data->reg] & data->mask) 427 wm8350_irq_call_handler(wm8350, i); 428 } 429 430 return IRQ_HANDLED; 431 } 432 433 int wm8350_register_irq(struct wm8350 *wm8350, int irq, 434 irq_handler_t handler, unsigned long flags, 435 const char *name, void *data) 436 { 437 if (irq < 0 || irq > WM8350_NUM_IRQ || !handler) 438 return -EINVAL; 439 440 if (wm8350->irq[irq].handler) 441 return -EBUSY; 442 443 mutex_lock(&wm8350->irq_mutex); 444 wm8350->irq[irq].handler = handler; 445 wm8350->irq[irq].data = data; 446 mutex_unlock(&wm8350->irq_mutex); 447 448 wm8350_unmask_irq(wm8350, irq); 449 450 return 0; 451 } 452 EXPORT_SYMBOL_GPL(wm8350_register_irq); 453 454 int wm8350_free_irq(struct wm8350 *wm8350, int irq) 455 { 456 if (irq < 0 || irq > WM8350_NUM_IRQ) 457 return -EINVAL; 458 459 wm8350_mask_irq(wm8350, irq); 460 461 mutex_lock(&wm8350->irq_mutex); 462 wm8350->irq[irq].handler = NULL; 463 mutex_unlock(&wm8350->irq_mutex); 464 return 0; 465 } 466 EXPORT_SYMBOL_GPL(wm8350_free_irq); 467 468 int wm8350_mask_irq(struct wm8350 *wm8350, int irq) 469 { 470 return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK + 471 wm8350_irqs[irq].reg, 472 wm8350_irqs[irq].mask); 473 } 474 EXPORT_SYMBOL_GPL(wm8350_mask_irq); 475 476 int wm8350_unmask_irq(struct wm8350 *wm8350, int irq) 477 { 478 return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK + 479 wm8350_irqs[irq].reg, 480 wm8350_irqs[irq].mask); 481 } 482 EXPORT_SYMBOL_GPL(wm8350_unmask_irq); 483 484 int wm8350_irq_init(struct wm8350 *wm8350, int irq, 485 struct wm8350_platform_data *pdata) 486 { 487 int ret; 488 int flags = IRQF_ONESHOT; 489 490 if (!irq) { 491 dev_err(wm8350->dev, "No IRQ configured\n"); 492 return -EINVAL; 493 } 494 495 wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF); 496 wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF); 497 wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF); 498 wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF); 499 wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF); 500 wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF); 501 502 mutex_init(&wm8350->irq_mutex); 503 wm8350->chip_irq = irq; 504 505 if (pdata && pdata->irq_high) { 506 flags |= IRQF_TRIGGER_HIGH; 507 508 wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1, 509 WM8350_IRQ_POL); 510 } else { 511 flags |= IRQF_TRIGGER_LOW; 512 513 wm8350_clear_bits(wm8350, WM8350_SYSTEM_CONTROL_1, 514 WM8350_IRQ_POL); 515 } 516 517 ret = request_threaded_irq(irq, NULL, wm8350_irq, flags, 518 "wm8350", wm8350); 519 if (ret != 0) 520 dev_err(wm8350->dev, "Failed to request IRQ: %d\n", ret); 521 522 return ret; 523 } 524 525 int wm8350_irq_exit(struct wm8350 *wm8350) 526 { 527 free_irq(wm8350->chip_irq, wm8350); 528 return 0; 529 } 530