Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Arizona interrupt support
0004  *
0005  * Copyright 2012 Wolfson Microelectronics plc
0006  *
0007  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
0008  */
0009 
0010 #include <linux/delay.h>
0011 #include <linux/gpio.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/irq.h>
0014 #include <linux/irqdomain.h>
0015 #include <linux/module.h>
0016 #include <linux/pm_runtime.h>
0017 #include <linux/regmap.h>
0018 #include <linux/regulator/consumer.h>
0019 #include <linux/slab.h>
0020 
0021 #include <linux/mfd/arizona/core.h>
0022 #include <linux/mfd/arizona/registers.h>
0023 
0024 #include "arizona.h"
0025 
0026 #define ARIZONA_AOD_IRQ_INDEX 0
0027 #define ARIZONA_MAIN_IRQ_INDEX 1
0028 
0029 static int arizona_map_irq(struct arizona *arizona, int irq)
0030 {
0031     int ret;
0032 
0033     if (arizona->aod_irq_chip) {
0034         ret = regmap_irq_get_virq(arizona->aod_irq_chip, irq);
0035         if (ret >= 0)
0036             return ret;
0037     }
0038 
0039     return regmap_irq_get_virq(arizona->irq_chip, irq);
0040 }
0041 
0042 int arizona_request_irq(struct arizona *arizona, int irq, char *name,
0043                irq_handler_t handler, void *data)
0044 {
0045     irq = arizona_map_irq(arizona, irq);
0046     if (irq < 0)
0047         return irq;
0048 
0049     return request_threaded_irq(irq, NULL, handler, IRQF_ONESHOT,
0050                     name, data);
0051 }
0052 EXPORT_SYMBOL_GPL(arizona_request_irq);
0053 
0054 void arizona_free_irq(struct arizona *arizona, int irq, void *data)
0055 {
0056     irq = arizona_map_irq(arizona, irq);
0057     if (irq < 0)
0058         return;
0059 
0060     free_irq(irq, data);
0061 }
0062 EXPORT_SYMBOL_GPL(arizona_free_irq);
0063 
0064 int arizona_set_irq_wake(struct arizona *arizona, int irq, int on)
0065 {
0066     irq = arizona_map_irq(arizona, irq);
0067     if (irq < 0)
0068         return irq;
0069 
0070     return irq_set_irq_wake(irq, on);
0071 }
0072 EXPORT_SYMBOL_GPL(arizona_set_irq_wake);
0073 
0074 static irqreturn_t arizona_boot_done(int irq, void *data)
0075 {
0076     struct arizona *arizona = data;
0077 
0078     dev_dbg(arizona->dev, "Boot done\n");
0079 
0080     return IRQ_HANDLED;
0081 }
0082 
0083 static irqreturn_t arizona_ctrlif_err(int irq, void *data)
0084 {
0085     struct arizona *arizona = data;
0086 
0087     /*
0088      * For pretty much all potential sources a register cache sync
0089      * won't help, we've just got a software bug somewhere.
0090      */
0091     dev_err(arizona->dev, "Control interface error\n");
0092 
0093     return IRQ_HANDLED;
0094 }
0095 
0096 static irqreturn_t arizona_irq_thread(int irq, void *data)
0097 {
0098     struct arizona *arizona = data;
0099     bool poll;
0100     unsigned int val;
0101     int ret;
0102 
0103     ret = pm_runtime_resume_and_get(arizona->dev);
0104     if (ret < 0) {
0105         dev_err(arizona->dev, "Failed to resume device: %d\n", ret);
0106         return IRQ_NONE;
0107     }
0108 
0109     do {
0110         poll = false;
0111 
0112         if (arizona->aod_irq_chip) {
0113             /*
0114              * Check the AOD status register to determine whether
0115              * the nested IRQ handler should be called.
0116              */
0117             ret = regmap_read(arizona->regmap,
0118                       ARIZONA_AOD_IRQ1, &val);
0119             if (ret)
0120                 dev_warn(arizona->dev,
0121                     "Failed to read AOD IRQ1 %d\n", ret);
0122             else if (val)
0123                 handle_nested_irq(
0124                     irq_find_mapping(arizona->virq, 0));
0125         }
0126 
0127         /*
0128          * Check if one of the main interrupts is asserted and only
0129          * check that domain if it is.
0130          */
0131         ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS,
0132                   &val);
0133         if (ret == 0 && val & ARIZONA_IRQ1_STS) {
0134             handle_nested_irq(irq_find_mapping(arizona->virq, 1));
0135         } else if (ret != 0) {
0136             dev_err(arizona->dev,
0137                 "Failed to read main IRQ status: %d\n", ret);
0138         }
0139 
0140         /*
0141          * Poll the IRQ pin status to see if we're really done
0142          * if the interrupt controller can't do it for us.
0143          */
0144         if (!arizona->pdata.irq_gpio) {
0145             break;
0146         } else if (arizona->pdata.irq_flags & IRQF_TRIGGER_RISING &&
0147                gpio_get_value_cansleep(arizona->pdata.irq_gpio)) {
0148             poll = true;
0149         } else if (arizona->pdata.irq_flags & IRQF_TRIGGER_FALLING &&
0150                !gpio_get_value_cansleep(arizona->pdata.irq_gpio)) {
0151             poll = true;
0152         }
0153     } while (poll);
0154 
0155     pm_runtime_mark_last_busy(arizona->dev);
0156     pm_runtime_put_autosuspend(arizona->dev);
0157 
0158     return IRQ_HANDLED;
0159 }
0160 
0161 static void arizona_irq_enable(struct irq_data *data)
0162 {
0163 }
0164 
0165 static void arizona_irq_disable(struct irq_data *data)
0166 {
0167 }
0168 
0169 static int arizona_irq_set_wake(struct irq_data *data, unsigned int on)
0170 {
0171     struct arizona *arizona = irq_data_get_irq_chip_data(data);
0172 
0173     return irq_set_irq_wake(arizona->irq, on);
0174 }
0175 
0176 static struct irq_chip arizona_irq_chip = {
0177     .name           = "arizona",
0178     .irq_disable        = arizona_irq_disable,
0179     .irq_enable     = arizona_irq_enable,
0180     .irq_set_wake       = arizona_irq_set_wake,
0181 };
0182 
0183 static struct lock_class_key arizona_irq_lock_class;
0184 static struct lock_class_key arizona_irq_request_class;
0185 
0186 static int arizona_irq_map(struct irq_domain *h, unsigned int virq,
0187                   irq_hw_number_t hw)
0188 {
0189     struct arizona *data = h->host_data;
0190 
0191     irq_set_chip_data(virq, data);
0192     irq_set_lockdep_class(virq, &arizona_irq_lock_class,
0193         &arizona_irq_request_class);
0194     irq_set_chip_and_handler(virq, &arizona_irq_chip, handle_simple_irq);
0195     irq_set_nested_thread(virq, 1);
0196     irq_set_noprobe(virq);
0197 
0198     return 0;
0199 }
0200 
0201 static const struct irq_domain_ops arizona_domain_ops = {
0202     .map    = arizona_irq_map,
0203     .xlate  = irq_domain_xlate_twocell,
0204 };
0205 
0206 int arizona_irq_init(struct arizona *arizona)
0207 {
0208     int flags = IRQF_ONESHOT;
0209     int ret;
0210     const struct regmap_irq_chip *aod, *irq;
0211     struct irq_data *irq_data;
0212     unsigned int virq;
0213 
0214     arizona->ctrlif_error = true;
0215 
0216     switch (arizona->type) {
0217 #ifdef CONFIG_MFD_WM5102
0218     case WM5102:
0219         aod = &wm5102_aod;
0220         irq = &wm5102_irq;
0221 
0222         arizona->ctrlif_error = false;
0223         break;
0224 #endif
0225 #ifdef CONFIG_MFD_WM5110
0226     case WM5110:
0227     case WM8280:
0228         aod = &wm5110_aod;
0229 
0230         switch (arizona->rev) {
0231         case 0 ... 2:
0232             irq = &wm5110_irq;
0233             break;
0234         default:
0235             irq = &wm5110_revd_irq;
0236             break;
0237         }
0238 
0239         arizona->ctrlif_error = false;
0240         break;
0241 #endif
0242 #ifdef CONFIG_MFD_CS47L24
0243     case WM1831:
0244     case CS47L24:
0245         aod = NULL;
0246         irq = &cs47l24_irq;
0247 
0248         arizona->ctrlif_error = false;
0249         break;
0250 #endif
0251 #ifdef CONFIG_MFD_WM8997
0252     case WM8997:
0253         aod = &wm8997_aod;
0254         irq = &wm8997_irq;
0255 
0256         arizona->ctrlif_error = false;
0257         break;
0258 #endif
0259 #ifdef CONFIG_MFD_WM8998
0260     case WM8998:
0261     case WM1814:
0262         aod = &wm8998_aod;
0263         irq = &wm8998_irq;
0264 
0265         arizona->ctrlif_error = false;
0266         break;
0267 #endif
0268     default:
0269         BUG_ON("Unknown Arizona class device" == NULL);
0270         return -EINVAL;
0271     }
0272 
0273     /* Disable all wake sources by default */
0274     regmap_write(arizona->regmap, ARIZONA_WAKE_CONTROL, 0);
0275 
0276     /* Read the flags from the interrupt controller if not specified */
0277     if (!arizona->pdata.irq_flags) {
0278         irq_data = irq_get_irq_data(arizona->irq);
0279         if (!irq_data) {
0280             dev_err(arizona->dev, "Invalid IRQ: %d\n",
0281                 arizona->irq);
0282             return -EINVAL;
0283         }
0284 
0285         arizona->pdata.irq_flags = irqd_get_trigger_type(irq_data);
0286         switch (arizona->pdata.irq_flags) {
0287         case IRQF_TRIGGER_LOW:
0288         case IRQF_TRIGGER_HIGH:
0289         case IRQF_TRIGGER_RISING:
0290         case IRQF_TRIGGER_FALLING:
0291             break;
0292 
0293         case IRQ_TYPE_NONE:
0294         default:
0295             /* Device default */
0296             arizona->pdata.irq_flags = IRQF_TRIGGER_LOW;
0297             break;
0298         }
0299     }
0300 
0301     if (arizona->pdata.irq_flags & (IRQF_TRIGGER_HIGH |
0302                     IRQF_TRIGGER_RISING)) {
0303         ret = regmap_update_bits(arizona->regmap, ARIZONA_IRQ_CTRL_1,
0304                      ARIZONA_IRQ_POL, 0);
0305         if (ret != 0) {
0306             dev_err(arizona->dev, "Couldn't set IRQ polarity: %d\n",
0307                 ret);
0308             goto err;
0309         }
0310     }
0311 
0312     flags |= arizona->pdata.irq_flags;
0313 
0314     /* Allocate a virtual IRQ domain to distribute to the regmap domains */
0315     arizona->virq = irq_domain_add_linear(NULL, 2, &arizona_domain_ops,
0316                           arizona);
0317     if (!arizona->virq) {
0318         dev_err(arizona->dev, "Failed to add core IRQ domain\n");
0319         ret = -EINVAL;
0320         goto err;
0321     }
0322 
0323     if (aod) {
0324         virq = irq_create_mapping(arizona->virq, ARIZONA_AOD_IRQ_INDEX);
0325         if (!virq) {
0326             dev_err(arizona->dev, "Failed to map AOD IRQs\n");
0327             ret = -EINVAL;
0328             goto err_domain;
0329         }
0330 
0331         ret = regmap_add_irq_chip(arizona->regmap, virq, IRQF_ONESHOT,
0332                       0, aod, &arizona->aod_irq_chip);
0333         if (ret != 0) {
0334             dev_err(arizona->dev,
0335                 "Failed to add AOD IRQs: %d\n", ret);
0336             goto err_map_aod;
0337         }
0338     }
0339 
0340     virq = irq_create_mapping(arizona->virq, ARIZONA_MAIN_IRQ_INDEX);
0341     if (!virq) {
0342         dev_err(arizona->dev, "Failed to map main IRQs\n");
0343         ret = -EINVAL;
0344         goto err_aod;
0345     }
0346 
0347     ret = regmap_add_irq_chip(arizona->regmap, virq, IRQF_ONESHOT,
0348                   0, irq, &arizona->irq_chip);
0349     if (ret != 0) {
0350         dev_err(arizona->dev, "Failed to add main IRQs: %d\n", ret);
0351         goto err_map_main_irq;
0352     }
0353 
0354     /* Used to emulate edge trigger and to work around broken pinmux */
0355     if (arizona->pdata.irq_gpio) {
0356         if (gpio_to_irq(arizona->pdata.irq_gpio) != arizona->irq) {
0357             dev_warn(arizona->dev, "IRQ %d is not GPIO %d (%d)\n",
0358                  arizona->irq, arizona->pdata.irq_gpio,
0359                  gpio_to_irq(arizona->pdata.irq_gpio));
0360             arizona->irq = gpio_to_irq(arizona->pdata.irq_gpio);
0361         }
0362 
0363         ret = devm_gpio_request_one(arizona->dev,
0364                         arizona->pdata.irq_gpio,
0365                         GPIOF_IN, "arizona IRQ");
0366         if (ret != 0) {
0367             dev_err(arizona->dev,
0368                 "Failed to request IRQ GPIO %d:: %d\n",
0369                 arizona->pdata.irq_gpio, ret);
0370             arizona->pdata.irq_gpio = 0;
0371         }
0372     }
0373 
0374     ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread,
0375                    flags, "arizona", arizona);
0376 
0377     if (ret != 0) {
0378         dev_err(arizona->dev, "Failed to request primary IRQ %d: %d\n",
0379             arizona->irq, ret);
0380         goto err_main_irq;
0381     }
0382 
0383     /* Make sure the boot done IRQ is unmasked for resumes */
0384     ret = arizona_request_irq(arizona, ARIZONA_IRQ_BOOT_DONE, "Boot done",
0385                   arizona_boot_done, arizona);
0386     if (ret != 0) {
0387         dev_err(arizona->dev, "Failed to request boot done %d: %d\n",
0388             arizona->irq, ret);
0389         goto err_boot_done;
0390     }
0391 
0392     /* Handle control interface errors in the core */
0393     if (arizona->ctrlif_error) {
0394         ret = arizona_request_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR,
0395                       "Control interface error",
0396                       arizona_ctrlif_err, arizona);
0397         if (ret != 0) {
0398             dev_err(arizona->dev,
0399                 "Failed to request CTRLIF_ERR %d: %d\n",
0400                 arizona->irq, ret);
0401             goto err_ctrlif;
0402         }
0403     }
0404 
0405     return 0;
0406 
0407 err_ctrlif:
0408     arizona_free_irq(arizona, ARIZONA_IRQ_BOOT_DONE, arizona);
0409 err_boot_done:
0410     free_irq(arizona->irq, arizona);
0411 err_main_irq:
0412     regmap_del_irq_chip(irq_find_mapping(arizona->virq,
0413                          ARIZONA_MAIN_IRQ_INDEX),
0414                 arizona->irq_chip);
0415 err_map_main_irq:
0416     irq_dispose_mapping(irq_find_mapping(arizona->virq,
0417                          ARIZONA_MAIN_IRQ_INDEX));
0418 err_aod:
0419     regmap_del_irq_chip(irq_find_mapping(arizona->virq,
0420                          ARIZONA_AOD_IRQ_INDEX),
0421                 arizona->aod_irq_chip);
0422 err_map_aod:
0423     irq_dispose_mapping(irq_find_mapping(arizona->virq,
0424                          ARIZONA_AOD_IRQ_INDEX));
0425 err_domain:
0426     irq_domain_remove(arizona->virq);
0427 err:
0428     return ret;
0429 }
0430 
0431 int arizona_irq_exit(struct arizona *arizona)
0432 {
0433     unsigned int virq;
0434 
0435     if (arizona->ctrlif_error)
0436         arizona_free_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR, arizona);
0437     arizona_free_irq(arizona, ARIZONA_IRQ_BOOT_DONE, arizona);
0438 
0439     virq = irq_find_mapping(arizona->virq, ARIZONA_MAIN_IRQ_INDEX);
0440     regmap_del_irq_chip(virq, arizona->irq_chip);
0441     irq_dispose_mapping(virq);
0442 
0443     virq = irq_find_mapping(arizona->virq, ARIZONA_AOD_IRQ_INDEX);
0444     regmap_del_irq_chip(virq, arizona->aod_irq_chip);
0445     irq_dispose_mapping(virq);
0446 
0447     irq_domain_remove(arizona->virq);
0448 
0449     free_irq(arizona->irq, arizona);
0450 
0451     return 0;
0452 }