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