cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mt6397-irq.c (5218B)


      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}