xref: /openbmc/linux/drivers/mfd/wm8350-core.c (revision da09155a)
189b4012bSMark Brown /*
289b4012bSMark Brown  * wm8350-core.c  --  Device access for Wolfson WM8350
389b4012bSMark Brown  *
489b4012bSMark Brown  * Copyright 2007, 2008 Wolfson Microelectronics PLC.
589b4012bSMark Brown  *
689b4012bSMark Brown  * Author: Liam Girdwood, Mark Brown
789b4012bSMark Brown  *
889b4012bSMark Brown  *  This program is free software; you can redistribute  it and/or modify it
989b4012bSMark Brown  *  under  the terms of  the GNU General  Public License as published by the
1089b4012bSMark Brown  *  Free Software Foundation;  either version 2 of the  License, or (at your
1189b4012bSMark Brown  *  option) any later version.
1289b4012bSMark Brown  *
1389b4012bSMark Brown  */
1489b4012bSMark Brown 
1589b4012bSMark Brown #include <linux/kernel.h>
1689b4012bSMark Brown #include <linux/module.h>
1789b4012bSMark Brown #include <linux/init.h>
18ebccec0fSMark Brown #include <linux/bug.h>
1989b4012bSMark Brown #include <linux/device.h>
2089b4012bSMark Brown #include <linux/delay.h>
2189b4012bSMark Brown #include <linux/interrupt.h>
22ebccec0fSMark Brown #include <linux/workqueue.h>
2389b4012bSMark Brown 
2489b4012bSMark Brown #include <linux/mfd/wm8350/core.h>
2589b4012bSMark Brown #include <linux/mfd/wm8350/audio.h>
26ebccec0fSMark Brown #include <linux/mfd/wm8350/comparator.h>
2789b4012bSMark Brown #include <linux/mfd/wm8350/gpio.h>
2889b4012bSMark Brown #include <linux/mfd/wm8350/pmic.h>
29ebccec0fSMark Brown #include <linux/mfd/wm8350/rtc.h>
3089b4012bSMark Brown #include <linux/mfd/wm8350/supply.h>
31ebccec0fSMark Brown #include <linux/mfd/wm8350/wdt.h>
3289b4012bSMark Brown 
3389b4012bSMark Brown #define WM8350_UNLOCK_KEY		0x0013
3489b4012bSMark Brown #define WM8350_LOCK_KEY			0x0000
3589b4012bSMark Brown 
3689b4012bSMark Brown #define WM8350_CLOCK_CONTROL_1		0x28
3789b4012bSMark Brown #define WM8350_AIF_TEST			0x74
3889b4012bSMark Brown 
3989b4012bSMark Brown /* debug */
4089b4012bSMark Brown #define WM8350_BUS_DEBUG 0
4189b4012bSMark Brown #if WM8350_BUS_DEBUG
4289b4012bSMark Brown #define dump(regs, src) do { \
4389b4012bSMark Brown 	int i_; \
4489b4012bSMark Brown 	u16 *src_ = src; \
4589b4012bSMark Brown 	printk(KERN_DEBUG); \
4689b4012bSMark Brown 	for (i_ = 0; i_ < regs; i_++) \
4789b4012bSMark Brown 		printk(" 0x%4.4x", *src_++); \
4889b4012bSMark Brown 	printk("\n"); \
4989b4012bSMark Brown } while (0);
5089b4012bSMark Brown #else
5189b4012bSMark Brown #define dump(bytes, src)
5289b4012bSMark Brown #endif
5389b4012bSMark Brown 
5489b4012bSMark Brown #define WM8350_LOCK_DEBUG 0
5589b4012bSMark Brown #if WM8350_LOCK_DEBUG
5689b4012bSMark Brown #define ldbg(format, arg...) printk(format, ## arg)
5789b4012bSMark Brown #else
5889b4012bSMark Brown #define ldbg(format, arg...)
5989b4012bSMark Brown #endif
6089b4012bSMark Brown 
6189b4012bSMark Brown /*
6289b4012bSMark Brown  * WM8350 Device IO
6389b4012bSMark Brown  */
6489b4012bSMark Brown static DEFINE_MUTEX(io_mutex);
6589b4012bSMark Brown static DEFINE_MUTEX(reg_lock_mutex);
6689b4012bSMark Brown static DEFINE_MUTEX(auxadc_mutex);
6789b4012bSMark Brown 
6889b4012bSMark Brown /* Perform a physical read from the device.
6989b4012bSMark Brown  */
7089b4012bSMark Brown static int wm8350_phys_read(struct wm8350 *wm8350, u8 reg, int num_regs,
7189b4012bSMark Brown 			    u16 *dest)
7289b4012bSMark Brown {
7389b4012bSMark Brown 	int i, ret;
7489b4012bSMark Brown 	int bytes = num_regs * 2;
7589b4012bSMark Brown 
7689b4012bSMark Brown 	dev_dbg(wm8350->dev, "volatile read\n");
7789b4012bSMark Brown 	ret = wm8350->read_dev(wm8350, reg, bytes, (char *)dest);
7889b4012bSMark Brown 
7989b4012bSMark Brown 	for (i = reg; i < reg + num_regs; i++) {
8089b4012bSMark Brown 		/* Cache is CPU endian */
8189b4012bSMark Brown 		dest[i - reg] = be16_to_cpu(dest[i - reg]);
8289b4012bSMark Brown 
8389b4012bSMark Brown 		/* Satisfy non-volatile bits from cache */
8489b4012bSMark Brown 		dest[i - reg] &= wm8350_reg_io_map[i].vol;
8589b4012bSMark Brown 		dest[i - reg] |= wm8350->reg_cache[i];
8689b4012bSMark Brown 
8789b4012bSMark Brown 		/* Mask out non-readable bits */
8889b4012bSMark Brown 		dest[i - reg] &= wm8350_reg_io_map[i].readable;
8989b4012bSMark Brown 	}
9089b4012bSMark Brown 
9189b4012bSMark Brown 	dump(num_regs, dest);
9289b4012bSMark Brown 
9389b4012bSMark Brown 	return ret;
9489b4012bSMark Brown }
9589b4012bSMark Brown 
9689b4012bSMark Brown static int wm8350_read(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *dest)
9789b4012bSMark Brown {
9889b4012bSMark Brown 	int i;
9989b4012bSMark Brown 	int end = reg + num_regs;
10089b4012bSMark Brown 	int ret = 0;
10189b4012bSMark Brown 	int bytes = num_regs * 2;
10289b4012bSMark Brown 
10389b4012bSMark Brown 	if (wm8350->read_dev == NULL)
10489b4012bSMark Brown 		return -ENODEV;
10589b4012bSMark Brown 
10689b4012bSMark Brown 	if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) {
10789b4012bSMark Brown 		dev_err(wm8350->dev, "invalid reg %x\n",
10889b4012bSMark Brown 			reg + num_regs - 1);
10989b4012bSMark Brown 		return -EINVAL;
11089b4012bSMark Brown 	}
11189b4012bSMark Brown 
11289b4012bSMark Brown 	dev_dbg(wm8350->dev,
11389b4012bSMark Brown 		"%s R%d(0x%2.2x) %d regs\n", __func__, reg, reg, num_regs);
11489b4012bSMark Brown 
11589b4012bSMark Brown #if WM8350_BUS_DEBUG
11689b4012bSMark Brown 	/* we can _safely_ read any register, but warn if read not supported */
11789b4012bSMark Brown 	for (i = reg; i < end; i++) {
11889b4012bSMark Brown 		if (!wm8350_reg_io_map[i].readable)
11989b4012bSMark Brown 			dev_warn(wm8350->dev,
12089b4012bSMark Brown 				"reg R%d is not readable\n", i);
12189b4012bSMark Brown 	}
12289b4012bSMark Brown #endif
12389b4012bSMark Brown 
12489b4012bSMark Brown 	/* if any volatile registers are required, then read back all */
12589b4012bSMark Brown 	for (i = reg; i < end; i++)
12689b4012bSMark Brown 		if (wm8350_reg_io_map[i].vol)
12789b4012bSMark Brown 			return wm8350_phys_read(wm8350, reg, num_regs, dest);
12889b4012bSMark Brown 
12989b4012bSMark Brown 	/* no volatiles, then cache is good */
13089b4012bSMark Brown 	dev_dbg(wm8350->dev, "cache read\n");
13189b4012bSMark Brown 	memcpy(dest, &wm8350->reg_cache[reg], bytes);
13289b4012bSMark Brown 	dump(num_regs, dest);
13389b4012bSMark Brown 	return ret;
13489b4012bSMark Brown }
13589b4012bSMark Brown 
13689b4012bSMark Brown static inline int is_reg_locked(struct wm8350 *wm8350, u8 reg)
13789b4012bSMark Brown {
13889b4012bSMark Brown 	if (reg == WM8350_SECURITY ||
13989b4012bSMark Brown 	    wm8350->reg_cache[WM8350_SECURITY] == WM8350_UNLOCK_KEY)
14089b4012bSMark Brown 		return 0;
14189b4012bSMark Brown 
14289b4012bSMark Brown 	if ((reg == WM8350_GPIO_CONFIGURATION_I_O) ||
14389b4012bSMark Brown 	    (reg >= WM8350_GPIO_FUNCTION_SELECT_1 &&
14489b4012bSMark Brown 	     reg <= WM8350_GPIO_FUNCTION_SELECT_4) ||
14589b4012bSMark Brown 	    (reg >= WM8350_BATTERY_CHARGER_CONTROL_1 &&
14689b4012bSMark Brown 	     reg <= WM8350_BATTERY_CHARGER_CONTROL_3))
14789b4012bSMark Brown 		return 1;
14889b4012bSMark Brown 	return 0;
14989b4012bSMark Brown }
15089b4012bSMark Brown 
15189b4012bSMark Brown static int wm8350_write(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *src)
15289b4012bSMark Brown {
15389b4012bSMark Brown 	int i;
15489b4012bSMark Brown 	int end = reg + num_regs;
15589b4012bSMark Brown 	int bytes = num_regs * 2;
15689b4012bSMark Brown 
15789b4012bSMark Brown 	if (wm8350->write_dev == NULL)
15889b4012bSMark Brown 		return -ENODEV;
15989b4012bSMark Brown 
16089b4012bSMark Brown 	if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) {
16189b4012bSMark Brown 		dev_err(wm8350->dev, "invalid reg %x\n",
16289b4012bSMark Brown 			reg + num_regs - 1);
16389b4012bSMark Brown 		return -EINVAL;
16489b4012bSMark Brown 	}
16589b4012bSMark Brown 
16689b4012bSMark Brown 	/* it's generally not a good idea to write to RO or locked registers */
16789b4012bSMark Brown 	for (i = reg; i < end; i++) {
16889b4012bSMark Brown 		if (!wm8350_reg_io_map[i].writable) {
16989b4012bSMark Brown 			dev_err(wm8350->dev,
17089b4012bSMark Brown 				"attempted write to read only reg R%d\n", i);
17189b4012bSMark Brown 			return -EINVAL;
17289b4012bSMark Brown 		}
17389b4012bSMark Brown 
17489b4012bSMark Brown 		if (is_reg_locked(wm8350, i)) {
17589b4012bSMark Brown 			dev_err(wm8350->dev,
17689b4012bSMark Brown 			       "attempted write to locked reg R%d\n", i);
17789b4012bSMark Brown 			return -EINVAL;
17889b4012bSMark Brown 		}
17989b4012bSMark Brown 
18089b4012bSMark Brown 		src[i - reg] &= wm8350_reg_io_map[i].writable;
18189b4012bSMark Brown 
18289b4012bSMark Brown 		wm8350->reg_cache[i] =
18389b4012bSMark Brown 			(wm8350->reg_cache[i] & ~wm8350_reg_io_map[i].writable)
18489b4012bSMark Brown 			| src[i - reg];
18589b4012bSMark Brown 
18689b4012bSMark Brown 		src[i - reg] = cpu_to_be16(src[i - reg]);
18789b4012bSMark Brown 	}
18889b4012bSMark Brown 
18989b4012bSMark Brown 	/* Actually write it out */
19089b4012bSMark Brown 	return wm8350->write_dev(wm8350, reg, bytes, (char *)src);
19189b4012bSMark Brown }
19289b4012bSMark Brown 
19389b4012bSMark Brown /*
19489b4012bSMark Brown  * Safe read, modify, write methods
19589b4012bSMark Brown  */
19689b4012bSMark Brown int wm8350_clear_bits(struct wm8350 *wm8350, u16 reg, u16 mask)
19789b4012bSMark Brown {
19889b4012bSMark Brown 	u16 data;
19989b4012bSMark Brown 	int err;
20089b4012bSMark Brown 
20189b4012bSMark Brown 	mutex_lock(&io_mutex);
20289b4012bSMark Brown 	err = wm8350_read(wm8350, reg, 1, &data);
20389b4012bSMark Brown 	if (err) {
20489b4012bSMark Brown 		dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
20589b4012bSMark Brown 		goto out;
20689b4012bSMark Brown 	}
20789b4012bSMark Brown 
20889b4012bSMark Brown 	data &= ~mask;
20989b4012bSMark Brown 	err = wm8350_write(wm8350, reg, 1, &data);
21089b4012bSMark Brown 	if (err)
21189b4012bSMark Brown 		dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
21289b4012bSMark Brown out:
21389b4012bSMark Brown 	mutex_unlock(&io_mutex);
21489b4012bSMark Brown 	return err;
21589b4012bSMark Brown }
21689b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_clear_bits);
21789b4012bSMark Brown 
21889b4012bSMark Brown int wm8350_set_bits(struct wm8350 *wm8350, u16 reg, u16 mask)
21989b4012bSMark Brown {
22089b4012bSMark Brown 	u16 data;
22189b4012bSMark Brown 	int err;
22289b4012bSMark Brown 
22389b4012bSMark Brown 	mutex_lock(&io_mutex);
22489b4012bSMark Brown 	err = wm8350_read(wm8350, reg, 1, &data);
22589b4012bSMark Brown 	if (err) {
22689b4012bSMark Brown 		dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
22789b4012bSMark Brown 		goto out;
22889b4012bSMark Brown 	}
22989b4012bSMark Brown 
23089b4012bSMark Brown 	data |= mask;
23189b4012bSMark Brown 	err = wm8350_write(wm8350, reg, 1, &data);
23289b4012bSMark Brown 	if (err)
23389b4012bSMark Brown 		dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
23489b4012bSMark Brown out:
23589b4012bSMark Brown 	mutex_unlock(&io_mutex);
23689b4012bSMark Brown 	return err;
23789b4012bSMark Brown }
23889b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_set_bits);
23989b4012bSMark Brown 
24089b4012bSMark Brown u16 wm8350_reg_read(struct wm8350 *wm8350, int reg)
24189b4012bSMark Brown {
24289b4012bSMark Brown 	u16 data;
24389b4012bSMark Brown 	int err;
24489b4012bSMark Brown 
24589b4012bSMark Brown 	mutex_lock(&io_mutex);
24689b4012bSMark Brown 	err = wm8350_read(wm8350, reg, 1, &data);
24789b4012bSMark Brown 	if (err)
24889b4012bSMark Brown 		dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
24989b4012bSMark Brown 
25089b4012bSMark Brown 	mutex_unlock(&io_mutex);
25189b4012bSMark Brown 	return data;
25289b4012bSMark Brown }
25389b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_reg_read);
25489b4012bSMark Brown 
25589b4012bSMark Brown int wm8350_reg_write(struct wm8350 *wm8350, int reg, u16 val)
25689b4012bSMark Brown {
25789b4012bSMark Brown 	int ret;
25889b4012bSMark Brown 	u16 data = val;
25989b4012bSMark Brown 
26089b4012bSMark Brown 	mutex_lock(&io_mutex);
26189b4012bSMark Brown 	ret = wm8350_write(wm8350, reg, 1, &data);
26289b4012bSMark Brown 	if (ret)
26389b4012bSMark Brown 		dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
26489b4012bSMark Brown 	mutex_unlock(&io_mutex);
26589b4012bSMark Brown 	return ret;
26689b4012bSMark Brown }
26789b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_reg_write);
26889b4012bSMark Brown 
26989b4012bSMark Brown int wm8350_block_read(struct wm8350 *wm8350, int start_reg, int regs,
27089b4012bSMark Brown 		      u16 *dest)
27189b4012bSMark Brown {
27289b4012bSMark Brown 	int err = 0;
27389b4012bSMark Brown 
27489b4012bSMark Brown 	mutex_lock(&io_mutex);
27589b4012bSMark Brown 	err = wm8350_read(wm8350, start_reg, regs, dest);
27689b4012bSMark Brown 	if (err)
27789b4012bSMark Brown 		dev_err(wm8350->dev, "block read starting from R%d failed\n",
27889b4012bSMark Brown 			start_reg);
27989b4012bSMark Brown 	mutex_unlock(&io_mutex);
28089b4012bSMark Brown 	return err;
28189b4012bSMark Brown }
28289b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_block_read);
28389b4012bSMark Brown 
28489b4012bSMark Brown int wm8350_block_write(struct wm8350 *wm8350, int start_reg, int regs,
28589b4012bSMark Brown 		       u16 *src)
28689b4012bSMark Brown {
28789b4012bSMark Brown 	int ret = 0;
28889b4012bSMark Brown 
28989b4012bSMark Brown 	mutex_lock(&io_mutex);
29089b4012bSMark Brown 	ret = wm8350_write(wm8350, start_reg, regs, src);
29189b4012bSMark Brown 	if (ret)
29289b4012bSMark Brown 		dev_err(wm8350->dev, "block write starting at R%d failed\n",
29389b4012bSMark Brown 			start_reg);
29489b4012bSMark Brown 	mutex_unlock(&io_mutex);
29589b4012bSMark Brown 	return ret;
29689b4012bSMark Brown }
29789b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_block_write);
29889b4012bSMark Brown 
29989b4012bSMark Brown int wm8350_reg_lock(struct wm8350 *wm8350)
30089b4012bSMark Brown {
30189b4012bSMark Brown 	u16 key = WM8350_LOCK_KEY;
30289b4012bSMark Brown 	int ret;
30389b4012bSMark Brown 
30489b4012bSMark Brown 	ldbg(__func__);
30589b4012bSMark Brown 	mutex_lock(&io_mutex);
30689b4012bSMark Brown 	ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key);
30789b4012bSMark Brown 	if (ret)
30889b4012bSMark Brown 		dev_err(wm8350->dev, "lock failed\n");
30989b4012bSMark Brown 	mutex_unlock(&io_mutex);
31089b4012bSMark Brown 	return ret;
31189b4012bSMark Brown }
31289b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_reg_lock);
31389b4012bSMark Brown 
31489b4012bSMark Brown int wm8350_reg_unlock(struct wm8350 *wm8350)
31589b4012bSMark Brown {
31689b4012bSMark Brown 	u16 key = WM8350_UNLOCK_KEY;
31789b4012bSMark Brown 	int ret;
31889b4012bSMark Brown 
31989b4012bSMark Brown 	ldbg(__func__);
32089b4012bSMark Brown 	mutex_lock(&io_mutex);
32189b4012bSMark Brown 	ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key);
32289b4012bSMark Brown 	if (ret)
32389b4012bSMark Brown 		dev_err(wm8350->dev, "unlock failed\n");
32489b4012bSMark Brown 	mutex_unlock(&io_mutex);
32589b4012bSMark Brown 	return ret;
32689b4012bSMark Brown }
32789b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_reg_unlock);
32889b4012bSMark Brown 
329ebccec0fSMark Brown static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq)
330ebccec0fSMark Brown {
331ebccec0fSMark Brown 	mutex_lock(&wm8350->irq_mutex);
332ebccec0fSMark Brown 
333ebccec0fSMark Brown 	if (wm8350->irq[irq].handler)
334ebccec0fSMark Brown 		wm8350->irq[irq].handler(wm8350, irq, wm8350->irq[irq].data);
335ebccec0fSMark Brown 	else {
336ebccec0fSMark Brown 		dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n",
337ebccec0fSMark Brown 			irq);
338ebccec0fSMark Brown 		wm8350_mask_irq(wm8350, irq);
339ebccec0fSMark Brown 	}
340ebccec0fSMark Brown 
341ebccec0fSMark Brown 	mutex_unlock(&wm8350->irq_mutex);
342ebccec0fSMark Brown }
343ebccec0fSMark Brown 
344ebccec0fSMark Brown /*
345ebccec0fSMark Brown  * wm8350_irq_worker actually handles the interrupts.  Since all
346ebccec0fSMark Brown  * interrupts are clear on read the IRQ line will be reasserted and
347ebccec0fSMark Brown  * the physical IRQ will be handled again if another interrupt is
348ebccec0fSMark Brown  * asserted while we run - in the normal course of events this is a
349ebccec0fSMark Brown  * rare occurrence so we save I2C/SPI reads.
350ebccec0fSMark Brown  */
351ebccec0fSMark Brown static void wm8350_irq_worker(struct work_struct *work)
352ebccec0fSMark Brown {
353ebccec0fSMark Brown 	struct wm8350 *wm8350 = container_of(work, struct wm8350, irq_work);
354ebccec0fSMark Brown 	u16 level_one, status1, status2, comp;
355ebccec0fSMark Brown 
356ebccec0fSMark Brown 	/* TODO: Use block reads to improve performance? */
357ebccec0fSMark Brown 	level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS)
358ebccec0fSMark Brown 		& ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK);
359ebccec0fSMark Brown 	status1 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_1)
360ebccec0fSMark Brown 		& ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_1_MASK);
361ebccec0fSMark Brown 	status2 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_2)
362ebccec0fSMark Brown 		& ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_2_MASK);
363ebccec0fSMark Brown 	comp = wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS)
364ebccec0fSMark Brown 		& ~wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK);
365ebccec0fSMark Brown 
366ebccec0fSMark Brown 	/* over current */
367ebccec0fSMark Brown 	if (level_one & WM8350_OC_INT) {
368ebccec0fSMark Brown 		u16 oc;
369ebccec0fSMark Brown 
370ebccec0fSMark Brown 		oc = wm8350_reg_read(wm8350, WM8350_OVER_CURRENT_INT_STATUS);
371ebccec0fSMark Brown 		oc &= ~wm8350_reg_read(wm8350,
372ebccec0fSMark Brown 				       WM8350_OVER_CURRENT_INT_STATUS_MASK);
373ebccec0fSMark Brown 
374ebccec0fSMark Brown 		if (oc & WM8350_OC_LS_EINT)	/* limit switch */
375ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_OC_LS);
376ebccec0fSMark Brown 	}
377ebccec0fSMark Brown 
378ebccec0fSMark Brown 	/* under voltage */
379ebccec0fSMark Brown 	if (level_one & WM8350_UV_INT) {
380ebccec0fSMark Brown 		u16 uv;
381ebccec0fSMark Brown 
382ebccec0fSMark Brown 		uv = wm8350_reg_read(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS);
383ebccec0fSMark Brown 		uv &= ~wm8350_reg_read(wm8350,
384ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK);
385ebccec0fSMark Brown 
386ebccec0fSMark Brown 		if (uv & WM8350_UV_DC1_EINT)
387ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC1);
388ebccec0fSMark Brown 		if (uv & WM8350_UV_DC2_EINT)
389ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC2);
390ebccec0fSMark Brown 		if (uv & WM8350_UV_DC3_EINT)
391ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC3);
392ebccec0fSMark Brown 		if (uv & WM8350_UV_DC4_EINT)
393ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC4);
394ebccec0fSMark Brown 		if (uv & WM8350_UV_DC5_EINT)
395ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC5);
396ebccec0fSMark Brown 		if (uv & WM8350_UV_DC6_EINT)
397ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC6);
398ebccec0fSMark Brown 		if (uv & WM8350_UV_LDO1_EINT)
399ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO1);
400ebccec0fSMark Brown 		if (uv & WM8350_UV_LDO2_EINT)
401ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO2);
402ebccec0fSMark Brown 		if (uv & WM8350_UV_LDO3_EINT)
403ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO3);
404ebccec0fSMark Brown 		if (uv & WM8350_UV_LDO4_EINT)
405ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO4);
406ebccec0fSMark Brown 	}
407ebccec0fSMark Brown 
408ebccec0fSMark Brown 	/* charger, RTC */
409ebccec0fSMark Brown 	if (status1) {
410ebccec0fSMark Brown 		if (status1 & WM8350_CHG_BAT_HOT_EINT)
411ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
412ebccec0fSMark Brown 						WM8350_IRQ_CHG_BAT_HOT);
413ebccec0fSMark Brown 		if (status1 & WM8350_CHG_BAT_COLD_EINT)
414ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
415ebccec0fSMark Brown 						WM8350_IRQ_CHG_BAT_COLD);
416ebccec0fSMark Brown 		if (status1 & WM8350_CHG_BAT_FAIL_EINT)
417ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
418ebccec0fSMark Brown 						WM8350_IRQ_CHG_BAT_FAIL);
419ebccec0fSMark Brown 		if (status1 & WM8350_CHG_TO_EINT)
420ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_TO);
421ebccec0fSMark Brown 		if (status1 & WM8350_CHG_END_EINT)
422ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_END);
423ebccec0fSMark Brown 		if (status1 & WM8350_CHG_START_EINT)
424ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_START);
425ebccec0fSMark Brown 		if (status1 & WM8350_CHG_FAST_RDY_EINT)
426ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
427ebccec0fSMark Brown 						WM8350_IRQ_CHG_FAST_RDY);
428ebccec0fSMark Brown 		if (status1 & WM8350_CHG_VBATT_LT_3P9_EINT)
429ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
430ebccec0fSMark Brown 						WM8350_IRQ_CHG_VBATT_LT_3P9);
431ebccec0fSMark Brown 		if (status1 & WM8350_CHG_VBATT_LT_3P1_EINT)
432ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
433ebccec0fSMark Brown 						WM8350_IRQ_CHG_VBATT_LT_3P1);
434ebccec0fSMark Brown 		if (status1 & WM8350_CHG_VBATT_LT_2P85_EINT)
435ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
436ebccec0fSMark Brown 						WM8350_IRQ_CHG_VBATT_LT_2P85);
437ebccec0fSMark Brown 		if (status1 & WM8350_RTC_ALM_EINT)
438ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_ALM);
439ebccec0fSMark Brown 		if (status1 & WM8350_RTC_SEC_EINT)
440ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_SEC);
441ebccec0fSMark Brown 		if (status1 & WM8350_RTC_PER_EINT)
442ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_PER);
443ebccec0fSMark Brown 	}
444ebccec0fSMark Brown 
445ebccec0fSMark Brown 	/* current sink, system, aux adc */
446ebccec0fSMark Brown 	if (status2) {
447ebccec0fSMark Brown 		if (status2 & WM8350_CS1_EINT)
448ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS1);
449ebccec0fSMark Brown 		if (status2 & WM8350_CS2_EINT)
450ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS2);
451ebccec0fSMark Brown 
452ebccec0fSMark Brown 		if (status2 & WM8350_SYS_HYST_COMP_FAIL_EINT)
453ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
454ebccec0fSMark Brown 						WM8350_IRQ_SYS_HYST_COMP_FAIL);
455ebccec0fSMark Brown 		if (status2 & WM8350_SYS_CHIP_GT115_EINT)
456ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
457ebccec0fSMark Brown 						WM8350_IRQ_SYS_CHIP_GT115);
458ebccec0fSMark Brown 		if (status2 & WM8350_SYS_CHIP_GT140_EINT)
459ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
460ebccec0fSMark Brown 						WM8350_IRQ_SYS_CHIP_GT140);
461ebccec0fSMark Brown 		if (status2 & WM8350_SYS_WDOG_TO_EINT)
462ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
463ebccec0fSMark Brown 						WM8350_IRQ_SYS_WDOG_TO);
464ebccec0fSMark Brown 
465ebccec0fSMark Brown 		if (status2 & WM8350_AUXADC_DATARDY_EINT)
466ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
467ebccec0fSMark Brown 						WM8350_IRQ_AUXADC_DATARDY);
468ebccec0fSMark Brown 		if (status2 & WM8350_AUXADC_DCOMP4_EINT)
469ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
470ebccec0fSMark Brown 						WM8350_IRQ_AUXADC_DCOMP4);
471ebccec0fSMark Brown 		if (status2 & WM8350_AUXADC_DCOMP3_EINT)
472ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
473ebccec0fSMark Brown 						WM8350_IRQ_AUXADC_DCOMP3);
474ebccec0fSMark Brown 		if (status2 & WM8350_AUXADC_DCOMP2_EINT)
475ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
476ebccec0fSMark Brown 						WM8350_IRQ_AUXADC_DCOMP2);
477ebccec0fSMark Brown 		if (status2 & WM8350_AUXADC_DCOMP1_EINT)
478ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
479ebccec0fSMark Brown 						WM8350_IRQ_AUXADC_DCOMP1);
480ebccec0fSMark Brown 
481ebccec0fSMark Brown 		if (status2 & WM8350_USB_LIMIT_EINT)
482ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_USB_LIMIT);
483ebccec0fSMark Brown 	}
484ebccec0fSMark Brown 
485ebccec0fSMark Brown 	/* wake, codec, ext */
486ebccec0fSMark Brown 	if (comp) {
487ebccec0fSMark Brown 		if (comp & WM8350_WKUP_OFF_STATE_EINT)
488ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
489ebccec0fSMark Brown 						WM8350_IRQ_WKUP_OFF_STATE);
490ebccec0fSMark Brown 		if (comp & WM8350_WKUP_HIB_STATE_EINT)
491ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
492ebccec0fSMark Brown 						WM8350_IRQ_WKUP_HIB_STATE);
493ebccec0fSMark Brown 		if (comp & WM8350_WKUP_CONV_FAULT_EINT)
494ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
495ebccec0fSMark Brown 						WM8350_IRQ_WKUP_CONV_FAULT);
496ebccec0fSMark Brown 		if (comp & WM8350_WKUP_WDOG_RST_EINT)
497ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
498ebccec0fSMark Brown 						WM8350_IRQ_WKUP_WDOG_RST);
499ebccec0fSMark Brown 		if (comp & WM8350_WKUP_GP_PWR_ON_EINT)
500ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
501ebccec0fSMark Brown 						WM8350_IRQ_WKUP_GP_PWR_ON);
502ebccec0fSMark Brown 		if (comp & WM8350_WKUP_ONKEY_EINT)
503ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_WKUP_ONKEY);
504ebccec0fSMark Brown 		if (comp & WM8350_WKUP_GP_WAKEUP_EINT)
505ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
506ebccec0fSMark Brown 						WM8350_IRQ_WKUP_GP_WAKEUP);
507ebccec0fSMark Brown 
508ebccec0fSMark Brown 		if (comp & WM8350_CODEC_JCK_DET_L_EINT)
509ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
510ebccec0fSMark Brown 						WM8350_IRQ_CODEC_JCK_DET_L);
511ebccec0fSMark Brown 		if (comp & WM8350_CODEC_JCK_DET_R_EINT)
512ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
513ebccec0fSMark Brown 						WM8350_IRQ_CODEC_JCK_DET_R);
514ebccec0fSMark Brown 		if (comp & WM8350_CODEC_MICSCD_EINT)
515ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
516ebccec0fSMark Brown 						WM8350_IRQ_CODEC_MICSCD);
517ebccec0fSMark Brown 		if (comp & WM8350_CODEC_MICD_EINT)
518ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CODEC_MICD);
519ebccec0fSMark Brown 
520ebccec0fSMark Brown 		if (comp & WM8350_EXT_USB_FB_EINT)
521ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_USB_FB);
522ebccec0fSMark Brown 		if (comp & WM8350_EXT_WALL_FB_EINT)
523ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
524ebccec0fSMark Brown 						WM8350_IRQ_EXT_WALL_FB);
525ebccec0fSMark Brown 		if (comp & WM8350_EXT_BAT_FB_EINT)
526ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_BAT_FB);
527ebccec0fSMark Brown 	}
528ebccec0fSMark Brown 
529ebccec0fSMark Brown 	if (level_one & WM8350_GP_INT) {
530ebccec0fSMark Brown 		int i;
531ebccec0fSMark Brown 		u16 gpio;
532ebccec0fSMark Brown 
533ebccec0fSMark Brown 		gpio = wm8350_reg_read(wm8350, WM8350_GPIO_INT_STATUS);
534ebccec0fSMark Brown 		gpio &= ~wm8350_reg_read(wm8350,
535ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK);
536ebccec0fSMark Brown 
537ebccec0fSMark Brown 		for (i = 0; i < 12; i++) {
538ebccec0fSMark Brown 			if (gpio & (1 << i))
539ebccec0fSMark Brown 				wm8350_irq_call_handler(wm8350,
540ebccec0fSMark Brown 							WM8350_IRQ_GPIO(i));
541ebccec0fSMark Brown 		}
542ebccec0fSMark Brown 	}
543ebccec0fSMark Brown 
544ebccec0fSMark Brown 	enable_irq(wm8350->chip_irq);
545ebccec0fSMark Brown }
546ebccec0fSMark Brown 
547ebccec0fSMark Brown static irqreturn_t wm8350_irq(int irq, void *data)
548ebccec0fSMark Brown {
549ebccec0fSMark Brown 	struct wm8350 *wm8350 = data;
550ebccec0fSMark Brown 
551ebccec0fSMark Brown 	disable_irq_nosync(irq);
552ebccec0fSMark Brown 	schedule_work(&wm8350->irq_work);
553ebccec0fSMark Brown 
554ebccec0fSMark Brown 	return IRQ_HANDLED;
555ebccec0fSMark Brown }
556ebccec0fSMark Brown 
557ebccec0fSMark Brown int wm8350_register_irq(struct wm8350 *wm8350, int irq,
558ebccec0fSMark Brown 			void (*handler) (struct wm8350 *, int, void *),
559ebccec0fSMark Brown 			void *data)
560ebccec0fSMark Brown {
561ebccec0fSMark Brown 	if (irq < 0 || irq > WM8350_NUM_IRQ || !handler)
562ebccec0fSMark Brown 		return -EINVAL;
563ebccec0fSMark Brown 
564ebccec0fSMark Brown 	if (wm8350->irq[irq].handler)
565ebccec0fSMark Brown 		return -EBUSY;
566ebccec0fSMark Brown 
567ebccec0fSMark Brown 	mutex_lock(&wm8350->irq_mutex);
568ebccec0fSMark Brown 	wm8350->irq[irq].handler = handler;
569ebccec0fSMark Brown 	wm8350->irq[irq].data = data;
570ebccec0fSMark Brown 	mutex_unlock(&wm8350->irq_mutex);
571ebccec0fSMark Brown 
572ebccec0fSMark Brown 	return 0;
573ebccec0fSMark Brown }
574ebccec0fSMark Brown EXPORT_SYMBOL_GPL(wm8350_register_irq);
575ebccec0fSMark Brown 
576ebccec0fSMark Brown int wm8350_free_irq(struct wm8350 *wm8350, int irq)
577ebccec0fSMark Brown {
578ebccec0fSMark Brown 	if (irq < 0 || irq > WM8350_NUM_IRQ)
579ebccec0fSMark Brown 		return -EINVAL;
580ebccec0fSMark Brown 
581ebccec0fSMark Brown 	mutex_lock(&wm8350->irq_mutex);
582ebccec0fSMark Brown 	wm8350->irq[irq].handler = NULL;
583ebccec0fSMark Brown 	mutex_unlock(&wm8350->irq_mutex);
584ebccec0fSMark Brown 	return 0;
585ebccec0fSMark Brown }
586ebccec0fSMark Brown EXPORT_SYMBOL_GPL(wm8350_free_irq);
587ebccec0fSMark Brown 
588ebccec0fSMark Brown int wm8350_mask_irq(struct wm8350 *wm8350, int irq)
589ebccec0fSMark Brown {
590ebccec0fSMark Brown 	switch (irq) {
591ebccec0fSMark Brown 	case WM8350_IRQ_CHG_BAT_HOT:
592ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
593ebccec0fSMark Brown 				       WM8350_IM_CHG_BAT_HOT_EINT);
594ebccec0fSMark Brown 	case WM8350_IRQ_CHG_BAT_COLD:
595ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
596ebccec0fSMark Brown 				       WM8350_IM_CHG_BAT_COLD_EINT);
597ebccec0fSMark Brown 	case WM8350_IRQ_CHG_BAT_FAIL:
598ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
599ebccec0fSMark Brown 				       WM8350_IM_CHG_BAT_FAIL_EINT);
600ebccec0fSMark Brown 	case WM8350_IRQ_CHG_TO:
601ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
602ebccec0fSMark Brown 				       WM8350_IM_CHG_TO_EINT);
603ebccec0fSMark Brown 	case WM8350_IRQ_CHG_END:
604ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
605ebccec0fSMark Brown 				       WM8350_IM_CHG_END_EINT);
606ebccec0fSMark Brown 	case WM8350_IRQ_CHG_START:
607ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
608ebccec0fSMark Brown 				       WM8350_IM_CHG_START_EINT);
609ebccec0fSMark Brown 	case WM8350_IRQ_CHG_FAST_RDY:
610ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
611ebccec0fSMark Brown 				       WM8350_IM_CHG_FAST_RDY_EINT);
612ebccec0fSMark Brown 	case WM8350_IRQ_RTC_PER:
613ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
614ebccec0fSMark Brown 				       WM8350_IM_RTC_PER_EINT);
615ebccec0fSMark Brown 	case WM8350_IRQ_RTC_SEC:
616ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
617ebccec0fSMark Brown 				       WM8350_IM_RTC_SEC_EINT);
618ebccec0fSMark Brown 	case WM8350_IRQ_RTC_ALM:
619ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
620ebccec0fSMark Brown 				       WM8350_IM_RTC_ALM_EINT);
621ebccec0fSMark Brown 	case WM8350_IRQ_CHG_VBATT_LT_3P9:
622ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
623ebccec0fSMark Brown 				       WM8350_IM_CHG_VBATT_LT_3P9_EINT);
624ebccec0fSMark Brown 	case WM8350_IRQ_CHG_VBATT_LT_3P1:
625ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
626ebccec0fSMark Brown 				       WM8350_IM_CHG_VBATT_LT_3P1_EINT);
627ebccec0fSMark Brown 	case WM8350_IRQ_CHG_VBATT_LT_2P85:
628ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
629ebccec0fSMark Brown 				       WM8350_IM_CHG_VBATT_LT_2P85_EINT);
630ebccec0fSMark Brown 	case WM8350_IRQ_CS1:
631ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
632ebccec0fSMark Brown 				       WM8350_IM_CS1_EINT);
633ebccec0fSMark Brown 	case WM8350_IRQ_CS2:
634ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
635ebccec0fSMark Brown 				       WM8350_IM_CS2_EINT);
636ebccec0fSMark Brown 	case WM8350_IRQ_USB_LIMIT:
637ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
638ebccec0fSMark Brown 				       WM8350_IM_USB_LIMIT_EINT);
639ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DATARDY:
640ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
641ebccec0fSMark Brown 				       WM8350_IM_AUXADC_DATARDY_EINT);
642ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DCOMP4:
643ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
644ebccec0fSMark Brown 				       WM8350_IM_AUXADC_DCOMP4_EINT);
645ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DCOMP3:
646ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
647ebccec0fSMark Brown 				       WM8350_IM_AUXADC_DCOMP3_EINT);
648ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DCOMP2:
649ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
650ebccec0fSMark Brown 				       WM8350_IM_AUXADC_DCOMP2_EINT);
651ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DCOMP1:
652ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
653ebccec0fSMark Brown 				       WM8350_IM_AUXADC_DCOMP1_EINT);
654ebccec0fSMark Brown 	case WM8350_IRQ_SYS_HYST_COMP_FAIL:
655ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
656ebccec0fSMark Brown 				       WM8350_IM_SYS_HYST_COMP_FAIL_EINT);
657ebccec0fSMark Brown 	case WM8350_IRQ_SYS_CHIP_GT115:
658ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
659ebccec0fSMark Brown 				       WM8350_IM_SYS_CHIP_GT115_EINT);
660ebccec0fSMark Brown 	case WM8350_IRQ_SYS_CHIP_GT140:
661ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
662ebccec0fSMark Brown 				       WM8350_IM_SYS_CHIP_GT140_EINT);
663ebccec0fSMark Brown 	case WM8350_IRQ_SYS_WDOG_TO:
664ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
665ebccec0fSMark Brown 				       WM8350_IM_SYS_WDOG_TO_EINT);
666ebccec0fSMark Brown 	case WM8350_IRQ_UV_LDO4:
667ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
668ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
669ebccec0fSMark Brown 				       WM8350_IM_UV_LDO4_EINT);
670ebccec0fSMark Brown 	case WM8350_IRQ_UV_LDO3:
671ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
672ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
673ebccec0fSMark Brown 				       WM8350_IM_UV_LDO3_EINT);
674ebccec0fSMark Brown 	case WM8350_IRQ_UV_LDO2:
675ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
676ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
677ebccec0fSMark Brown 				       WM8350_IM_UV_LDO2_EINT);
678ebccec0fSMark Brown 	case WM8350_IRQ_UV_LDO1:
679ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
680ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
681ebccec0fSMark Brown 				       WM8350_IM_UV_LDO1_EINT);
682ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC6:
683ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
684ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
685ebccec0fSMark Brown 				       WM8350_IM_UV_DC6_EINT);
686ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC5:
687ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
688ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
689ebccec0fSMark Brown 				       WM8350_IM_UV_DC5_EINT);
690ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC4:
691ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
692ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
693ebccec0fSMark Brown 				       WM8350_IM_UV_DC4_EINT);
694ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC3:
695ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
696ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
697ebccec0fSMark Brown 				       WM8350_IM_UV_DC3_EINT);
698ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC2:
699ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
700ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
701ebccec0fSMark Brown 				       WM8350_IM_UV_DC2_EINT);
702ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC1:
703ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
704ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
705ebccec0fSMark Brown 				       WM8350_IM_UV_DC1_EINT);
706ebccec0fSMark Brown 	case WM8350_IRQ_OC_LS:
707ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
708ebccec0fSMark Brown 				       WM8350_OVER_CURRENT_INT_STATUS_MASK,
709ebccec0fSMark Brown 				       WM8350_IM_OC_LS_EINT);
710ebccec0fSMark Brown 	case WM8350_IRQ_EXT_USB_FB:
711ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
712ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
713ebccec0fSMark Brown 				       WM8350_IM_EXT_USB_FB_EINT);
714ebccec0fSMark Brown 	case WM8350_IRQ_EXT_WALL_FB:
715ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
716ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
717ebccec0fSMark Brown 				       WM8350_IM_EXT_WALL_FB_EINT);
718ebccec0fSMark Brown 	case WM8350_IRQ_EXT_BAT_FB:
719ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
720ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
721ebccec0fSMark Brown 				       WM8350_IM_EXT_BAT_FB_EINT);
722ebccec0fSMark Brown 	case WM8350_IRQ_CODEC_JCK_DET_L:
723ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
724ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
725ebccec0fSMark Brown 				       WM8350_IM_CODEC_JCK_DET_L_EINT);
726ebccec0fSMark Brown 	case WM8350_IRQ_CODEC_JCK_DET_R:
727ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
728ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
729ebccec0fSMark Brown 				       WM8350_IM_CODEC_JCK_DET_R_EINT);
730ebccec0fSMark Brown 	case WM8350_IRQ_CODEC_MICSCD:
731ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
732ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
733ebccec0fSMark Brown 				       WM8350_IM_CODEC_MICSCD_EINT);
734ebccec0fSMark Brown 	case WM8350_IRQ_CODEC_MICD:
735ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
736ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
737ebccec0fSMark Brown 				       WM8350_IM_CODEC_MICD_EINT);
738ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_OFF_STATE:
739ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
740ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
741ebccec0fSMark Brown 				       WM8350_IM_WKUP_OFF_STATE_EINT);
742ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_HIB_STATE:
743ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
744ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
745ebccec0fSMark Brown 				       WM8350_IM_WKUP_HIB_STATE_EINT);
746ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_CONV_FAULT:
747ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
748ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
749ebccec0fSMark Brown 				       WM8350_IM_WKUP_CONV_FAULT_EINT);
750ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_WDOG_RST:
751ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
752ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
753ebccec0fSMark Brown 				       WM8350_IM_WKUP_OFF_STATE_EINT);
754ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_GP_PWR_ON:
755ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
756ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
757ebccec0fSMark Brown 				       WM8350_IM_WKUP_GP_PWR_ON_EINT);
758ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_ONKEY:
759ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
760ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
761ebccec0fSMark Brown 				       WM8350_IM_WKUP_ONKEY_EINT);
762ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_GP_WAKEUP:
763ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
764ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
765ebccec0fSMark Brown 				       WM8350_IM_WKUP_GP_WAKEUP_EINT);
766ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(0):
767ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
768ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
769ebccec0fSMark Brown 				       WM8350_IM_GP0_EINT);
770ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(1):
771ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
772ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
773ebccec0fSMark Brown 				       WM8350_IM_GP1_EINT);
774ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(2):
775ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
776ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
777ebccec0fSMark Brown 				       WM8350_IM_GP2_EINT);
778ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(3):
779ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
780ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
781ebccec0fSMark Brown 				       WM8350_IM_GP3_EINT);
782ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(4):
783ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
784ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
785ebccec0fSMark Brown 				       WM8350_IM_GP4_EINT);
786ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(5):
787ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
788ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
789ebccec0fSMark Brown 				       WM8350_IM_GP5_EINT);
790ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(6):
791ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
792ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
793ebccec0fSMark Brown 				       WM8350_IM_GP6_EINT);
794ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(7):
795ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
796ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
797ebccec0fSMark Brown 				       WM8350_IM_GP7_EINT);
798ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(8):
799ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
800ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
801ebccec0fSMark Brown 				       WM8350_IM_GP8_EINT);
802ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(9):
803ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
804ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
805ebccec0fSMark Brown 				       WM8350_IM_GP9_EINT);
806ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(10):
807ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
808ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
809ebccec0fSMark Brown 				       WM8350_IM_GP10_EINT);
810ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(11):
811ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
812ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
813ebccec0fSMark Brown 				       WM8350_IM_GP11_EINT);
814ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(12):
815ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
816ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
817ebccec0fSMark Brown 				       WM8350_IM_GP12_EINT);
818ebccec0fSMark Brown 	default:
819ebccec0fSMark Brown 		dev_warn(wm8350->dev, "Attempting to mask unknown IRQ %d\n",
820ebccec0fSMark Brown 			 irq);
821ebccec0fSMark Brown 		return -EINVAL;
822ebccec0fSMark Brown 	}
823ebccec0fSMark Brown 	return 0;
824ebccec0fSMark Brown }
825ebccec0fSMark Brown EXPORT_SYMBOL_GPL(wm8350_mask_irq);
826ebccec0fSMark Brown 
827ebccec0fSMark Brown int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
828ebccec0fSMark Brown {
829ebccec0fSMark Brown 	switch (irq) {
830ebccec0fSMark Brown 	case WM8350_IRQ_CHG_BAT_HOT:
831ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
832ebccec0fSMark Brown 					 WM8350_IM_CHG_BAT_HOT_EINT);
833ebccec0fSMark Brown 	case WM8350_IRQ_CHG_BAT_COLD:
834ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
835ebccec0fSMark Brown 					 WM8350_IM_CHG_BAT_COLD_EINT);
836ebccec0fSMark Brown 	case WM8350_IRQ_CHG_BAT_FAIL:
837ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
838ebccec0fSMark Brown 					 WM8350_IM_CHG_BAT_FAIL_EINT);
839ebccec0fSMark Brown 	case WM8350_IRQ_CHG_TO:
840ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
841ebccec0fSMark Brown 					 WM8350_IM_CHG_TO_EINT);
842ebccec0fSMark Brown 	case WM8350_IRQ_CHG_END:
843ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
844ebccec0fSMark Brown 					 WM8350_IM_CHG_END_EINT);
845ebccec0fSMark Brown 	case WM8350_IRQ_CHG_START:
846ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
847ebccec0fSMark Brown 					 WM8350_IM_CHG_START_EINT);
848ebccec0fSMark Brown 	case WM8350_IRQ_CHG_FAST_RDY:
849ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
850ebccec0fSMark Brown 					 WM8350_IM_CHG_FAST_RDY_EINT);
851ebccec0fSMark Brown 	case WM8350_IRQ_RTC_PER:
852ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
853ebccec0fSMark Brown 					 WM8350_IM_RTC_PER_EINT);
854ebccec0fSMark Brown 	case WM8350_IRQ_RTC_SEC:
855ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
856ebccec0fSMark Brown 					 WM8350_IM_RTC_SEC_EINT);
857ebccec0fSMark Brown 	case WM8350_IRQ_RTC_ALM:
858ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
859ebccec0fSMark Brown 					 WM8350_IM_RTC_ALM_EINT);
860ebccec0fSMark Brown 	case WM8350_IRQ_CHG_VBATT_LT_3P9:
861ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
862ebccec0fSMark Brown 					 WM8350_IM_CHG_VBATT_LT_3P9_EINT);
863ebccec0fSMark Brown 	case WM8350_IRQ_CHG_VBATT_LT_3P1:
864ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
865ebccec0fSMark Brown 					 WM8350_IM_CHG_VBATT_LT_3P1_EINT);
866ebccec0fSMark Brown 	case WM8350_IRQ_CHG_VBATT_LT_2P85:
867ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
868ebccec0fSMark Brown 					 WM8350_IM_CHG_VBATT_LT_2P85_EINT);
869ebccec0fSMark Brown 	case WM8350_IRQ_CS1:
870ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
871ebccec0fSMark Brown 					 WM8350_IM_CS1_EINT);
872ebccec0fSMark Brown 	case WM8350_IRQ_CS2:
873ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
874ebccec0fSMark Brown 					 WM8350_IM_CS2_EINT);
875ebccec0fSMark Brown 	case WM8350_IRQ_USB_LIMIT:
876ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
877ebccec0fSMark Brown 					 WM8350_IM_USB_LIMIT_EINT);
878ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DATARDY:
879ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
880ebccec0fSMark Brown 					 WM8350_IM_AUXADC_DATARDY_EINT);
881ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DCOMP4:
882ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
883ebccec0fSMark Brown 					 WM8350_IM_AUXADC_DCOMP4_EINT);
884ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DCOMP3:
885ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
886ebccec0fSMark Brown 					 WM8350_IM_AUXADC_DCOMP3_EINT);
887ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DCOMP2:
888ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
889ebccec0fSMark Brown 					 WM8350_IM_AUXADC_DCOMP2_EINT);
890ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DCOMP1:
891ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
892ebccec0fSMark Brown 					 WM8350_IM_AUXADC_DCOMP1_EINT);
893ebccec0fSMark Brown 	case WM8350_IRQ_SYS_HYST_COMP_FAIL:
894ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
895ebccec0fSMark Brown 					 WM8350_IM_SYS_HYST_COMP_FAIL_EINT);
896ebccec0fSMark Brown 	case WM8350_IRQ_SYS_CHIP_GT115:
897ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
898ebccec0fSMark Brown 					 WM8350_IM_SYS_CHIP_GT115_EINT);
899ebccec0fSMark Brown 	case WM8350_IRQ_SYS_CHIP_GT140:
900ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
901ebccec0fSMark Brown 					 WM8350_IM_SYS_CHIP_GT140_EINT);
902ebccec0fSMark Brown 	case WM8350_IRQ_SYS_WDOG_TO:
903ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
904ebccec0fSMark Brown 					 WM8350_IM_SYS_WDOG_TO_EINT);
905ebccec0fSMark Brown 	case WM8350_IRQ_UV_LDO4:
906ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
907ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
908ebccec0fSMark Brown 					 WM8350_IM_UV_LDO4_EINT);
909ebccec0fSMark Brown 	case WM8350_IRQ_UV_LDO3:
910ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
911ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
912ebccec0fSMark Brown 					 WM8350_IM_UV_LDO3_EINT);
913ebccec0fSMark Brown 	case WM8350_IRQ_UV_LDO2:
914ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
915ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
916ebccec0fSMark Brown 					 WM8350_IM_UV_LDO2_EINT);
917ebccec0fSMark Brown 	case WM8350_IRQ_UV_LDO1:
918ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
919ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
920ebccec0fSMark Brown 					 WM8350_IM_UV_LDO1_EINT);
921ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC6:
922ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
923ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
924ebccec0fSMark Brown 					 WM8350_IM_UV_DC6_EINT);
925ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC5:
926ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
927ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
928ebccec0fSMark Brown 					 WM8350_IM_UV_DC5_EINT);
929ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC4:
930ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
931ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
932ebccec0fSMark Brown 					 WM8350_IM_UV_DC4_EINT);
933ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC3:
934ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
935ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
936ebccec0fSMark Brown 					 WM8350_IM_UV_DC3_EINT);
937ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC2:
938ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
939ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
940ebccec0fSMark Brown 					 WM8350_IM_UV_DC2_EINT);
941ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC1:
942ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
943ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
944ebccec0fSMark Brown 					 WM8350_IM_UV_DC1_EINT);
945ebccec0fSMark Brown 	case WM8350_IRQ_OC_LS:
946ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
947ebccec0fSMark Brown 					 WM8350_OVER_CURRENT_INT_STATUS_MASK,
948ebccec0fSMark Brown 					 WM8350_IM_OC_LS_EINT);
949ebccec0fSMark Brown 	case WM8350_IRQ_EXT_USB_FB:
950ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
951ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
952ebccec0fSMark Brown 					 WM8350_IM_EXT_USB_FB_EINT);
953ebccec0fSMark Brown 	case WM8350_IRQ_EXT_WALL_FB:
954ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
955ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
956ebccec0fSMark Brown 					 WM8350_IM_EXT_WALL_FB_EINT);
957ebccec0fSMark Brown 	case WM8350_IRQ_EXT_BAT_FB:
958ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
959ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
960ebccec0fSMark Brown 					 WM8350_IM_EXT_BAT_FB_EINT);
961ebccec0fSMark Brown 	case WM8350_IRQ_CODEC_JCK_DET_L:
962ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
963ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
964ebccec0fSMark Brown 					 WM8350_IM_CODEC_JCK_DET_L_EINT);
965ebccec0fSMark Brown 	case WM8350_IRQ_CODEC_JCK_DET_R:
966ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
967ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
968ebccec0fSMark Brown 					 WM8350_IM_CODEC_JCK_DET_R_EINT);
969ebccec0fSMark Brown 	case WM8350_IRQ_CODEC_MICSCD:
970ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
971ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
972ebccec0fSMark Brown 					 WM8350_IM_CODEC_MICSCD_EINT);
973ebccec0fSMark Brown 	case WM8350_IRQ_CODEC_MICD:
974ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
975ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
976ebccec0fSMark Brown 					 WM8350_IM_CODEC_MICD_EINT);
977ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_OFF_STATE:
978ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
979ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
980ebccec0fSMark Brown 					 WM8350_IM_WKUP_OFF_STATE_EINT);
981ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_HIB_STATE:
982ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
983ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
984ebccec0fSMark Brown 					 WM8350_IM_WKUP_HIB_STATE_EINT);
985ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_CONV_FAULT:
986ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
987ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
988ebccec0fSMark Brown 					 WM8350_IM_WKUP_CONV_FAULT_EINT);
989ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_WDOG_RST:
990ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
991ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
992ebccec0fSMark Brown 					 WM8350_IM_WKUP_OFF_STATE_EINT);
993ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_GP_PWR_ON:
994ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
995ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
996ebccec0fSMark Brown 					 WM8350_IM_WKUP_GP_PWR_ON_EINT);
997ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_ONKEY:
998ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
999ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
1000ebccec0fSMark Brown 					 WM8350_IM_WKUP_ONKEY_EINT);
1001ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_GP_WAKEUP:
1002ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1003ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
1004ebccec0fSMark Brown 					 WM8350_IM_WKUP_GP_WAKEUP_EINT);
1005ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(0):
1006ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1007ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1008ebccec0fSMark Brown 					 WM8350_IM_GP0_EINT);
1009ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(1):
1010ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1011ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1012ebccec0fSMark Brown 					 WM8350_IM_GP1_EINT);
1013ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(2):
1014ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1015ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1016ebccec0fSMark Brown 					 WM8350_IM_GP2_EINT);
1017ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(3):
1018ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1019ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1020ebccec0fSMark Brown 					 WM8350_IM_GP3_EINT);
1021ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(4):
1022ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1023ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1024ebccec0fSMark Brown 					 WM8350_IM_GP4_EINT);
1025ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(5):
1026ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1027ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1028ebccec0fSMark Brown 					 WM8350_IM_GP5_EINT);
1029ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(6):
1030ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1031ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1032ebccec0fSMark Brown 					 WM8350_IM_GP6_EINT);
1033ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(7):
1034ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1035ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1036ebccec0fSMark Brown 					 WM8350_IM_GP7_EINT);
1037ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(8):
1038ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1039ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1040ebccec0fSMark Brown 					 WM8350_IM_GP8_EINT);
1041ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(9):
1042ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1043ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1044ebccec0fSMark Brown 					 WM8350_IM_GP9_EINT);
1045ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(10):
1046ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1047ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1048ebccec0fSMark Brown 					 WM8350_IM_GP10_EINT);
1049ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(11):
1050ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1051ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1052ebccec0fSMark Brown 					 WM8350_IM_GP11_EINT);
1053ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(12):
1054ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1055ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1056ebccec0fSMark Brown 					 WM8350_IM_GP12_EINT);
1057ebccec0fSMark Brown 	default:
1058ebccec0fSMark Brown 		dev_warn(wm8350->dev, "Attempting to unmask unknown IRQ %d\n",
1059ebccec0fSMark Brown 			 irq);
1060ebccec0fSMark Brown 		return -EINVAL;
1061ebccec0fSMark Brown 	}
1062ebccec0fSMark Brown 	return 0;
1063ebccec0fSMark Brown }
1064ebccec0fSMark Brown EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
1065ebccec0fSMark Brown 
106689b4012bSMark Brown /*
106789b4012bSMark Brown  * Cache is always host endian.
106889b4012bSMark Brown  */
106989b4012bSMark Brown static int wm8350_create_cache(struct wm8350 *wm8350, int mode)
107089b4012bSMark Brown {
107189b4012bSMark Brown 	int i, ret = 0;
107289b4012bSMark Brown 	u16 value;
107389b4012bSMark Brown 	const u16 *reg_map;
107489b4012bSMark Brown 
107589b4012bSMark Brown 	switch (mode) {
107689b4012bSMark Brown #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
107789b4012bSMark Brown 	case 0:
107889b4012bSMark Brown 		reg_map = wm8350_mode0_defaults;
107989b4012bSMark Brown 		break;
108089b4012bSMark Brown #endif
108189b4012bSMark Brown #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1
108289b4012bSMark Brown 	case 1:
108389b4012bSMark Brown 		reg_map = wm8350_mode1_defaults;
108489b4012bSMark Brown 		break;
108589b4012bSMark Brown #endif
108689b4012bSMark Brown #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2
108789b4012bSMark Brown 	case 2:
108889b4012bSMark Brown 		reg_map = wm8350_mode2_defaults;
108989b4012bSMark Brown 		break;
109089b4012bSMark Brown #endif
109189b4012bSMark Brown #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3
109289b4012bSMark Brown 	case 3:
109389b4012bSMark Brown 		reg_map = wm8350_mode3_defaults;
109489b4012bSMark Brown 		break;
109589b4012bSMark Brown #endif
109689b4012bSMark Brown 	default:
109789b4012bSMark Brown 		dev_err(wm8350->dev, "Configuration mode %d not supported\n",
109889b4012bSMark Brown 			mode);
109989b4012bSMark Brown 		return -EINVAL;
110089b4012bSMark Brown 	}
110189b4012bSMark Brown 
110289b4012bSMark Brown 	wm8350->reg_cache =
110389b4012bSMark Brown 	    kzalloc(sizeof(u16) * (WM8350_MAX_REGISTER + 1), GFP_KERNEL);
110489b4012bSMark Brown 	if (wm8350->reg_cache == NULL)
110589b4012bSMark Brown 		return -ENOMEM;
110689b4012bSMark Brown 
110789b4012bSMark Brown 	/* Read the initial cache state back from the device - this is
110889b4012bSMark Brown 	 * a PMIC so the device many not be in a virgin state and we
110989b4012bSMark Brown 	 * can't rely on the silicon values.
111089b4012bSMark Brown 	 */
111189b4012bSMark Brown 	for (i = 0; i < WM8350_MAX_REGISTER; i++) {
111289b4012bSMark Brown 		/* audio register range */
111389b4012bSMark Brown 		if (wm8350_reg_io_map[i].readable &&
111489b4012bSMark Brown 		    (i < WM8350_CLOCK_CONTROL_1 || i > WM8350_AIF_TEST)) {
111589b4012bSMark Brown 			ret = wm8350->read_dev(wm8350, i, 2, (char *)&value);
111689b4012bSMark Brown 			if (ret < 0) {
111789b4012bSMark Brown 				dev_err(wm8350->dev,
111889b4012bSMark Brown 				       "failed to read initial cache value\n");
111989b4012bSMark Brown 				goto out;
112089b4012bSMark Brown 			}
112189b4012bSMark Brown 			value = be16_to_cpu(value);
112289b4012bSMark Brown 			value &= wm8350_reg_io_map[i].readable;
112389b4012bSMark Brown 			wm8350->reg_cache[i] = value;
112489b4012bSMark Brown 		} else
112589b4012bSMark Brown 			wm8350->reg_cache[i] = reg_map[i];
112689b4012bSMark Brown 	}
112789b4012bSMark Brown 
112889b4012bSMark Brown out:
112989b4012bSMark Brown 	return ret;
113089b4012bSMark Brown }
113189b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_create_cache);
113289b4012bSMark Brown 
1133ebccec0fSMark Brown int wm8350_device_init(struct wm8350 *wm8350, int irq,
1134bcdd4efcSMark Brown 		       struct wm8350_platform_data *pdata)
113589b4012bSMark Brown {
113689b4012bSMark Brown 	int ret = -EINVAL;
113789b4012bSMark Brown 	u16 id1, id2, mask, mode;
1138ebccec0fSMark Brown 	int i;
113989b4012bSMark Brown 
114089b4012bSMark Brown 	/* get WM8350 revision and config mode */
114189b4012bSMark Brown 	wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1);
114289b4012bSMark Brown 	wm8350->read_dev(wm8350, WM8350_ID, sizeof(id2), &id2);
114389b4012bSMark Brown 
114489b4012bSMark Brown 	id1 = be16_to_cpu(id1);
114589b4012bSMark Brown 	id2 = be16_to_cpu(id2);
114689b4012bSMark Brown 
1147ebccec0fSMark Brown 	if (id1 == 0x6143) {
114889b4012bSMark Brown 		switch ((id2 & WM8350_CHIP_REV_MASK) >> 12) {
114989b4012bSMark Brown 		case WM8350_REV_E:
115089b4012bSMark Brown 			dev_info(wm8350->dev, "Found Rev E device\n");
115189b4012bSMark Brown 			wm8350->rev = WM8350_REV_E;
115289b4012bSMark Brown 			break;
115389b4012bSMark Brown 		case WM8350_REV_F:
115489b4012bSMark Brown 			dev_info(wm8350->dev, "Found Rev F device\n");
115589b4012bSMark Brown 			wm8350->rev = WM8350_REV_F;
115689b4012bSMark Brown 			break;
115789b4012bSMark Brown 		case WM8350_REV_G:
115889b4012bSMark Brown 			dev_info(wm8350->dev, "Found Rev G device\n");
115989b4012bSMark Brown 			wm8350->rev = WM8350_REV_G;
116089b4012bSMark Brown 			break;
116189b4012bSMark Brown 		default:
116289b4012bSMark Brown 			/* For safety we refuse to run on unknown hardware */
116389b4012bSMark Brown 			dev_info(wm8350->dev, "Found unknown rev\n");
116489b4012bSMark Brown 			ret = -ENODEV;
116589b4012bSMark Brown 			goto err;
116689b4012bSMark Brown 		}
116789b4012bSMark Brown 	} else {
116889b4012bSMark Brown 		dev_info(wm8350->dev, "Device with ID %x is not a WM8350\n",
116989b4012bSMark Brown 			 id1);
117089b4012bSMark Brown 		ret = -ENODEV;
117189b4012bSMark Brown 		goto err;
117289b4012bSMark Brown 	}
117389b4012bSMark Brown 
117489b4012bSMark Brown 	mode = id2 & WM8350_CONF_STS_MASK >> 10;
117589b4012bSMark Brown 	mask = id2 & WM8350_CUST_ID_MASK;
117689b4012bSMark Brown 	dev_info(wm8350->dev, "Config mode %d, ROM mask %d\n", mode, mask);
117789b4012bSMark Brown 
117889b4012bSMark Brown 	ret = wm8350_create_cache(wm8350, mode);
117989b4012bSMark Brown 	if (ret < 0) {
118089b4012bSMark Brown 		printk(KERN_ERR "wm8350: failed to create register cache\n");
118189b4012bSMark Brown 		return ret;
118289b4012bSMark Brown 	}
118389b4012bSMark Brown 
1184bcdd4efcSMark Brown 	if (pdata->init) {
1185bcdd4efcSMark Brown 		ret = pdata->init(wm8350);
1186bcdd4efcSMark Brown 		if (ret != 0) {
1187bcdd4efcSMark Brown 			dev_err(wm8350->dev, "Platform init() failed: %d\n",
1188bcdd4efcSMark Brown 				ret);
1189bcdd4efcSMark Brown 			goto err;
1190bcdd4efcSMark Brown 		}
1191bcdd4efcSMark Brown 	}
1192bcdd4efcSMark Brown 
1193ebccec0fSMark Brown 	mutex_init(&wm8350->irq_mutex);
1194ebccec0fSMark Brown 	INIT_WORK(&wm8350->irq_work, wm8350_irq_worker);
1195ebccec0fSMark Brown 	if (irq != NO_IRQ) {
1196ebccec0fSMark Brown 		ret = request_irq(irq, wm8350_irq, 0,
1197ebccec0fSMark Brown 				  "wm8350", wm8350);
1198ebccec0fSMark Brown 		if (ret != 0) {
1199ebccec0fSMark Brown 			dev_err(wm8350->dev, "Failed to request IRQ: %d\n",
1200ebccec0fSMark Brown 				ret);
1201ebccec0fSMark Brown 			goto err;
1202ebccec0fSMark Brown 		}
1203ebccec0fSMark Brown 	} else {
1204ebccec0fSMark Brown 		dev_err(wm8350->dev, "No IRQ configured\n");
1205ebccec0fSMark Brown 		goto err;
1206ebccec0fSMark Brown 	}
1207ebccec0fSMark Brown 	wm8350->chip_irq = irq;
1208ebccec0fSMark Brown 
1209ebccec0fSMark Brown 	wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0x0);
1210ebccec0fSMark Brown 
121189b4012bSMark Brown 	return 0;
121289b4012bSMark Brown 
121389b4012bSMark Brown err:
121489b4012bSMark Brown 	kfree(wm8350->reg_cache);
121589b4012bSMark Brown 	return ret;
121689b4012bSMark Brown }
121789b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_device_init);
121889b4012bSMark Brown 
121989b4012bSMark Brown void wm8350_device_exit(struct wm8350 *wm8350)
122089b4012bSMark Brown {
1221da09155aSMark Brown 	int i;
1222da09155aSMark Brown 
1223da09155aSMark Brown 	for (i = 0; i < ARRAY_SIZE(wm8350->pmic.pdev); i++)
1224da09155aSMark Brown 		if (wm8350->pmic.pdev[i] != NULL)
1225da09155aSMark Brown 			platform_device_unregister(wm8350->pmic.pdev[i]);
1226da09155aSMark Brown 
1227ebccec0fSMark Brown 	free_irq(wm8350->chip_irq, wm8350);
1228ebccec0fSMark Brown 	flush_work(&wm8350->irq_work);
122989b4012bSMark Brown 	kfree(wm8350->reg_cache);
123089b4012bSMark Brown }
123189b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_device_exit);
123289b4012bSMark Brown 
1233ebccec0fSMark Brown MODULE_DESCRIPTION("WM8350 AudioPlus PMIC core driver");
123489b4012bSMark Brown MODULE_LICENSE("GPL");
1235