0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/bug.h>
0013 #include <linux/device.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/irq.h>
0016
0017 #include <linux/mfd/wm8350/core.h>
0018 #include <linux/mfd/wm8350/audio.h>
0019 #include <linux/mfd/wm8350/comparator.h>
0020 #include <linux/mfd/wm8350/gpio.h>
0021 #include <linux/mfd/wm8350/pmic.h>
0022 #include <linux/mfd/wm8350/rtc.h>
0023 #include <linux/mfd/wm8350/supply.h>
0024 #include <linux/mfd/wm8350/wdt.h>
0025
0026 #define WM8350_INT_OFFSET_1 0
0027 #define WM8350_INT_OFFSET_2 1
0028 #define WM8350_POWER_UP_INT_OFFSET 2
0029 #define WM8350_UNDER_VOLTAGE_INT_OFFSET 3
0030 #define WM8350_OVER_CURRENT_INT_OFFSET 4
0031 #define WM8350_GPIO_INT_OFFSET 5
0032 #define WM8350_COMPARATOR_INT_OFFSET 6
0033
0034 struct wm8350_irq_data {
0035 int primary;
0036 int reg;
0037 int mask;
0038 int primary_only;
0039 };
0040
0041 static struct wm8350_irq_data wm8350_irqs[] = {
0042 [WM8350_IRQ_OC_LS] = {
0043 .primary = WM8350_OC_INT,
0044 .reg = WM8350_OVER_CURRENT_INT_OFFSET,
0045 .mask = WM8350_OC_LS_EINT,
0046 .primary_only = 1,
0047 },
0048 [WM8350_IRQ_UV_DC1] = {
0049 .primary = WM8350_UV_INT,
0050 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0051 .mask = WM8350_UV_DC1_EINT,
0052 },
0053 [WM8350_IRQ_UV_DC2] = {
0054 .primary = WM8350_UV_INT,
0055 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0056 .mask = WM8350_UV_DC2_EINT,
0057 },
0058 [WM8350_IRQ_UV_DC3] = {
0059 .primary = WM8350_UV_INT,
0060 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0061 .mask = WM8350_UV_DC3_EINT,
0062 },
0063 [WM8350_IRQ_UV_DC4] = {
0064 .primary = WM8350_UV_INT,
0065 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0066 .mask = WM8350_UV_DC4_EINT,
0067 },
0068 [WM8350_IRQ_UV_DC5] = {
0069 .primary = WM8350_UV_INT,
0070 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0071 .mask = WM8350_UV_DC5_EINT,
0072 },
0073 [WM8350_IRQ_UV_DC6] = {
0074 .primary = WM8350_UV_INT,
0075 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0076 .mask = WM8350_UV_DC6_EINT,
0077 },
0078 [WM8350_IRQ_UV_LDO1] = {
0079 .primary = WM8350_UV_INT,
0080 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0081 .mask = WM8350_UV_LDO1_EINT,
0082 },
0083 [WM8350_IRQ_UV_LDO2] = {
0084 .primary = WM8350_UV_INT,
0085 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0086 .mask = WM8350_UV_LDO2_EINT,
0087 },
0088 [WM8350_IRQ_UV_LDO3] = {
0089 .primary = WM8350_UV_INT,
0090 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0091 .mask = WM8350_UV_LDO3_EINT,
0092 },
0093 [WM8350_IRQ_UV_LDO4] = {
0094 .primary = WM8350_UV_INT,
0095 .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
0096 .mask = WM8350_UV_LDO4_EINT,
0097 },
0098 [WM8350_IRQ_CHG_BAT_HOT] = {
0099 .primary = WM8350_CHG_INT,
0100 .reg = WM8350_INT_OFFSET_1,
0101 .mask = WM8350_CHG_BAT_HOT_EINT,
0102 },
0103 [WM8350_IRQ_CHG_BAT_COLD] = {
0104 .primary = WM8350_CHG_INT,
0105 .reg = WM8350_INT_OFFSET_1,
0106 .mask = WM8350_CHG_BAT_COLD_EINT,
0107 },
0108 [WM8350_IRQ_CHG_BAT_FAIL] = {
0109 .primary = WM8350_CHG_INT,
0110 .reg = WM8350_INT_OFFSET_1,
0111 .mask = WM8350_CHG_BAT_FAIL_EINT,
0112 },
0113 [WM8350_IRQ_CHG_TO] = {
0114 .primary = WM8350_CHG_INT,
0115 .reg = WM8350_INT_OFFSET_1,
0116 .mask = WM8350_CHG_TO_EINT,
0117 },
0118 [WM8350_IRQ_CHG_END] = {
0119 .primary = WM8350_CHG_INT,
0120 .reg = WM8350_INT_OFFSET_1,
0121 .mask = WM8350_CHG_END_EINT,
0122 },
0123 [WM8350_IRQ_CHG_START] = {
0124 .primary = WM8350_CHG_INT,
0125 .reg = WM8350_INT_OFFSET_1,
0126 .mask = WM8350_CHG_START_EINT,
0127 },
0128 [WM8350_IRQ_CHG_FAST_RDY] = {
0129 .primary = WM8350_CHG_INT,
0130 .reg = WM8350_INT_OFFSET_1,
0131 .mask = WM8350_CHG_FAST_RDY_EINT,
0132 },
0133 [WM8350_IRQ_CHG_VBATT_LT_3P9] = {
0134 .primary = WM8350_CHG_INT,
0135 .reg = WM8350_INT_OFFSET_1,
0136 .mask = WM8350_CHG_VBATT_LT_3P9_EINT,
0137 },
0138 [WM8350_IRQ_CHG_VBATT_LT_3P1] = {
0139 .primary = WM8350_CHG_INT,
0140 .reg = WM8350_INT_OFFSET_1,
0141 .mask = WM8350_CHG_VBATT_LT_3P1_EINT,
0142 },
0143 [WM8350_IRQ_CHG_VBATT_LT_2P85] = {
0144 .primary = WM8350_CHG_INT,
0145 .reg = WM8350_INT_OFFSET_1,
0146 .mask = WM8350_CHG_VBATT_LT_2P85_EINT,
0147 },
0148 [WM8350_IRQ_RTC_ALM] = {
0149 .primary = WM8350_RTC_INT,
0150 .reg = WM8350_INT_OFFSET_1,
0151 .mask = WM8350_RTC_ALM_EINT,
0152 },
0153 [WM8350_IRQ_RTC_SEC] = {
0154 .primary = WM8350_RTC_INT,
0155 .reg = WM8350_INT_OFFSET_1,
0156 .mask = WM8350_RTC_SEC_EINT,
0157 },
0158 [WM8350_IRQ_RTC_PER] = {
0159 .primary = WM8350_RTC_INT,
0160 .reg = WM8350_INT_OFFSET_1,
0161 .mask = WM8350_RTC_PER_EINT,
0162 },
0163 [WM8350_IRQ_CS1] = {
0164 .primary = WM8350_CS_INT,
0165 .reg = WM8350_INT_OFFSET_2,
0166 .mask = WM8350_CS1_EINT,
0167 },
0168 [WM8350_IRQ_CS2] = {
0169 .primary = WM8350_CS_INT,
0170 .reg = WM8350_INT_OFFSET_2,
0171 .mask = WM8350_CS2_EINT,
0172 },
0173 [WM8350_IRQ_SYS_HYST_COMP_FAIL] = {
0174 .primary = WM8350_SYS_INT,
0175 .reg = WM8350_INT_OFFSET_2,
0176 .mask = WM8350_SYS_HYST_COMP_FAIL_EINT,
0177 },
0178 [WM8350_IRQ_SYS_CHIP_GT115] = {
0179 .primary = WM8350_SYS_INT,
0180 .reg = WM8350_INT_OFFSET_2,
0181 .mask = WM8350_SYS_CHIP_GT115_EINT,
0182 },
0183 [WM8350_IRQ_SYS_CHIP_GT140] = {
0184 .primary = WM8350_SYS_INT,
0185 .reg = WM8350_INT_OFFSET_2,
0186 .mask = WM8350_SYS_CHIP_GT140_EINT,
0187 },
0188 [WM8350_IRQ_SYS_WDOG_TO] = {
0189 .primary = WM8350_SYS_INT,
0190 .reg = WM8350_INT_OFFSET_2,
0191 .mask = WM8350_SYS_WDOG_TO_EINT,
0192 },
0193 [WM8350_IRQ_AUXADC_DATARDY] = {
0194 .primary = WM8350_AUXADC_INT,
0195 .reg = WM8350_INT_OFFSET_2,
0196 .mask = WM8350_AUXADC_DATARDY_EINT,
0197 },
0198 [WM8350_IRQ_AUXADC_DCOMP4] = {
0199 .primary = WM8350_AUXADC_INT,
0200 .reg = WM8350_INT_OFFSET_2,
0201 .mask = WM8350_AUXADC_DCOMP4_EINT,
0202 },
0203 [WM8350_IRQ_AUXADC_DCOMP3] = {
0204 .primary = WM8350_AUXADC_INT,
0205 .reg = WM8350_INT_OFFSET_2,
0206 .mask = WM8350_AUXADC_DCOMP3_EINT,
0207 },
0208 [WM8350_IRQ_AUXADC_DCOMP2] = {
0209 .primary = WM8350_AUXADC_INT,
0210 .reg = WM8350_INT_OFFSET_2,
0211 .mask = WM8350_AUXADC_DCOMP2_EINT,
0212 },
0213 [WM8350_IRQ_AUXADC_DCOMP1] = {
0214 .primary = WM8350_AUXADC_INT,
0215 .reg = WM8350_INT_OFFSET_2,
0216 .mask = WM8350_AUXADC_DCOMP1_EINT,
0217 },
0218 [WM8350_IRQ_USB_LIMIT] = {
0219 .primary = WM8350_USB_INT,
0220 .reg = WM8350_INT_OFFSET_2,
0221 .mask = WM8350_USB_LIMIT_EINT,
0222 .primary_only = 1,
0223 },
0224 [WM8350_IRQ_WKUP_OFF_STATE] = {
0225 .primary = WM8350_WKUP_INT,
0226 .reg = WM8350_COMPARATOR_INT_OFFSET,
0227 .mask = WM8350_WKUP_OFF_STATE_EINT,
0228 },
0229 [WM8350_IRQ_WKUP_HIB_STATE] = {
0230 .primary = WM8350_WKUP_INT,
0231 .reg = WM8350_COMPARATOR_INT_OFFSET,
0232 .mask = WM8350_WKUP_HIB_STATE_EINT,
0233 },
0234 [WM8350_IRQ_WKUP_CONV_FAULT] = {
0235 .primary = WM8350_WKUP_INT,
0236 .reg = WM8350_COMPARATOR_INT_OFFSET,
0237 .mask = WM8350_WKUP_CONV_FAULT_EINT,
0238 },
0239 [WM8350_IRQ_WKUP_WDOG_RST] = {
0240 .primary = WM8350_WKUP_INT,
0241 .reg = WM8350_COMPARATOR_INT_OFFSET,
0242 .mask = WM8350_WKUP_WDOG_RST_EINT,
0243 },
0244 [WM8350_IRQ_WKUP_GP_PWR_ON] = {
0245 .primary = WM8350_WKUP_INT,
0246 .reg = WM8350_COMPARATOR_INT_OFFSET,
0247 .mask = WM8350_WKUP_GP_PWR_ON_EINT,
0248 },
0249 [WM8350_IRQ_WKUP_ONKEY] = {
0250 .primary = WM8350_WKUP_INT,
0251 .reg = WM8350_COMPARATOR_INT_OFFSET,
0252 .mask = WM8350_WKUP_ONKEY_EINT,
0253 },
0254 [WM8350_IRQ_WKUP_GP_WAKEUP] = {
0255 .primary = WM8350_WKUP_INT,
0256 .reg = WM8350_COMPARATOR_INT_OFFSET,
0257 .mask = WM8350_WKUP_GP_WAKEUP_EINT,
0258 },
0259 [WM8350_IRQ_CODEC_JCK_DET_L] = {
0260 .primary = WM8350_CODEC_INT,
0261 .reg = WM8350_COMPARATOR_INT_OFFSET,
0262 .mask = WM8350_CODEC_JCK_DET_L_EINT,
0263 },
0264 [WM8350_IRQ_CODEC_JCK_DET_R] = {
0265 .primary = WM8350_CODEC_INT,
0266 .reg = WM8350_COMPARATOR_INT_OFFSET,
0267 .mask = WM8350_CODEC_JCK_DET_R_EINT,
0268 },
0269 [WM8350_IRQ_CODEC_MICSCD] = {
0270 .primary = WM8350_CODEC_INT,
0271 .reg = WM8350_COMPARATOR_INT_OFFSET,
0272 .mask = WM8350_CODEC_MICSCD_EINT,
0273 },
0274 [WM8350_IRQ_CODEC_MICD] = {
0275 .primary = WM8350_CODEC_INT,
0276 .reg = WM8350_COMPARATOR_INT_OFFSET,
0277 .mask = WM8350_CODEC_MICD_EINT,
0278 },
0279 [WM8350_IRQ_EXT_USB_FB] = {
0280 .primary = WM8350_EXT_INT,
0281 .reg = WM8350_COMPARATOR_INT_OFFSET,
0282 .mask = WM8350_EXT_USB_FB_EINT,
0283 },
0284 [WM8350_IRQ_EXT_WALL_FB] = {
0285 .primary = WM8350_EXT_INT,
0286 .reg = WM8350_COMPARATOR_INT_OFFSET,
0287 .mask = WM8350_EXT_WALL_FB_EINT,
0288 },
0289 [WM8350_IRQ_EXT_BAT_FB] = {
0290 .primary = WM8350_EXT_INT,
0291 .reg = WM8350_COMPARATOR_INT_OFFSET,
0292 .mask = WM8350_EXT_BAT_FB_EINT,
0293 },
0294 [WM8350_IRQ_GPIO(0)] = {
0295 .primary = WM8350_GP_INT,
0296 .reg = WM8350_GPIO_INT_OFFSET,
0297 .mask = WM8350_GP0_EINT,
0298 },
0299 [WM8350_IRQ_GPIO(1)] = {
0300 .primary = WM8350_GP_INT,
0301 .reg = WM8350_GPIO_INT_OFFSET,
0302 .mask = WM8350_GP1_EINT,
0303 },
0304 [WM8350_IRQ_GPIO(2)] = {
0305 .primary = WM8350_GP_INT,
0306 .reg = WM8350_GPIO_INT_OFFSET,
0307 .mask = WM8350_GP2_EINT,
0308 },
0309 [WM8350_IRQ_GPIO(3)] = {
0310 .primary = WM8350_GP_INT,
0311 .reg = WM8350_GPIO_INT_OFFSET,
0312 .mask = WM8350_GP3_EINT,
0313 },
0314 [WM8350_IRQ_GPIO(4)] = {
0315 .primary = WM8350_GP_INT,
0316 .reg = WM8350_GPIO_INT_OFFSET,
0317 .mask = WM8350_GP4_EINT,
0318 },
0319 [WM8350_IRQ_GPIO(5)] = {
0320 .primary = WM8350_GP_INT,
0321 .reg = WM8350_GPIO_INT_OFFSET,
0322 .mask = WM8350_GP5_EINT,
0323 },
0324 [WM8350_IRQ_GPIO(6)] = {
0325 .primary = WM8350_GP_INT,
0326 .reg = WM8350_GPIO_INT_OFFSET,
0327 .mask = WM8350_GP6_EINT,
0328 },
0329 [WM8350_IRQ_GPIO(7)] = {
0330 .primary = WM8350_GP_INT,
0331 .reg = WM8350_GPIO_INT_OFFSET,
0332 .mask = WM8350_GP7_EINT,
0333 },
0334 [WM8350_IRQ_GPIO(8)] = {
0335 .primary = WM8350_GP_INT,
0336 .reg = WM8350_GPIO_INT_OFFSET,
0337 .mask = WM8350_GP8_EINT,
0338 },
0339 [WM8350_IRQ_GPIO(9)] = {
0340 .primary = WM8350_GP_INT,
0341 .reg = WM8350_GPIO_INT_OFFSET,
0342 .mask = WM8350_GP9_EINT,
0343 },
0344 [WM8350_IRQ_GPIO(10)] = {
0345 .primary = WM8350_GP_INT,
0346 .reg = WM8350_GPIO_INT_OFFSET,
0347 .mask = WM8350_GP10_EINT,
0348 },
0349 [WM8350_IRQ_GPIO(11)] = {
0350 .primary = WM8350_GP_INT,
0351 .reg = WM8350_GPIO_INT_OFFSET,
0352 .mask = WM8350_GP11_EINT,
0353 },
0354 [WM8350_IRQ_GPIO(12)] = {
0355 .primary = WM8350_GP_INT,
0356 .reg = WM8350_GPIO_INT_OFFSET,
0357 .mask = WM8350_GP12_EINT,
0358 },
0359 };
0360
0361 static inline struct wm8350_irq_data *irq_to_wm8350_irq(struct wm8350 *wm8350,
0362 int irq)
0363 {
0364 return &wm8350_irqs[irq - wm8350->irq_base];
0365 }
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376 static irqreturn_t wm8350_irq(int irq, void *irq_data)
0377 {
0378 struct wm8350 *wm8350 = irq_data;
0379 u16 level_one;
0380 u16 sub_reg[WM8350_NUM_IRQ_REGS];
0381 int read_done[WM8350_NUM_IRQ_REGS];
0382 struct wm8350_irq_data *data;
0383 int i;
0384
0385 level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS)
0386 & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK);
0387
0388 if (!level_one)
0389 return IRQ_NONE;
0390
0391 memset(&read_done, 0, sizeof(read_done));
0392
0393 for (i = 0; i < ARRAY_SIZE(wm8350_irqs); i++) {
0394 data = &wm8350_irqs[i];
0395
0396 if (!(level_one & data->primary))
0397 continue;
0398
0399 if (!read_done[data->reg]) {
0400 sub_reg[data->reg] =
0401 wm8350_reg_read(wm8350, WM8350_INT_STATUS_1 +
0402 data->reg);
0403 sub_reg[data->reg] &= ~wm8350->irq_masks[data->reg];
0404 read_done[data->reg] = 1;
0405 }
0406
0407 if (sub_reg[data->reg] & data->mask)
0408 handle_nested_irq(wm8350->irq_base + i);
0409 }
0410
0411 return IRQ_HANDLED;
0412 }
0413
0414 static void wm8350_irq_lock(struct irq_data *data)
0415 {
0416 struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
0417
0418 mutex_lock(&wm8350->irq_lock);
0419 }
0420
0421 static void wm8350_irq_sync_unlock(struct irq_data *data)
0422 {
0423 struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
0424 int i;
0425
0426 for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) {
0427
0428
0429 WARN_ON(regmap_update_bits(wm8350->regmap,
0430 WM8350_INT_STATUS_1_MASK + i,
0431 0xffff, wm8350->irq_masks[i]));
0432 }
0433
0434 mutex_unlock(&wm8350->irq_lock);
0435 }
0436
0437 static void wm8350_irq_enable(struct irq_data *data)
0438 {
0439 struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
0440 struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350,
0441 data->irq);
0442
0443 wm8350->irq_masks[irq_data->reg] &= ~irq_data->mask;
0444 }
0445
0446 static void wm8350_irq_disable(struct irq_data *data)
0447 {
0448 struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
0449 struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350,
0450 data->irq);
0451
0452 wm8350->irq_masks[irq_data->reg] |= irq_data->mask;
0453 }
0454
0455 static struct irq_chip wm8350_irq_chip = {
0456 .name = "wm8350",
0457 .irq_bus_lock = wm8350_irq_lock,
0458 .irq_bus_sync_unlock = wm8350_irq_sync_unlock,
0459 .irq_disable = wm8350_irq_disable,
0460 .irq_enable = wm8350_irq_enable,
0461 };
0462
0463 int wm8350_irq_init(struct wm8350 *wm8350, int irq,
0464 struct wm8350_platform_data *pdata)
0465 {
0466 int ret, cur_irq, i;
0467 int flags = IRQF_ONESHOT;
0468 int irq_base = -1;
0469
0470 if (!irq) {
0471 dev_warn(wm8350->dev, "No interrupt support, no core IRQ\n");
0472 return 0;
0473 }
0474
0475
0476 wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
0477
0478
0479
0480
0481 for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) {
0482 wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK + i,
0483 0xFFFF);
0484 wm8350->irq_masks[i] =
0485 wm8350_reg_read(wm8350,
0486 WM8350_INT_STATUS_1_MASK + i);
0487 }
0488
0489 mutex_init(&wm8350->irq_lock);
0490 wm8350->chip_irq = irq;
0491
0492 if (pdata && pdata->irq_base > 0)
0493 irq_base = pdata->irq_base;
0494
0495 wm8350->irq_base =
0496 irq_alloc_descs(irq_base, 0, ARRAY_SIZE(wm8350_irqs), 0);
0497 if (wm8350->irq_base < 0) {
0498 dev_warn(wm8350->dev, "Allocating irqs failed with %d\n",
0499 wm8350->irq_base);
0500 return 0;
0501 }
0502
0503 if (pdata && pdata->irq_high) {
0504 flags |= IRQF_TRIGGER_HIGH;
0505
0506 wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
0507 WM8350_IRQ_POL);
0508 } else {
0509 flags |= IRQF_TRIGGER_LOW;
0510
0511 wm8350_clear_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
0512 WM8350_IRQ_POL);
0513 }
0514
0515
0516 for (cur_irq = wm8350->irq_base;
0517 cur_irq < ARRAY_SIZE(wm8350_irqs) + wm8350->irq_base;
0518 cur_irq++) {
0519 irq_set_chip_data(cur_irq, wm8350);
0520 irq_set_chip_and_handler(cur_irq, &wm8350_irq_chip,
0521 handle_edge_irq);
0522 irq_set_nested_thread(cur_irq, 1);
0523
0524 irq_clear_status_flags(cur_irq, IRQ_NOREQUEST | IRQ_NOPROBE);
0525 }
0526
0527 ret = request_threaded_irq(irq, NULL, wm8350_irq, flags,
0528 "wm8350", wm8350);
0529 if (ret != 0)
0530 dev_err(wm8350->dev, "Failed to request IRQ: %d\n", ret);
0531
0532
0533 wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0);
0534
0535 return ret;
0536 }
0537
0538 int wm8350_irq_exit(struct wm8350 *wm8350)
0539 {
0540 free_irq(wm8350->chip_irq, wm8350);
0541 return 0;
0542 }