1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * DA9052 interrupt support 4 * 5 * Author: Fabio Estevam <fabio.estevam@freescale.com> 6 * Based on arizona-irq.c, which is: 7 * 8 * Copyright 2012 Wolfson Microelectronics plc 9 * 10 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 11 */ 12 13 #include <linux/device.h> 14 #include <linux/delay.h> 15 #include <linux/input.h> 16 #include <linux/interrupt.h> 17 #include <linux/irq.h> 18 #include <linux/irqdomain.h> 19 #include <linux/slab.h> 20 #include <linux/module.h> 21 22 #include <linux/mfd/da9052/da9052.h> 23 #include <linux/mfd/da9052/reg.h> 24 25 #define DA9052_NUM_IRQ_REGS 4 26 #define DA9052_IRQ_MASK_POS_1 0x01 27 #define DA9052_IRQ_MASK_POS_2 0x02 28 #define DA9052_IRQ_MASK_POS_3 0x04 29 #define DA9052_IRQ_MASK_POS_4 0x08 30 #define DA9052_IRQ_MASK_POS_5 0x10 31 #define DA9052_IRQ_MASK_POS_6 0x20 32 #define DA9052_IRQ_MASK_POS_7 0x40 33 #define DA9052_IRQ_MASK_POS_8 0x80 34 35 static const struct regmap_irq da9052_irqs[] = { 36 [DA9052_IRQ_DCIN] = { 37 .reg_offset = 0, 38 .mask = DA9052_IRQ_MASK_POS_1, 39 }, 40 [DA9052_IRQ_VBUS] = { 41 .reg_offset = 0, 42 .mask = DA9052_IRQ_MASK_POS_2, 43 }, 44 [DA9052_IRQ_DCINREM] = { 45 .reg_offset = 0, 46 .mask = DA9052_IRQ_MASK_POS_3, 47 }, 48 [DA9052_IRQ_VBUSREM] = { 49 .reg_offset = 0, 50 .mask = DA9052_IRQ_MASK_POS_4, 51 }, 52 [DA9052_IRQ_VDDLOW] = { 53 .reg_offset = 0, 54 .mask = DA9052_IRQ_MASK_POS_5, 55 }, 56 [DA9052_IRQ_ALARM] = { 57 .reg_offset = 0, 58 .mask = DA9052_IRQ_MASK_POS_6, 59 }, 60 [DA9052_IRQ_SEQRDY] = { 61 .reg_offset = 0, 62 .mask = DA9052_IRQ_MASK_POS_7, 63 }, 64 [DA9052_IRQ_COMP1V2] = { 65 .reg_offset = 0, 66 .mask = DA9052_IRQ_MASK_POS_8, 67 }, 68 [DA9052_IRQ_NONKEY] = { 69 .reg_offset = 1, 70 .mask = DA9052_IRQ_MASK_POS_1, 71 }, 72 [DA9052_IRQ_IDFLOAT] = { 73 .reg_offset = 1, 74 .mask = DA9052_IRQ_MASK_POS_2, 75 }, 76 [DA9052_IRQ_IDGND] = { 77 .reg_offset = 1, 78 .mask = DA9052_IRQ_MASK_POS_3, 79 }, 80 [DA9052_IRQ_CHGEND] = { 81 .reg_offset = 1, 82 .mask = DA9052_IRQ_MASK_POS_4, 83 }, 84 [DA9052_IRQ_TBAT] = { 85 .reg_offset = 1, 86 .mask = DA9052_IRQ_MASK_POS_5, 87 }, 88 [DA9052_IRQ_ADC_EOM] = { 89 .reg_offset = 1, 90 .mask = DA9052_IRQ_MASK_POS_6, 91 }, 92 [DA9052_IRQ_PENDOWN] = { 93 .reg_offset = 1, 94 .mask = DA9052_IRQ_MASK_POS_7, 95 }, 96 [DA9052_IRQ_TSIREADY] = { 97 .reg_offset = 1, 98 .mask = DA9052_IRQ_MASK_POS_8, 99 }, 100 [DA9052_IRQ_GPI0] = { 101 .reg_offset = 2, 102 .mask = DA9052_IRQ_MASK_POS_1, 103 }, 104 [DA9052_IRQ_GPI1] = { 105 .reg_offset = 2, 106 .mask = DA9052_IRQ_MASK_POS_2, 107 }, 108 [DA9052_IRQ_GPI2] = { 109 .reg_offset = 2, 110 .mask = DA9052_IRQ_MASK_POS_3, 111 }, 112 [DA9052_IRQ_GPI3] = { 113 .reg_offset = 2, 114 .mask = DA9052_IRQ_MASK_POS_4, 115 }, 116 [DA9052_IRQ_GPI4] = { 117 .reg_offset = 2, 118 .mask = DA9052_IRQ_MASK_POS_5, 119 }, 120 [DA9052_IRQ_GPI5] = { 121 .reg_offset = 2, 122 .mask = DA9052_IRQ_MASK_POS_6, 123 }, 124 [DA9052_IRQ_GPI6] = { 125 .reg_offset = 2, 126 .mask = DA9052_IRQ_MASK_POS_7, 127 }, 128 [DA9052_IRQ_GPI7] = { 129 .reg_offset = 2, 130 .mask = DA9052_IRQ_MASK_POS_8, 131 }, 132 [DA9052_IRQ_GPI8] = { 133 .reg_offset = 3, 134 .mask = DA9052_IRQ_MASK_POS_1, 135 }, 136 [DA9052_IRQ_GPI9] = { 137 .reg_offset = 3, 138 .mask = DA9052_IRQ_MASK_POS_2, 139 }, 140 [DA9052_IRQ_GPI10] = { 141 .reg_offset = 3, 142 .mask = DA9052_IRQ_MASK_POS_3, 143 }, 144 [DA9052_IRQ_GPI11] = { 145 .reg_offset = 3, 146 .mask = DA9052_IRQ_MASK_POS_4, 147 }, 148 [DA9052_IRQ_GPI12] = { 149 .reg_offset = 3, 150 .mask = DA9052_IRQ_MASK_POS_5, 151 }, 152 [DA9052_IRQ_GPI13] = { 153 .reg_offset = 3, 154 .mask = DA9052_IRQ_MASK_POS_6, 155 }, 156 [DA9052_IRQ_GPI14] = { 157 .reg_offset = 3, 158 .mask = DA9052_IRQ_MASK_POS_7, 159 }, 160 [DA9052_IRQ_GPI15] = { 161 .reg_offset = 3, 162 .mask = DA9052_IRQ_MASK_POS_8, 163 }, 164 }; 165 166 static const struct regmap_irq_chip da9052_regmap_irq_chip = { 167 .name = "da9052_irq", 168 .status_base = DA9052_EVENT_A_REG, 169 .mask_base = DA9052_IRQ_MASK_A_REG, 170 .ack_base = DA9052_EVENT_A_REG, 171 .num_regs = DA9052_NUM_IRQ_REGS, 172 .irqs = da9052_irqs, 173 .num_irqs = ARRAY_SIZE(da9052_irqs), 174 }; 175 176 static int da9052_map_irq(struct da9052 *da9052, int irq) 177 { 178 return regmap_irq_get_virq(da9052->irq_data, irq); 179 } 180 181 int da9052_enable_irq(struct da9052 *da9052, int irq) 182 { 183 irq = da9052_map_irq(da9052, irq); 184 if (irq < 0) 185 return irq; 186 187 enable_irq(irq); 188 189 return 0; 190 } 191 EXPORT_SYMBOL_GPL(da9052_enable_irq); 192 193 int da9052_disable_irq(struct da9052 *da9052, int irq) 194 { 195 irq = da9052_map_irq(da9052, irq); 196 if (irq < 0) 197 return irq; 198 199 disable_irq(irq); 200 201 return 0; 202 } 203 EXPORT_SYMBOL_GPL(da9052_disable_irq); 204 205 int da9052_disable_irq_nosync(struct da9052 *da9052, int irq) 206 { 207 irq = da9052_map_irq(da9052, irq); 208 if (irq < 0) 209 return irq; 210 211 disable_irq_nosync(irq); 212 213 return 0; 214 } 215 EXPORT_SYMBOL_GPL(da9052_disable_irq_nosync); 216 217 int da9052_request_irq(struct da9052 *da9052, int irq, char *name, 218 irq_handler_t handler, void *data) 219 { 220 irq = da9052_map_irq(da9052, irq); 221 if (irq < 0) 222 return irq; 223 224 return request_threaded_irq(irq, NULL, handler, 225 IRQF_TRIGGER_LOW | IRQF_ONESHOT, 226 name, data); 227 } 228 EXPORT_SYMBOL_GPL(da9052_request_irq); 229 230 void da9052_free_irq(struct da9052 *da9052, int irq, void *data) 231 { 232 irq = da9052_map_irq(da9052, irq); 233 if (irq < 0) 234 return; 235 236 free_irq(irq, data); 237 } 238 EXPORT_SYMBOL_GPL(da9052_free_irq); 239 240 static irqreturn_t da9052_auxadc_irq(int irq, void *irq_data) 241 { 242 struct da9052 *da9052 = irq_data; 243 244 complete(&da9052->done); 245 246 return IRQ_HANDLED; 247 } 248 249 int da9052_irq_init(struct da9052 *da9052) 250 { 251 int ret; 252 253 ret = regmap_add_irq_chip(da9052->regmap, da9052->chip_irq, 254 IRQF_TRIGGER_LOW | IRQF_ONESHOT, 255 -1, &da9052_regmap_irq_chip, 256 &da9052->irq_data); 257 if (ret < 0) { 258 dev_err(da9052->dev, "regmap_add_irq_chip failed: %d\n", ret); 259 goto regmap_err; 260 } 261 262 enable_irq_wake(da9052->chip_irq); 263 264 ret = da9052_request_irq(da9052, DA9052_IRQ_ADC_EOM, "adc-irq", 265 da9052_auxadc_irq, da9052); 266 267 if (ret != 0) { 268 dev_err(da9052->dev, "DA9052_IRQ_ADC_EOM failed: %d\n", ret); 269 goto request_irq_err; 270 } 271 272 return 0; 273 274 request_irq_err: 275 regmap_del_irq_chip(da9052->chip_irq, da9052->irq_data); 276 regmap_err: 277 return ret; 278 279 } 280 281 int da9052_irq_exit(struct da9052 *da9052) 282 { 283 da9052_free_irq(da9052, DA9052_IRQ_ADC_EOM, da9052); 284 regmap_del_irq_chip(da9052->chip_irq, da9052->irq_data); 285 286 return 0; 287 } 288