288 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * DA9052 interrupt support4 *5 * Author: Fabio Estevam <fabio.estevam@freescale.com>6 * Based on arizona-irq.c, which is:7 *8 * Copyright 2012 Wolfson Microelectronics plc9 *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 426#define DA9052_IRQ_MASK_POS_1 0x0127#define DA9052_IRQ_MASK_POS_2 0x0228#define DA9052_IRQ_MASK_POS_3 0x0429#define DA9052_IRQ_MASK_POS_4 0x0830#define DA9052_IRQ_MASK_POS_5 0x1031#define DA9052_IRQ_MASK_POS_6 0x2032#define DA9052_IRQ_MASK_POS_7 0x4033#define DA9052_IRQ_MASK_POS_8 0x8034 35static 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 166static 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 176static int da9052_map_irq(struct da9052 *da9052, int irq)177{178 return regmap_irq_get_virq(da9052->irq_data, irq);179}180 181int 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}191EXPORT_SYMBOL_GPL(da9052_enable_irq);192 193int 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}203EXPORT_SYMBOL_GPL(da9052_disable_irq);204 205int 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}215EXPORT_SYMBOL_GPL(da9052_disable_irq_nosync);216 217int 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}228EXPORT_SYMBOL_GPL(da9052_request_irq);229 230void 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}238EXPORT_SYMBOL_GPL(da9052_free_irq);239 240static 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 249int 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 274request_irq_err:275 regmap_del_irq_chip(da9052->chip_irq, da9052->irq_data);276regmap_err:277 return ret;278 279}280 281int 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