xref: /openbmc/linux/drivers/mfd/arizona-irq.c (revision fe6df2b4)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2966cdc96SMark Brown /*
3966cdc96SMark Brown  * Arizona interrupt support
4966cdc96SMark Brown  *
5966cdc96SMark Brown  * Copyright 2012 Wolfson Microelectronics plc
6966cdc96SMark Brown  *
7966cdc96SMark Brown  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
8966cdc96SMark Brown  */
9966cdc96SMark Brown 
10966cdc96SMark Brown #include <linux/delay.h>
11966cdc96SMark Brown #include <linux/gpio.h>
12966cdc96SMark Brown #include <linux/interrupt.h>
13966cdc96SMark Brown #include <linux/irq.h>
14966cdc96SMark Brown #include <linux/irqdomain.h>
15966cdc96SMark Brown #include <linux/module.h>
16966cdc96SMark Brown #include <linux/pm_runtime.h>
17966cdc96SMark Brown #include <linux/regmap.h>
18966cdc96SMark Brown #include <linux/regulator/consumer.h>
19966cdc96SMark Brown #include <linux/slab.h>
20966cdc96SMark Brown 
21966cdc96SMark Brown #include <linux/mfd/arizona/core.h>
22966cdc96SMark Brown #include <linux/mfd/arizona/registers.h>
23966cdc96SMark Brown 
24966cdc96SMark Brown #include "arizona.h"
25966cdc96SMark Brown 
261a86dcb3SCharles Keepax #define ARIZONA_AOD_IRQ_INDEX 0
271a86dcb3SCharles Keepax #define ARIZONA_MAIN_IRQ_INDEX 1
281a86dcb3SCharles Keepax 
arizona_map_irq(struct arizona * arizona,int irq)29966cdc96SMark Brown static int arizona_map_irq(struct arizona *arizona, int irq)
30966cdc96SMark Brown {
31966cdc96SMark Brown 	int ret;
32966cdc96SMark Brown 
33ea1f3339SRichard Fitzgerald 	if (arizona->aod_irq_chip) {
34966cdc96SMark Brown 		ret = regmap_irq_get_virq(arizona->aod_irq_chip, irq);
35ea1f3339SRichard Fitzgerald 		if (ret >= 0)
36966cdc96SMark Brown 			return ret;
37966cdc96SMark Brown 	}
38966cdc96SMark Brown 
39ea1f3339SRichard Fitzgerald 	return regmap_irq_get_virq(arizona->irq_chip, irq);
40ea1f3339SRichard Fitzgerald }
41ea1f3339SRichard Fitzgerald 
arizona_request_irq(struct arizona * arizona,int irq,char * name,irq_handler_t handler,void * data)42966cdc96SMark Brown int arizona_request_irq(struct arizona *arizona, int irq, char *name,
43966cdc96SMark Brown 			   irq_handler_t handler, void *data)
44966cdc96SMark Brown {
45966cdc96SMark Brown 	irq = arizona_map_irq(arizona, irq);
46966cdc96SMark Brown 	if (irq < 0)
47966cdc96SMark Brown 		return irq;
48966cdc96SMark Brown 
49966cdc96SMark Brown 	return request_threaded_irq(irq, NULL, handler, IRQF_ONESHOT,
50966cdc96SMark Brown 				    name, data);
51966cdc96SMark Brown }
52966cdc96SMark Brown EXPORT_SYMBOL_GPL(arizona_request_irq);
53966cdc96SMark Brown 
arizona_free_irq(struct arizona * arizona,int irq,void * data)54966cdc96SMark Brown void arizona_free_irq(struct arizona *arizona, int irq, void *data)
55966cdc96SMark Brown {
56966cdc96SMark Brown 	irq = arizona_map_irq(arizona, irq);
57966cdc96SMark Brown 	if (irq < 0)
58966cdc96SMark Brown 		return;
59966cdc96SMark Brown 
60966cdc96SMark Brown 	free_irq(irq, data);
61966cdc96SMark Brown }
62966cdc96SMark Brown EXPORT_SYMBOL_GPL(arizona_free_irq);
63966cdc96SMark Brown 
arizona_set_irq_wake(struct arizona * arizona,int irq,int on)64966cdc96SMark Brown int arizona_set_irq_wake(struct arizona *arizona, int irq, int on)
65966cdc96SMark Brown {
66966cdc96SMark Brown 	irq = arizona_map_irq(arizona, irq);
67966cdc96SMark Brown 	if (irq < 0)
68966cdc96SMark Brown 		return irq;
69966cdc96SMark Brown 
70966cdc96SMark Brown 	return irq_set_irq_wake(irq, on);
71966cdc96SMark Brown }
72966cdc96SMark Brown EXPORT_SYMBOL_GPL(arizona_set_irq_wake);
73966cdc96SMark Brown 
arizona_boot_done(int irq,void * data)74966cdc96SMark Brown static irqreturn_t arizona_boot_done(int irq, void *data)
75966cdc96SMark Brown {
76966cdc96SMark Brown 	struct arizona *arizona = data;
77966cdc96SMark Brown 
78966cdc96SMark Brown 	dev_dbg(arizona->dev, "Boot done\n");
79966cdc96SMark Brown 
80966cdc96SMark Brown 	return IRQ_HANDLED;
81966cdc96SMark Brown }
82966cdc96SMark Brown 
arizona_ctrlif_err(int irq,void * data)83966cdc96SMark Brown static irqreturn_t arizona_ctrlif_err(int irq, void *data)
84966cdc96SMark Brown {
85966cdc96SMark Brown 	struct arizona *arizona = data;
86966cdc96SMark Brown 
87966cdc96SMark Brown 	/*
88966cdc96SMark Brown 	 * For pretty much all potential sources a register cache sync
89966cdc96SMark Brown 	 * won't help, we've just got a software bug somewhere.
90966cdc96SMark Brown 	 */
91966cdc96SMark Brown 	dev_err(arizona->dev, "Control interface error\n");
92966cdc96SMark Brown 
93966cdc96SMark Brown 	return IRQ_HANDLED;
94966cdc96SMark Brown }
95966cdc96SMark Brown 
arizona_irq_thread(int irq,void * data)96966cdc96SMark Brown static irqreturn_t arizona_irq_thread(int irq, void *data)
97966cdc96SMark Brown {
98966cdc96SMark Brown 	struct arizona *arizona = data;
993092f805SMark Brown 	bool poll;
1003080de4eSMark Brown 	unsigned int val;
101cdabc1c8SMark Brown 	int ret;
102966cdc96SMark Brown 
103*fe6df2b4SDinghao Liu 	ret = pm_runtime_resume_and_get(arizona->dev);
104966cdc96SMark Brown 	if (ret < 0) {
105966cdc96SMark Brown 		dev_err(arizona->dev, "Failed to resume device: %d\n", ret);
106966cdc96SMark Brown 		return IRQ_NONE;
107966cdc96SMark Brown 	}
108966cdc96SMark Brown 
1093092f805SMark Brown 	do {
1103092f805SMark Brown 		poll = false;
1113092f805SMark Brown 
1121f2c3972SRichard Fitzgerald 		if (arizona->aod_irq_chip) {
1131f2c3972SRichard Fitzgerald 			/*
1141f2c3972SRichard Fitzgerald 			 * Check the AOD status register to determine whether
1151f2c3972SRichard Fitzgerald 			 * the nested IRQ handler should be called.
1161f2c3972SRichard Fitzgerald 			 */
1171f2c3972SRichard Fitzgerald 			ret = regmap_read(arizona->regmap,
1181f2c3972SRichard Fitzgerald 					  ARIZONA_AOD_IRQ1, &val);
1191f2c3972SRichard Fitzgerald 			if (ret)
1201f2c3972SRichard Fitzgerald 				dev_warn(arizona->dev,
1211f2c3972SRichard Fitzgerald 					"Failed to read AOD IRQ1 %d\n", ret);
1221f2c3972SRichard Fitzgerald 			else if (val)
1231f2c3972SRichard Fitzgerald 				handle_nested_irq(
1241f2c3972SRichard Fitzgerald 					irq_find_mapping(arizona->virq, 0));
1251f2c3972SRichard Fitzgerald 		}
1263080de4eSMark Brown 
1273080de4eSMark Brown 		/*
1283080de4eSMark Brown 		 * Check if one of the main interrupts is asserted and only
1293080de4eSMark Brown 		 * check that domain if it is.
1303080de4eSMark Brown 		 */
1313092f805SMark Brown 		ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS,
1323092f805SMark Brown 				  &val);
1333080de4eSMark Brown 		if (ret == 0 && val & ARIZONA_IRQ1_STS) {
1343080de4eSMark Brown 			handle_nested_irq(irq_find_mapping(arizona->virq, 1));
1353080de4eSMark Brown 		} else if (ret != 0) {
1363092f805SMark Brown 			dev_err(arizona->dev,
1373092f805SMark Brown 				"Failed to read main IRQ status: %d\n", ret);
1383080de4eSMark Brown 		}
139966cdc96SMark Brown 
1403092f805SMark Brown 		/*
1413092f805SMark Brown 		 * Poll the IRQ pin status to see if we're really done
1423092f805SMark Brown 		 * if the interrupt controller can't do it for us.
1433092f805SMark Brown 		 */
1443092f805SMark Brown 		if (!arizona->pdata.irq_gpio) {
1453092f805SMark Brown 			break;
1463092f805SMark Brown 		} else if (arizona->pdata.irq_flags & IRQF_TRIGGER_RISING &&
1473092f805SMark Brown 			   gpio_get_value_cansleep(arizona->pdata.irq_gpio)) {
1483092f805SMark Brown 			poll = true;
1493092f805SMark Brown 		} else if (arizona->pdata.irq_flags & IRQF_TRIGGER_FALLING &&
1503092f805SMark Brown 			   !gpio_get_value_cansleep(arizona->pdata.irq_gpio)) {
1513092f805SMark Brown 			poll = true;
1523092f805SMark Brown 		}
1533092f805SMark Brown 	} while (poll);
1543092f805SMark Brown 
155966cdc96SMark Brown 	pm_runtime_mark_last_busy(arizona->dev);
156966cdc96SMark Brown 	pm_runtime_put_autosuspend(arizona->dev);
157966cdc96SMark Brown 
158966cdc96SMark Brown 	return IRQ_HANDLED;
159966cdc96SMark Brown }
160966cdc96SMark Brown 
arizona_irq_enable(struct irq_data * data)161966cdc96SMark Brown static void arizona_irq_enable(struct irq_data *data)
162966cdc96SMark Brown {
163966cdc96SMark Brown }
164966cdc96SMark Brown 
arizona_irq_disable(struct irq_data * data)165966cdc96SMark Brown static void arizona_irq_disable(struct irq_data *data)
166966cdc96SMark Brown {
167966cdc96SMark Brown }
168966cdc96SMark Brown 
arizona_irq_set_wake(struct irq_data * data,unsigned int on)169c38715feSCharles Keepax static int arizona_irq_set_wake(struct irq_data *data, unsigned int on)
170c38715feSCharles Keepax {
171c38715feSCharles Keepax 	struct arizona *arizona = irq_data_get_irq_chip_data(data);
172c38715feSCharles Keepax 
173c38715feSCharles Keepax 	return irq_set_irq_wake(arizona->irq, on);
174c38715feSCharles Keepax }
175c38715feSCharles Keepax 
176966cdc96SMark Brown static struct irq_chip arizona_irq_chip = {
177966cdc96SMark Brown 	.name			= "arizona",
178966cdc96SMark Brown 	.irq_disable		= arizona_irq_disable,
179966cdc96SMark Brown 	.irq_enable		= arizona_irq_enable,
180c38715feSCharles Keepax 	.irq_set_wake		= arizona_irq_set_wake,
181966cdc96SMark Brown };
182966cdc96SMark Brown 
183dedf24a2SCharles Keepax static struct lock_class_key arizona_irq_lock_class;
18439c3fd58SAndrew Lunn static struct lock_class_key arizona_irq_request_class;
185dedf24a2SCharles Keepax 
arizona_irq_map(struct irq_domain * h,unsigned int virq,irq_hw_number_t hw)186966cdc96SMark Brown static int arizona_irq_map(struct irq_domain *h, unsigned int virq,
187966cdc96SMark Brown 			      irq_hw_number_t hw)
188966cdc96SMark Brown {
1890a464dfdSCharles Keepax 	struct arizona *data = h->host_data;
190966cdc96SMark Brown 
191966cdc96SMark Brown 	irq_set_chip_data(virq, data);
19239c3fd58SAndrew Lunn 	irq_set_lockdep_class(virq, &arizona_irq_lock_class,
19339c3fd58SAndrew Lunn 		&arizona_irq_request_class);
194cfeb35daSCharles Keepax 	irq_set_chip_and_handler(virq, &arizona_irq_chip, handle_simple_irq);
195966cdc96SMark Brown 	irq_set_nested_thread(virq, 1);
196966cdc96SMark Brown 	irq_set_noprobe(virq);
197966cdc96SMark Brown 
198966cdc96SMark Brown 	return 0;
199966cdc96SMark Brown }
200966cdc96SMark Brown 
2017ce7b26fSKrzysztof Kozlowski static const struct irq_domain_ops arizona_domain_ops = {
202966cdc96SMark Brown 	.map	= arizona_irq_map,
203966cdc96SMark Brown 	.xlate	= irq_domain_xlate_twocell,
204966cdc96SMark Brown };
205966cdc96SMark Brown 
arizona_irq_init(struct arizona * arizona)206966cdc96SMark Brown int arizona_irq_init(struct arizona *arizona)
207966cdc96SMark Brown {
208966cdc96SMark Brown 	int flags = IRQF_ONESHOT;
209003db34eSCharles Keepax 	int ret;
210966cdc96SMark Brown 	const struct regmap_irq_chip *aod, *irq;
21122c75fe7SMark Brown 	struct irq_data *irq_data;
2123dfaff27SCharles Keepax 	unsigned int virq;
213966cdc96SMark Brown 
21430a2af3aSCharles Keepax 	arizona->ctrlif_error = true;
21530a2af3aSCharles Keepax 
216966cdc96SMark Brown 	switch (arizona->type) {
217863df8d5SMark Brown #ifdef CONFIG_MFD_WM5102
218966cdc96SMark Brown 	case WM5102:
219966cdc96SMark Brown 		aod = &wm5102_aod;
220966cdc96SMark Brown 		irq = &wm5102_irq;
22192d80139SMark Brown 
22230a2af3aSCharles Keepax 		arizona->ctrlif_error = false;
22392d80139SMark Brown 		break;
224863df8d5SMark Brown #endif
225e102befeSMark Brown #ifdef CONFIG_MFD_WM5110
226e102befeSMark Brown 	case WM5110:
227e5d4ef0dSRichard Fitzgerald 	case WM8280:
228e102befeSMark Brown 		aod = &wm5110_aod;
2293215501fSCharles Keepax 
2303215501fSCharles Keepax 		switch (arizona->rev) {
2313215501fSCharles Keepax 		case 0 ... 2:
232e102befeSMark Brown 			irq = &wm5110_irq;
2333215501fSCharles Keepax 			break;
2343215501fSCharles Keepax 		default:
2353215501fSCharles Keepax 			irq = &wm5110_revd_irq;
2363215501fSCharles Keepax 			break;
2373215501fSCharles Keepax 		}
23892d80139SMark Brown 
23930a2af3aSCharles Keepax 		arizona->ctrlif_error = false;
24092d80139SMark Brown 		break;
241e102befeSMark Brown #endif
242ea1f3339SRichard Fitzgerald #ifdef CONFIG_MFD_CS47L24
243ea1f3339SRichard Fitzgerald 	case WM1831:
244ea1f3339SRichard Fitzgerald 	case CS47L24:
245ea1f3339SRichard Fitzgerald 		aod = NULL;
246ea1f3339SRichard Fitzgerald 		irq = &cs47l24_irq;
247ea1f3339SRichard Fitzgerald 
248ea1f3339SRichard Fitzgerald 		arizona->ctrlif_error = false;
249ea1f3339SRichard Fitzgerald 		break;
250ea1f3339SRichard Fitzgerald #endif
251dc7d4863SCharles Keepax #ifdef CONFIG_MFD_WM8997
252dc7d4863SCharles Keepax 	case WM8997:
253dc7d4863SCharles Keepax 		aod = &wm8997_aod;
254dc7d4863SCharles Keepax 		irq = &wm8997_irq;
255dc7d4863SCharles Keepax 
25630a2af3aSCharles Keepax 		arizona->ctrlif_error = false;
257dc7d4863SCharles Keepax 		break;
258dc7d4863SCharles Keepax #endif
2596887b042SRichard Fitzgerald #ifdef CONFIG_MFD_WM8998
2606887b042SRichard Fitzgerald 	case WM8998:
2616887b042SRichard Fitzgerald 	case WM1814:
2626887b042SRichard Fitzgerald 		aod = &wm8998_aod;
2636887b042SRichard Fitzgerald 		irq = &wm8998_irq;
2646887b042SRichard Fitzgerald 
2656887b042SRichard Fitzgerald 		arizona->ctrlif_error = false;
2666887b042SRichard Fitzgerald 		break;
2676887b042SRichard Fitzgerald #endif
268966cdc96SMark Brown 	default:
269966cdc96SMark Brown 		BUG_ON("Unknown Arizona class device" == NULL);
270966cdc96SMark Brown 		return -EINVAL;
271966cdc96SMark Brown 	}
272966cdc96SMark Brown 
2731816cb34SMark Brown 	/* Disable all wake sources by default */
2741816cb34SMark Brown 	regmap_write(arizona->regmap, ARIZONA_WAKE_CONTROL, 0);
2751816cb34SMark Brown 
27622c75fe7SMark Brown 	/* Read the flags from the interrupt controller if not specified */
27722c75fe7SMark Brown 	if (!arizona->pdata.irq_flags) {
27822c75fe7SMark Brown 		irq_data = irq_get_irq_data(arizona->irq);
27922c75fe7SMark Brown 		if (!irq_data) {
28022c75fe7SMark Brown 			dev_err(arizona->dev, "Invalid IRQ: %d\n",
28122c75fe7SMark Brown 				arizona->irq);
28222c75fe7SMark Brown 			return -EINVAL;
28322c75fe7SMark Brown 		}
28422c75fe7SMark Brown 
28522c75fe7SMark Brown 		arizona->pdata.irq_flags = irqd_get_trigger_type(irq_data);
28622c75fe7SMark Brown 		switch (arizona->pdata.irq_flags) {
28722c75fe7SMark Brown 		case IRQF_TRIGGER_LOW:
28822c75fe7SMark Brown 		case IRQF_TRIGGER_HIGH:
28922c75fe7SMark Brown 		case IRQF_TRIGGER_RISING:
29022c75fe7SMark Brown 		case IRQF_TRIGGER_FALLING:
29122c75fe7SMark Brown 			break;
29222c75fe7SMark Brown 
29322c75fe7SMark Brown 		case IRQ_TYPE_NONE:
29422c75fe7SMark Brown 		default:
29522c75fe7SMark Brown 			/* Device default */
296f8a0941fSMark Brown 			arizona->pdata.irq_flags = IRQF_TRIGGER_LOW;
29722c75fe7SMark Brown 			break;
29822c75fe7SMark Brown 		}
29922c75fe7SMark Brown 	}
300f8a0941fSMark Brown 
301f8a0941fSMark Brown 	if (arizona->pdata.irq_flags & (IRQF_TRIGGER_HIGH |
302f8a0941fSMark Brown 					IRQF_TRIGGER_RISING)) {
303966cdc96SMark Brown 		ret = regmap_update_bits(arizona->regmap, ARIZONA_IRQ_CTRL_1,
304966cdc96SMark Brown 					 ARIZONA_IRQ_POL, 0);
305966cdc96SMark Brown 		if (ret != 0) {
306966cdc96SMark Brown 			dev_err(arizona->dev, "Couldn't set IRQ polarity: %d\n",
307966cdc96SMark Brown 				ret);
308966cdc96SMark Brown 			goto err;
309966cdc96SMark Brown 		}
310966cdc96SMark Brown 	}
311966cdc96SMark Brown 
312f8a0941fSMark Brown 	flags |= arizona->pdata.irq_flags;
313f8a0941fSMark Brown 
314966cdc96SMark Brown 	/* Allocate a virtual IRQ domain to distribute to the regmap domains */
315966cdc96SMark Brown 	arizona->virq = irq_domain_add_linear(NULL, 2, &arizona_domain_ops,
316966cdc96SMark Brown 					      arizona);
317966cdc96SMark Brown 	if (!arizona->virq) {
318b7dea5dcSMark Brown 		dev_err(arizona->dev, "Failed to add core IRQ domain\n");
319966cdc96SMark Brown 		ret = -EINVAL;
320966cdc96SMark Brown 		goto err;
321966cdc96SMark Brown 	}
322966cdc96SMark Brown 
323ea1f3339SRichard Fitzgerald 	if (aod) {
3243dfaff27SCharles Keepax 		virq = irq_create_mapping(arizona->virq, ARIZONA_AOD_IRQ_INDEX);
3253dfaff27SCharles Keepax 		if (!virq) {
3263dfaff27SCharles Keepax 			dev_err(arizona->dev, "Failed to map AOD IRQs\n");
3273dfaff27SCharles Keepax 			ret = -EINVAL;
3283dfaff27SCharles Keepax 			goto err_domain;
3293dfaff27SCharles Keepax 		}
3303dfaff27SCharles Keepax 
3313dfaff27SCharles Keepax 		ret = regmap_add_irq_chip(arizona->regmap, virq, IRQF_ONESHOT,
3323dfaff27SCharles Keepax 					  0, aod, &arizona->aod_irq_chip);
333966cdc96SMark Brown 		if (ret != 0) {
334ea1f3339SRichard Fitzgerald 			dev_err(arizona->dev,
335ea1f3339SRichard Fitzgerald 				"Failed to add AOD IRQs: %d\n", ret);
3363dfaff27SCharles Keepax 			goto err_map_aod;
337966cdc96SMark Brown 		}
338ea1f3339SRichard Fitzgerald 	}
339966cdc96SMark Brown 
3403dfaff27SCharles Keepax 	virq = irq_create_mapping(arizona->virq, ARIZONA_MAIN_IRQ_INDEX);
3413dfaff27SCharles Keepax 	if (!virq) {
3423dfaff27SCharles Keepax 		dev_err(arizona->dev, "Failed to map main IRQs\n");
3433dfaff27SCharles Keepax 		ret = -EINVAL;
3443dfaff27SCharles Keepax 		goto err_aod;
3453dfaff27SCharles Keepax 	}
3463dfaff27SCharles Keepax 
3473dfaff27SCharles Keepax 	ret = regmap_add_irq_chip(arizona->regmap, virq, IRQF_ONESHOT,
3483dfaff27SCharles Keepax 				  0, irq, &arizona->irq_chip);
349966cdc96SMark Brown 	if (ret != 0) {
350d1cb4cc9SCharles Keepax 		dev_err(arizona->dev, "Failed to add main IRQs: %d\n", ret);
3513dfaff27SCharles Keepax 		goto err_map_main_irq;
352966cdc96SMark Brown 	}
353966cdc96SMark Brown 
3543092f805SMark Brown 	/* Used to emulate edge trigger and to work around broken pinmux */
3553092f805SMark Brown 	if (arizona->pdata.irq_gpio) {
3563092f805SMark Brown 		if (gpio_to_irq(arizona->pdata.irq_gpio) != arizona->irq) {
3573092f805SMark Brown 			dev_warn(arizona->dev, "IRQ %d is not GPIO %d (%d)\n",
3583092f805SMark Brown 				 arizona->irq, arizona->pdata.irq_gpio,
3593092f805SMark Brown 				 gpio_to_irq(arizona->pdata.irq_gpio));
3603092f805SMark Brown 			arizona->irq = gpio_to_irq(arizona->pdata.irq_gpio);
3613092f805SMark Brown 		}
3623092f805SMark Brown 
3633092f805SMark Brown 		ret = devm_gpio_request_one(arizona->dev,
3643092f805SMark Brown 					    arizona->pdata.irq_gpio,
3653092f805SMark Brown 					    GPIOF_IN, "arizona IRQ");
3663092f805SMark Brown 		if (ret != 0) {
3673092f805SMark Brown 			dev_err(arizona->dev,
3683092f805SMark Brown 				"Failed to request IRQ GPIO %d:: %d\n",
3693092f805SMark Brown 				arizona->pdata.irq_gpio, ret);
3703092f805SMark Brown 			arizona->pdata.irq_gpio = 0;
3713092f805SMark Brown 		}
3723092f805SMark Brown 	}
3733092f805SMark Brown 
374966cdc96SMark Brown 	ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread,
375966cdc96SMark Brown 				   flags, "arizona", arizona);
376966cdc96SMark Brown 
377966cdc96SMark Brown 	if (ret != 0) {
3787994c664SMark Brown 		dev_err(arizona->dev, "Failed to request primary IRQ %d: %d\n",
379966cdc96SMark Brown 			arizona->irq, ret);
380966cdc96SMark Brown 		goto err_main_irq;
381966cdc96SMark Brown 	}
382966cdc96SMark Brown 
3836c006b1bSCharles Keepax 	/* Make sure the boot done IRQ is unmasked for resumes */
384003db34eSCharles Keepax 	ret = arizona_request_irq(arizona, ARIZONA_IRQ_BOOT_DONE, "Boot done",
385003db34eSCharles Keepax 				  arizona_boot_done, arizona);
3866c006b1bSCharles Keepax 	if (ret != 0) {
3876c006b1bSCharles Keepax 		dev_err(arizona->dev, "Failed to request boot done %d: %d\n",
3886c006b1bSCharles Keepax 			arizona->irq, ret);
3896c006b1bSCharles Keepax 		goto err_boot_done;
3906c006b1bSCharles Keepax 	}
3916c006b1bSCharles Keepax 
3926c006b1bSCharles Keepax 	/* Handle control interface errors in the core */
3936c006b1bSCharles Keepax 	if (arizona->ctrlif_error) {
394003db34eSCharles Keepax 		ret = arizona_request_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR,
395003db34eSCharles Keepax 					  "Control interface error",
396003db34eSCharles Keepax 					  arizona_ctrlif_err, arizona);
3976c006b1bSCharles Keepax 		if (ret != 0) {
3986c006b1bSCharles Keepax 			dev_err(arizona->dev,
3996c006b1bSCharles Keepax 				"Failed to request CTRLIF_ERR %d: %d\n",
4006c006b1bSCharles Keepax 				arizona->irq, ret);
4016c006b1bSCharles Keepax 			goto err_ctrlif;
4026c006b1bSCharles Keepax 		}
4036c006b1bSCharles Keepax 	}
4046c006b1bSCharles Keepax 
405966cdc96SMark Brown 	return 0;
406966cdc96SMark Brown 
407966cdc96SMark Brown err_ctrlif:
408003db34eSCharles Keepax 	arizona_free_irq(arizona, ARIZONA_IRQ_BOOT_DONE, arizona);
409966cdc96SMark Brown err_boot_done:
4106c006b1bSCharles Keepax 	free_irq(arizona->irq, arizona);
4116c006b1bSCharles Keepax err_main_irq:
4121a86dcb3SCharles Keepax 	regmap_del_irq_chip(irq_find_mapping(arizona->virq,
4131a86dcb3SCharles Keepax 					     ARIZONA_MAIN_IRQ_INDEX),
414966cdc96SMark Brown 			    arizona->irq_chip);
4153dfaff27SCharles Keepax err_map_main_irq:
4163dfaff27SCharles Keepax 	irq_dispose_mapping(irq_find_mapping(arizona->virq,
4173dfaff27SCharles Keepax 					     ARIZONA_MAIN_IRQ_INDEX));
418966cdc96SMark Brown err_aod:
4191a86dcb3SCharles Keepax 	regmap_del_irq_chip(irq_find_mapping(arizona->virq,
4201a86dcb3SCharles Keepax 					     ARIZONA_AOD_IRQ_INDEX),
421966cdc96SMark Brown 			    arizona->aod_irq_chip);
4223dfaff27SCharles Keepax err_map_aod:
4233dfaff27SCharles Keepax 	irq_dispose_mapping(irq_find_mapping(arizona->virq,
4243dfaff27SCharles Keepax 					     ARIZONA_AOD_IRQ_INDEX));
4253dfaff27SCharles Keepax err_domain:
4263dfaff27SCharles Keepax 	irq_domain_remove(arizona->virq);
427966cdc96SMark Brown err:
428966cdc96SMark Brown 	return ret;
429966cdc96SMark Brown }
430966cdc96SMark Brown 
arizona_irq_exit(struct arizona * arizona)431966cdc96SMark Brown int arizona_irq_exit(struct arizona *arizona)
432966cdc96SMark Brown {
4333dfaff27SCharles Keepax 	unsigned int virq;
4343dfaff27SCharles Keepax 
43530a2af3aSCharles Keepax 	if (arizona->ctrlif_error)
436003db34eSCharles Keepax 		arizona_free_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR, arizona);
437003db34eSCharles Keepax 	arizona_free_irq(arizona, ARIZONA_IRQ_BOOT_DONE, arizona);
438003db34eSCharles Keepax 
4393dfaff27SCharles Keepax 	virq = irq_find_mapping(arizona->virq, ARIZONA_MAIN_IRQ_INDEX);
4403dfaff27SCharles Keepax 	regmap_del_irq_chip(virq, arizona->irq_chip);
4413dfaff27SCharles Keepax 	irq_dispose_mapping(virq);
4423dfaff27SCharles Keepax 
4433dfaff27SCharles Keepax 	virq = irq_find_mapping(arizona->virq, ARIZONA_AOD_IRQ_INDEX);
4443dfaff27SCharles Keepax 	regmap_del_irq_chip(virq, arizona->aod_irq_chip);
4453dfaff27SCharles Keepax 	irq_dispose_mapping(virq);
4463dfaff27SCharles Keepax 
4473dfaff27SCharles Keepax 	irq_domain_remove(arizona->virq);
4483dfaff27SCharles Keepax 
449966cdc96SMark Brown 	free_irq(arizona->irq, arizona);
450966cdc96SMark Brown 
451966cdc96SMark Brown 	return 0;
452966cdc96SMark Brown }
453