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(unsigned int irq) 160 { 161 struct wm8994 *wm8994 = get_irq_chip_data(irq); 162 163 mutex_lock(&wm8994->irq_lock); 164 } 165 166 static void wm8994_irq_sync_unlock(unsigned int irq) 167 { 168 struct wm8994 *wm8994 = get_irq_chip_data(irq); 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_unmask(unsigned int irq) 186 { 187 struct wm8994 *wm8994 = get_irq_chip_data(irq); 188 struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq); 189 190 wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; 191 } 192 193 static void wm8994_irq_mask(unsigned int irq) 194 { 195 struct wm8994 *wm8994 = get_irq_chip_data(irq); 196 struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq); 197 198 wm8994->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; 199 } 200 201 static struct irq_chip wm8994_irq_chip = { 202 .name = "wm8994", 203 .bus_lock = wm8994_irq_lock, 204 .bus_sync_unlock = wm8994_irq_sync_unlock, 205 .mask = wm8994_irq_mask, 206 .unmask = wm8994_irq_unmask, 207 }; 208 209 /* The processing of the primary interrupt occurs in a thread so that 210 * we can interact with the device over I2C or SPI. */ 211 static irqreturn_t wm8994_irq_thread(int irq, void *data) 212 { 213 struct wm8994 *wm8994 = data; 214 unsigned int i; 215 u16 status[WM8994_NUM_IRQ_REGS]; 216 int ret; 217 218 ret = wm8994_bulk_read(wm8994, WM8994_INTERRUPT_STATUS_1, 219 WM8994_NUM_IRQ_REGS, status); 220 if (ret < 0) { 221 dev_err(wm8994->dev, "Failed to read interrupt status: %d\n", 222 ret); 223 return IRQ_NONE; 224 } 225 226 /* Apply masking */ 227 for (i = 0; i < WM8994_NUM_IRQ_REGS; i++) 228 status[i] &= ~wm8994->irq_masks_cur[i]; 229 230 /* Report */ 231 for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) { 232 if (status[wm8994_irqs[i].reg - 1] & wm8994_irqs[i].mask) 233 handle_nested_irq(wm8994->irq_base + i); 234 } 235 236 /* Ack any unmasked IRQs */ 237 for (i = 0; i < ARRAY_SIZE(status); i++) { 238 if (status[i]) 239 wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1 + i, 240 status[i]); 241 } 242 243 return IRQ_HANDLED; 244 } 245 246 int wm8994_irq_init(struct wm8994 *wm8994) 247 { 248 int i, cur_irq, ret; 249 250 mutex_init(&wm8994->irq_lock); 251 252 /* Mask the individual interrupt sources */ 253 for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) { 254 wm8994->irq_masks_cur[i] = 0xffff; 255 wm8994->irq_masks_cache[i] = 0xffff; 256 wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK + i, 257 0xffff); 258 } 259 260 if (!wm8994->irq) { 261 dev_warn(wm8994->dev, 262 "No interrupt specified, no interrupts\n"); 263 wm8994->irq_base = 0; 264 return 0; 265 } 266 267 if (!wm8994->irq_base) { 268 dev_err(wm8994->dev, 269 "No interrupt base specified, no interrupts\n"); 270 return 0; 271 } 272 273 /* Register them with genirq */ 274 for (cur_irq = wm8994->irq_base; 275 cur_irq < ARRAY_SIZE(wm8994_irqs) + wm8994->irq_base; 276 cur_irq++) { 277 set_irq_chip_data(cur_irq, wm8994); 278 set_irq_chip_and_handler(cur_irq, &wm8994_irq_chip, 279 handle_edge_irq); 280 set_irq_nested_thread(cur_irq, 1); 281 282 /* ARM needs us to explicitly flag the IRQ as valid 283 * and will set them noprobe when we do so. */ 284 #ifdef CONFIG_ARM 285 set_irq_flags(cur_irq, IRQF_VALID); 286 #else 287 set_irq_noprobe(cur_irq); 288 #endif 289 } 290 291 ret = request_threaded_irq(wm8994->irq, NULL, wm8994_irq_thread, 292 IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 293 "wm8994", wm8994); 294 if (ret != 0) { 295 dev_err(wm8994->dev, "Failed to request IRQ %d: %d\n", 296 wm8994->irq, ret); 297 return ret; 298 } 299 300 /* Enable top level interrupt if it was masked */ 301 wm8994_reg_write(wm8994, WM8994_INTERRUPT_CONTROL, 0); 302 303 return 0; 304 } 305 306 void wm8994_irq_exit(struct wm8994 *wm8994) 307 { 308 if (wm8994->irq) 309 free_irq(wm8994->irq, wm8994); 310 } 311