xref: /openbmc/linux/drivers/mfd/wm8350-core.c (revision 0081e802)
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 
6789b4012bSMark Brown /* Perform a physical read from the device.
6889b4012bSMark Brown  */
6989b4012bSMark Brown static int wm8350_phys_read(struct wm8350 *wm8350, u8 reg, int num_regs,
7089b4012bSMark Brown 			    u16 *dest)
7189b4012bSMark Brown {
7289b4012bSMark Brown 	int i, ret;
7389b4012bSMark Brown 	int bytes = num_regs * 2;
7489b4012bSMark Brown 
7589b4012bSMark Brown 	dev_dbg(wm8350->dev, "volatile read\n");
7689b4012bSMark Brown 	ret = wm8350->read_dev(wm8350, reg, bytes, (char *)dest);
7789b4012bSMark Brown 
7889b4012bSMark Brown 	for (i = reg; i < reg + num_regs; i++) {
7989b4012bSMark Brown 		/* Cache is CPU endian */
8089b4012bSMark Brown 		dest[i - reg] = be16_to_cpu(dest[i - reg]);
8189b4012bSMark Brown 
8289b4012bSMark Brown 		/* Satisfy non-volatile bits from cache */
8389b4012bSMark Brown 		dest[i - reg] &= wm8350_reg_io_map[i].vol;
8489b4012bSMark Brown 		dest[i - reg] |= wm8350->reg_cache[i];
8589b4012bSMark Brown 
8689b4012bSMark Brown 		/* Mask out non-readable bits */
8789b4012bSMark Brown 		dest[i - reg] &= wm8350_reg_io_map[i].readable;
8889b4012bSMark Brown 	}
8989b4012bSMark Brown 
9089b4012bSMark Brown 	dump(num_regs, dest);
9189b4012bSMark Brown 
9289b4012bSMark Brown 	return ret;
9389b4012bSMark Brown }
9489b4012bSMark Brown 
9589b4012bSMark Brown static int wm8350_read(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *dest)
9689b4012bSMark Brown {
9789b4012bSMark Brown 	int i;
9889b4012bSMark Brown 	int end = reg + num_regs;
9989b4012bSMark Brown 	int ret = 0;
10089b4012bSMark Brown 	int bytes = num_regs * 2;
10189b4012bSMark Brown 
10289b4012bSMark Brown 	if (wm8350->read_dev == NULL)
10389b4012bSMark Brown 		return -ENODEV;
10489b4012bSMark Brown 
10589b4012bSMark Brown 	if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) {
10689b4012bSMark Brown 		dev_err(wm8350->dev, "invalid reg %x\n",
10789b4012bSMark Brown 			reg + num_regs - 1);
10889b4012bSMark Brown 		return -EINVAL;
10989b4012bSMark Brown 	}
11089b4012bSMark Brown 
11189b4012bSMark Brown 	dev_dbg(wm8350->dev,
11289b4012bSMark Brown 		"%s R%d(0x%2.2x) %d regs\n", __func__, reg, reg, num_regs);
11389b4012bSMark Brown 
11489b4012bSMark Brown #if WM8350_BUS_DEBUG
11589b4012bSMark Brown 	/* we can _safely_ read any register, but warn if read not supported */
11689b4012bSMark Brown 	for (i = reg; i < end; i++) {
11789b4012bSMark Brown 		if (!wm8350_reg_io_map[i].readable)
11889b4012bSMark Brown 			dev_warn(wm8350->dev,
11989b4012bSMark Brown 				"reg R%d is not readable\n", i);
12089b4012bSMark Brown 	}
12189b4012bSMark Brown #endif
12289b4012bSMark Brown 
12389b4012bSMark Brown 	/* if any volatile registers are required, then read back all */
12489b4012bSMark Brown 	for (i = reg; i < end; i++)
12589b4012bSMark Brown 		if (wm8350_reg_io_map[i].vol)
12689b4012bSMark Brown 			return wm8350_phys_read(wm8350, reg, num_regs, dest);
12789b4012bSMark Brown 
12889b4012bSMark Brown 	/* no volatiles, then cache is good */
12989b4012bSMark Brown 	dev_dbg(wm8350->dev, "cache read\n");
13089b4012bSMark Brown 	memcpy(dest, &wm8350->reg_cache[reg], bytes);
13189b4012bSMark Brown 	dump(num_regs, dest);
13289b4012bSMark Brown 	return ret;
13389b4012bSMark Brown }
13489b4012bSMark Brown 
13589b4012bSMark Brown static inline int is_reg_locked(struct wm8350 *wm8350, u8 reg)
13689b4012bSMark Brown {
13789b4012bSMark Brown 	if (reg == WM8350_SECURITY ||
13889b4012bSMark Brown 	    wm8350->reg_cache[WM8350_SECURITY] == WM8350_UNLOCK_KEY)
13989b4012bSMark Brown 		return 0;
14089b4012bSMark Brown 
14189b4012bSMark Brown 	if ((reg == WM8350_GPIO_CONFIGURATION_I_O) ||
14289b4012bSMark Brown 	    (reg >= WM8350_GPIO_FUNCTION_SELECT_1 &&
14389b4012bSMark Brown 	     reg <= WM8350_GPIO_FUNCTION_SELECT_4) ||
14489b4012bSMark Brown 	    (reg >= WM8350_BATTERY_CHARGER_CONTROL_1 &&
14589b4012bSMark Brown 	     reg <= WM8350_BATTERY_CHARGER_CONTROL_3))
14689b4012bSMark Brown 		return 1;
14789b4012bSMark Brown 	return 0;
14889b4012bSMark Brown }
14989b4012bSMark Brown 
15089b4012bSMark Brown static int wm8350_write(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *src)
15189b4012bSMark Brown {
15289b4012bSMark Brown 	int i;
15389b4012bSMark Brown 	int end = reg + num_regs;
15489b4012bSMark Brown 	int bytes = num_regs * 2;
15589b4012bSMark Brown 
15689b4012bSMark Brown 	if (wm8350->write_dev == NULL)
15789b4012bSMark Brown 		return -ENODEV;
15889b4012bSMark Brown 
15989b4012bSMark Brown 	if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) {
16089b4012bSMark Brown 		dev_err(wm8350->dev, "invalid reg %x\n",
16189b4012bSMark Brown 			reg + num_regs - 1);
16289b4012bSMark Brown 		return -EINVAL;
16389b4012bSMark Brown 	}
16489b4012bSMark Brown 
16589b4012bSMark Brown 	/* it's generally not a good idea to write to RO or locked registers */
16689b4012bSMark Brown 	for (i = reg; i < end; i++) {
16789b4012bSMark Brown 		if (!wm8350_reg_io_map[i].writable) {
16889b4012bSMark Brown 			dev_err(wm8350->dev,
16989b4012bSMark Brown 				"attempted write to read only reg R%d\n", i);
17089b4012bSMark Brown 			return -EINVAL;
17189b4012bSMark Brown 		}
17289b4012bSMark Brown 
17389b4012bSMark Brown 		if (is_reg_locked(wm8350, i)) {
17489b4012bSMark Brown 			dev_err(wm8350->dev,
17589b4012bSMark Brown 			       "attempted write to locked reg R%d\n", i);
17689b4012bSMark Brown 			return -EINVAL;
17789b4012bSMark Brown 		}
17889b4012bSMark Brown 
17989b4012bSMark Brown 		src[i - reg] &= wm8350_reg_io_map[i].writable;
18089b4012bSMark Brown 
18189b4012bSMark Brown 		wm8350->reg_cache[i] =
18289b4012bSMark Brown 			(wm8350->reg_cache[i] & ~wm8350_reg_io_map[i].writable)
18389b4012bSMark Brown 			| src[i - reg];
18489b4012bSMark Brown 
185e76f7558SMark Brown 		/* Don't store volatile bits */
186e76f7558SMark Brown 		wm8350->reg_cache[i] &= ~wm8350_reg_io_map[i].vol;
187e76f7558SMark Brown 
18889b4012bSMark Brown 		src[i - reg] = cpu_to_be16(src[i - reg]);
18989b4012bSMark Brown 	}
19089b4012bSMark Brown 
19189b4012bSMark Brown 	/* Actually write it out */
19289b4012bSMark Brown 	return wm8350->write_dev(wm8350, reg, bytes, (char *)src);
19389b4012bSMark Brown }
19489b4012bSMark Brown 
19589b4012bSMark Brown /*
19689b4012bSMark Brown  * Safe read, modify, write methods
19789b4012bSMark Brown  */
19889b4012bSMark Brown int wm8350_clear_bits(struct wm8350 *wm8350, u16 reg, u16 mask)
19989b4012bSMark Brown {
20089b4012bSMark Brown 	u16 data;
20189b4012bSMark Brown 	int err;
20289b4012bSMark Brown 
20389b4012bSMark Brown 	mutex_lock(&io_mutex);
20489b4012bSMark Brown 	err = wm8350_read(wm8350, reg, 1, &data);
20589b4012bSMark Brown 	if (err) {
20689b4012bSMark Brown 		dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
20789b4012bSMark Brown 		goto out;
20889b4012bSMark Brown 	}
20989b4012bSMark Brown 
21089b4012bSMark Brown 	data &= ~mask;
21189b4012bSMark Brown 	err = wm8350_write(wm8350, reg, 1, &data);
21289b4012bSMark Brown 	if (err)
21389b4012bSMark Brown 		dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
21489b4012bSMark Brown out:
21589b4012bSMark Brown 	mutex_unlock(&io_mutex);
21689b4012bSMark Brown 	return err;
21789b4012bSMark Brown }
21889b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_clear_bits);
21989b4012bSMark Brown 
22089b4012bSMark Brown int wm8350_set_bits(struct wm8350 *wm8350, u16 reg, u16 mask)
22189b4012bSMark Brown {
22289b4012bSMark Brown 	u16 data;
22389b4012bSMark Brown 	int err;
22489b4012bSMark Brown 
22589b4012bSMark Brown 	mutex_lock(&io_mutex);
22689b4012bSMark Brown 	err = wm8350_read(wm8350, reg, 1, &data);
22789b4012bSMark Brown 	if (err) {
22889b4012bSMark Brown 		dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
22989b4012bSMark Brown 		goto out;
23089b4012bSMark Brown 	}
23189b4012bSMark Brown 
23289b4012bSMark Brown 	data |= mask;
23389b4012bSMark Brown 	err = wm8350_write(wm8350, reg, 1, &data);
23489b4012bSMark Brown 	if (err)
23589b4012bSMark Brown 		dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
23689b4012bSMark Brown out:
23789b4012bSMark Brown 	mutex_unlock(&io_mutex);
23889b4012bSMark Brown 	return err;
23989b4012bSMark Brown }
24089b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_set_bits);
24189b4012bSMark Brown 
24289b4012bSMark Brown u16 wm8350_reg_read(struct wm8350 *wm8350, int reg)
24389b4012bSMark Brown {
24489b4012bSMark Brown 	u16 data;
24589b4012bSMark Brown 	int err;
24689b4012bSMark Brown 
24789b4012bSMark Brown 	mutex_lock(&io_mutex);
24889b4012bSMark Brown 	err = wm8350_read(wm8350, reg, 1, &data);
24989b4012bSMark Brown 	if (err)
25089b4012bSMark Brown 		dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
25189b4012bSMark Brown 
25289b4012bSMark Brown 	mutex_unlock(&io_mutex);
25389b4012bSMark Brown 	return data;
25489b4012bSMark Brown }
25589b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_reg_read);
25689b4012bSMark Brown 
25789b4012bSMark Brown int wm8350_reg_write(struct wm8350 *wm8350, int reg, u16 val)
25889b4012bSMark Brown {
25989b4012bSMark Brown 	int ret;
26089b4012bSMark Brown 	u16 data = val;
26189b4012bSMark Brown 
26289b4012bSMark Brown 	mutex_lock(&io_mutex);
26389b4012bSMark Brown 	ret = wm8350_write(wm8350, reg, 1, &data);
26489b4012bSMark Brown 	if (ret)
26589b4012bSMark Brown 		dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
26689b4012bSMark Brown 	mutex_unlock(&io_mutex);
26789b4012bSMark Brown 	return ret;
26889b4012bSMark Brown }
26989b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_reg_write);
27089b4012bSMark Brown 
27189b4012bSMark Brown int wm8350_block_read(struct wm8350 *wm8350, int start_reg, int regs,
27289b4012bSMark Brown 		      u16 *dest)
27389b4012bSMark Brown {
27489b4012bSMark Brown 	int err = 0;
27589b4012bSMark Brown 
27689b4012bSMark Brown 	mutex_lock(&io_mutex);
27789b4012bSMark Brown 	err = wm8350_read(wm8350, start_reg, regs, dest);
27889b4012bSMark Brown 	if (err)
27989b4012bSMark Brown 		dev_err(wm8350->dev, "block read starting from R%d failed\n",
28089b4012bSMark Brown 			start_reg);
28189b4012bSMark Brown 	mutex_unlock(&io_mutex);
28289b4012bSMark Brown 	return err;
28389b4012bSMark Brown }
28489b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_block_read);
28589b4012bSMark Brown 
28689b4012bSMark Brown int wm8350_block_write(struct wm8350 *wm8350, int start_reg, int regs,
28789b4012bSMark Brown 		       u16 *src)
28889b4012bSMark Brown {
28989b4012bSMark Brown 	int ret = 0;
29089b4012bSMark Brown 
29189b4012bSMark Brown 	mutex_lock(&io_mutex);
29289b4012bSMark Brown 	ret = wm8350_write(wm8350, start_reg, regs, src);
29389b4012bSMark Brown 	if (ret)
29489b4012bSMark Brown 		dev_err(wm8350->dev, "block write starting at R%d failed\n",
29589b4012bSMark Brown 			start_reg);
29689b4012bSMark Brown 	mutex_unlock(&io_mutex);
29789b4012bSMark Brown 	return ret;
29889b4012bSMark Brown }
29989b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_block_write);
30089b4012bSMark Brown 
301858e6744SMark Brown /**
302858e6744SMark Brown  * wm8350_reg_lock()
303858e6744SMark Brown  *
304858e6744SMark Brown  * The WM8350 has a hardware lock which can be used to prevent writes to
305858e6744SMark Brown  * some registers (generally those which can cause particularly serious
306858e6744SMark Brown  * problems if misused).  This function enables that lock.
307858e6744SMark Brown  */
30889b4012bSMark Brown int wm8350_reg_lock(struct wm8350 *wm8350)
30989b4012bSMark Brown {
31089b4012bSMark Brown 	u16 key = WM8350_LOCK_KEY;
31189b4012bSMark Brown 	int ret;
31289b4012bSMark Brown 
31389b4012bSMark Brown 	ldbg(__func__);
31489b4012bSMark Brown 	mutex_lock(&io_mutex);
31589b4012bSMark Brown 	ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key);
31689b4012bSMark Brown 	if (ret)
31789b4012bSMark Brown 		dev_err(wm8350->dev, "lock failed\n");
31889b4012bSMark Brown 	mutex_unlock(&io_mutex);
31989b4012bSMark Brown 	return ret;
32089b4012bSMark Brown }
32189b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_reg_lock);
32289b4012bSMark Brown 
323858e6744SMark Brown /**
324858e6744SMark Brown  * wm8350_reg_unlock()
325858e6744SMark Brown  *
326858e6744SMark Brown  * The WM8350 has a hardware lock which can be used to prevent writes to
327858e6744SMark Brown  * some registers (generally those which can cause particularly serious
328858e6744SMark Brown  * problems if misused).  This function disables that lock so updates
329858e6744SMark Brown  * can be performed.  For maximum safety this should be done only when
330858e6744SMark Brown  * required.
331858e6744SMark Brown  */
33289b4012bSMark Brown int wm8350_reg_unlock(struct wm8350 *wm8350)
33389b4012bSMark Brown {
33489b4012bSMark Brown 	u16 key = WM8350_UNLOCK_KEY;
33589b4012bSMark Brown 	int ret;
33689b4012bSMark Brown 
33789b4012bSMark Brown 	ldbg(__func__);
33889b4012bSMark Brown 	mutex_lock(&io_mutex);
33989b4012bSMark Brown 	ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key);
34089b4012bSMark Brown 	if (ret)
34189b4012bSMark Brown 		dev_err(wm8350->dev, "unlock failed\n");
34289b4012bSMark Brown 	mutex_unlock(&io_mutex);
34389b4012bSMark Brown 	return ret;
34489b4012bSMark Brown }
34589b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_reg_unlock);
34689b4012bSMark Brown 
347ebccec0fSMark Brown static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq)
348ebccec0fSMark Brown {
349ebccec0fSMark Brown 	mutex_lock(&wm8350->irq_mutex);
350ebccec0fSMark Brown 
351ebccec0fSMark Brown 	if (wm8350->irq[irq].handler)
352ebccec0fSMark Brown 		wm8350->irq[irq].handler(wm8350, irq, wm8350->irq[irq].data);
353ebccec0fSMark Brown 	else {
354ebccec0fSMark Brown 		dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n",
355ebccec0fSMark Brown 			irq);
356ebccec0fSMark Brown 		wm8350_mask_irq(wm8350, irq);
357ebccec0fSMark Brown 	}
358ebccec0fSMark Brown 
359ebccec0fSMark Brown 	mutex_unlock(&wm8350->irq_mutex);
360ebccec0fSMark Brown }
361ebccec0fSMark Brown 
362ebccec0fSMark Brown /*
363ebccec0fSMark Brown  * wm8350_irq_worker actually handles the interrupts.  Since all
364ebccec0fSMark Brown  * interrupts are clear on read the IRQ line will be reasserted and
365ebccec0fSMark Brown  * the physical IRQ will be handled again if another interrupt is
366ebccec0fSMark Brown  * asserted while we run - in the normal course of events this is a
367ebccec0fSMark Brown  * rare occurrence so we save I2C/SPI reads.
368ebccec0fSMark Brown  */
369ebccec0fSMark Brown static void wm8350_irq_worker(struct work_struct *work)
370ebccec0fSMark Brown {
371ebccec0fSMark Brown 	struct wm8350 *wm8350 = container_of(work, struct wm8350, irq_work);
372ebccec0fSMark Brown 	u16 level_one, status1, status2, comp;
373ebccec0fSMark Brown 
374ebccec0fSMark Brown 	/* TODO: Use block reads to improve performance? */
375ebccec0fSMark Brown 	level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS)
376ebccec0fSMark Brown 		& ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK);
377ebccec0fSMark Brown 	status1 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_1)
378ebccec0fSMark Brown 		& ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_1_MASK);
379ebccec0fSMark Brown 	status2 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_2)
380ebccec0fSMark Brown 		& ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_2_MASK);
381ebccec0fSMark Brown 	comp = wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS)
382ebccec0fSMark Brown 		& ~wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK);
383ebccec0fSMark Brown 
384ebccec0fSMark Brown 	/* over current */
385ebccec0fSMark Brown 	if (level_one & WM8350_OC_INT) {
386ebccec0fSMark Brown 		u16 oc;
387ebccec0fSMark Brown 
388ebccec0fSMark Brown 		oc = wm8350_reg_read(wm8350, WM8350_OVER_CURRENT_INT_STATUS);
389ebccec0fSMark Brown 		oc &= ~wm8350_reg_read(wm8350,
390ebccec0fSMark Brown 				       WM8350_OVER_CURRENT_INT_STATUS_MASK);
391ebccec0fSMark Brown 
392ebccec0fSMark Brown 		if (oc & WM8350_OC_LS_EINT)	/* limit switch */
393ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_OC_LS);
394ebccec0fSMark Brown 	}
395ebccec0fSMark Brown 
396ebccec0fSMark Brown 	/* under voltage */
397ebccec0fSMark Brown 	if (level_one & WM8350_UV_INT) {
398ebccec0fSMark Brown 		u16 uv;
399ebccec0fSMark Brown 
400ebccec0fSMark Brown 		uv = wm8350_reg_read(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS);
401ebccec0fSMark Brown 		uv &= ~wm8350_reg_read(wm8350,
402ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK);
403ebccec0fSMark Brown 
404ebccec0fSMark Brown 		if (uv & WM8350_UV_DC1_EINT)
405ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC1);
406ebccec0fSMark Brown 		if (uv & WM8350_UV_DC2_EINT)
407ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC2);
408ebccec0fSMark Brown 		if (uv & WM8350_UV_DC3_EINT)
409ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC3);
410ebccec0fSMark Brown 		if (uv & WM8350_UV_DC4_EINT)
411ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC4);
412ebccec0fSMark Brown 		if (uv & WM8350_UV_DC5_EINT)
413ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC5);
414ebccec0fSMark Brown 		if (uv & WM8350_UV_DC6_EINT)
415ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC6);
416ebccec0fSMark Brown 		if (uv & WM8350_UV_LDO1_EINT)
417ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO1);
418ebccec0fSMark Brown 		if (uv & WM8350_UV_LDO2_EINT)
419ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO2);
420ebccec0fSMark Brown 		if (uv & WM8350_UV_LDO3_EINT)
421ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO3);
422ebccec0fSMark Brown 		if (uv & WM8350_UV_LDO4_EINT)
423ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO4);
424ebccec0fSMark Brown 	}
425ebccec0fSMark Brown 
426ebccec0fSMark Brown 	/* charger, RTC */
427ebccec0fSMark Brown 	if (status1) {
428ebccec0fSMark Brown 		if (status1 & WM8350_CHG_BAT_HOT_EINT)
429ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
430ebccec0fSMark Brown 						WM8350_IRQ_CHG_BAT_HOT);
431ebccec0fSMark Brown 		if (status1 & WM8350_CHG_BAT_COLD_EINT)
432ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
433ebccec0fSMark Brown 						WM8350_IRQ_CHG_BAT_COLD);
434ebccec0fSMark Brown 		if (status1 & WM8350_CHG_BAT_FAIL_EINT)
435ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
436ebccec0fSMark Brown 						WM8350_IRQ_CHG_BAT_FAIL);
437ebccec0fSMark Brown 		if (status1 & WM8350_CHG_TO_EINT)
438ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_TO);
439ebccec0fSMark Brown 		if (status1 & WM8350_CHG_END_EINT)
440ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_END);
441ebccec0fSMark Brown 		if (status1 & WM8350_CHG_START_EINT)
442ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_START);
443ebccec0fSMark Brown 		if (status1 & WM8350_CHG_FAST_RDY_EINT)
444ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
445ebccec0fSMark Brown 						WM8350_IRQ_CHG_FAST_RDY);
446ebccec0fSMark Brown 		if (status1 & WM8350_CHG_VBATT_LT_3P9_EINT)
447ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
448ebccec0fSMark Brown 						WM8350_IRQ_CHG_VBATT_LT_3P9);
449ebccec0fSMark Brown 		if (status1 & WM8350_CHG_VBATT_LT_3P1_EINT)
450ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
451ebccec0fSMark Brown 						WM8350_IRQ_CHG_VBATT_LT_3P1);
452ebccec0fSMark Brown 		if (status1 & WM8350_CHG_VBATT_LT_2P85_EINT)
453ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
454ebccec0fSMark Brown 						WM8350_IRQ_CHG_VBATT_LT_2P85);
455ebccec0fSMark Brown 		if (status1 & WM8350_RTC_ALM_EINT)
456ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_ALM);
457ebccec0fSMark Brown 		if (status1 & WM8350_RTC_SEC_EINT)
458ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_SEC);
459ebccec0fSMark Brown 		if (status1 & WM8350_RTC_PER_EINT)
460ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_PER);
461ebccec0fSMark Brown 	}
462ebccec0fSMark Brown 
463ebccec0fSMark Brown 	/* current sink, system, aux adc */
464ebccec0fSMark Brown 	if (status2) {
465ebccec0fSMark Brown 		if (status2 & WM8350_CS1_EINT)
466ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS1);
467ebccec0fSMark Brown 		if (status2 & WM8350_CS2_EINT)
468ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS2);
469ebccec0fSMark Brown 
470ebccec0fSMark Brown 		if (status2 & WM8350_SYS_HYST_COMP_FAIL_EINT)
471ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
472ebccec0fSMark Brown 						WM8350_IRQ_SYS_HYST_COMP_FAIL);
473ebccec0fSMark Brown 		if (status2 & WM8350_SYS_CHIP_GT115_EINT)
474ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
475ebccec0fSMark Brown 						WM8350_IRQ_SYS_CHIP_GT115);
476ebccec0fSMark Brown 		if (status2 & WM8350_SYS_CHIP_GT140_EINT)
477ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
478ebccec0fSMark Brown 						WM8350_IRQ_SYS_CHIP_GT140);
479ebccec0fSMark Brown 		if (status2 & WM8350_SYS_WDOG_TO_EINT)
480ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
481ebccec0fSMark Brown 						WM8350_IRQ_SYS_WDOG_TO);
482ebccec0fSMark Brown 
483ebccec0fSMark Brown 		if (status2 & WM8350_AUXADC_DATARDY_EINT)
484ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
485ebccec0fSMark Brown 						WM8350_IRQ_AUXADC_DATARDY);
486ebccec0fSMark Brown 		if (status2 & WM8350_AUXADC_DCOMP4_EINT)
487ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
488ebccec0fSMark Brown 						WM8350_IRQ_AUXADC_DCOMP4);
489ebccec0fSMark Brown 		if (status2 & WM8350_AUXADC_DCOMP3_EINT)
490ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
491ebccec0fSMark Brown 						WM8350_IRQ_AUXADC_DCOMP3);
492ebccec0fSMark Brown 		if (status2 & WM8350_AUXADC_DCOMP2_EINT)
493ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
494ebccec0fSMark Brown 						WM8350_IRQ_AUXADC_DCOMP2);
495ebccec0fSMark Brown 		if (status2 & WM8350_AUXADC_DCOMP1_EINT)
496ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
497ebccec0fSMark Brown 						WM8350_IRQ_AUXADC_DCOMP1);
498ebccec0fSMark Brown 
499ebccec0fSMark Brown 		if (status2 & WM8350_USB_LIMIT_EINT)
500ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_USB_LIMIT);
501ebccec0fSMark Brown 	}
502ebccec0fSMark Brown 
503ebccec0fSMark Brown 	/* wake, codec, ext */
504ebccec0fSMark Brown 	if (comp) {
505ebccec0fSMark Brown 		if (comp & WM8350_WKUP_OFF_STATE_EINT)
506ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
507ebccec0fSMark Brown 						WM8350_IRQ_WKUP_OFF_STATE);
508ebccec0fSMark Brown 		if (comp & WM8350_WKUP_HIB_STATE_EINT)
509ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
510ebccec0fSMark Brown 						WM8350_IRQ_WKUP_HIB_STATE);
511ebccec0fSMark Brown 		if (comp & WM8350_WKUP_CONV_FAULT_EINT)
512ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
513ebccec0fSMark Brown 						WM8350_IRQ_WKUP_CONV_FAULT);
514ebccec0fSMark Brown 		if (comp & WM8350_WKUP_WDOG_RST_EINT)
515ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
516ebccec0fSMark Brown 						WM8350_IRQ_WKUP_WDOG_RST);
517ebccec0fSMark Brown 		if (comp & WM8350_WKUP_GP_PWR_ON_EINT)
518ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
519ebccec0fSMark Brown 						WM8350_IRQ_WKUP_GP_PWR_ON);
520ebccec0fSMark Brown 		if (comp & WM8350_WKUP_ONKEY_EINT)
521ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_WKUP_ONKEY);
522ebccec0fSMark Brown 		if (comp & WM8350_WKUP_GP_WAKEUP_EINT)
523ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
524ebccec0fSMark Brown 						WM8350_IRQ_WKUP_GP_WAKEUP);
525ebccec0fSMark Brown 
526ebccec0fSMark Brown 		if (comp & WM8350_CODEC_JCK_DET_L_EINT)
527ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
528ebccec0fSMark Brown 						WM8350_IRQ_CODEC_JCK_DET_L);
529ebccec0fSMark Brown 		if (comp & WM8350_CODEC_JCK_DET_R_EINT)
530ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
531ebccec0fSMark Brown 						WM8350_IRQ_CODEC_JCK_DET_R);
532ebccec0fSMark Brown 		if (comp & WM8350_CODEC_MICSCD_EINT)
533ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
534ebccec0fSMark Brown 						WM8350_IRQ_CODEC_MICSCD);
535ebccec0fSMark Brown 		if (comp & WM8350_CODEC_MICD_EINT)
536ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_CODEC_MICD);
537ebccec0fSMark Brown 
538ebccec0fSMark Brown 		if (comp & WM8350_EXT_USB_FB_EINT)
539ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_USB_FB);
540ebccec0fSMark Brown 		if (comp & WM8350_EXT_WALL_FB_EINT)
541ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350,
542ebccec0fSMark Brown 						WM8350_IRQ_EXT_WALL_FB);
543ebccec0fSMark Brown 		if (comp & WM8350_EXT_BAT_FB_EINT)
544ebccec0fSMark Brown 			wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_BAT_FB);
545ebccec0fSMark Brown 	}
546ebccec0fSMark Brown 
547ebccec0fSMark Brown 	if (level_one & WM8350_GP_INT) {
548ebccec0fSMark Brown 		int i;
549ebccec0fSMark Brown 		u16 gpio;
550ebccec0fSMark Brown 
551ebccec0fSMark Brown 		gpio = wm8350_reg_read(wm8350, WM8350_GPIO_INT_STATUS);
552ebccec0fSMark Brown 		gpio &= ~wm8350_reg_read(wm8350,
553ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK);
554ebccec0fSMark Brown 
555ebccec0fSMark Brown 		for (i = 0; i < 12; i++) {
556ebccec0fSMark Brown 			if (gpio & (1 << i))
557ebccec0fSMark Brown 				wm8350_irq_call_handler(wm8350,
558ebccec0fSMark Brown 							WM8350_IRQ_GPIO(i));
559ebccec0fSMark Brown 		}
560ebccec0fSMark Brown 	}
561ebccec0fSMark Brown 
562ebccec0fSMark Brown 	enable_irq(wm8350->chip_irq);
563ebccec0fSMark Brown }
564ebccec0fSMark Brown 
565ebccec0fSMark Brown static irqreturn_t wm8350_irq(int irq, void *data)
566ebccec0fSMark Brown {
567ebccec0fSMark Brown 	struct wm8350 *wm8350 = data;
568ebccec0fSMark Brown 
569ebccec0fSMark Brown 	disable_irq_nosync(irq);
570ebccec0fSMark Brown 	schedule_work(&wm8350->irq_work);
571ebccec0fSMark Brown 
572ebccec0fSMark Brown 	return IRQ_HANDLED;
573ebccec0fSMark Brown }
574ebccec0fSMark Brown 
575ebccec0fSMark Brown int wm8350_register_irq(struct wm8350 *wm8350, int irq,
576ebccec0fSMark Brown 			void (*handler) (struct wm8350 *, int, void *),
577ebccec0fSMark Brown 			void *data)
578ebccec0fSMark Brown {
579ebccec0fSMark Brown 	if (irq < 0 || irq > WM8350_NUM_IRQ || !handler)
580ebccec0fSMark Brown 		return -EINVAL;
581ebccec0fSMark Brown 
582ebccec0fSMark Brown 	if (wm8350->irq[irq].handler)
583ebccec0fSMark Brown 		return -EBUSY;
584ebccec0fSMark Brown 
585ebccec0fSMark Brown 	mutex_lock(&wm8350->irq_mutex);
586ebccec0fSMark Brown 	wm8350->irq[irq].handler = handler;
587ebccec0fSMark Brown 	wm8350->irq[irq].data = data;
588ebccec0fSMark Brown 	mutex_unlock(&wm8350->irq_mutex);
589ebccec0fSMark Brown 
590ebccec0fSMark Brown 	return 0;
591ebccec0fSMark Brown }
592ebccec0fSMark Brown EXPORT_SYMBOL_GPL(wm8350_register_irq);
593ebccec0fSMark Brown 
594ebccec0fSMark Brown int wm8350_free_irq(struct wm8350 *wm8350, int irq)
595ebccec0fSMark Brown {
596ebccec0fSMark Brown 	if (irq < 0 || irq > WM8350_NUM_IRQ)
597ebccec0fSMark Brown 		return -EINVAL;
598ebccec0fSMark Brown 
599ebccec0fSMark Brown 	mutex_lock(&wm8350->irq_mutex);
600ebccec0fSMark Brown 	wm8350->irq[irq].handler = NULL;
601ebccec0fSMark Brown 	mutex_unlock(&wm8350->irq_mutex);
602ebccec0fSMark Brown 	return 0;
603ebccec0fSMark Brown }
604ebccec0fSMark Brown EXPORT_SYMBOL_GPL(wm8350_free_irq);
605ebccec0fSMark Brown 
606ebccec0fSMark Brown int wm8350_mask_irq(struct wm8350 *wm8350, int irq)
607ebccec0fSMark Brown {
608ebccec0fSMark Brown 	switch (irq) {
609ebccec0fSMark Brown 	case WM8350_IRQ_CHG_BAT_HOT:
610ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
611ebccec0fSMark Brown 				       WM8350_IM_CHG_BAT_HOT_EINT);
612ebccec0fSMark Brown 	case WM8350_IRQ_CHG_BAT_COLD:
613ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
614ebccec0fSMark Brown 				       WM8350_IM_CHG_BAT_COLD_EINT);
615ebccec0fSMark Brown 	case WM8350_IRQ_CHG_BAT_FAIL:
616ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
617ebccec0fSMark Brown 				       WM8350_IM_CHG_BAT_FAIL_EINT);
618ebccec0fSMark Brown 	case WM8350_IRQ_CHG_TO:
619ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
620ebccec0fSMark Brown 				       WM8350_IM_CHG_TO_EINT);
621ebccec0fSMark Brown 	case WM8350_IRQ_CHG_END:
622ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
623ebccec0fSMark Brown 				       WM8350_IM_CHG_END_EINT);
624ebccec0fSMark Brown 	case WM8350_IRQ_CHG_START:
625ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
626ebccec0fSMark Brown 				       WM8350_IM_CHG_START_EINT);
627ebccec0fSMark Brown 	case WM8350_IRQ_CHG_FAST_RDY:
628ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
629ebccec0fSMark Brown 				       WM8350_IM_CHG_FAST_RDY_EINT);
630ebccec0fSMark Brown 	case WM8350_IRQ_RTC_PER:
631ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
632ebccec0fSMark Brown 				       WM8350_IM_RTC_PER_EINT);
633ebccec0fSMark Brown 	case WM8350_IRQ_RTC_SEC:
634ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
635ebccec0fSMark Brown 				       WM8350_IM_RTC_SEC_EINT);
636ebccec0fSMark Brown 	case WM8350_IRQ_RTC_ALM:
637ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
638ebccec0fSMark Brown 				       WM8350_IM_RTC_ALM_EINT);
639ebccec0fSMark Brown 	case WM8350_IRQ_CHG_VBATT_LT_3P9:
640ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
641ebccec0fSMark Brown 				       WM8350_IM_CHG_VBATT_LT_3P9_EINT);
642ebccec0fSMark Brown 	case WM8350_IRQ_CHG_VBATT_LT_3P1:
643ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
644ebccec0fSMark Brown 				       WM8350_IM_CHG_VBATT_LT_3P1_EINT);
645ebccec0fSMark Brown 	case WM8350_IRQ_CHG_VBATT_LT_2P85:
646ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
647ebccec0fSMark Brown 				       WM8350_IM_CHG_VBATT_LT_2P85_EINT);
648ebccec0fSMark Brown 	case WM8350_IRQ_CS1:
649ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
650ebccec0fSMark Brown 				       WM8350_IM_CS1_EINT);
651ebccec0fSMark Brown 	case WM8350_IRQ_CS2:
652ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
653ebccec0fSMark Brown 				       WM8350_IM_CS2_EINT);
654ebccec0fSMark Brown 	case WM8350_IRQ_USB_LIMIT:
655ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
656ebccec0fSMark Brown 				       WM8350_IM_USB_LIMIT_EINT);
657ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DATARDY:
658ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
659ebccec0fSMark Brown 				       WM8350_IM_AUXADC_DATARDY_EINT);
660ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DCOMP4:
661ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
662ebccec0fSMark Brown 				       WM8350_IM_AUXADC_DCOMP4_EINT);
663ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DCOMP3:
664ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
665ebccec0fSMark Brown 				       WM8350_IM_AUXADC_DCOMP3_EINT);
666ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DCOMP2:
667ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
668ebccec0fSMark Brown 				       WM8350_IM_AUXADC_DCOMP2_EINT);
669ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DCOMP1:
670ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
671ebccec0fSMark Brown 				       WM8350_IM_AUXADC_DCOMP1_EINT);
672ebccec0fSMark Brown 	case WM8350_IRQ_SYS_HYST_COMP_FAIL:
673ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
674ebccec0fSMark Brown 				       WM8350_IM_SYS_HYST_COMP_FAIL_EINT);
675ebccec0fSMark Brown 	case WM8350_IRQ_SYS_CHIP_GT115:
676ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
677ebccec0fSMark Brown 				       WM8350_IM_SYS_CHIP_GT115_EINT);
678ebccec0fSMark Brown 	case WM8350_IRQ_SYS_CHIP_GT140:
679ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
680ebccec0fSMark Brown 				       WM8350_IM_SYS_CHIP_GT140_EINT);
681ebccec0fSMark Brown 	case WM8350_IRQ_SYS_WDOG_TO:
682ebccec0fSMark Brown 		return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
683ebccec0fSMark Brown 				       WM8350_IM_SYS_WDOG_TO_EINT);
684ebccec0fSMark Brown 	case WM8350_IRQ_UV_LDO4:
685ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
686ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
687ebccec0fSMark Brown 				       WM8350_IM_UV_LDO4_EINT);
688ebccec0fSMark Brown 	case WM8350_IRQ_UV_LDO3:
689ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
690ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
691ebccec0fSMark Brown 				       WM8350_IM_UV_LDO3_EINT);
692ebccec0fSMark Brown 	case WM8350_IRQ_UV_LDO2:
693ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
694ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
695ebccec0fSMark Brown 				       WM8350_IM_UV_LDO2_EINT);
696ebccec0fSMark Brown 	case WM8350_IRQ_UV_LDO1:
697ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
698ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
699ebccec0fSMark Brown 				       WM8350_IM_UV_LDO1_EINT);
700ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC6:
701ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
702ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
703ebccec0fSMark Brown 				       WM8350_IM_UV_DC6_EINT);
704ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC5:
705ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
706ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
707ebccec0fSMark Brown 				       WM8350_IM_UV_DC5_EINT);
708ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC4:
709ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
710ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
711ebccec0fSMark Brown 				       WM8350_IM_UV_DC4_EINT);
712ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC3:
713ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
714ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
715ebccec0fSMark Brown 				       WM8350_IM_UV_DC3_EINT);
716ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC2:
717ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
718ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
719ebccec0fSMark Brown 				       WM8350_IM_UV_DC2_EINT);
720ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC1:
721ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
722ebccec0fSMark Brown 				       WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
723ebccec0fSMark Brown 				       WM8350_IM_UV_DC1_EINT);
724ebccec0fSMark Brown 	case WM8350_IRQ_OC_LS:
725ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
726ebccec0fSMark Brown 				       WM8350_OVER_CURRENT_INT_STATUS_MASK,
727ebccec0fSMark Brown 				       WM8350_IM_OC_LS_EINT);
728ebccec0fSMark Brown 	case WM8350_IRQ_EXT_USB_FB:
729ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
730ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
731ebccec0fSMark Brown 				       WM8350_IM_EXT_USB_FB_EINT);
732ebccec0fSMark Brown 	case WM8350_IRQ_EXT_WALL_FB:
733ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
734ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
735ebccec0fSMark Brown 				       WM8350_IM_EXT_WALL_FB_EINT);
736ebccec0fSMark Brown 	case WM8350_IRQ_EXT_BAT_FB:
737ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
738ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
739ebccec0fSMark Brown 				       WM8350_IM_EXT_BAT_FB_EINT);
740ebccec0fSMark Brown 	case WM8350_IRQ_CODEC_JCK_DET_L:
741ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
742ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
743ebccec0fSMark Brown 				       WM8350_IM_CODEC_JCK_DET_L_EINT);
744ebccec0fSMark Brown 	case WM8350_IRQ_CODEC_JCK_DET_R:
745ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
746ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
747ebccec0fSMark Brown 				       WM8350_IM_CODEC_JCK_DET_R_EINT);
748ebccec0fSMark Brown 	case WM8350_IRQ_CODEC_MICSCD:
749ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
750ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
751ebccec0fSMark Brown 				       WM8350_IM_CODEC_MICSCD_EINT);
752ebccec0fSMark Brown 	case WM8350_IRQ_CODEC_MICD:
753ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
754ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
755ebccec0fSMark Brown 				       WM8350_IM_CODEC_MICD_EINT);
756ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_OFF_STATE:
757ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
758ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
759ebccec0fSMark Brown 				       WM8350_IM_WKUP_OFF_STATE_EINT);
760ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_HIB_STATE:
761ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
762ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
763ebccec0fSMark Brown 				       WM8350_IM_WKUP_HIB_STATE_EINT);
764ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_CONV_FAULT:
765ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
766ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
767ebccec0fSMark Brown 				       WM8350_IM_WKUP_CONV_FAULT_EINT);
768ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_WDOG_RST:
769ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
770ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
771ebccec0fSMark Brown 				       WM8350_IM_WKUP_OFF_STATE_EINT);
772ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_GP_PWR_ON:
773ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
774ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
775ebccec0fSMark Brown 				       WM8350_IM_WKUP_GP_PWR_ON_EINT);
776ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_ONKEY:
777ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
778ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
779ebccec0fSMark Brown 				       WM8350_IM_WKUP_ONKEY_EINT);
780ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_GP_WAKEUP:
781ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
782ebccec0fSMark Brown 				       WM8350_COMPARATOR_INT_STATUS_MASK,
783ebccec0fSMark Brown 				       WM8350_IM_WKUP_GP_WAKEUP_EINT);
784ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(0):
785ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
786ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
787ebccec0fSMark Brown 				       WM8350_IM_GP0_EINT);
788ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(1):
789ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
790ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
791ebccec0fSMark Brown 				       WM8350_IM_GP1_EINT);
792ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(2):
793ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
794ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
795ebccec0fSMark Brown 				       WM8350_IM_GP2_EINT);
796ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(3):
797ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
798ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
799ebccec0fSMark Brown 				       WM8350_IM_GP3_EINT);
800ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(4):
801ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
802ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
803ebccec0fSMark Brown 				       WM8350_IM_GP4_EINT);
804ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(5):
805ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
806ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
807ebccec0fSMark Brown 				       WM8350_IM_GP5_EINT);
808ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(6):
809ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
810ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
811ebccec0fSMark Brown 				       WM8350_IM_GP6_EINT);
812ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(7):
813ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
814ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
815ebccec0fSMark Brown 				       WM8350_IM_GP7_EINT);
816ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(8):
817ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
818ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
819ebccec0fSMark Brown 				       WM8350_IM_GP8_EINT);
820ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(9):
821ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
822ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
823ebccec0fSMark Brown 				       WM8350_IM_GP9_EINT);
824ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(10):
825ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
826ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
827ebccec0fSMark Brown 				       WM8350_IM_GP10_EINT);
828ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(11):
829ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
830ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
831ebccec0fSMark Brown 				       WM8350_IM_GP11_EINT);
832ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(12):
833ebccec0fSMark Brown 		return wm8350_set_bits(wm8350,
834ebccec0fSMark Brown 				       WM8350_GPIO_INT_STATUS_MASK,
835ebccec0fSMark Brown 				       WM8350_IM_GP12_EINT);
836ebccec0fSMark Brown 	default:
837ebccec0fSMark Brown 		dev_warn(wm8350->dev, "Attempting to mask unknown IRQ %d\n",
838ebccec0fSMark Brown 			 irq);
839ebccec0fSMark Brown 		return -EINVAL;
840ebccec0fSMark Brown 	}
841ebccec0fSMark Brown 	return 0;
842ebccec0fSMark Brown }
843ebccec0fSMark Brown EXPORT_SYMBOL_GPL(wm8350_mask_irq);
844ebccec0fSMark Brown 
845ebccec0fSMark Brown int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
846ebccec0fSMark Brown {
847ebccec0fSMark Brown 	switch (irq) {
848ebccec0fSMark Brown 	case WM8350_IRQ_CHG_BAT_HOT:
849ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
850ebccec0fSMark Brown 					 WM8350_IM_CHG_BAT_HOT_EINT);
851ebccec0fSMark Brown 	case WM8350_IRQ_CHG_BAT_COLD:
852ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
853ebccec0fSMark Brown 					 WM8350_IM_CHG_BAT_COLD_EINT);
854ebccec0fSMark Brown 	case WM8350_IRQ_CHG_BAT_FAIL:
855ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
856ebccec0fSMark Brown 					 WM8350_IM_CHG_BAT_FAIL_EINT);
857ebccec0fSMark Brown 	case WM8350_IRQ_CHG_TO:
858ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
859ebccec0fSMark Brown 					 WM8350_IM_CHG_TO_EINT);
860ebccec0fSMark Brown 	case WM8350_IRQ_CHG_END:
861ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
862ebccec0fSMark Brown 					 WM8350_IM_CHG_END_EINT);
863ebccec0fSMark Brown 	case WM8350_IRQ_CHG_START:
864ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
865ebccec0fSMark Brown 					 WM8350_IM_CHG_START_EINT);
866ebccec0fSMark Brown 	case WM8350_IRQ_CHG_FAST_RDY:
867ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
868ebccec0fSMark Brown 					 WM8350_IM_CHG_FAST_RDY_EINT);
869ebccec0fSMark Brown 	case WM8350_IRQ_RTC_PER:
870ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
871ebccec0fSMark Brown 					 WM8350_IM_RTC_PER_EINT);
872ebccec0fSMark Brown 	case WM8350_IRQ_RTC_SEC:
873ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
874ebccec0fSMark Brown 					 WM8350_IM_RTC_SEC_EINT);
875ebccec0fSMark Brown 	case WM8350_IRQ_RTC_ALM:
876ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
877ebccec0fSMark Brown 					 WM8350_IM_RTC_ALM_EINT);
878ebccec0fSMark Brown 	case WM8350_IRQ_CHG_VBATT_LT_3P9:
879ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
880ebccec0fSMark Brown 					 WM8350_IM_CHG_VBATT_LT_3P9_EINT);
881ebccec0fSMark Brown 	case WM8350_IRQ_CHG_VBATT_LT_3P1:
882ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
883ebccec0fSMark Brown 					 WM8350_IM_CHG_VBATT_LT_3P1_EINT);
884ebccec0fSMark Brown 	case WM8350_IRQ_CHG_VBATT_LT_2P85:
885ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
886ebccec0fSMark Brown 					 WM8350_IM_CHG_VBATT_LT_2P85_EINT);
887ebccec0fSMark Brown 	case WM8350_IRQ_CS1:
888ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
889ebccec0fSMark Brown 					 WM8350_IM_CS1_EINT);
890ebccec0fSMark Brown 	case WM8350_IRQ_CS2:
891ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
892ebccec0fSMark Brown 					 WM8350_IM_CS2_EINT);
893ebccec0fSMark Brown 	case WM8350_IRQ_USB_LIMIT:
894ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
895ebccec0fSMark Brown 					 WM8350_IM_USB_LIMIT_EINT);
896ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DATARDY:
897ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
898ebccec0fSMark Brown 					 WM8350_IM_AUXADC_DATARDY_EINT);
899ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DCOMP4:
900ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
901ebccec0fSMark Brown 					 WM8350_IM_AUXADC_DCOMP4_EINT);
902ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DCOMP3:
903ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
904ebccec0fSMark Brown 					 WM8350_IM_AUXADC_DCOMP3_EINT);
905ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DCOMP2:
906ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
907ebccec0fSMark Brown 					 WM8350_IM_AUXADC_DCOMP2_EINT);
908ebccec0fSMark Brown 	case WM8350_IRQ_AUXADC_DCOMP1:
909ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
910ebccec0fSMark Brown 					 WM8350_IM_AUXADC_DCOMP1_EINT);
911ebccec0fSMark Brown 	case WM8350_IRQ_SYS_HYST_COMP_FAIL:
912ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
913ebccec0fSMark Brown 					 WM8350_IM_SYS_HYST_COMP_FAIL_EINT);
914ebccec0fSMark Brown 	case WM8350_IRQ_SYS_CHIP_GT115:
915ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
916ebccec0fSMark Brown 					 WM8350_IM_SYS_CHIP_GT115_EINT);
917ebccec0fSMark Brown 	case WM8350_IRQ_SYS_CHIP_GT140:
918ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
919ebccec0fSMark Brown 					 WM8350_IM_SYS_CHIP_GT140_EINT);
920ebccec0fSMark Brown 	case WM8350_IRQ_SYS_WDOG_TO:
921ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
922ebccec0fSMark Brown 					 WM8350_IM_SYS_WDOG_TO_EINT);
923ebccec0fSMark Brown 	case WM8350_IRQ_UV_LDO4:
924ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
925ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
926ebccec0fSMark Brown 					 WM8350_IM_UV_LDO4_EINT);
927ebccec0fSMark Brown 	case WM8350_IRQ_UV_LDO3:
928ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
929ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
930ebccec0fSMark Brown 					 WM8350_IM_UV_LDO3_EINT);
931ebccec0fSMark Brown 	case WM8350_IRQ_UV_LDO2:
932ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
933ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
934ebccec0fSMark Brown 					 WM8350_IM_UV_LDO2_EINT);
935ebccec0fSMark Brown 	case WM8350_IRQ_UV_LDO1:
936ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
937ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
938ebccec0fSMark Brown 					 WM8350_IM_UV_LDO1_EINT);
939ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC6:
940ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
941ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
942ebccec0fSMark Brown 					 WM8350_IM_UV_DC6_EINT);
943ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC5:
944ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
945ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
946ebccec0fSMark Brown 					 WM8350_IM_UV_DC5_EINT);
947ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC4:
948ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
949ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
950ebccec0fSMark Brown 					 WM8350_IM_UV_DC4_EINT);
951ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC3:
952ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
953ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
954ebccec0fSMark Brown 					 WM8350_IM_UV_DC3_EINT);
955ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC2:
956ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
957ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
958ebccec0fSMark Brown 					 WM8350_IM_UV_DC2_EINT);
959ebccec0fSMark Brown 	case WM8350_IRQ_UV_DC1:
960ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
961ebccec0fSMark Brown 					 WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
962ebccec0fSMark Brown 					 WM8350_IM_UV_DC1_EINT);
963ebccec0fSMark Brown 	case WM8350_IRQ_OC_LS:
964ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
965ebccec0fSMark Brown 					 WM8350_OVER_CURRENT_INT_STATUS_MASK,
966ebccec0fSMark Brown 					 WM8350_IM_OC_LS_EINT);
967ebccec0fSMark Brown 	case WM8350_IRQ_EXT_USB_FB:
968ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
969ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
970ebccec0fSMark Brown 					 WM8350_IM_EXT_USB_FB_EINT);
971ebccec0fSMark Brown 	case WM8350_IRQ_EXT_WALL_FB:
972ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
973ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
974ebccec0fSMark Brown 					 WM8350_IM_EXT_WALL_FB_EINT);
975ebccec0fSMark Brown 	case WM8350_IRQ_EXT_BAT_FB:
976ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
977ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
978ebccec0fSMark Brown 					 WM8350_IM_EXT_BAT_FB_EINT);
979ebccec0fSMark Brown 	case WM8350_IRQ_CODEC_JCK_DET_L:
980ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
981ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
982ebccec0fSMark Brown 					 WM8350_IM_CODEC_JCK_DET_L_EINT);
983ebccec0fSMark Brown 	case WM8350_IRQ_CODEC_JCK_DET_R:
984ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
985ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
986ebccec0fSMark Brown 					 WM8350_IM_CODEC_JCK_DET_R_EINT);
987ebccec0fSMark Brown 	case WM8350_IRQ_CODEC_MICSCD:
988ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
989ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
990ebccec0fSMark Brown 					 WM8350_IM_CODEC_MICSCD_EINT);
991ebccec0fSMark Brown 	case WM8350_IRQ_CODEC_MICD:
992ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
993ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
994ebccec0fSMark Brown 					 WM8350_IM_CODEC_MICD_EINT);
995ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_OFF_STATE:
996ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
997ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
998ebccec0fSMark Brown 					 WM8350_IM_WKUP_OFF_STATE_EINT);
999ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_HIB_STATE:
1000ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1001ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
1002ebccec0fSMark Brown 					 WM8350_IM_WKUP_HIB_STATE_EINT);
1003ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_CONV_FAULT:
1004ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1005ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
1006ebccec0fSMark Brown 					 WM8350_IM_WKUP_CONV_FAULT_EINT);
1007ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_WDOG_RST:
1008ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1009ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
1010ebccec0fSMark Brown 					 WM8350_IM_WKUP_OFF_STATE_EINT);
1011ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_GP_PWR_ON:
1012ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1013ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
1014ebccec0fSMark Brown 					 WM8350_IM_WKUP_GP_PWR_ON_EINT);
1015ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_ONKEY:
1016ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1017ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
1018ebccec0fSMark Brown 					 WM8350_IM_WKUP_ONKEY_EINT);
1019ebccec0fSMark Brown 	case WM8350_IRQ_WKUP_GP_WAKEUP:
1020ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1021ebccec0fSMark Brown 					 WM8350_COMPARATOR_INT_STATUS_MASK,
1022ebccec0fSMark Brown 					 WM8350_IM_WKUP_GP_WAKEUP_EINT);
1023ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(0):
1024ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1025ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1026ebccec0fSMark Brown 					 WM8350_IM_GP0_EINT);
1027ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(1):
1028ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1029ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1030ebccec0fSMark Brown 					 WM8350_IM_GP1_EINT);
1031ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(2):
1032ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1033ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1034ebccec0fSMark Brown 					 WM8350_IM_GP2_EINT);
1035ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(3):
1036ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1037ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1038ebccec0fSMark Brown 					 WM8350_IM_GP3_EINT);
1039ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(4):
1040ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1041ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1042ebccec0fSMark Brown 					 WM8350_IM_GP4_EINT);
1043ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(5):
1044ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1045ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1046ebccec0fSMark Brown 					 WM8350_IM_GP5_EINT);
1047ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(6):
1048ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1049ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1050ebccec0fSMark Brown 					 WM8350_IM_GP6_EINT);
1051ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(7):
1052ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1053ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1054ebccec0fSMark Brown 					 WM8350_IM_GP7_EINT);
1055ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(8):
1056ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1057ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1058ebccec0fSMark Brown 					 WM8350_IM_GP8_EINT);
1059ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(9):
1060ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1061ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1062ebccec0fSMark Brown 					 WM8350_IM_GP9_EINT);
1063ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(10):
1064ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1065ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1066ebccec0fSMark Brown 					 WM8350_IM_GP10_EINT);
1067ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(11):
1068ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1069ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1070ebccec0fSMark Brown 					 WM8350_IM_GP11_EINT);
1071ebccec0fSMark Brown 	case WM8350_IRQ_GPIO(12):
1072ebccec0fSMark Brown 		return wm8350_clear_bits(wm8350,
1073ebccec0fSMark Brown 					 WM8350_GPIO_INT_STATUS_MASK,
1074ebccec0fSMark Brown 					 WM8350_IM_GP12_EINT);
1075ebccec0fSMark Brown 	default:
1076ebccec0fSMark Brown 		dev_warn(wm8350->dev, "Attempting to unmask unknown IRQ %d\n",
1077ebccec0fSMark Brown 			 irq);
1078ebccec0fSMark Brown 		return -EINVAL;
1079ebccec0fSMark Brown 	}
1080ebccec0fSMark Brown 	return 0;
1081ebccec0fSMark Brown }
1082ebccec0fSMark Brown EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
1083ebccec0fSMark Brown 
108467488526SMark Brown int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref)
108567488526SMark Brown {
108667488526SMark Brown 	u16 reg, result = 0;
108767488526SMark Brown 	int tries = 5;
108867488526SMark Brown 
108967488526SMark Brown 	if (channel < WM8350_AUXADC_AUX1 || channel > WM8350_AUXADC_TEMP)
109067488526SMark Brown 		return -EINVAL;
109167488526SMark Brown 	if (channel >= WM8350_AUXADC_USB && channel <= WM8350_AUXADC_TEMP
109267488526SMark Brown 	    && (scale != 0 || vref != 0))
109367488526SMark Brown 		return -EINVAL;
109467488526SMark Brown 
109567488526SMark Brown 	mutex_lock(&wm8350->auxadc_mutex);
109667488526SMark Brown 
109767488526SMark Brown 	/* Turn on the ADC */
109867488526SMark Brown 	reg = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
109967488526SMark Brown 	wm8350_reg_write(wm8350, WM8350_POWER_MGMT_5, reg | WM8350_AUXADC_ENA);
110067488526SMark Brown 
110167488526SMark Brown 	if (scale || vref) {
110267488526SMark Brown 		reg = scale << 13;
110367488526SMark Brown 		reg |= vref << 12;
110467488526SMark Brown 		wm8350_reg_write(wm8350, WM8350_AUX1_READBACK + channel, reg);
110567488526SMark Brown 	}
110667488526SMark Brown 
110767488526SMark Brown 	reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
110867488526SMark Brown 	reg |= 1 << channel | WM8350_AUXADC_POLL;
110967488526SMark Brown 	wm8350_reg_write(wm8350, WM8350_DIGITISER_CONTROL_1, reg);
111067488526SMark Brown 
111167488526SMark Brown 	do {
111267488526SMark Brown 		schedule_timeout_interruptible(1);
111367488526SMark Brown 		reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
111467488526SMark Brown 	} while (tries-- && (reg & WM8350_AUXADC_POLL));
111567488526SMark Brown 
111667488526SMark Brown 	if (!tries)
111767488526SMark Brown 		dev_err(wm8350->dev, "adc chn %d read timeout\n", channel);
111867488526SMark Brown 	else
111967488526SMark Brown 		result = wm8350_reg_read(wm8350,
112067488526SMark Brown 					 WM8350_AUX1_READBACK + channel);
112167488526SMark Brown 
112267488526SMark Brown 	/* Turn off the ADC */
112367488526SMark Brown 	reg = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
112467488526SMark Brown 	wm8350_reg_write(wm8350, WM8350_POWER_MGMT_5,
112567488526SMark Brown 			 reg & ~WM8350_AUXADC_ENA);
112667488526SMark Brown 
112767488526SMark Brown 	mutex_unlock(&wm8350->auxadc_mutex);
112867488526SMark Brown 
112967488526SMark Brown 	return result & WM8350_AUXADC_DATA1_MASK;
113067488526SMark Brown }
113167488526SMark Brown EXPORT_SYMBOL_GPL(wm8350_read_auxadc);
113267488526SMark Brown 
113389b4012bSMark Brown /*
113489b4012bSMark Brown  * Cache is always host endian.
113589b4012bSMark Brown  */
113696920630SMark Brown static int wm8350_create_cache(struct wm8350 *wm8350, int type, int mode)
113789b4012bSMark Brown {
113889b4012bSMark Brown 	int i, ret = 0;
113989b4012bSMark Brown 	u16 value;
114089b4012bSMark Brown 	const u16 *reg_map;
114189b4012bSMark Brown 
114296920630SMark Brown 	switch (type) {
114396920630SMark Brown 	case 0:
114489b4012bSMark Brown 		switch (mode) {
114589b4012bSMark Brown #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
114689b4012bSMark Brown 		case 0:
114789b4012bSMark Brown 			reg_map = wm8350_mode0_defaults;
114889b4012bSMark Brown 			break;
114989b4012bSMark Brown #endif
115089b4012bSMark Brown #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1
115189b4012bSMark Brown 		case 1:
115289b4012bSMark Brown 			reg_map = wm8350_mode1_defaults;
115389b4012bSMark Brown 			break;
115489b4012bSMark Brown #endif
115589b4012bSMark Brown #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2
115689b4012bSMark Brown 		case 2:
115789b4012bSMark Brown 			reg_map = wm8350_mode2_defaults;
115889b4012bSMark Brown 			break;
115989b4012bSMark Brown #endif
116089b4012bSMark Brown #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3
116189b4012bSMark Brown 		case 3:
116289b4012bSMark Brown 			reg_map = wm8350_mode3_defaults;
116389b4012bSMark Brown 			break;
116489b4012bSMark Brown #endif
116589b4012bSMark Brown 		default:
116696920630SMark Brown 			dev_err(wm8350->dev,
116796920630SMark Brown 				"WM8350 configuration mode %d not supported\n",
116896920630SMark Brown 				mode);
116996920630SMark Brown 			return -EINVAL;
117096920630SMark Brown 		}
11714331bb32SMark Brown 		break;
117296920630SMark Brown 
1173ca23f8c1SMark Brown 	case 1:
1174ca23f8c1SMark Brown 		switch (mode) {
1175ca23f8c1SMark Brown #ifdef CONFIG_MFD_WM8351_CONFIG_MODE_0
1176ca23f8c1SMark Brown 		case 0:
1177ca23f8c1SMark Brown 			reg_map = wm8351_mode0_defaults;
1178ca23f8c1SMark Brown 			break;
1179ca23f8c1SMark Brown #endif
1180ca23f8c1SMark Brown #ifdef CONFIG_MFD_WM8351_CONFIG_MODE_1
1181ca23f8c1SMark Brown 		case 1:
1182ca23f8c1SMark Brown 			reg_map = wm8351_mode1_defaults;
1183ca23f8c1SMark Brown 			break;
1184ca23f8c1SMark Brown #endif
1185ca23f8c1SMark Brown #ifdef CONFIG_MFD_WM8351_CONFIG_MODE_2
1186ca23f8c1SMark Brown 		case 2:
1187ca23f8c1SMark Brown 			reg_map = wm8351_mode2_defaults;
1188ca23f8c1SMark Brown 			break;
1189ca23f8c1SMark Brown #endif
1190ca23f8c1SMark Brown #ifdef CONFIG_MFD_WM8351_CONFIG_MODE_3
1191ca23f8c1SMark Brown 		case 3:
1192ca23f8c1SMark Brown 			reg_map = wm8351_mode3_defaults;
1193ca23f8c1SMark Brown 			break;
1194ca23f8c1SMark Brown #endif
1195ca23f8c1SMark Brown 		default:
1196ca23f8c1SMark Brown 			dev_err(wm8350->dev,
1197ca23f8c1SMark Brown 				"WM8351 configuration mode %d not supported\n",
1198ca23f8c1SMark Brown 				mode);
1199ca23f8c1SMark Brown 			return -EINVAL;
1200ca23f8c1SMark Brown 		}
1201ca23f8c1SMark Brown 		break;
1202ca23f8c1SMark Brown 
120396920630SMark Brown 	case 2:
120496920630SMark Brown 		switch (mode) {
120596920630SMark Brown #ifdef CONFIG_MFD_WM8352_CONFIG_MODE_0
120696920630SMark Brown 		case 0:
120796920630SMark Brown 			reg_map = wm8352_mode0_defaults;
120896920630SMark Brown 			break;
120996920630SMark Brown #endif
121096920630SMark Brown #ifdef CONFIG_MFD_WM8352_CONFIG_MODE_1
121196920630SMark Brown 		case 1:
121296920630SMark Brown 			reg_map = wm8352_mode1_defaults;
121396920630SMark Brown 			break;
121496920630SMark Brown #endif
121596920630SMark Brown #ifdef CONFIG_MFD_WM8352_CONFIG_MODE_2
121696920630SMark Brown 		case 2:
121796920630SMark Brown 			reg_map = wm8352_mode2_defaults;
121896920630SMark Brown 			break;
121996920630SMark Brown #endif
122096920630SMark Brown #ifdef CONFIG_MFD_WM8352_CONFIG_MODE_3
122196920630SMark Brown 		case 3:
122296920630SMark Brown 			reg_map = wm8352_mode3_defaults;
122396920630SMark Brown 			break;
122496920630SMark Brown #endif
122596920630SMark Brown 		default:
122696920630SMark Brown 			dev_err(wm8350->dev,
122796920630SMark Brown 				"WM8352 configuration mode %d not supported\n",
122896920630SMark Brown 				mode);
122996920630SMark Brown 			return -EINVAL;
123096920630SMark Brown 		}
123196920630SMark Brown 		break;
123296920630SMark Brown 
123396920630SMark Brown 	default:
123496920630SMark Brown 		dev_err(wm8350->dev,
123596920630SMark Brown 			"WM835x configuration mode %d not supported\n",
123689b4012bSMark Brown 			mode);
123789b4012bSMark Brown 		return -EINVAL;
123889b4012bSMark Brown 	}
123989b4012bSMark Brown 
124089b4012bSMark Brown 	wm8350->reg_cache =
124189b4012bSMark Brown 	    kzalloc(sizeof(u16) * (WM8350_MAX_REGISTER + 1), GFP_KERNEL);
124289b4012bSMark Brown 	if (wm8350->reg_cache == NULL)
124389b4012bSMark Brown 		return -ENOMEM;
124489b4012bSMark Brown 
124589b4012bSMark Brown 	/* Read the initial cache state back from the device - this is
124689b4012bSMark Brown 	 * a PMIC so the device many not be in a virgin state and we
124789b4012bSMark Brown 	 * can't rely on the silicon values.
124889b4012bSMark Brown 	 */
124989b4012bSMark Brown 	for (i = 0; i < WM8350_MAX_REGISTER; i++) {
125089b4012bSMark Brown 		/* audio register range */
125189b4012bSMark Brown 		if (wm8350_reg_io_map[i].readable &&
125289b4012bSMark Brown 		    (i < WM8350_CLOCK_CONTROL_1 || i > WM8350_AIF_TEST)) {
125389b4012bSMark Brown 			ret = wm8350->read_dev(wm8350, i, 2, (char *)&value);
125489b4012bSMark Brown 			if (ret < 0) {
125589b4012bSMark Brown 				dev_err(wm8350->dev,
125689b4012bSMark Brown 				       "failed to read initial cache value\n");
125789b4012bSMark Brown 				goto out;
125889b4012bSMark Brown 			}
125989b4012bSMark Brown 			value = be16_to_cpu(value);
126089b4012bSMark Brown 			value &= wm8350_reg_io_map[i].readable;
1261e76f7558SMark Brown 			value &= ~wm8350_reg_io_map[i].vol;
126289b4012bSMark Brown 			wm8350->reg_cache[i] = value;
126389b4012bSMark Brown 		} else
126489b4012bSMark Brown 			wm8350->reg_cache[i] = reg_map[i];
126589b4012bSMark Brown 	}
126689b4012bSMark Brown 
126789b4012bSMark Brown out:
126889b4012bSMark Brown 	return ret;
126989b4012bSMark Brown }
127089b4012bSMark Brown 
12719201d38bSMark Brown /*
12729201d38bSMark Brown  * Register a client device.  This is non-fatal since there is no need to
12739201d38bSMark Brown  * fail the entire device init due to a single platform device failing.
12749201d38bSMark Brown  */
12759201d38bSMark Brown static void wm8350_client_dev_register(struct wm8350 *wm8350,
12769201d38bSMark Brown 				       const char *name,
12779201d38bSMark Brown 				       struct platform_device **pdev)
12789201d38bSMark Brown {
12799201d38bSMark Brown 	int ret;
12809201d38bSMark Brown 
12819201d38bSMark Brown 	*pdev = platform_device_alloc(name, -1);
12829201d38bSMark Brown 	if (pdev == NULL) {
12839201d38bSMark Brown 		dev_err(wm8350->dev, "Failed to allocate %s\n", name);
12849201d38bSMark Brown 		return;
12859201d38bSMark Brown 	}
12869201d38bSMark Brown 
12879201d38bSMark Brown 	(*pdev)->dev.parent = wm8350->dev;
12889201d38bSMark Brown 	platform_set_drvdata(*pdev, wm8350);
12899201d38bSMark Brown 	ret = platform_device_add(*pdev);
12909201d38bSMark Brown 	if (ret != 0) {
12919201d38bSMark Brown 		dev_err(wm8350->dev, "Failed to register %s: %d\n", name, ret);
12929201d38bSMark Brown 		platform_device_put(*pdev);
12939201d38bSMark Brown 		*pdev = NULL;
12949201d38bSMark Brown 	}
12959201d38bSMark Brown }
12969201d38bSMark Brown 
1297ebccec0fSMark Brown int wm8350_device_init(struct wm8350 *wm8350, int irq,
1298bcdd4efcSMark Brown 		       struct wm8350_platform_data *pdata)
129989b4012bSMark Brown {
130089b4012bSMark Brown 	int ret = -EINVAL;
1301b797a555SMark Brown 	u16 id1, id2, mask_rev;
1302b797a555SMark Brown 	u16 cust_id, mode, chip_rev;
130389b4012bSMark Brown 
130489b4012bSMark Brown 	/* get WM8350 revision and config mode */
130589b4012bSMark Brown 	wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1);
130689b4012bSMark Brown 	wm8350->read_dev(wm8350, WM8350_ID, sizeof(id2), &id2);
1307b797a555SMark Brown 	wm8350->read_dev(wm8350, WM8350_REVISION, sizeof(mask_rev), &mask_rev);
130889b4012bSMark Brown 
130989b4012bSMark Brown 	id1 = be16_to_cpu(id1);
131089b4012bSMark Brown 	id2 = be16_to_cpu(id2);
1311b797a555SMark Brown 	mask_rev = be16_to_cpu(mask_rev);
131289b4012bSMark Brown 
1313b797a555SMark Brown 	if (id1 != 0x6143) {
1314b797a555SMark Brown 		dev_err(wm8350->dev,
1315b797a555SMark Brown 			"Device with ID %x is not a WM8350\n", id1);
131689b4012bSMark Brown 		ret = -ENODEV;
131789b4012bSMark Brown 		goto err;
131889b4012bSMark Brown 	}
131989b4012bSMark Brown 
132089b4012bSMark Brown 	mode = id2 & WM8350_CONF_STS_MASK >> 10;
1321b797a555SMark Brown 	cust_id = id2 & WM8350_CUST_ID_MASK;
1322b797a555SMark Brown 	chip_rev = (id2 & WM8350_CHIP_REV_MASK) >> 12;
1323b797a555SMark Brown 	dev_info(wm8350->dev,
1324b797a555SMark Brown 		 "CONF_STS %d, CUST_ID %d, MASK_REV %d, CHIP_REV %d\n",
1325b797a555SMark Brown 		 mode, cust_id, mask_rev, chip_rev);
1326b797a555SMark Brown 
1327b797a555SMark Brown 	if (cust_id != 0) {
1328b797a555SMark Brown 		dev_err(wm8350->dev, "Unsupported CUST_ID\n");
1329b797a555SMark Brown 		ret = -ENODEV;
1330b797a555SMark Brown 		goto err;
1331b797a555SMark Brown 	}
1332b797a555SMark Brown 
1333b797a555SMark Brown 	switch (mask_rev) {
1334b797a555SMark Brown 	case 0:
1335645524a9SMark Brown 		wm8350->pmic.max_dcdc = WM8350_DCDC_6;
1336645524a9SMark Brown 		wm8350->pmic.max_isink = WM8350_ISINK_B;
1337645524a9SMark Brown 
1338b797a555SMark Brown 		switch (chip_rev) {
1339b797a555SMark Brown 		case WM8350_REV_E:
1340b797a555SMark Brown 			dev_info(wm8350->dev, "WM8350 Rev E\n");
1341b797a555SMark Brown 			break;
1342b797a555SMark Brown 		case WM8350_REV_F:
1343b797a555SMark Brown 			dev_info(wm8350->dev, "WM8350 Rev F\n");
1344b797a555SMark Brown 			break;
1345b797a555SMark Brown 		case WM8350_REV_G:
1346b797a555SMark Brown 			dev_info(wm8350->dev, "WM8350 Rev G\n");
1347b797a555SMark Brown 			wm8350->power.rev_g_coeff = 1;
1348b797a555SMark Brown 			break;
1349b797a555SMark Brown 		case WM8350_REV_H:
1350b797a555SMark Brown 			dev_info(wm8350->dev, "WM8350 Rev H\n");
1351b797a555SMark Brown 			wm8350->power.rev_g_coeff = 1;
1352b797a555SMark Brown 			break;
1353b797a555SMark Brown 		default:
1354b797a555SMark Brown 			/* For safety we refuse to run on unknown hardware */
1355b797a555SMark Brown 			dev_err(wm8350->dev, "Unknown WM8350 CHIP_REV\n");
1356b797a555SMark Brown 			ret = -ENODEV;
1357b797a555SMark Brown 			goto err;
1358b797a555SMark Brown 		}
1359b797a555SMark Brown 		break;
1360b797a555SMark Brown 
1361ca23f8c1SMark Brown 	case 1:
1362ca23f8c1SMark Brown 		wm8350->pmic.max_dcdc = WM8350_DCDC_4;
1363ca23f8c1SMark Brown 		wm8350->pmic.max_isink = WM8350_ISINK_A;
1364ca23f8c1SMark Brown 
1365ca23f8c1SMark Brown 		switch (chip_rev) {
1366ca23f8c1SMark Brown 		case 0:
1367ca23f8c1SMark Brown 			dev_info(wm8350->dev, "WM8351 Rev A\n");
1368ca23f8c1SMark Brown 			wm8350->power.rev_g_coeff = 1;
1369ca23f8c1SMark Brown 			break;
1370ca23f8c1SMark Brown 
1371ca23f8c1SMark Brown 		default:
1372ca23f8c1SMark Brown 			dev_err(wm8350->dev, "Unknown WM8351 CHIP_REV\n");
1373ca23f8c1SMark Brown 			ret = -ENODEV;
1374ca23f8c1SMark Brown 			goto err;
1375ca23f8c1SMark Brown 		}
1376ca23f8c1SMark Brown 		break;
1377ca23f8c1SMark Brown 
137896920630SMark Brown 	case 2:
1379645524a9SMark Brown 		wm8350->pmic.max_dcdc = WM8350_DCDC_6;
1380645524a9SMark Brown 		wm8350->pmic.max_isink = WM8350_ISINK_B;
1381645524a9SMark Brown 
138296920630SMark Brown 		switch (chip_rev) {
138396920630SMark Brown 		case 0:
138496920630SMark Brown 			dev_info(wm8350->dev, "WM8352 Rev A\n");
138596920630SMark Brown 			wm8350->power.rev_g_coeff = 1;
138696920630SMark Brown 			break;
138796920630SMark Brown 
138896920630SMark Brown 		default:
138996920630SMark Brown 			dev_err(wm8350->dev, "Unknown WM8352 CHIP_REV\n");
139096920630SMark Brown 			ret = -ENODEV;
139196920630SMark Brown 			goto err;
139296920630SMark Brown 		}
139396920630SMark Brown 		break;
139496920630SMark Brown 
1395b797a555SMark Brown 	default:
1396b797a555SMark Brown 		dev_err(wm8350->dev, "Unknown MASK_REV\n");
1397b797a555SMark Brown 		ret = -ENODEV;
1398b797a555SMark Brown 		goto err;
1399b797a555SMark Brown 	}
140089b4012bSMark Brown 
140196920630SMark Brown 	ret = wm8350_create_cache(wm8350, mask_rev, mode);
140289b4012bSMark Brown 	if (ret < 0) {
1403b797a555SMark Brown 		dev_err(wm8350->dev, "Failed to create register cache\n");
140489b4012bSMark Brown 		return ret;
140589b4012bSMark Brown 	}
140689b4012bSMark Brown 
140753a0d99bSMark Brown 	if (pdata && pdata->init) {
1408bcdd4efcSMark Brown 		ret = pdata->init(wm8350);
1409bcdd4efcSMark Brown 		if (ret != 0) {
1410bcdd4efcSMark Brown 			dev_err(wm8350->dev, "Platform init() failed: %d\n",
1411bcdd4efcSMark Brown 				ret);
1412bcdd4efcSMark Brown 			goto err;
1413bcdd4efcSMark Brown 		}
1414bcdd4efcSMark Brown 	}
1415bcdd4efcSMark Brown 
141667488526SMark Brown 	mutex_init(&wm8350->auxadc_mutex);
1417ebccec0fSMark Brown 	mutex_init(&wm8350->irq_mutex);
1418ebccec0fSMark Brown 	INIT_WORK(&wm8350->irq_work, wm8350_irq_worker);
1419c7752351SMark Brown 	if (irq) {
1420ebccec0fSMark Brown 		ret = request_irq(irq, wm8350_irq, 0,
1421ebccec0fSMark Brown 				  "wm8350", wm8350);
1422ebccec0fSMark Brown 		if (ret != 0) {
1423ebccec0fSMark Brown 			dev_err(wm8350->dev, "Failed to request IRQ: %d\n",
1424ebccec0fSMark Brown 				ret);
1425ebccec0fSMark Brown 			goto err;
1426ebccec0fSMark Brown 		}
1427ebccec0fSMark Brown 	} else {
1428ebccec0fSMark Brown 		dev_err(wm8350->dev, "No IRQ configured\n");
1429ebccec0fSMark Brown 		goto err;
1430ebccec0fSMark Brown 	}
1431ebccec0fSMark Brown 	wm8350->chip_irq = irq;
1432ebccec0fSMark Brown 
1433ebccec0fSMark Brown 	wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0x0);
1434ebccec0fSMark Brown 
1435add41cb4SMark Brown 	wm8350_client_dev_register(wm8350, "wm8350-codec",
1436add41cb4SMark Brown 				   &(wm8350->codec.pdev));
1437add41cb4SMark Brown 	wm8350_client_dev_register(wm8350, "wm8350-gpio",
1438add41cb4SMark Brown 				   &(wm8350->gpio.pdev));
1439add41cb4SMark Brown 	wm8350_client_dev_register(wm8350, "wm8350-power",
1440add41cb4SMark Brown 				   &(wm8350->power.pdev));
1441add41cb4SMark Brown 	wm8350_client_dev_register(wm8350, "wm8350-rtc", &(wm8350->rtc.pdev));
1442add41cb4SMark Brown 	wm8350_client_dev_register(wm8350, "wm8350-wdt", &(wm8350->wdt.pdev));
1443add41cb4SMark Brown 
144489b4012bSMark Brown 	return 0;
144589b4012bSMark Brown 
144689b4012bSMark Brown err:
144789b4012bSMark Brown 	kfree(wm8350->reg_cache);
144889b4012bSMark Brown 	return ret;
144989b4012bSMark Brown }
145089b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_device_init);
145189b4012bSMark Brown 
145289b4012bSMark Brown void wm8350_device_exit(struct wm8350 *wm8350)
145389b4012bSMark Brown {
1454da09155aSMark Brown 	int i;
1455da09155aSMark Brown 
14560081e802SMark Brown 	for (i = 0; i < ARRAY_SIZE(wm8350->pmic.led); i++)
14570081e802SMark Brown 		platform_device_unregister(wm8350->pmic.led[i].pdev);
14580081e802SMark Brown 
1459da09155aSMark Brown 	for (i = 0; i < ARRAY_SIZE(wm8350->pmic.pdev); i++)
1460da09155aSMark Brown 		platform_device_unregister(wm8350->pmic.pdev[i]);
1461da09155aSMark Brown 
1462add41cb4SMark Brown 	platform_device_unregister(wm8350->wdt.pdev);
1463add41cb4SMark Brown 	platform_device_unregister(wm8350->rtc.pdev);
1464add41cb4SMark Brown 	platform_device_unregister(wm8350->power.pdev);
1465add41cb4SMark Brown 	platform_device_unregister(wm8350->gpio.pdev);
1466add41cb4SMark Brown 	platform_device_unregister(wm8350->codec.pdev);
1467add41cb4SMark Brown 
1468ebccec0fSMark Brown 	free_irq(wm8350->chip_irq, wm8350);
1469ebccec0fSMark Brown 	flush_work(&wm8350->irq_work);
147089b4012bSMark Brown 	kfree(wm8350->reg_cache);
147189b4012bSMark Brown }
147289b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_device_exit);
147389b4012bSMark Brown 
1474ebccec0fSMark Brown MODULE_DESCRIPTION("WM8350 AudioPlus PMIC core driver");
147589b4012bSMark Brown MODULE_LICENSE("GPL");
1476