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

wm8994-irq.c (5951B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * wm8994-irq.c  --  Interrupt controller support for Wolfson WM8994
      4 *
      5 * Copyright 2010 Wolfson Microelectronics PLC.
      6 *
      7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
      8 */
      9
     10#include <linux/kernel.h>
     11#include <linux/module.h>
     12#include <linux/gpio.h>
     13#include <linux/i2c.h>
     14#include <linux/irq.h>
     15#include <linux/mfd/core.h>
     16#include <linux/interrupt.h>
     17#include <linux/irqdomain.h>
     18#include <linux/regmap.h>
     19
     20#include <linux/mfd/wm8994/core.h>
     21#include <linux/mfd/wm8994/pdata.h>
     22#include <linux/mfd/wm8994/registers.h>
     23
     24#include <linux/delay.h>
     25
     26static const struct regmap_irq wm8994_irqs[] = {
     27	[WM8994_IRQ_TEMP_SHUT] = {
     28		.reg_offset = 1,
     29		.mask = WM8994_TEMP_SHUT_EINT,
     30	},
     31	[WM8994_IRQ_MIC1_DET] = {
     32		.reg_offset = 1,
     33		.mask = WM8994_MIC1_DET_EINT,
     34	},
     35	[WM8994_IRQ_MIC1_SHRT] = {
     36		.reg_offset = 1,
     37		.mask = WM8994_MIC1_SHRT_EINT,
     38	},
     39	[WM8994_IRQ_MIC2_DET] = {
     40		.reg_offset = 1,
     41		.mask = WM8994_MIC2_DET_EINT,
     42	},
     43	[WM8994_IRQ_MIC2_SHRT] = {
     44		.reg_offset = 1,
     45		.mask = WM8994_MIC2_SHRT_EINT,
     46	},
     47	[WM8994_IRQ_FLL1_LOCK] = {
     48		.reg_offset = 1,
     49		.mask = WM8994_FLL1_LOCK_EINT,
     50	},
     51	[WM8994_IRQ_FLL2_LOCK] = {
     52		.reg_offset = 1,
     53		.mask = WM8994_FLL2_LOCK_EINT,
     54	},
     55	[WM8994_IRQ_SRC1_LOCK] = {
     56		.reg_offset = 1,
     57		.mask = WM8994_SRC1_LOCK_EINT,
     58	},
     59	[WM8994_IRQ_SRC2_LOCK] = {
     60		.reg_offset = 1,
     61		.mask = WM8994_SRC2_LOCK_EINT,
     62	},
     63	[WM8994_IRQ_AIF1DRC1_SIG_DET] = {
     64		.reg_offset = 1,
     65		.mask = WM8994_AIF1DRC1_SIG_DET,
     66	},
     67	[WM8994_IRQ_AIF1DRC2_SIG_DET] = {
     68		.reg_offset = 1,
     69		.mask = WM8994_AIF1DRC2_SIG_DET_EINT,
     70	},
     71	[WM8994_IRQ_AIF2DRC_SIG_DET] = {
     72		.reg_offset = 1,
     73		.mask = WM8994_AIF2DRC_SIG_DET_EINT,
     74	},
     75	[WM8994_IRQ_FIFOS_ERR] = {
     76		.reg_offset = 1,
     77		.mask = WM8994_FIFOS_ERR_EINT,
     78	},
     79	[WM8994_IRQ_WSEQ_DONE] = {
     80		.reg_offset = 1,
     81		.mask = WM8994_WSEQ_DONE_EINT,
     82	},
     83	[WM8994_IRQ_DCS_DONE] = {
     84		.reg_offset = 1,
     85		.mask = WM8994_DCS_DONE_EINT,
     86	},
     87	[WM8994_IRQ_TEMP_WARN] = {
     88		.reg_offset = 1,
     89		.mask = WM8994_TEMP_WARN_EINT,
     90	},
     91	[WM8994_IRQ_GPIO(1)] = {
     92		.mask = WM8994_GP1_EINT,
     93	},
     94	[WM8994_IRQ_GPIO(2)] = {
     95		.mask = WM8994_GP2_EINT,
     96	},
     97	[WM8994_IRQ_GPIO(3)] = {
     98		.mask = WM8994_GP3_EINT,
     99	},
    100	[WM8994_IRQ_GPIO(4)] = {
    101		.mask = WM8994_GP4_EINT,
    102	},
    103	[WM8994_IRQ_GPIO(5)] = {
    104		.mask = WM8994_GP5_EINT,
    105	},
    106	[WM8994_IRQ_GPIO(6)] = {
    107		.mask = WM8994_GP6_EINT,
    108	},
    109	[WM8994_IRQ_GPIO(7)] = {
    110		.mask = WM8994_GP7_EINT,
    111	},
    112	[WM8994_IRQ_GPIO(8)] = {
    113		.mask = WM8994_GP8_EINT,
    114	},
    115	[WM8994_IRQ_GPIO(9)] = {
    116		.mask = WM8994_GP8_EINT,
    117	},
    118	[WM8994_IRQ_GPIO(10)] = {
    119		.mask = WM8994_GP10_EINT,
    120	},
    121	[WM8994_IRQ_GPIO(11)] = {
    122		.mask = WM8994_GP11_EINT,
    123	},
    124};
    125
    126static const struct regmap_irq_chip wm8994_irq_chip = {
    127	.name = "wm8994",
    128	.irqs = wm8994_irqs,
    129	.num_irqs = ARRAY_SIZE(wm8994_irqs),
    130
    131	.num_regs = 2,
    132	.status_base = WM8994_INTERRUPT_STATUS_1,
    133	.mask_base = WM8994_INTERRUPT_STATUS_1_MASK,
    134	.ack_base = WM8994_INTERRUPT_STATUS_1,
    135	.runtime_pm = true,
    136};
    137
    138static void wm8994_edge_irq_enable(struct irq_data *data)
    139{
    140}
    141
    142static void wm8994_edge_irq_disable(struct irq_data *data)
    143{
    144}
    145
    146static struct irq_chip wm8994_edge_irq_chip = {
    147	.name			= "wm8994_edge",
    148	.irq_disable		= wm8994_edge_irq_disable,
    149	.irq_enable		= wm8994_edge_irq_enable,
    150};
    151
    152static irqreturn_t wm8994_edge_irq(int irq, void *data)
    153{
    154	struct wm8994 *wm8994 = data;
    155
    156	while (gpio_get_value_cansleep(wm8994->pdata.irq_gpio))
    157		handle_nested_irq(irq_find_mapping(wm8994->edge_irq, 0));
    158
    159	return IRQ_HANDLED;
    160}
    161
    162static int wm8994_edge_irq_map(struct irq_domain *h, unsigned int virq,
    163			       irq_hw_number_t hw)
    164{
    165	struct wm8994 *wm8994 = h->host_data;
    166
    167	irq_set_chip_data(virq, wm8994);
    168	irq_set_chip_and_handler(virq, &wm8994_edge_irq_chip, handle_edge_irq);
    169	irq_set_nested_thread(virq, 1);
    170	irq_set_noprobe(virq);
    171
    172	return 0;
    173}
    174
    175static const struct irq_domain_ops wm8994_edge_irq_ops = {
    176	.map	= wm8994_edge_irq_map,
    177	.xlate	= irq_domain_xlate_twocell,
    178};
    179
    180int wm8994_irq_init(struct wm8994 *wm8994)
    181{
    182	int ret;
    183	unsigned long irqflags;
    184	struct wm8994_pdata *pdata = &wm8994->pdata;
    185
    186	if (!wm8994->irq) {
    187		dev_warn(wm8994->dev,
    188			 "No interrupt specified, no interrupts\n");
    189		wm8994->irq_base = 0;
    190		return 0;
    191	}
    192
    193	/* select user or default irq flags */
    194	irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
    195	if (pdata->irq_flags)
    196		irqflags = pdata->irq_flags;
    197
    198	/* use a GPIO for edge triggered controllers */
    199	if (irqflags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
    200		if (gpio_to_irq(pdata->irq_gpio) != wm8994->irq) {
    201			dev_warn(wm8994->dev, "IRQ %d is not GPIO %d (%d)\n",
    202				 wm8994->irq, pdata->irq_gpio,
    203				 gpio_to_irq(pdata->irq_gpio));
    204			wm8994->irq = gpio_to_irq(pdata->irq_gpio);
    205		}
    206
    207		ret = devm_gpio_request_one(wm8994->dev, pdata->irq_gpio,
    208					    GPIOF_IN, "WM8994 IRQ");
    209
    210		if (ret != 0) {
    211			dev_err(wm8994->dev, "Failed to get IRQ GPIO: %d\n",
    212				ret);
    213			return ret;
    214		}
    215
    216		wm8994->edge_irq = irq_domain_add_linear(NULL, 1,
    217							 &wm8994_edge_irq_ops,
    218							 wm8994);
    219
    220		ret = regmap_add_irq_chip(wm8994->regmap,
    221					  irq_create_mapping(wm8994->edge_irq,
    222							     0),
    223					  IRQF_ONESHOT,
    224					  wm8994->irq_base, &wm8994_irq_chip,
    225					  &wm8994->irq_data);
    226		if (ret != 0) {
    227			dev_err(wm8994->dev, "Failed to get IRQ: %d\n",
    228				ret);
    229			return ret;
    230		}
    231
    232		ret = request_threaded_irq(wm8994->irq,
    233					   NULL, wm8994_edge_irq,
    234					   irqflags,
    235					   "WM8994 edge", wm8994);
    236	} else {
    237		ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq,
    238					  irqflags,
    239					  wm8994->irq_base, &wm8994_irq_chip,
    240					  &wm8994->irq_data);
    241	}
    242
    243	if (ret != 0) {
    244		dev_err(wm8994->dev, "Failed to register IRQ chip: %d\n", ret);
    245		return ret;
    246	}
    247
    248	/* Enable top level interrupt if it was masked */
    249	wm8994_reg_write(wm8994, WM8994_INTERRUPT_CONTROL, 0);
    250
    251	return 0;
    252}
    253EXPORT_SYMBOL(wm8994_irq_init);
    254
    255void wm8994_irq_exit(struct wm8994 *wm8994)
    256{
    257	regmap_del_irq_chip(wm8994->irq, wm8994->irq_data);
    258}
    259EXPORT_SYMBOL(wm8994_irq_exit);