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

arizona-irq.c (10820B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Arizona interrupt support
      4 *
      5 * Copyright 2012 Wolfson Microelectronics plc
      6 *
      7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
      8 */
      9
     10#include <linux/delay.h>
     11#include <linux/gpio.h>
     12#include <linux/interrupt.h>
     13#include <linux/irq.h>
     14#include <linux/irqdomain.h>
     15#include <linux/module.h>
     16#include <linux/pm_runtime.h>
     17#include <linux/regmap.h>
     18#include <linux/regulator/consumer.h>
     19#include <linux/slab.h>
     20
     21#include <linux/mfd/arizona/core.h>
     22#include <linux/mfd/arizona/registers.h>
     23
     24#include "arizona.h"
     25
     26#define ARIZONA_AOD_IRQ_INDEX 0
     27#define ARIZONA_MAIN_IRQ_INDEX 1
     28
     29static int arizona_map_irq(struct arizona *arizona, int irq)
     30{
     31	int ret;
     32
     33	if (arizona->aod_irq_chip) {
     34		ret = regmap_irq_get_virq(arizona->aod_irq_chip, irq);
     35		if (ret >= 0)
     36			return ret;
     37	}
     38
     39	return regmap_irq_get_virq(arizona->irq_chip, irq);
     40}
     41
     42int arizona_request_irq(struct arizona *arizona, int irq, char *name,
     43			   irq_handler_t handler, void *data)
     44{
     45	irq = arizona_map_irq(arizona, irq);
     46	if (irq < 0)
     47		return irq;
     48
     49	return request_threaded_irq(irq, NULL, handler, IRQF_ONESHOT,
     50				    name, data);
     51}
     52EXPORT_SYMBOL_GPL(arizona_request_irq);
     53
     54void arizona_free_irq(struct arizona *arizona, int irq, void *data)
     55{
     56	irq = arizona_map_irq(arizona, irq);
     57	if (irq < 0)
     58		return;
     59
     60	free_irq(irq, data);
     61}
     62EXPORT_SYMBOL_GPL(arizona_free_irq);
     63
     64int arizona_set_irq_wake(struct arizona *arizona, int irq, int on)
     65{
     66	irq = arizona_map_irq(arizona, irq);
     67	if (irq < 0)
     68		return irq;
     69
     70	return irq_set_irq_wake(irq, on);
     71}
     72EXPORT_SYMBOL_GPL(arizona_set_irq_wake);
     73
     74static irqreturn_t arizona_boot_done(int irq, void *data)
     75{
     76	struct arizona *arizona = data;
     77
     78	dev_dbg(arizona->dev, "Boot done\n");
     79
     80	return IRQ_HANDLED;
     81}
     82
     83static irqreturn_t arizona_ctrlif_err(int irq, void *data)
     84{
     85	struct arizona *arizona = data;
     86
     87	/*
     88	 * For pretty much all potential sources a register cache sync
     89	 * won't help, we've just got a software bug somewhere.
     90	 */
     91	dev_err(arizona->dev, "Control interface error\n");
     92
     93	return IRQ_HANDLED;
     94}
     95
     96static irqreturn_t arizona_irq_thread(int irq, void *data)
     97{
     98	struct arizona *arizona = data;
     99	bool poll;
    100	unsigned int val;
    101	int ret;
    102
    103	ret = pm_runtime_resume_and_get(arizona->dev);
    104	if (ret < 0) {
    105		dev_err(arizona->dev, "Failed to resume device: %d\n", ret);
    106		return IRQ_NONE;
    107	}
    108
    109	do {
    110		poll = false;
    111
    112		if (arizona->aod_irq_chip) {
    113			/*
    114			 * Check the AOD status register to determine whether
    115			 * the nested IRQ handler should be called.
    116			 */
    117			ret = regmap_read(arizona->regmap,
    118					  ARIZONA_AOD_IRQ1, &val);
    119			if (ret)
    120				dev_warn(arizona->dev,
    121					"Failed to read AOD IRQ1 %d\n", ret);
    122			else if (val)
    123				handle_nested_irq(
    124					irq_find_mapping(arizona->virq, 0));
    125		}
    126
    127		/*
    128		 * Check if one of the main interrupts is asserted and only
    129		 * check that domain if it is.
    130		 */
    131		ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS,
    132				  &val);
    133		if (ret == 0 && val & ARIZONA_IRQ1_STS) {
    134			handle_nested_irq(irq_find_mapping(arizona->virq, 1));
    135		} else if (ret != 0) {
    136			dev_err(arizona->dev,
    137				"Failed to read main IRQ status: %d\n", ret);
    138		}
    139
    140		/*
    141		 * Poll the IRQ pin status to see if we're really done
    142		 * if the interrupt controller can't do it for us.
    143		 */
    144		if (!arizona->pdata.irq_gpio) {
    145			break;
    146		} else if (arizona->pdata.irq_flags & IRQF_TRIGGER_RISING &&
    147			   gpio_get_value_cansleep(arizona->pdata.irq_gpio)) {
    148			poll = true;
    149		} else if (arizona->pdata.irq_flags & IRQF_TRIGGER_FALLING &&
    150			   !gpio_get_value_cansleep(arizona->pdata.irq_gpio)) {
    151			poll = true;
    152		}
    153	} while (poll);
    154
    155	pm_runtime_mark_last_busy(arizona->dev);
    156	pm_runtime_put_autosuspend(arizona->dev);
    157
    158	return IRQ_HANDLED;
    159}
    160
    161static void arizona_irq_enable(struct irq_data *data)
    162{
    163}
    164
    165static void arizona_irq_disable(struct irq_data *data)
    166{
    167}
    168
    169static int arizona_irq_set_wake(struct irq_data *data, unsigned int on)
    170{
    171	struct arizona *arizona = irq_data_get_irq_chip_data(data);
    172
    173	return irq_set_irq_wake(arizona->irq, on);
    174}
    175
    176static struct irq_chip arizona_irq_chip = {
    177	.name			= "arizona",
    178	.irq_disable		= arizona_irq_disable,
    179	.irq_enable		= arizona_irq_enable,
    180	.irq_set_wake		= arizona_irq_set_wake,
    181};
    182
    183static struct lock_class_key arizona_irq_lock_class;
    184static struct lock_class_key arizona_irq_request_class;
    185
    186static int arizona_irq_map(struct irq_domain *h, unsigned int virq,
    187			      irq_hw_number_t hw)
    188{
    189	struct arizona *data = h->host_data;
    190
    191	irq_set_chip_data(virq, data);
    192	irq_set_lockdep_class(virq, &arizona_irq_lock_class,
    193		&arizona_irq_request_class);
    194	irq_set_chip_and_handler(virq, &arizona_irq_chip, handle_simple_irq);
    195	irq_set_nested_thread(virq, 1);
    196	irq_set_noprobe(virq);
    197
    198	return 0;
    199}
    200
    201static const struct irq_domain_ops arizona_domain_ops = {
    202	.map	= arizona_irq_map,
    203	.xlate	= irq_domain_xlate_twocell,
    204};
    205
    206int arizona_irq_init(struct arizona *arizona)
    207{
    208	int flags = IRQF_ONESHOT;
    209	int ret;
    210	const struct regmap_irq_chip *aod, *irq;
    211	struct irq_data *irq_data;
    212	unsigned int virq;
    213
    214	arizona->ctrlif_error = true;
    215
    216	switch (arizona->type) {
    217#ifdef CONFIG_MFD_WM5102
    218	case WM5102:
    219		aod = &wm5102_aod;
    220		irq = &wm5102_irq;
    221
    222		arizona->ctrlif_error = false;
    223		break;
    224#endif
    225#ifdef CONFIG_MFD_WM5110
    226	case WM5110:
    227	case WM8280:
    228		aod = &wm5110_aod;
    229
    230		switch (arizona->rev) {
    231		case 0 ... 2:
    232			irq = &wm5110_irq;
    233			break;
    234		default:
    235			irq = &wm5110_revd_irq;
    236			break;
    237		}
    238
    239		arizona->ctrlif_error = false;
    240		break;
    241#endif
    242#ifdef CONFIG_MFD_CS47L24
    243	case WM1831:
    244	case CS47L24:
    245		aod = NULL;
    246		irq = &cs47l24_irq;
    247
    248		arizona->ctrlif_error = false;
    249		break;
    250#endif
    251#ifdef CONFIG_MFD_WM8997
    252	case WM8997:
    253		aod = &wm8997_aod;
    254		irq = &wm8997_irq;
    255
    256		arizona->ctrlif_error = false;
    257		break;
    258#endif
    259#ifdef CONFIG_MFD_WM8998
    260	case WM8998:
    261	case WM1814:
    262		aod = &wm8998_aod;
    263		irq = &wm8998_irq;
    264
    265		arizona->ctrlif_error = false;
    266		break;
    267#endif
    268	default:
    269		BUG_ON("Unknown Arizona class device" == NULL);
    270		return -EINVAL;
    271	}
    272
    273	/* Disable all wake sources by default */
    274	regmap_write(arizona->regmap, ARIZONA_WAKE_CONTROL, 0);
    275
    276	/* Read the flags from the interrupt controller if not specified */
    277	if (!arizona->pdata.irq_flags) {
    278		irq_data = irq_get_irq_data(arizona->irq);
    279		if (!irq_data) {
    280			dev_err(arizona->dev, "Invalid IRQ: %d\n",
    281				arizona->irq);
    282			return -EINVAL;
    283		}
    284
    285		arizona->pdata.irq_flags = irqd_get_trigger_type(irq_data);
    286		switch (arizona->pdata.irq_flags) {
    287		case IRQF_TRIGGER_LOW:
    288		case IRQF_TRIGGER_HIGH:
    289		case IRQF_TRIGGER_RISING:
    290		case IRQF_TRIGGER_FALLING:
    291			break;
    292
    293		case IRQ_TYPE_NONE:
    294		default:
    295			/* Device default */
    296			arizona->pdata.irq_flags = IRQF_TRIGGER_LOW;
    297			break;
    298		}
    299	}
    300
    301	if (arizona->pdata.irq_flags & (IRQF_TRIGGER_HIGH |
    302					IRQF_TRIGGER_RISING)) {
    303		ret = regmap_update_bits(arizona->regmap, ARIZONA_IRQ_CTRL_1,
    304					 ARIZONA_IRQ_POL, 0);
    305		if (ret != 0) {
    306			dev_err(arizona->dev, "Couldn't set IRQ polarity: %d\n",
    307				ret);
    308			goto err;
    309		}
    310	}
    311
    312	flags |= arizona->pdata.irq_flags;
    313
    314	/* Allocate a virtual IRQ domain to distribute to the regmap domains */
    315	arizona->virq = irq_domain_add_linear(NULL, 2, &arizona_domain_ops,
    316					      arizona);
    317	if (!arizona->virq) {
    318		dev_err(arizona->dev, "Failed to add core IRQ domain\n");
    319		ret = -EINVAL;
    320		goto err;
    321	}
    322
    323	if (aod) {
    324		virq = irq_create_mapping(arizona->virq, ARIZONA_AOD_IRQ_INDEX);
    325		if (!virq) {
    326			dev_err(arizona->dev, "Failed to map AOD IRQs\n");
    327			ret = -EINVAL;
    328			goto err_domain;
    329		}
    330
    331		ret = regmap_add_irq_chip(arizona->regmap, virq, IRQF_ONESHOT,
    332					  0, aod, &arizona->aod_irq_chip);
    333		if (ret != 0) {
    334			dev_err(arizona->dev,
    335				"Failed to add AOD IRQs: %d\n", ret);
    336			goto err_map_aod;
    337		}
    338	}
    339
    340	virq = irq_create_mapping(arizona->virq, ARIZONA_MAIN_IRQ_INDEX);
    341	if (!virq) {
    342		dev_err(arizona->dev, "Failed to map main IRQs\n");
    343		ret = -EINVAL;
    344		goto err_aod;
    345	}
    346
    347	ret = regmap_add_irq_chip(arizona->regmap, virq, IRQF_ONESHOT,
    348				  0, irq, &arizona->irq_chip);
    349	if (ret != 0) {
    350		dev_err(arizona->dev, "Failed to add main IRQs: %d\n", ret);
    351		goto err_map_main_irq;
    352	}
    353
    354	/* Used to emulate edge trigger and to work around broken pinmux */
    355	if (arizona->pdata.irq_gpio) {
    356		if (gpio_to_irq(arizona->pdata.irq_gpio) != arizona->irq) {
    357			dev_warn(arizona->dev, "IRQ %d is not GPIO %d (%d)\n",
    358				 arizona->irq, arizona->pdata.irq_gpio,
    359				 gpio_to_irq(arizona->pdata.irq_gpio));
    360			arizona->irq = gpio_to_irq(arizona->pdata.irq_gpio);
    361		}
    362
    363		ret = devm_gpio_request_one(arizona->dev,
    364					    arizona->pdata.irq_gpio,
    365					    GPIOF_IN, "arizona IRQ");
    366		if (ret != 0) {
    367			dev_err(arizona->dev,
    368				"Failed to request IRQ GPIO %d:: %d\n",
    369				arizona->pdata.irq_gpio, ret);
    370			arizona->pdata.irq_gpio = 0;
    371		}
    372	}
    373
    374	ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread,
    375				   flags, "arizona", arizona);
    376
    377	if (ret != 0) {
    378		dev_err(arizona->dev, "Failed to request primary IRQ %d: %d\n",
    379			arizona->irq, ret);
    380		goto err_main_irq;
    381	}
    382
    383	/* Make sure the boot done IRQ is unmasked for resumes */
    384	ret = arizona_request_irq(arizona, ARIZONA_IRQ_BOOT_DONE, "Boot done",
    385				  arizona_boot_done, arizona);
    386	if (ret != 0) {
    387		dev_err(arizona->dev, "Failed to request boot done %d: %d\n",
    388			arizona->irq, ret);
    389		goto err_boot_done;
    390	}
    391
    392	/* Handle control interface errors in the core */
    393	if (arizona->ctrlif_error) {
    394		ret = arizona_request_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR,
    395					  "Control interface error",
    396					  arizona_ctrlif_err, arizona);
    397		if (ret != 0) {
    398			dev_err(arizona->dev,
    399				"Failed to request CTRLIF_ERR %d: %d\n",
    400				arizona->irq, ret);
    401			goto err_ctrlif;
    402		}
    403	}
    404
    405	return 0;
    406
    407err_ctrlif:
    408	arizona_free_irq(arizona, ARIZONA_IRQ_BOOT_DONE, arizona);
    409err_boot_done:
    410	free_irq(arizona->irq, arizona);
    411err_main_irq:
    412	regmap_del_irq_chip(irq_find_mapping(arizona->virq,
    413					     ARIZONA_MAIN_IRQ_INDEX),
    414			    arizona->irq_chip);
    415err_map_main_irq:
    416	irq_dispose_mapping(irq_find_mapping(arizona->virq,
    417					     ARIZONA_MAIN_IRQ_INDEX));
    418err_aod:
    419	regmap_del_irq_chip(irq_find_mapping(arizona->virq,
    420					     ARIZONA_AOD_IRQ_INDEX),
    421			    arizona->aod_irq_chip);
    422err_map_aod:
    423	irq_dispose_mapping(irq_find_mapping(arizona->virq,
    424					     ARIZONA_AOD_IRQ_INDEX));
    425err_domain:
    426	irq_domain_remove(arizona->virq);
    427err:
    428	return ret;
    429}
    430
    431int arizona_irq_exit(struct arizona *arizona)
    432{
    433	unsigned int virq;
    434
    435	if (arizona->ctrlif_error)
    436		arizona_free_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR, arizona);
    437	arizona_free_irq(arizona, ARIZONA_IRQ_BOOT_DONE, arizona);
    438
    439	virq = irq_find_mapping(arizona->virq, ARIZONA_MAIN_IRQ_INDEX);
    440	regmap_del_irq_chip(virq, arizona->irq_chip);
    441	irq_dispose_mapping(virq);
    442
    443	virq = irq_find_mapping(arizona->virq, ARIZONA_AOD_IRQ_INDEX);
    444	regmap_del_irq_chip(virq, arizona->aod_irq_chip);
    445	irq_dispose_mapping(virq);
    446
    447	irq_domain_remove(arizona->virq);
    448
    449	free_irq(arizona->irq, arizona);
    450
    451	return 0;
    452}