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