Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * wm8994-irq.c  --  Interrupt controller support for Wolfson WM8994
0004  *
0005  * Copyright 2010 Wolfson Microelectronics PLC.
0006  *
0007  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
0008  */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/gpio.h>
0013 #include <linux/i2c.h>
0014 #include <linux/irq.h>
0015 #include <linux/mfd/core.h>
0016 #include <linux/interrupt.h>
0017 #include <linux/irqdomain.h>
0018 #include <linux/regmap.h>
0019 
0020 #include <linux/mfd/wm8994/core.h>
0021 #include <linux/mfd/wm8994/pdata.h>
0022 #include <linux/mfd/wm8994/registers.h>
0023 
0024 #include <linux/delay.h>
0025 
0026 static const struct regmap_irq wm8994_irqs[] = {
0027     [WM8994_IRQ_TEMP_SHUT] = {
0028         .reg_offset = 1,
0029         .mask = WM8994_TEMP_SHUT_EINT,
0030     },
0031     [WM8994_IRQ_MIC1_DET] = {
0032         .reg_offset = 1,
0033         .mask = WM8994_MIC1_DET_EINT,
0034     },
0035     [WM8994_IRQ_MIC1_SHRT] = {
0036         .reg_offset = 1,
0037         .mask = WM8994_MIC1_SHRT_EINT,
0038     },
0039     [WM8994_IRQ_MIC2_DET] = {
0040         .reg_offset = 1,
0041         .mask = WM8994_MIC2_DET_EINT,
0042     },
0043     [WM8994_IRQ_MIC2_SHRT] = {
0044         .reg_offset = 1,
0045         .mask = WM8994_MIC2_SHRT_EINT,
0046     },
0047     [WM8994_IRQ_FLL1_LOCK] = {
0048         .reg_offset = 1,
0049         .mask = WM8994_FLL1_LOCK_EINT,
0050     },
0051     [WM8994_IRQ_FLL2_LOCK] = {
0052         .reg_offset = 1,
0053         .mask = WM8994_FLL2_LOCK_EINT,
0054     },
0055     [WM8994_IRQ_SRC1_LOCK] = {
0056         .reg_offset = 1,
0057         .mask = WM8994_SRC1_LOCK_EINT,
0058     },
0059     [WM8994_IRQ_SRC2_LOCK] = {
0060         .reg_offset = 1,
0061         .mask = WM8994_SRC2_LOCK_EINT,
0062     },
0063     [WM8994_IRQ_AIF1DRC1_SIG_DET] = {
0064         .reg_offset = 1,
0065         .mask = WM8994_AIF1DRC1_SIG_DET,
0066     },
0067     [WM8994_IRQ_AIF1DRC2_SIG_DET] = {
0068         .reg_offset = 1,
0069         .mask = WM8994_AIF1DRC2_SIG_DET_EINT,
0070     },
0071     [WM8994_IRQ_AIF2DRC_SIG_DET] = {
0072         .reg_offset = 1,
0073         .mask = WM8994_AIF2DRC_SIG_DET_EINT,
0074     },
0075     [WM8994_IRQ_FIFOS_ERR] = {
0076         .reg_offset = 1,
0077         .mask = WM8994_FIFOS_ERR_EINT,
0078     },
0079     [WM8994_IRQ_WSEQ_DONE] = {
0080         .reg_offset = 1,
0081         .mask = WM8994_WSEQ_DONE_EINT,
0082     },
0083     [WM8994_IRQ_DCS_DONE] = {
0084         .reg_offset = 1,
0085         .mask = WM8994_DCS_DONE_EINT,
0086     },
0087     [WM8994_IRQ_TEMP_WARN] = {
0088         .reg_offset = 1,
0089         .mask = WM8994_TEMP_WARN_EINT,
0090     },
0091     [WM8994_IRQ_GPIO(1)] = {
0092         .mask = WM8994_GP1_EINT,
0093     },
0094     [WM8994_IRQ_GPIO(2)] = {
0095         .mask = WM8994_GP2_EINT,
0096     },
0097     [WM8994_IRQ_GPIO(3)] = {
0098         .mask = WM8994_GP3_EINT,
0099     },
0100     [WM8994_IRQ_GPIO(4)] = {
0101         .mask = WM8994_GP4_EINT,
0102     },
0103     [WM8994_IRQ_GPIO(5)] = {
0104         .mask = WM8994_GP5_EINT,
0105     },
0106     [WM8994_IRQ_GPIO(6)] = {
0107         .mask = WM8994_GP6_EINT,
0108     },
0109     [WM8994_IRQ_GPIO(7)] = {
0110         .mask = WM8994_GP7_EINT,
0111     },
0112     [WM8994_IRQ_GPIO(8)] = {
0113         .mask = WM8994_GP8_EINT,
0114     },
0115     [WM8994_IRQ_GPIO(9)] = {
0116         .mask = WM8994_GP8_EINT,
0117     },
0118     [WM8994_IRQ_GPIO(10)] = {
0119         .mask = WM8994_GP10_EINT,
0120     },
0121     [WM8994_IRQ_GPIO(11)] = {
0122         .mask = WM8994_GP11_EINT,
0123     },
0124 };
0125 
0126 static const struct regmap_irq_chip wm8994_irq_chip = {
0127     .name = "wm8994",
0128     .irqs = wm8994_irqs,
0129     .num_irqs = ARRAY_SIZE(wm8994_irqs),
0130 
0131     .num_regs = 2,
0132     .status_base = WM8994_INTERRUPT_STATUS_1,
0133     .mask_base = WM8994_INTERRUPT_STATUS_1_MASK,
0134     .ack_base = WM8994_INTERRUPT_STATUS_1,
0135     .runtime_pm = true,
0136 };
0137 
0138 static void wm8994_edge_irq_enable(struct irq_data *data)
0139 {
0140 }
0141 
0142 static void wm8994_edge_irq_disable(struct irq_data *data)
0143 {
0144 }
0145 
0146 static struct irq_chip wm8994_edge_irq_chip = {
0147     .name           = "wm8994_edge",
0148     .irq_disable        = wm8994_edge_irq_disable,
0149     .irq_enable     = wm8994_edge_irq_enable,
0150 };
0151 
0152 static irqreturn_t wm8994_edge_irq(int irq, void *data)
0153 {
0154     struct wm8994 *wm8994 = data;
0155 
0156     while (gpio_get_value_cansleep(wm8994->pdata.irq_gpio))
0157         handle_nested_irq(irq_find_mapping(wm8994->edge_irq, 0));
0158 
0159     return IRQ_HANDLED;
0160 }
0161 
0162 static int wm8994_edge_irq_map(struct irq_domain *h, unsigned int virq,
0163                    irq_hw_number_t hw)
0164 {
0165     struct wm8994 *wm8994 = h->host_data;
0166 
0167     irq_set_chip_data(virq, wm8994);
0168     irq_set_chip_and_handler(virq, &wm8994_edge_irq_chip, handle_edge_irq);
0169     irq_set_nested_thread(virq, 1);
0170     irq_set_noprobe(virq);
0171 
0172     return 0;
0173 }
0174 
0175 static const struct irq_domain_ops wm8994_edge_irq_ops = {
0176     .map    = wm8994_edge_irq_map,
0177     .xlate  = irq_domain_xlate_twocell,
0178 };
0179 
0180 int wm8994_irq_init(struct wm8994 *wm8994)
0181 {
0182     int ret;
0183     unsigned long irqflags;
0184     struct wm8994_pdata *pdata = &wm8994->pdata;
0185 
0186     if (!wm8994->irq) {
0187         dev_warn(wm8994->dev,
0188              "No interrupt specified, no interrupts\n");
0189         wm8994->irq_base = 0;
0190         return 0;
0191     }
0192 
0193     /* select user or default irq flags */
0194     irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
0195     if (pdata->irq_flags)
0196         irqflags = pdata->irq_flags;
0197 
0198     /* use a GPIO for edge triggered controllers */
0199     if (irqflags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
0200         if (gpio_to_irq(pdata->irq_gpio) != wm8994->irq) {
0201             dev_warn(wm8994->dev, "IRQ %d is not GPIO %d (%d)\n",
0202                  wm8994->irq, pdata->irq_gpio,
0203                  gpio_to_irq(pdata->irq_gpio));
0204             wm8994->irq = gpio_to_irq(pdata->irq_gpio);
0205         }
0206 
0207         ret = devm_gpio_request_one(wm8994->dev, pdata->irq_gpio,
0208                         GPIOF_IN, "WM8994 IRQ");
0209 
0210         if (ret != 0) {
0211             dev_err(wm8994->dev, "Failed to get IRQ GPIO: %d\n",
0212                 ret);
0213             return ret;
0214         }
0215 
0216         wm8994->edge_irq = irq_domain_add_linear(NULL, 1,
0217                              &wm8994_edge_irq_ops,
0218                              wm8994);
0219 
0220         ret = regmap_add_irq_chip(wm8994->regmap,
0221                       irq_create_mapping(wm8994->edge_irq,
0222                                  0),
0223                       IRQF_ONESHOT,
0224                       wm8994->irq_base, &wm8994_irq_chip,
0225                       &wm8994->irq_data);
0226         if (ret != 0) {
0227             dev_err(wm8994->dev, "Failed to get IRQ: %d\n",
0228                 ret);
0229             return ret;
0230         }
0231 
0232         ret = request_threaded_irq(wm8994->irq,
0233                        NULL, wm8994_edge_irq,
0234                        irqflags,
0235                        "WM8994 edge", wm8994);
0236     } else {
0237         ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq,
0238                       irqflags,
0239                       wm8994->irq_base, &wm8994_irq_chip,
0240                       &wm8994->irq_data);
0241     }
0242 
0243     if (ret != 0) {
0244         dev_err(wm8994->dev, "Failed to register IRQ chip: %d\n", ret);
0245         return ret;
0246     }
0247 
0248     /* Enable top level interrupt if it was masked */
0249     wm8994_reg_write(wm8994, WM8994_INTERRUPT_CONTROL, 0);
0250 
0251     return 0;
0252 }
0253 EXPORT_SYMBOL(wm8994_irq_init);
0254 
0255 void wm8994_irq_exit(struct wm8994 *wm8994)
0256 {
0257     regmap_del_irq_chip(wm8994->irq, wm8994->irq_data);
0258 }
0259 EXPORT_SYMBOL(wm8994_irq_exit);