linux/drivers/mfd/mt6397-irq.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// Copyright (c) 2019 MediaTek Inc.
   4
   5#include <linux/interrupt.h>
   6#include <linux/module.h>
   7#include <linux/of.h>
   8#include <linux/of_device.h>
   9#include <linux/of_irq.h>
  10#include <linux/platform_device.h>
  11#include <linux/regmap.h>
  12#include <linux/suspend.h>
  13#include <linux/mfd/mt6323/core.h>
  14#include <linux/mfd/mt6323/registers.h>
  15#include <linux/mfd/mt6397/core.h>
  16#include <linux/mfd/mt6397/registers.h>
  17
  18static void mt6397_irq_lock(struct irq_data *data)
  19{
  20        struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);
  21
  22        mutex_lock(&mt6397->irqlock);
  23}
  24
  25static void mt6397_irq_sync_unlock(struct irq_data *data)
  26{
  27        struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);
  28
  29        regmap_write(mt6397->regmap, mt6397->int_con[0],
  30                     mt6397->irq_masks_cur[0]);
  31        regmap_write(mt6397->regmap, mt6397->int_con[1],
  32                     mt6397->irq_masks_cur[1]);
  33
  34        mutex_unlock(&mt6397->irqlock);
  35}
  36
  37static void mt6397_irq_disable(struct irq_data *data)
  38{
  39        struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);
  40        int shift = data->hwirq & 0xf;
  41        int reg = data->hwirq >> 4;
  42
  43        mt6397->irq_masks_cur[reg] &= ~BIT(shift);
  44}
  45
  46static void mt6397_irq_enable(struct irq_data *data)
  47{
  48        struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);
  49        int shift = data->hwirq & 0xf;
  50        int reg = data->hwirq >> 4;
  51
  52        mt6397->irq_masks_cur[reg] |= BIT(shift);
  53}
  54
  55#ifdef CONFIG_PM_SLEEP
  56static int mt6397_irq_set_wake(struct irq_data *irq_data, unsigned int on)
  57{
  58        struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(irq_data);
  59        int shift = irq_data->hwirq & 0xf;
  60        int reg = irq_data->hwirq >> 4;
  61
  62        if (on)
  63                mt6397->wake_mask[reg] |= BIT(shift);
  64        else
  65                mt6397->wake_mask[reg] &= ~BIT(shift);
  66
  67        return 0;
  68}
  69#else
  70#define mt6397_irq_set_wake NULL
  71#endif
  72
  73static struct irq_chip mt6397_irq_chip = {
  74        .name = "mt6397-irq",
  75        .irq_bus_lock = mt6397_irq_lock,
  76        .irq_bus_sync_unlock = mt6397_irq_sync_unlock,
  77        .irq_enable = mt6397_irq_enable,
  78        .irq_disable = mt6397_irq_disable,
  79        .irq_set_wake = mt6397_irq_set_wake,
  80};
  81
  82static void mt6397_irq_handle_reg(struct mt6397_chip *mt6397, int reg,
  83                                  int irqbase)
  84{
  85        unsigned int status = 0;
  86        int i, irq, ret;
  87
  88        ret = regmap_read(mt6397->regmap, reg, &status);
  89        if (ret) {
  90                dev_err(mt6397->dev, "Failed to read irq status: %d\n", ret);
  91                return;
  92        }
  93
  94        for (i = 0; i < 16; i++) {
  95                if (status & BIT(i)) {
  96                        irq = irq_find_mapping(mt6397->irq_domain, irqbase + i);
  97                        if (irq)
  98                                handle_nested_irq(irq);
  99                }
 100        }
 101
 102        regmap_write(mt6397->regmap, reg, status);
 103}
 104
 105static irqreturn_t mt6397_irq_thread(int irq, void *data)
 106{
 107        struct mt6397_chip *mt6397 = data;
 108
 109        mt6397_irq_handle_reg(mt6397, mt6397->int_status[0], 0);
 110        mt6397_irq_handle_reg(mt6397, mt6397->int_status[1], 16);
 111
 112        return IRQ_HANDLED;
 113}
 114
 115static int mt6397_irq_domain_map(struct irq_domain *d, unsigned int irq,
 116                                 irq_hw_number_t hw)
 117{
 118        struct mt6397_chip *mt6397 = d->host_data;
 119
 120        irq_set_chip_data(irq, mt6397);
 121        irq_set_chip_and_handler(irq, &mt6397_irq_chip, handle_level_irq);
 122        irq_set_nested_thread(irq, 1);
 123        irq_set_noprobe(irq);
 124
 125        return 0;
 126}
 127
 128static const struct irq_domain_ops mt6397_irq_domain_ops = {
 129        .map = mt6397_irq_domain_map,
 130};
 131
 132static int mt6397_irq_pm_notifier(struct notifier_block *notifier,
 133                                  unsigned long pm_event, void *unused)
 134{
 135        struct mt6397_chip *chip =
 136                container_of(notifier, struct mt6397_chip, pm_nb);
 137
 138        switch (pm_event) {
 139        case PM_SUSPEND_PREPARE:
 140                regmap_write(chip->regmap,
 141                             chip->int_con[0], chip->wake_mask[0]);
 142                regmap_write(chip->regmap,
 143                             chip->int_con[1], chip->wake_mask[1]);
 144                enable_irq_wake(chip->irq);
 145                break;
 146
 147        case PM_POST_SUSPEND:
 148                regmap_write(chip->regmap,
 149                             chip->int_con[0], chip->irq_masks_cur[0]);
 150                regmap_write(chip->regmap,
 151                             chip->int_con[1], chip->irq_masks_cur[1]);
 152                disable_irq_wake(chip->irq);
 153                break;
 154
 155        default:
 156                break;
 157        }
 158
 159        return NOTIFY_DONE;
 160}
 161
 162int mt6397_irq_init(struct mt6397_chip *chip)
 163{
 164        int ret;
 165
 166        mutex_init(&chip->irqlock);
 167
 168        switch (chip->chip_id) {
 169        case MT6323_CHIP_ID:
 170                chip->int_con[0] = MT6323_INT_CON0;
 171                chip->int_con[1] = MT6323_INT_CON1;
 172                chip->int_status[0] = MT6323_INT_STATUS0;
 173                chip->int_status[1] = MT6323_INT_STATUS1;
 174                break;
 175
 176        case MT6391_CHIP_ID:
 177        case MT6397_CHIP_ID:
 178                chip->int_con[0] = MT6397_INT_CON0;
 179                chip->int_con[1] = MT6397_INT_CON1;
 180                chip->int_status[0] = MT6397_INT_STATUS0;
 181                chip->int_status[1] = MT6397_INT_STATUS1;
 182                break;
 183
 184        default:
 185                dev_err(chip->dev, "unsupported chip: 0x%x\n", chip->chip_id);
 186                return -ENODEV;
 187        }
 188
 189        /* Mask all interrupt sources */
 190        regmap_write(chip->regmap, chip->int_con[0], 0x0);
 191        regmap_write(chip->regmap, chip->int_con[1], 0x0);
 192
 193        chip->pm_nb.notifier_call = mt6397_irq_pm_notifier;
 194        chip->irq_domain = irq_domain_add_linear(chip->dev->of_node,
 195                                                 MT6397_IRQ_NR,
 196                                                 &mt6397_irq_domain_ops,
 197                                                 chip);
 198        if (!chip->irq_domain) {
 199                dev_err(chip->dev, "could not create irq domain\n");
 200                return -ENOMEM;
 201        }
 202
 203        ret = devm_request_threaded_irq(chip->dev, chip->irq, NULL,
 204                                        mt6397_irq_thread, IRQF_ONESHOT,
 205                                        "mt6397-pmic", chip);
 206        if (ret) {
 207                dev_err(chip->dev, "failed to register irq=%d; err: %d\n",
 208                        chip->irq, ret);
 209                return ret;
 210        }
 211
 212        register_pm_notifier(&chip->pm_nb);
 213        return 0;
 214}
 215