1 /* 2 * wm8994-irq.c -- Interrupt controller support for Wolfson WM8994 3 * 4 * Copyright 2010 Wolfson Microelectronics PLC. 5 * 6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 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/i2c.h> 18 #include <linux/irq.h> 19 #include <linux/mfd/core.h> 20 #include <linux/interrupt.h> 21 22 #include <linux/mfd/wm8994/core.h> 23 #include <linux/mfd/wm8994/registers.h> 24 25 #include <linux/delay.h> 26 27 struct wm8994_irq_data { 28 int reg; 29 int mask; 30 }; 31 32 static struct wm8994_irq_data wm8994_irqs[] = { 33 [WM8994_IRQ_TEMP_SHUT] = { 34 .reg = 2, 35 .mask = WM8994_TEMP_SHUT_EINT, 36 }, 37 [WM8994_IRQ_MIC1_DET] = { 38 .reg = 2, 39 .mask = WM8994_MIC1_DET_EINT, 40 }, 41 [WM8994_IRQ_MIC1_SHRT] = { 42 .reg = 2, 43 .mask = WM8994_MIC1_SHRT_EINT, 44 }, 45 [WM8994_IRQ_MIC2_DET] = { 46 .reg = 2, 47 .mask = WM8994_MIC2_DET_EINT, 48 }, 49 [WM8994_IRQ_MIC2_SHRT] = { 50 .reg = 2, 51 .mask = WM8994_MIC2_SHRT_EINT, 52 }, 53 [WM8994_IRQ_FLL1_LOCK] = { 54 .reg = 2, 55 .mask = WM8994_FLL1_LOCK_EINT, 56 }, 57 [WM8994_IRQ_FLL2_LOCK] = { 58 .reg = 2, 59 .mask = WM8994_FLL2_LOCK_EINT, 60 }, 61 [WM8994_IRQ_SRC1_LOCK] = { 62 .reg = 2, 63 .mask = WM8994_SRC1_LOCK_EINT, 64 }, 65 [WM8994_IRQ_SRC2_LOCK] = { 66 .reg = 2, 67 .mask = WM8994_SRC2_LOCK_EINT, 68 }, 69 [WM8994_IRQ_AIF1DRC1_SIG_DET] = { 70 .reg = 2, 71 .mask = WM8994_AIF1DRC1_SIG_DET, 72 }, 73 [WM8994_IRQ_AIF1DRC2_SIG_DET] = { 74 .reg = 2, 75 .mask = WM8994_AIF1DRC2_SIG_DET_EINT, 76 }, 77 [WM8994_IRQ_AIF2DRC_SIG_DET] = { 78 .reg = 2, 79 .mask = WM8994_AIF2DRC_SIG_DET_EINT, 80 }, 81 [WM8994_IRQ_FIFOS_ERR] = { 82 .reg = 2, 83 .mask = WM8994_FIFOS_ERR_EINT, 84 }, 85 [WM8994_IRQ_WSEQ_DONE] = { 86 .reg = 2, 87 .mask = WM8994_WSEQ_DONE_EINT, 88 }, 89 [WM8994_IRQ_DCS_DONE] = { 90 .reg = 2, 91 .mask = WM8994_DCS_DONE_EINT, 92 }, 93 [WM8994_IRQ_TEMP_WARN] = { 94 .reg = 2, 95 .mask = WM8994_TEMP_WARN_EINT, 96 }, 97 [WM8994_IRQ_GPIO(1)] = { 98 .reg = 1, 99 .mask = WM8994_GP1_EINT, 100 }, 101 [WM8994_IRQ_GPIO(2)] = { 102 .reg = 1, 103 .mask = WM8994_GP2_EINT, 104 }, 105 [WM8994_IRQ_GPIO(3)] = { 106 .reg = 1, 107 .mask = WM8994_GP3_EINT, 108 }, 109 [WM8994_IRQ_GPIO(4)] = { 110 .reg = 1, 111 .mask = WM8994_GP4_EINT, 112 }, 113 [WM8994_IRQ_GPIO(5)] = { 114 .reg = 1, 115 .mask = WM8994_GP5_EINT, 116 }, 117 [WM8994_IRQ_GPIO(6)] = { 118 .reg = 1, 119 .mask = WM8994_GP6_EINT, 120 }, 121 [WM8994_IRQ_GPIO(7)] = { 122 .reg = 1, 123 .mask = WM8994_GP7_EINT, 124 }, 125 [WM8994_IRQ_GPIO(8)] = { 126 .reg = 1, 127 .mask = WM8994_GP8_EINT, 128 }, 129 [WM8994_IRQ_GPIO(9)] = { 130 .reg = 1, 131 .mask = WM8994_GP8_EINT, 132 }, 133 [WM8994_IRQ_GPIO(10)] = { 134 .reg = 1, 135 .mask = WM8994_GP10_EINT, 136 }, 137 [WM8994_IRQ_GPIO(11)] = { 138 .reg = 1, 139 .mask = WM8994_GP11_EINT, 140 }, 141 }; 142 143 static inline int irq_data_to_status_reg(struct wm8994_irq_data *irq_data) 144 { 145 return WM8994_INTERRUPT_STATUS_1 - 1 + irq_data->reg; 146 } 147 148 static inline int irq_data_to_mask_reg(struct wm8994_irq_data *irq_data) 149 { 150 return WM8994_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg; 151 } 152 153 static inline struct wm8994_irq_data *irq_to_wm8994_irq(struct wm8994 *wm8994, 154 int irq) 155 { 156 return &wm8994_irqs[irq - wm8994->irq_base]; 157 } 158 159 static void wm8994_irq_lock(struct irq_data *data) 160 { 161 struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); 162 163 mutex_lock(&wm8994->irq_lock); 164 } 165 166 static void wm8994_irq_sync_unlock(struct irq_data *data) 167 { 168 struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); 169 int i; 170 171 for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) { 172 /* If there's been a change in the mask write it back 173 * to the hardware. */ 174 if (wm8994->irq_masks_cur[i] != wm8994->irq_masks_cache[i]) { 175 wm8994->irq_masks_cache[i] = wm8994->irq_masks_cur[i]; 176 wm8994_reg_write(wm8994, 177 WM8994_INTERRUPT_STATUS_1_MASK + i, 178 wm8994->irq_masks_cur[i]); 179 } 180 } 181 182 mutex_unlock(&wm8994->irq_lock); 183 } 184 185 static void wm8994_irq_enable(struct irq_data *data) 186 { 187 struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); 188 struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, 189 data->irq); 190 191 wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; 192 } 193 194 static void wm8994_irq_disable(struct irq_data *data) 195 { 196 struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); 197 struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, 198 data->irq); 199 200 wm8994->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; 201 } 202 203 static struct irq_chip wm8994_irq_chip = { 204 .name = "wm8994", 205 .irq_bus_lock = wm8994_irq_lock, 206 .irq_bus_sync_unlock = wm8994_irq_sync_unlock, 207 .irq_disable = wm8994_irq_disable, 208 .irq_enable = wm8994_irq_enable, 209 }; 210 211 /* The processing of the primary interrupt occurs in a thread so that 212 * we can interact with the device over I2C or SPI. */ 213 static irqreturn_t wm8994_irq_thread(int irq, void *data) 214 { 215 struct wm8994 *wm8994 = data; 216 unsigned int i; 217 u16 status[WM8994_NUM_IRQ_REGS]; 218 int ret; 219 220 ret = wm8994_bulk_read(wm8994, WM8994_INTERRUPT_STATUS_1, 221 WM8994_NUM_IRQ_REGS, status); 222 if (ret < 0) { 223 dev_err(wm8994->dev, "Failed to read interrupt status: %d\n", 224 ret); 225 return IRQ_NONE; 226 } 227 228 /* Bit swap and apply masking */ 229 for (i = 0; i < WM8994_NUM_IRQ_REGS; i++) { 230 status[i] = be16_to_cpu(status[i]); 231 status[i] &= ~wm8994->irq_masks_cur[i]; 232 } 233 234 /* Ack any unmasked IRQs */ 235 for (i = 0; i < ARRAY_SIZE(status); i++) { 236 if (status[i]) 237 wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1 + i, 238 status[i]); 239 } 240 241 /* Report */ 242 for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) { 243 if (status[wm8994_irqs[i].reg - 1] & wm8994_irqs[i].mask) 244 handle_nested_irq(wm8994->irq_base + i); 245 } 246 247 return IRQ_HANDLED; 248 } 249 250 int wm8994_irq_init(struct wm8994 *wm8994) 251 { 252 int i, cur_irq, ret; 253 254 mutex_init(&wm8994->irq_lock); 255 256 /* Mask the individual interrupt sources */ 257 for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) { 258 wm8994->irq_masks_cur[i] = 0xffff; 259 wm8994->irq_masks_cache[i] = 0xffff; 260 wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK + i, 261 0xffff); 262 } 263 264 if (!wm8994->irq) { 265 dev_warn(wm8994->dev, 266 "No interrupt specified, no interrupts\n"); 267 wm8994->irq_base = 0; 268 return 0; 269 } 270 271 if (!wm8994->irq_base) { 272 dev_err(wm8994->dev, 273 "No interrupt base specified, no interrupts\n"); 274 return 0; 275 } 276 277 /* Register them with genirq */ 278 for (cur_irq = wm8994->irq_base; 279 cur_irq < ARRAY_SIZE(wm8994_irqs) + wm8994->irq_base; 280 cur_irq++) { 281 irq_set_chip_data(cur_irq, wm8994); 282 irq_set_chip_and_handler(cur_irq, &wm8994_irq_chip, 283 handle_edge_irq); 284 irq_set_nested_thread(cur_irq, 1); 285 286 /* ARM needs us to explicitly flag the IRQ as valid 287 * and will set them noprobe when we do so. */ 288 #ifdef CONFIG_ARM 289 set_irq_flags(cur_irq, IRQF_VALID); 290 #else 291 irq_set_noprobe(cur_irq); 292 #endif 293 } 294 295 ret = request_threaded_irq(wm8994->irq, NULL, wm8994_irq_thread, 296 IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 297 "wm8994", wm8994); 298 if (ret != 0) { 299 dev_err(wm8994->dev, "Failed to request IRQ %d: %d\n", 300 wm8994->irq, ret); 301 return ret; 302 } 303 304 /* Enable top level interrupt if it was masked */ 305 wm8994_reg_write(wm8994, WM8994_INTERRUPT_CONTROL, 0); 306 307 return 0; 308 } 309 310 void wm8994_irq_exit(struct wm8994 *wm8994) 311 { 312 if (wm8994->irq) 313 free_irq(wm8994->irq, wm8994); 314 } 315