xref: /openbmc/linux/drivers/mfd/ab8500-core.c (revision 822672a7b496e724f879af703693f342e2215163)
162579266SRabin Vincent /*
262579266SRabin Vincent  * Copyright (C) ST-Ericsson SA 2010
362579266SRabin Vincent  *
462579266SRabin Vincent  * License Terms: GNU General Public License v2
562579266SRabin Vincent  * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
662579266SRabin Vincent  * Author: Rabin Vincent <rabin.vincent@stericsson.com>
7adceed62SMattias Wallin  * Author: Mattias Wallin <mattias.wallin@stericsson.com>
862579266SRabin Vincent  */
962579266SRabin Vincent 
1062579266SRabin Vincent #include <linux/kernel.h>
1162579266SRabin Vincent #include <linux/slab.h>
1262579266SRabin Vincent #include <linux/init.h>
1362579266SRabin Vincent #include <linux/irq.h>
1406e589efSLee Jones #include <linux/irqdomain.h>
1562579266SRabin Vincent #include <linux/delay.h>
1662579266SRabin Vincent #include <linux/interrupt.h>
1762579266SRabin Vincent #include <linux/module.h>
1862579266SRabin Vincent #include <linux/platform_device.h>
1962579266SRabin Vincent #include <linux/mfd/core.h>
2047c16975SMattias Wallin #include <linux/mfd/abx500.h>
21ee66e653SLinus Walleij #include <linux/mfd/abx500/ab8500.h>
22d28f1db8SLee Jones #include <linux/mfd/dbx500-prcmu.h>
23549931f9SSundar R Iyer #include <linux/regulator/ab8500.h>
246bc4a568SLee Jones #include <linux/of.h>
256bc4a568SLee Jones #include <linux/of_device.h>
2662579266SRabin Vincent 
2762579266SRabin Vincent /*
2862579266SRabin Vincent  * Interrupt register offsets
2962579266SRabin Vincent  * Bank : 0x0E
3062579266SRabin Vincent  */
3147c16975SMattias Wallin #define AB8500_IT_SOURCE1_REG		0x00
3247c16975SMattias Wallin #define AB8500_IT_SOURCE2_REG		0x01
3347c16975SMattias Wallin #define AB8500_IT_SOURCE3_REG		0x02
3447c16975SMattias Wallin #define AB8500_IT_SOURCE4_REG		0x03
3547c16975SMattias Wallin #define AB8500_IT_SOURCE5_REG		0x04
3647c16975SMattias Wallin #define AB8500_IT_SOURCE6_REG		0x05
3747c16975SMattias Wallin #define AB8500_IT_SOURCE7_REG		0x06
3847c16975SMattias Wallin #define AB8500_IT_SOURCE8_REG		0x07
39d6255529SLinus Walleij #define AB9540_IT_SOURCE13_REG		0x0C
4047c16975SMattias Wallin #define AB8500_IT_SOURCE19_REG		0x12
4147c16975SMattias Wallin #define AB8500_IT_SOURCE20_REG		0x13
4247c16975SMattias Wallin #define AB8500_IT_SOURCE21_REG		0x14
4347c16975SMattias Wallin #define AB8500_IT_SOURCE22_REG		0x15
4447c16975SMattias Wallin #define AB8500_IT_SOURCE23_REG		0x16
4547c16975SMattias Wallin #define AB8500_IT_SOURCE24_REG		0x17
4662579266SRabin Vincent 
4762579266SRabin Vincent /*
4862579266SRabin Vincent  * latch registers
4962579266SRabin Vincent  */
5047c16975SMattias Wallin #define AB8500_IT_LATCH1_REG		0x20
5147c16975SMattias Wallin #define AB8500_IT_LATCH2_REG		0x21
5247c16975SMattias Wallin #define AB8500_IT_LATCH3_REG		0x22
5347c16975SMattias Wallin #define AB8500_IT_LATCH4_REG		0x23
5447c16975SMattias Wallin #define AB8500_IT_LATCH5_REG		0x24
5547c16975SMattias Wallin #define AB8500_IT_LATCH6_REG		0x25
5647c16975SMattias Wallin #define AB8500_IT_LATCH7_REG		0x26
5747c16975SMattias Wallin #define AB8500_IT_LATCH8_REG		0x27
5847c16975SMattias Wallin #define AB8500_IT_LATCH9_REG		0x28
5947c16975SMattias Wallin #define AB8500_IT_LATCH10_REG		0x29
6092d50a41SMattias Wallin #define AB8500_IT_LATCH12_REG		0x2B
61d6255529SLinus Walleij #define AB9540_IT_LATCH13_REG		0x2C
6247c16975SMattias Wallin #define AB8500_IT_LATCH19_REG		0x32
6347c16975SMattias Wallin #define AB8500_IT_LATCH20_REG		0x33
6447c16975SMattias Wallin #define AB8500_IT_LATCH21_REG		0x34
6547c16975SMattias Wallin #define AB8500_IT_LATCH22_REG		0x35
6647c16975SMattias Wallin #define AB8500_IT_LATCH23_REG		0x36
6747c16975SMattias Wallin #define AB8500_IT_LATCH24_REG		0x37
6862579266SRabin Vincent 
6962579266SRabin Vincent /*
7062579266SRabin Vincent  * mask registers
7162579266SRabin Vincent  */
7262579266SRabin Vincent 
7347c16975SMattias Wallin #define AB8500_IT_MASK1_REG		0x40
7447c16975SMattias Wallin #define AB8500_IT_MASK2_REG		0x41
7547c16975SMattias Wallin #define AB8500_IT_MASK3_REG		0x42
7647c16975SMattias Wallin #define AB8500_IT_MASK4_REG		0x43
7747c16975SMattias Wallin #define AB8500_IT_MASK5_REG		0x44
7847c16975SMattias Wallin #define AB8500_IT_MASK6_REG		0x45
7947c16975SMattias Wallin #define AB8500_IT_MASK7_REG		0x46
8047c16975SMattias Wallin #define AB8500_IT_MASK8_REG		0x47
8147c16975SMattias Wallin #define AB8500_IT_MASK9_REG		0x48
8247c16975SMattias Wallin #define AB8500_IT_MASK10_REG		0x49
8347c16975SMattias Wallin #define AB8500_IT_MASK11_REG		0x4A
8447c16975SMattias Wallin #define AB8500_IT_MASK12_REG		0x4B
8547c16975SMattias Wallin #define AB8500_IT_MASK13_REG		0x4C
8647c16975SMattias Wallin #define AB8500_IT_MASK14_REG		0x4D
8747c16975SMattias Wallin #define AB8500_IT_MASK15_REG		0x4E
8847c16975SMattias Wallin #define AB8500_IT_MASK16_REG		0x4F
8947c16975SMattias Wallin #define AB8500_IT_MASK17_REG		0x50
9047c16975SMattias Wallin #define AB8500_IT_MASK18_REG		0x51
9147c16975SMattias Wallin #define AB8500_IT_MASK19_REG		0x52
9247c16975SMattias Wallin #define AB8500_IT_MASK20_REG		0x53
9347c16975SMattias Wallin #define AB8500_IT_MASK21_REG		0x54
9447c16975SMattias Wallin #define AB8500_IT_MASK22_REG		0x55
9547c16975SMattias Wallin #define AB8500_IT_MASK23_REG		0x56
9647c16975SMattias Wallin #define AB8500_IT_MASK24_REG		0x57
9762579266SRabin Vincent 
987ccfe9b1SMichel JAOUEN /*
997ccfe9b1SMichel JAOUEN  * latch hierarchy registers
1007ccfe9b1SMichel JAOUEN  */
1017ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER1_REG	0x60
1027ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER2_REG	0x61
1037ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER3_REG	0x62
1047ccfe9b1SMichel JAOUEN 
1057ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER_NUM		3
1067ccfe9b1SMichel JAOUEN 
10747c16975SMattias Wallin #define AB8500_REV_REG			0x80
1080f620837SLinus Walleij #define AB8500_IC_NAME_REG		0x82
109e5c238c3SMattias Wallin #define AB8500_SWITCH_OFF_STATUS	0x00
11062579266SRabin Vincent 
111b4a31037SAndrew Lynn #define AB8500_TURN_ON_STATUS		0x00
112b4a31037SAndrew Lynn 
1136ef9418cSRickard Andersson static bool no_bm; /* No battery management */
1146ef9418cSRickard Andersson module_param(no_bm, bool, S_IRUGO);
1156ef9418cSRickard Andersson 
116d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_REG			0x23
117d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT	BIT(2)
118d6255529SLinus Walleij 
11962579266SRabin Vincent /*
12062579266SRabin Vincent  * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
1212ced445eSLinus Walleij  * numbers are indexed into this array with (num / 8). The interupts are
1222ced445eSLinus Walleij  * defined in linux/mfd/ab8500.h
12362579266SRabin Vincent  *
12462579266SRabin Vincent  * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
12562579266SRabin Vincent  * offset 0.
12662579266SRabin Vincent  */
1272ced445eSLinus Walleij /* AB8500 support */
12862579266SRabin Vincent static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
12992d50a41SMattias Wallin 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
13062579266SRabin Vincent };
13162579266SRabin Vincent 
132d6255529SLinus Walleij /* AB9540 support */
133d6255529SLinus Walleij static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
134d6255529SLinus Walleij 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24,
135d6255529SLinus Walleij };
136d6255529SLinus Walleij 
1370f620837SLinus Walleij static const char ab8500_version_str[][7] = {
1380f620837SLinus Walleij 	[AB8500_VERSION_AB8500] = "AB8500",
1390f620837SLinus Walleij 	[AB8500_VERSION_AB8505] = "AB8505",
1400f620837SLinus Walleij 	[AB8500_VERSION_AB9540] = "AB9540",
1410f620837SLinus Walleij 	[AB8500_VERSION_AB8540] = "AB8540",
1420f620837SLinus Walleij };
1430f620837SLinus Walleij 
144*822672a7SLee Jones static int ab8500_prcmu_write(struct ab8500 *ab8500, u16 addr, u8 data)
145d28f1db8SLee Jones {
146d28f1db8SLee Jones 	int ret;
147d28f1db8SLee Jones 
148d28f1db8SLee Jones 	ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
149d28f1db8SLee Jones 	if (ret < 0)
150d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
151d28f1db8SLee Jones 	return ret;
152d28f1db8SLee Jones }
153d28f1db8SLee Jones 
154*822672a7SLee Jones static int ab8500_prcmu_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
155d28f1db8SLee Jones 	u8 data)
156d28f1db8SLee Jones {
157d28f1db8SLee Jones 	int ret;
158d28f1db8SLee Jones 
159d28f1db8SLee Jones 	ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data,
160d28f1db8SLee Jones 		&mask, 1);
161d28f1db8SLee Jones 	if (ret < 0)
162d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
163d28f1db8SLee Jones 	return ret;
164d28f1db8SLee Jones }
165d28f1db8SLee Jones 
166*822672a7SLee Jones static int ab8500_prcmu_read(struct ab8500 *ab8500, u16 addr)
167d28f1db8SLee Jones {
168d28f1db8SLee Jones 	int ret;
169d28f1db8SLee Jones 	u8 data;
170d28f1db8SLee Jones 
171d28f1db8SLee Jones 	ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
172d28f1db8SLee Jones 	if (ret < 0) {
173d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
174d28f1db8SLee Jones 		return ret;
175d28f1db8SLee Jones 	}
176d28f1db8SLee Jones 	return (int)data;
177d28f1db8SLee Jones }
178d28f1db8SLee Jones 
17947c16975SMattias Wallin static int ab8500_get_chip_id(struct device *dev)
18047c16975SMattias Wallin {
1816bce7bf1SMattias Wallin 	struct ab8500 *ab8500;
1826bce7bf1SMattias Wallin 
1836bce7bf1SMattias Wallin 	if (!dev)
1846bce7bf1SMattias Wallin 		return -EINVAL;
1856bce7bf1SMattias Wallin 	ab8500 = dev_get_drvdata(dev->parent);
1866bce7bf1SMattias Wallin 	return ab8500 ? (int)ab8500->chip_id : -EINVAL;
18747c16975SMattias Wallin }
18847c16975SMattias Wallin 
18947c16975SMattias Wallin static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
19047c16975SMattias Wallin 	u8 reg, u8 data)
19162579266SRabin Vincent {
19262579266SRabin Vincent 	int ret;
19347c16975SMattias Wallin 	/*
19447c16975SMattias Wallin 	 * Put the u8 bank and u8 register together into a an u16.
19547c16975SMattias Wallin 	 * The bank on higher 8 bits and register in lower 8 bits.
19647c16975SMattias Wallin 	 * */
19747c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
19862579266SRabin Vincent 
19962579266SRabin Vincent 	dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
20062579266SRabin Vincent 
201392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
20247c16975SMattias Wallin 
20347c16975SMattias Wallin 	ret = ab8500->write(ab8500, addr, data);
20447c16975SMattias Wallin 	if (ret < 0)
20547c16975SMattias Wallin 		dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
20647c16975SMattias Wallin 			addr, ret);
20747c16975SMattias Wallin 	mutex_unlock(&ab8500->lock);
20847c16975SMattias Wallin 
20947c16975SMattias Wallin 	return ret;
21047c16975SMattias Wallin }
21147c16975SMattias Wallin 
21247c16975SMattias Wallin static int ab8500_set_register(struct device *dev, u8 bank,
21347c16975SMattias Wallin 	u8 reg, u8 value)
21447c16975SMattias Wallin {
215112a80d2SJonas Aaberg 	int ret;
21647c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
21747c16975SMattias Wallin 
218112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
219112a80d2SJonas Aaberg 	ret = set_register_interruptible(ab8500, bank, reg, value);
220112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
221112a80d2SJonas Aaberg 	return ret;
22247c16975SMattias Wallin }
22347c16975SMattias Wallin 
22447c16975SMattias Wallin static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
22547c16975SMattias Wallin 	u8 reg, u8 *value)
22647c16975SMattias Wallin {
22747c16975SMattias Wallin 	int ret;
22847c16975SMattias Wallin 	/* put the u8 bank and u8 reg together into a an u16.
22947c16975SMattias Wallin 	 * bank on higher 8 bits and reg in lower */
23047c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
23147c16975SMattias Wallin 
232392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
23347c16975SMattias Wallin 
23447c16975SMattias Wallin 	ret = ab8500->read(ab8500, addr);
23547c16975SMattias Wallin 	if (ret < 0)
23647c16975SMattias Wallin 		dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
23747c16975SMattias Wallin 			addr, ret);
23847c16975SMattias Wallin 	else
23947c16975SMattias Wallin 		*value = ret;
24047c16975SMattias Wallin 
24147c16975SMattias Wallin 	mutex_unlock(&ab8500->lock);
24247c16975SMattias Wallin 	dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret);
24347c16975SMattias Wallin 
24447c16975SMattias Wallin 	return ret;
24547c16975SMattias Wallin }
24647c16975SMattias Wallin 
24747c16975SMattias Wallin static int ab8500_get_register(struct device *dev, u8 bank,
24847c16975SMattias Wallin 	u8 reg, u8 *value)
24947c16975SMattias Wallin {
250112a80d2SJonas Aaberg 	int ret;
25147c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
25247c16975SMattias Wallin 
253112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
254112a80d2SJonas Aaberg 	ret = get_register_interruptible(ab8500, bank, reg, value);
255112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
256112a80d2SJonas Aaberg 	return ret;
25747c16975SMattias Wallin }
25847c16975SMattias Wallin 
25947c16975SMattias Wallin static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
26047c16975SMattias Wallin 	u8 reg, u8 bitmask, u8 bitvalues)
26147c16975SMattias Wallin {
26247c16975SMattias Wallin 	int ret;
26347c16975SMattias Wallin 	/* put the u8 bank and u8 reg together into a an u16.
26447c16975SMattias Wallin 	 * bank on higher 8 bits and reg in lower */
26547c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
26647c16975SMattias Wallin 
267392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
26847c16975SMattias Wallin 
269bc628fd1SMattias Nilsson 	if (ab8500->write_masked == NULL) {
270bc628fd1SMattias Nilsson 		u8 data;
271bc628fd1SMattias Nilsson 
27247c16975SMattias Wallin 		ret = ab8500->read(ab8500, addr);
27347c16975SMattias Wallin 		if (ret < 0) {
27447c16975SMattias Wallin 			dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
27547c16975SMattias Wallin 				addr, ret);
27647c16975SMattias Wallin 			goto out;
27747c16975SMattias Wallin 		}
27847c16975SMattias Wallin 
27947c16975SMattias Wallin 		data = (u8)ret;
28047c16975SMattias Wallin 		data = (~bitmask & data) | (bitmask & bitvalues);
28147c16975SMattias Wallin 
28262579266SRabin Vincent 		ret = ab8500->write(ab8500, addr, data);
28362579266SRabin Vincent 		if (ret < 0)
28462579266SRabin Vincent 			dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
28562579266SRabin Vincent 				addr, ret);
28662579266SRabin Vincent 
287bc628fd1SMattias Nilsson 		dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr,
288bc628fd1SMattias Nilsson 			data);
289bc628fd1SMattias Nilsson 		goto out;
290bc628fd1SMattias Nilsson 	}
291bc628fd1SMattias Nilsson 	ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues);
292bc628fd1SMattias Nilsson 	if (ret < 0)
293bc628fd1SMattias Nilsson 		dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr,
294bc628fd1SMattias Nilsson 			ret);
29562579266SRabin Vincent out:
29662579266SRabin Vincent 	mutex_unlock(&ab8500->lock);
29762579266SRabin Vincent 	return ret;
29862579266SRabin Vincent }
29947c16975SMattias Wallin 
30047c16975SMattias Wallin static int ab8500_mask_and_set_register(struct device *dev,
30147c16975SMattias Wallin 	u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
30247c16975SMattias Wallin {
303112a80d2SJonas Aaberg 	int ret;
30447c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
30547c16975SMattias Wallin 
306112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
307112a80d2SJonas Aaberg 	ret= mask_and_set_register_interruptible(ab8500, bank, reg,
30847c16975SMattias Wallin 						 bitmask, bitvalues);
309112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
310112a80d2SJonas Aaberg 	return ret;
31147c16975SMattias Wallin }
31247c16975SMattias Wallin 
31347c16975SMattias Wallin static struct abx500_ops ab8500_ops = {
31447c16975SMattias Wallin 	.get_chip_id = ab8500_get_chip_id,
31547c16975SMattias Wallin 	.get_register = ab8500_get_register,
31647c16975SMattias Wallin 	.set_register = ab8500_set_register,
31747c16975SMattias Wallin 	.get_register_page = NULL,
31847c16975SMattias Wallin 	.set_register_page = NULL,
31947c16975SMattias Wallin 	.mask_and_set_register = ab8500_mask_and_set_register,
32047c16975SMattias Wallin 	.event_registers_startup_state_get = NULL,
32147c16975SMattias Wallin 	.startup_irq_enabled = NULL,
32247c16975SMattias Wallin };
32362579266SRabin Vincent 
3249505a0a0SMark Brown static void ab8500_irq_lock(struct irq_data *data)
32562579266SRabin Vincent {
3269505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
32762579266SRabin Vincent 
32862579266SRabin Vincent 	mutex_lock(&ab8500->irq_lock);
329112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
33062579266SRabin Vincent }
33162579266SRabin Vincent 
3329505a0a0SMark Brown static void ab8500_irq_sync_unlock(struct irq_data *data)
33362579266SRabin Vincent {
3349505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
33562579266SRabin Vincent 	int i;
33662579266SRabin Vincent 
3372ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++) {
33862579266SRabin Vincent 		u8 old = ab8500->oldmask[i];
33962579266SRabin Vincent 		u8 new = ab8500->mask[i];
34062579266SRabin Vincent 		int reg;
34162579266SRabin Vincent 
34262579266SRabin Vincent 		if (new == old)
34362579266SRabin Vincent 			continue;
34462579266SRabin Vincent 
3450f620837SLinus Walleij 		/*
3460f620837SLinus Walleij 		 * Interrupt register 12 doesn't exist prior to AB8500 version
3470f620837SLinus Walleij 		 * 2.0
3480f620837SLinus Walleij 		 */
3490f620837SLinus Walleij 		if (ab8500->irq_reg_offset[i] == 11 &&
3500f620837SLinus Walleij 			is_ab8500_1p1_or_earlier(ab8500))
35192d50a41SMattias Wallin 			continue;
35292d50a41SMattias Wallin 
35362579266SRabin Vincent 		ab8500->oldmask[i] = new;
35462579266SRabin Vincent 
3552ced445eSLinus Walleij 		reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
35647c16975SMattias Wallin 		set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
35762579266SRabin Vincent 	}
358112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
35962579266SRabin Vincent 	mutex_unlock(&ab8500->irq_lock);
36062579266SRabin Vincent }
36162579266SRabin Vincent 
3629505a0a0SMark Brown static void ab8500_irq_mask(struct irq_data *data)
36362579266SRabin Vincent {
3649505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
36506e589efSLee Jones 	int offset = data->hwirq;
36662579266SRabin Vincent 	int index = offset / 8;
36762579266SRabin Vincent 	int mask = 1 << (offset % 8);
36862579266SRabin Vincent 
36962579266SRabin Vincent 	ab8500->mask[index] |= mask;
37062579266SRabin Vincent }
37162579266SRabin Vincent 
3729505a0a0SMark Brown static void ab8500_irq_unmask(struct irq_data *data)
37362579266SRabin Vincent {
3749505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
37506e589efSLee Jones 	int offset = data->hwirq;
37662579266SRabin Vincent 	int index = offset / 8;
37762579266SRabin Vincent 	int mask = 1 << (offset % 8);
37862579266SRabin Vincent 
37962579266SRabin Vincent 	ab8500->mask[index] &= ~mask;
38062579266SRabin Vincent }
38162579266SRabin Vincent 
38262579266SRabin Vincent static struct irq_chip ab8500_irq_chip = {
38362579266SRabin Vincent 	.name			= "ab8500",
3849505a0a0SMark Brown 	.irq_bus_lock		= ab8500_irq_lock,
3859505a0a0SMark Brown 	.irq_bus_sync_unlock	= ab8500_irq_sync_unlock,
3869505a0a0SMark Brown 	.irq_mask		= ab8500_irq_mask,
387e6f9306eSVirupax Sadashivpetimath 	.irq_disable		= ab8500_irq_mask,
3889505a0a0SMark Brown 	.irq_unmask		= ab8500_irq_unmask,
38962579266SRabin Vincent };
39062579266SRabin Vincent 
3917ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
3927ccfe9b1SMichel JAOUEN 					int latch_offset, u8 latch_val)
3937ccfe9b1SMichel JAOUEN {
3947ccfe9b1SMichel JAOUEN 	int int_bit = __ffs(latch_val);
3957ccfe9b1SMichel JAOUEN 	int line, i;
3967ccfe9b1SMichel JAOUEN 
3977ccfe9b1SMichel JAOUEN 	do {
3987ccfe9b1SMichel JAOUEN 		int_bit = __ffs(latch_val);
3997ccfe9b1SMichel JAOUEN 
4007ccfe9b1SMichel JAOUEN 		for (i = 0; i < ab8500->mask_size; i++)
4017ccfe9b1SMichel JAOUEN 			if (ab8500->irq_reg_offset[i] == latch_offset)
4027ccfe9b1SMichel JAOUEN 				break;
4037ccfe9b1SMichel JAOUEN 
4047ccfe9b1SMichel JAOUEN 		if (i >= ab8500->mask_size) {
4057ccfe9b1SMichel JAOUEN 			dev_err(ab8500->dev, "Register offset 0x%2x not declared\n",
4067ccfe9b1SMichel JAOUEN 					latch_offset);
4077ccfe9b1SMichel JAOUEN 			return -ENXIO;
4087ccfe9b1SMichel JAOUEN 		}
4097ccfe9b1SMichel JAOUEN 
4107ccfe9b1SMichel JAOUEN 		line = (i << 3) + int_bit;
4117ccfe9b1SMichel JAOUEN 		latch_val &= ~(1 << int_bit);
4127ccfe9b1SMichel JAOUEN 
4137ccfe9b1SMichel JAOUEN 		handle_nested_irq(ab8500->irq_base + line);
4147ccfe9b1SMichel JAOUEN 	} while (latch_val);
4157ccfe9b1SMichel JAOUEN 
4167ccfe9b1SMichel JAOUEN 	return 0;
4177ccfe9b1SMichel JAOUEN }
4187ccfe9b1SMichel JAOUEN 
4197ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500,
4207ccfe9b1SMichel JAOUEN 					int hier_offset, u8 hier_val)
4217ccfe9b1SMichel JAOUEN {
4227ccfe9b1SMichel JAOUEN 	int latch_bit, status;
4237ccfe9b1SMichel JAOUEN 	u8 latch_offset, latch_val;
4247ccfe9b1SMichel JAOUEN 
4257ccfe9b1SMichel JAOUEN 	do {
4267ccfe9b1SMichel JAOUEN 		latch_bit = __ffs(hier_val);
4277ccfe9b1SMichel JAOUEN 		latch_offset = (hier_offset << 3) + latch_bit;
4287ccfe9b1SMichel JAOUEN 
4297ccfe9b1SMichel JAOUEN 		/* Fix inconsistent ITFromLatch25 bit mapping... */
4307ccfe9b1SMichel JAOUEN 		if (unlikely(latch_offset == 17))
4317ccfe9b1SMichel JAOUEN 			latch_offset = 24;
4327ccfe9b1SMichel JAOUEN 
4337ccfe9b1SMichel JAOUEN 		status = get_register_interruptible(ab8500,
4347ccfe9b1SMichel JAOUEN 				AB8500_INTERRUPT,
4357ccfe9b1SMichel JAOUEN 				AB8500_IT_LATCH1_REG + latch_offset,
4367ccfe9b1SMichel JAOUEN 				&latch_val);
4377ccfe9b1SMichel JAOUEN 		if (status < 0 || latch_val == 0)
4387ccfe9b1SMichel JAOUEN 			goto discard;
4397ccfe9b1SMichel JAOUEN 
4407ccfe9b1SMichel JAOUEN 		status = ab8500_handle_hierarchical_line(ab8500,
4417ccfe9b1SMichel JAOUEN 				latch_offset, latch_val);
4427ccfe9b1SMichel JAOUEN 		if (status < 0)
4437ccfe9b1SMichel JAOUEN 			return status;
4447ccfe9b1SMichel JAOUEN discard:
4457ccfe9b1SMichel JAOUEN 		hier_val &= ~(1 << latch_bit);
4467ccfe9b1SMichel JAOUEN 	} while (hier_val);
4477ccfe9b1SMichel JAOUEN 
4487ccfe9b1SMichel JAOUEN 	return 0;
4497ccfe9b1SMichel JAOUEN }
4507ccfe9b1SMichel JAOUEN 
4517ccfe9b1SMichel JAOUEN static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev)
4527ccfe9b1SMichel JAOUEN {
4537ccfe9b1SMichel JAOUEN 	struct ab8500 *ab8500 = dev;
4547ccfe9b1SMichel JAOUEN 	u8 i;
4557ccfe9b1SMichel JAOUEN 
4567ccfe9b1SMichel JAOUEN 	dev_vdbg(ab8500->dev, "interrupt\n");
4577ccfe9b1SMichel JAOUEN 
4587ccfe9b1SMichel JAOUEN 	/*  Hierarchical interrupt version */
4597ccfe9b1SMichel JAOUEN 	for (i = 0; i < AB8500_IT_LATCHHIER_NUM; i++) {
4607ccfe9b1SMichel JAOUEN 		int status;
4617ccfe9b1SMichel JAOUEN 		u8 hier_val;
4627ccfe9b1SMichel JAOUEN 
4637ccfe9b1SMichel JAOUEN 		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
4647ccfe9b1SMichel JAOUEN 			AB8500_IT_LATCHHIER1_REG + i, &hier_val);
4657ccfe9b1SMichel JAOUEN 		if (status < 0 || hier_val == 0)
4667ccfe9b1SMichel JAOUEN 			continue;
4677ccfe9b1SMichel JAOUEN 
4687ccfe9b1SMichel JAOUEN 		status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val);
4697ccfe9b1SMichel JAOUEN 		if (status < 0)
4707ccfe9b1SMichel JAOUEN 			break;
4717ccfe9b1SMichel JAOUEN 	}
4727ccfe9b1SMichel JAOUEN 	return IRQ_HANDLED;
4737ccfe9b1SMichel JAOUEN }
4747ccfe9b1SMichel JAOUEN 
47562579266SRabin Vincent static irqreturn_t ab8500_irq(int irq, void *dev)
47662579266SRabin Vincent {
47762579266SRabin Vincent 	struct ab8500 *ab8500 = dev;
47862579266SRabin Vincent 	int i;
47962579266SRabin Vincent 
48062579266SRabin Vincent 	dev_vdbg(ab8500->dev, "interrupt\n");
48162579266SRabin Vincent 
482112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
483112a80d2SJonas Aaberg 
4842ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++) {
4852ced445eSLinus Walleij 		int regoffset = ab8500->irq_reg_offset[i];
48662579266SRabin Vincent 		int status;
48747c16975SMattias Wallin 		u8 value;
48862579266SRabin Vincent 
4890f620837SLinus Walleij 		/*
4900f620837SLinus Walleij 		 * Interrupt register 12 doesn't exist prior to AB8500 version
4910f620837SLinus Walleij 		 * 2.0
4920f620837SLinus Walleij 		 */
4930f620837SLinus Walleij 		if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500))
49492d50a41SMattias Wallin 			continue;
49592d50a41SMattias Wallin 
49647c16975SMattias Wallin 		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
49747c16975SMattias Wallin 			AB8500_IT_LATCH1_REG + regoffset, &value);
49847c16975SMattias Wallin 		if (status < 0 || value == 0)
49962579266SRabin Vincent 			continue;
50062579266SRabin Vincent 
50162579266SRabin Vincent 		do {
50288aec4f7SMattias Wallin 			int bit = __ffs(value);
50362579266SRabin Vincent 			int line = i * 8 + bit;
50462579266SRabin Vincent 
50562579266SRabin Vincent 			handle_nested_irq(ab8500->irq_base + line);
50647c16975SMattias Wallin 			value &= ~(1 << bit);
507112a80d2SJonas Aaberg 
50847c16975SMattias Wallin 		} while (value);
50962579266SRabin Vincent 	}
510112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
51162579266SRabin Vincent 	return IRQ_HANDLED;
51262579266SRabin Vincent }
51362579266SRabin Vincent 
51406e589efSLee Jones /**
51506e589efSLee Jones  * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
51606e589efSLee Jones  *
51706e589efSLee Jones  * @ab8500: ab8500_irq controller to operate on.
51806e589efSLee Jones  * @irq: index of the interrupt requested in the chip IRQs
51906e589efSLee Jones  *
52006e589efSLee Jones  * Useful for drivers to request their own IRQs.
52106e589efSLee Jones  */
52206e589efSLee Jones int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq)
52362579266SRabin Vincent {
52406e589efSLee Jones 	if (!ab8500)
52506e589efSLee Jones 		return -EINVAL;
52662579266SRabin Vincent 
52706e589efSLee Jones 	return irq_create_mapping(ab8500->domain, irq);
52862579266SRabin Vincent }
52906e589efSLee Jones EXPORT_SYMBOL_GPL(ab8500_irq_get_virq);
53006e589efSLee Jones 
53106e589efSLee Jones static int ab8500_irq_map(struct irq_domain *d, unsigned int virq,
53206e589efSLee Jones 				irq_hw_number_t hwirq)
53306e589efSLee Jones {
53406e589efSLee Jones 	struct ab8500 *ab8500 = d->host_data;
53506e589efSLee Jones 
53606e589efSLee Jones 	if (!ab8500)
53706e589efSLee Jones 		return -EINVAL;
53806e589efSLee Jones 
53906e589efSLee Jones 	irq_set_chip_data(virq, ab8500);
54006e589efSLee Jones 	irq_set_chip_and_handler(virq, &ab8500_irq_chip,
54106e589efSLee Jones 				handle_simple_irq);
54206e589efSLee Jones 	irq_set_nested_thread(virq, 1);
54306e589efSLee Jones #ifdef CONFIG_ARM
54406e589efSLee Jones 	set_irq_flags(virq, IRQF_VALID);
54506e589efSLee Jones #else
54606e589efSLee Jones 	irq_set_noprobe(virq);
54706e589efSLee Jones #endif
54862579266SRabin Vincent 
54962579266SRabin Vincent 	return 0;
55062579266SRabin Vincent }
55162579266SRabin Vincent 
55206e589efSLee Jones static struct irq_domain_ops ab8500_irq_ops = {
55306e589efSLee Jones         .map    = ab8500_irq_map,
55406e589efSLee Jones         .xlate  = irq_domain_xlate_twocell,
55506e589efSLee Jones };
55606e589efSLee Jones 
55706e589efSLee Jones static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np)
55862579266SRabin Vincent {
5592ced445eSLinus Walleij 	int num_irqs;
56062579266SRabin Vincent 
561d6255529SLinus Walleij 	if (is_ab9540(ab8500))
562d6255529SLinus Walleij 		num_irqs = AB9540_NR_IRQS;
563a982362cSBengt Jonsson 	else if (is_ab8505(ab8500))
564a982362cSBengt Jonsson 		num_irqs = AB8505_NR_IRQS;
565d6255529SLinus Walleij 	else
5662ced445eSLinus Walleij 		num_irqs = AB8500_NR_IRQS;
5672ced445eSLinus Walleij 
56806e589efSLee Jones 	if (ab8500->irq_base) {
56906e589efSLee Jones 		ab8500->domain = irq_domain_add_legacy(
57006e589efSLee Jones 			NULL, num_irqs, ab8500->irq_base,
57106e589efSLee Jones 			0, &ab8500_irq_ops, ab8500);
57262579266SRabin Vincent 	}
57306e589efSLee Jones 	else {
57406e589efSLee Jones 		ab8500->domain = irq_domain_add_linear(
57506e589efSLee Jones 			np, num_irqs, &ab8500_irq_ops, ab8500);
57606e589efSLee Jones 	}
57706e589efSLee Jones 
57806e589efSLee Jones 	if (!ab8500->domain) {
57906e589efSLee Jones 		dev_err(ab8500->dev, "Failed to create irqdomain\n");
58006e589efSLee Jones 		return -ENOSYS;
58106e589efSLee Jones 	}
58206e589efSLee Jones 
58306e589efSLee Jones 	return 0;
58462579266SRabin Vincent }
58562579266SRabin Vincent 
586112a80d2SJonas Aaberg int ab8500_suspend(struct ab8500 *ab8500)
587112a80d2SJonas Aaberg {
588112a80d2SJonas Aaberg 	if (atomic_read(&ab8500->transfer_ongoing))
589112a80d2SJonas Aaberg 		return -EINVAL;
590112a80d2SJonas Aaberg 	else
591112a80d2SJonas Aaberg 		return 0;
592112a80d2SJonas Aaberg }
593112a80d2SJonas Aaberg 
594d6255529SLinus Walleij /* AB8500 GPIO Resources */
5955cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_gpio_resources[] = {
5960cb3fcd7SBibek Basu 	{
5970cb3fcd7SBibek Basu 		.name	= "GPIO_INT6",
5980cb3fcd7SBibek Basu 		.start	= AB8500_INT_GPIO6R,
5990cb3fcd7SBibek Basu 		.end	= AB8500_INT_GPIO41F,
6000cb3fcd7SBibek Basu 		.flags	= IORESOURCE_IRQ,
6010cb3fcd7SBibek Basu 	}
6020cb3fcd7SBibek Basu };
6030cb3fcd7SBibek Basu 
604d6255529SLinus Walleij /* AB9540 GPIO Resources */
605d6255529SLinus Walleij static struct resource __devinitdata ab9540_gpio_resources[] = {
606d6255529SLinus Walleij 	{
607d6255529SLinus Walleij 		.name	= "GPIO_INT6",
608d6255529SLinus Walleij 		.start	= AB8500_INT_GPIO6R,
609d6255529SLinus Walleij 		.end	= AB8500_INT_GPIO41F,
610d6255529SLinus Walleij 		.flags	= IORESOURCE_IRQ,
611d6255529SLinus Walleij 	},
612d6255529SLinus Walleij 	{
613d6255529SLinus Walleij 		.name	= "GPIO_INT14",
614d6255529SLinus Walleij 		.start	= AB9540_INT_GPIO50R,
615d6255529SLinus Walleij 		.end	= AB9540_INT_GPIO54R,
616d6255529SLinus Walleij 		.flags	= IORESOURCE_IRQ,
617d6255529SLinus Walleij 	},
618d6255529SLinus Walleij 	{
619d6255529SLinus Walleij 		.name	= "GPIO_INT15",
620d6255529SLinus Walleij 		.start	= AB9540_INT_GPIO50F,
621d6255529SLinus Walleij 		.end	= AB9540_INT_GPIO54F,
622d6255529SLinus Walleij 		.flags	= IORESOURCE_IRQ,
623d6255529SLinus Walleij 	}
624d6255529SLinus Walleij };
625d6255529SLinus Walleij 
6265cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_gpadc_resources[] = {
62762579266SRabin Vincent 	{
62862579266SRabin Vincent 		.name	= "HW_CONV_END",
62962579266SRabin Vincent 		.start	= AB8500_INT_GP_HW_ADC_CONV_END,
63062579266SRabin Vincent 		.end	= AB8500_INT_GP_HW_ADC_CONV_END,
63162579266SRabin Vincent 		.flags	= IORESOURCE_IRQ,
63262579266SRabin Vincent 	},
63362579266SRabin Vincent 	{
63462579266SRabin Vincent 		.name	= "SW_CONV_END",
63562579266SRabin Vincent 		.start	= AB8500_INT_GP_SW_ADC_CONV_END,
63662579266SRabin Vincent 		.end	= AB8500_INT_GP_SW_ADC_CONV_END,
63762579266SRabin Vincent 		.flags	= IORESOURCE_IRQ,
63862579266SRabin Vincent 	},
63962579266SRabin Vincent };
64062579266SRabin Vincent 
6415cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_rtc_resources[] = {
64262579266SRabin Vincent 	{
64362579266SRabin Vincent 		.name	= "60S",
64462579266SRabin Vincent 		.start	= AB8500_INT_RTC_60S,
64562579266SRabin Vincent 		.end	= AB8500_INT_RTC_60S,
64662579266SRabin Vincent 		.flags	= IORESOURCE_IRQ,
64762579266SRabin Vincent 	},
64862579266SRabin Vincent 	{
64962579266SRabin Vincent 		.name	= "ALARM",
65062579266SRabin Vincent 		.start	= AB8500_INT_RTC_ALARM,
65162579266SRabin Vincent 		.end	= AB8500_INT_RTC_ALARM,
65262579266SRabin Vincent 		.flags	= IORESOURCE_IRQ,
65362579266SRabin Vincent 	},
65462579266SRabin Vincent };
65562579266SRabin Vincent 
6565cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_poweronkey_db_resources[] = {
65777686517SSundar R Iyer 	{
65877686517SSundar R Iyer 		.name	= "ONKEY_DBF",
65977686517SSundar R Iyer 		.start	= AB8500_INT_PON_KEY1DB_F,
66077686517SSundar R Iyer 		.end	= AB8500_INT_PON_KEY1DB_F,
66177686517SSundar R Iyer 		.flags	= IORESOURCE_IRQ,
66277686517SSundar R Iyer 	},
66377686517SSundar R Iyer 	{
66477686517SSundar R Iyer 		.name	= "ONKEY_DBR",
66577686517SSundar R Iyer 		.start	= AB8500_INT_PON_KEY1DB_R,
66677686517SSundar R Iyer 		.end	= AB8500_INT_PON_KEY1DB_R,
66777686517SSundar R Iyer 		.flags	= IORESOURCE_IRQ,
66877686517SSundar R Iyer 	},
66977686517SSundar R Iyer };
67077686517SSundar R Iyer 
6716af75ecdSLinus Walleij static struct resource __devinitdata ab8500_av_acc_detect_resources[] = {
672e098adedSMattias Wallin 	{
6736af75ecdSLinus Walleij 	       .name = "ACC_DETECT_1DB_F",
6746af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_1DB_F,
6756af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_1DB_F,
676e098adedSMattias Wallin 	       .flags = IORESOURCE_IRQ,
677e098adedSMattias Wallin 	},
678e098adedSMattias Wallin 	{
6796af75ecdSLinus Walleij 	       .name = "ACC_DETECT_1DB_R",
6806af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_1DB_R,
6816af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_1DB_R,
682e098adedSMattias Wallin 	       .flags = IORESOURCE_IRQ,
683e098adedSMattias Wallin 	},
684e098adedSMattias Wallin 	{
6856af75ecdSLinus Walleij 	       .name = "ACC_DETECT_21DB_F",
6866af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_21DB_F,
6876af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_21DB_F,
6886af75ecdSLinus Walleij 	       .flags = IORESOURCE_IRQ,
6896af75ecdSLinus Walleij 	},
6906af75ecdSLinus Walleij 	{
6916af75ecdSLinus Walleij 	       .name = "ACC_DETECT_21DB_R",
6926af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_21DB_R,
6936af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_21DB_R,
6946af75ecdSLinus Walleij 	       .flags = IORESOURCE_IRQ,
6956af75ecdSLinus Walleij 	},
6966af75ecdSLinus Walleij 	{
6976af75ecdSLinus Walleij 	       .name = "ACC_DETECT_22DB_F",
6986af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_22DB_F,
6996af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_22DB_F,
7006af75ecdSLinus Walleij 	       .flags = IORESOURCE_IRQ,
7016af75ecdSLinus Walleij 	},
7026af75ecdSLinus Walleij 	{
7036af75ecdSLinus Walleij 	       .name = "ACC_DETECT_22DB_R",
7046af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_22DB_R,
7056af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_22DB_R,
7066af75ecdSLinus Walleij 	       .flags = IORESOURCE_IRQ,
7076af75ecdSLinus Walleij 	},
7086af75ecdSLinus Walleij };
7096af75ecdSLinus Walleij 
7106af75ecdSLinus Walleij static struct resource __devinitdata ab8500_charger_resources[] = {
7116af75ecdSLinus Walleij 	{
712e098adedSMattias Wallin 		.name = "MAIN_CH_UNPLUG_DET",
713e098adedSMattias Wallin 		.start = AB8500_INT_MAIN_CH_UNPLUG_DET,
714e098adedSMattias Wallin 		.end = AB8500_INT_MAIN_CH_UNPLUG_DET,
715e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
716e098adedSMattias Wallin 	},
717e098adedSMattias Wallin 	{
718e098adedSMattias Wallin 		.name = "MAIN_CHARGE_PLUG_DET",
719e098adedSMattias Wallin 		.start = AB8500_INT_MAIN_CH_PLUG_DET,
720e098adedSMattias Wallin 		.end = AB8500_INT_MAIN_CH_PLUG_DET,
721e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
722e098adedSMattias Wallin 	},
723e098adedSMattias Wallin 	{
724e098adedSMattias Wallin 		.name = "VBUS_DET_R",
725e098adedSMattias Wallin 		.start = AB8500_INT_VBUS_DET_R,
726e098adedSMattias Wallin 		.end = AB8500_INT_VBUS_DET_R,
727e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
728e098adedSMattias Wallin 	},
729e098adedSMattias Wallin 	{
7306af75ecdSLinus Walleij 		.name = "VBUS_DET_F",
7316af75ecdSLinus Walleij 		.start = AB8500_INT_VBUS_DET_F,
7326af75ecdSLinus Walleij 		.end = AB8500_INT_VBUS_DET_F,
733e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
734e098adedSMattias Wallin 	},
735e098adedSMattias Wallin 	{
7366af75ecdSLinus Walleij 		.name = "USB_LINK_STATUS",
7376af75ecdSLinus Walleij 		.start = AB8500_INT_USB_LINK_STATUS,
7386af75ecdSLinus Walleij 		.end = AB8500_INT_USB_LINK_STATUS,
7396af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
7406af75ecdSLinus Walleij 	},
7416af75ecdSLinus Walleij 	{
742e098adedSMattias Wallin 		.name = "VBUS_OVV",
743e098adedSMattias Wallin 		.start = AB8500_INT_VBUS_OVV,
744e098adedSMattias Wallin 		.end = AB8500_INT_VBUS_OVV,
745e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
746e098adedSMattias Wallin 	},
747e098adedSMattias Wallin 	{
7486af75ecdSLinus Walleij 		.name = "USB_CH_TH_PROT_R",
7496af75ecdSLinus Walleij 		.start = AB8500_INT_USB_CH_TH_PROT_R,
7506af75ecdSLinus Walleij 		.end = AB8500_INT_USB_CH_TH_PROT_R,
751e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
752e098adedSMattias Wallin 	},
753e098adedSMattias Wallin 	{
7546af75ecdSLinus Walleij 		.name = "USB_CH_TH_PROT_F",
7556af75ecdSLinus Walleij 		.start = AB8500_INT_USB_CH_TH_PROT_F,
7566af75ecdSLinus Walleij 		.end = AB8500_INT_USB_CH_TH_PROT_F,
757e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
758e098adedSMattias Wallin 	},
759e098adedSMattias Wallin 	{
7606af75ecdSLinus Walleij 		.name = "MAIN_EXT_CH_NOT_OK",
7616af75ecdSLinus Walleij 		.start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
7626af75ecdSLinus Walleij 		.end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
7636af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
7646af75ecdSLinus Walleij 	},
7656af75ecdSLinus Walleij 	{
7666af75ecdSLinus Walleij 		.name = "MAIN_CH_TH_PROT_R",
7676af75ecdSLinus Walleij 		.start = AB8500_INT_MAIN_CH_TH_PROT_R,
7686af75ecdSLinus Walleij 		.end = AB8500_INT_MAIN_CH_TH_PROT_R,
7696af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
7706af75ecdSLinus Walleij 	},
7716af75ecdSLinus Walleij 	{
7726af75ecdSLinus Walleij 		.name = "MAIN_CH_TH_PROT_F",
7736af75ecdSLinus Walleij 		.start = AB8500_INT_MAIN_CH_TH_PROT_F,
7746af75ecdSLinus Walleij 		.end = AB8500_INT_MAIN_CH_TH_PROT_F,
7756af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
7766af75ecdSLinus Walleij 	},
7776af75ecdSLinus Walleij 	{
7786af75ecdSLinus Walleij 		.name = "USB_CHARGER_NOT_OKR",
779a982362cSBengt Jonsson 		.start = AB8500_INT_USB_CHARGER_NOT_OKR,
780a982362cSBengt Jonsson 		.end = AB8500_INT_USB_CHARGER_NOT_OKR,
7816af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
7826af75ecdSLinus Walleij 	},
7836af75ecdSLinus Walleij 	{
7846af75ecdSLinus Walleij 		.name = "CH_WD_EXP",
7856af75ecdSLinus Walleij 		.start = AB8500_INT_CH_WD_EXP,
7866af75ecdSLinus Walleij 		.end = AB8500_INT_CH_WD_EXP,
7876af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
7886af75ecdSLinus Walleij 	},
7896af75ecdSLinus Walleij };
7906af75ecdSLinus Walleij 
7916af75ecdSLinus Walleij static struct resource __devinitdata ab8500_btemp_resources[] = {
7926af75ecdSLinus Walleij 	{
7936af75ecdSLinus Walleij 		.name = "BAT_CTRL_INDB",
7946af75ecdSLinus Walleij 		.start = AB8500_INT_BAT_CTRL_INDB,
7956af75ecdSLinus Walleij 		.end = AB8500_INT_BAT_CTRL_INDB,
796e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
797e098adedSMattias Wallin 	},
798e098adedSMattias Wallin 	{
799e098adedSMattias Wallin 		.name = "BTEMP_LOW",
800e098adedSMattias Wallin 		.start = AB8500_INT_BTEMP_LOW,
801e098adedSMattias Wallin 		.end = AB8500_INT_BTEMP_LOW,
802e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
803e098adedSMattias Wallin 	},
804e098adedSMattias Wallin 	{
805e098adedSMattias Wallin 		.name = "BTEMP_HIGH",
806e098adedSMattias Wallin 		.start = AB8500_INT_BTEMP_HIGH,
807e098adedSMattias Wallin 		.end = AB8500_INT_BTEMP_HIGH,
808e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
809e098adedSMattias Wallin 	},
810e098adedSMattias Wallin 	{
8116af75ecdSLinus Walleij 		.name = "BTEMP_LOW_MEDIUM",
8126af75ecdSLinus Walleij 		.start = AB8500_INT_BTEMP_LOW_MEDIUM,
8136af75ecdSLinus Walleij 		.end = AB8500_INT_BTEMP_LOW_MEDIUM,
814e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
815e098adedSMattias Wallin 	},
816e098adedSMattias Wallin 	{
8176af75ecdSLinus Walleij 		.name = "BTEMP_MEDIUM_HIGH",
8186af75ecdSLinus Walleij 		.start = AB8500_INT_BTEMP_MEDIUM_HIGH,
8196af75ecdSLinus Walleij 		.end = AB8500_INT_BTEMP_MEDIUM_HIGH,
820e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
821e098adedSMattias Wallin 	},
822e098adedSMattias Wallin };
823e098adedSMattias Wallin 
8246af75ecdSLinus Walleij static struct resource __devinitdata ab8500_fg_resources[] = {
8256af75ecdSLinus Walleij 	{
8266af75ecdSLinus Walleij 		.name = "NCONV_ACCU",
8276af75ecdSLinus Walleij 		.start = AB8500_INT_CCN_CONV_ACC,
8286af75ecdSLinus Walleij 		.end = AB8500_INT_CCN_CONV_ACC,
8296af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8306af75ecdSLinus Walleij 	},
8316af75ecdSLinus Walleij 	{
8326af75ecdSLinus Walleij 		.name = "BATT_OVV",
8336af75ecdSLinus Walleij 		.start = AB8500_INT_BATT_OVV,
8346af75ecdSLinus Walleij 		.end = AB8500_INT_BATT_OVV,
8356af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8366af75ecdSLinus Walleij 	},
8376af75ecdSLinus Walleij 	{
8386af75ecdSLinus Walleij 		.name = "LOW_BAT_F",
8396af75ecdSLinus Walleij 		.start = AB8500_INT_LOW_BAT_F,
8406af75ecdSLinus Walleij 		.end = AB8500_INT_LOW_BAT_F,
8416af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8426af75ecdSLinus Walleij 	},
8436af75ecdSLinus Walleij 	{
8446af75ecdSLinus Walleij 		.name = "LOW_BAT_R",
8456af75ecdSLinus Walleij 		.start = AB8500_INT_LOW_BAT_R,
8466af75ecdSLinus Walleij 		.end = AB8500_INT_LOW_BAT_R,
8476af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8486af75ecdSLinus Walleij 	},
8496af75ecdSLinus Walleij 	{
8506af75ecdSLinus Walleij 		.name = "CC_INT_CALIB",
8516af75ecdSLinus Walleij 		.start = AB8500_INT_CC_INT_CALIB,
8526af75ecdSLinus Walleij 		.end = AB8500_INT_CC_INT_CALIB,
8536af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8546af75ecdSLinus Walleij 	},
855a982362cSBengt Jonsson 	{
856a982362cSBengt Jonsson 		.name = "CCEOC",
857a982362cSBengt Jonsson 		.start = AB8500_INT_CCEOC,
858a982362cSBengt Jonsson 		.end = AB8500_INT_CCEOC,
859a982362cSBengt Jonsson 		.flags = IORESOURCE_IRQ,
860a982362cSBengt Jonsson 	},
8616af75ecdSLinus Walleij };
8626af75ecdSLinus Walleij 
8636af75ecdSLinus Walleij static struct resource __devinitdata ab8500_chargalg_resources[] = {};
8646af75ecdSLinus Walleij 
865df720647SAxel Lin #ifdef CONFIG_DEBUG_FS
8665cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_debug_resources[] = {
867e098adedSMattias Wallin 	{
868e098adedSMattias Wallin 		.name	= "IRQ_FIRST",
869e098adedSMattias Wallin 		.start	= AB8500_INT_MAIN_EXT_CH_NOT_OK,
870e098adedSMattias Wallin 		.end	= AB8500_INT_MAIN_EXT_CH_NOT_OK,
871e098adedSMattias Wallin 		.flags	= IORESOURCE_IRQ,
872e098adedSMattias Wallin 	},
873e098adedSMattias Wallin 	{
874e098adedSMattias Wallin 		.name	= "IRQ_LAST",
875a982362cSBengt Jonsson 		.start	= AB8500_INT_XTAL32K_KO,
876a982362cSBengt Jonsson 		.end	= AB8500_INT_XTAL32K_KO,
877e098adedSMattias Wallin 		.flags	= IORESOURCE_IRQ,
878e098adedSMattias Wallin 	},
879e098adedSMattias Wallin };
880df720647SAxel Lin #endif
881e098adedSMattias Wallin 
8825cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_usb_resources[] = {
883e098adedSMattias Wallin 	{
884e098adedSMattias Wallin 		.name = "ID_WAKEUP_R",
885e098adedSMattias Wallin 		.start = AB8500_INT_ID_WAKEUP_R,
886e098adedSMattias Wallin 		.end = AB8500_INT_ID_WAKEUP_R,
887e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
888e098adedSMattias Wallin 	},
889e098adedSMattias Wallin 	{
890e098adedSMattias Wallin 		.name = "ID_WAKEUP_F",
891e098adedSMattias Wallin 		.start = AB8500_INT_ID_WAKEUP_F,
892e098adedSMattias Wallin 		.end = AB8500_INT_ID_WAKEUP_F,
893e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
894e098adedSMattias Wallin 	},
895e098adedSMattias Wallin 	{
896e098adedSMattias Wallin 		.name = "VBUS_DET_F",
897e098adedSMattias Wallin 		.start = AB8500_INT_VBUS_DET_F,
898e098adedSMattias Wallin 		.end = AB8500_INT_VBUS_DET_F,
899e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
900e098adedSMattias Wallin 	},
901e098adedSMattias Wallin 	{
902e098adedSMattias Wallin 		.name = "VBUS_DET_R",
903e098adedSMattias Wallin 		.start = AB8500_INT_VBUS_DET_R,
904e098adedSMattias Wallin 		.end = AB8500_INT_VBUS_DET_R,
905e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
906e098adedSMattias Wallin 	},
90792d50a41SMattias Wallin 	{
90892d50a41SMattias Wallin 		.name = "USB_LINK_STATUS",
90992d50a41SMattias Wallin 		.start = AB8500_INT_USB_LINK_STATUS,
91092d50a41SMattias Wallin 		.end = AB8500_INT_USB_LINK_STATUS,
91192d50a41SMattias Wallin 		.flags = IORESOURCE_IRQ,
91292d50a41SMattias Wallin 	},
9136af75ecdSLinus Walleij 	{
9146af75ecdSLinus Walleij 		.name = "USB_ADP_PROBE_PLUG",
9156af75ecdSLinus Walleij 		.start = AB8500_INT_ADP_PROBE_PLUG,
9166af75ecdSLinus Walleij 		.end = AB8500_INT_ADP_PROBE_PLUG,
9176af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
9186af75ecdSLinus Walleij 	},
9196af75ecdSLinus Walleij 	{
9206af75ecdSLinus Walleij 		.name = "USB_ADP_PROBE_UNPLUG",
9216af75ecdSLinus Walleij 		.start = AB8500_INT_ADP_PROBE_UNPLUG,
9226af75ecdSLinus Walleij 		.end = AB8500_INT_ADP_PROBE_UNPLUG,
9236af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
9246af75ecdSLinus Walleij 	},
925e098adedSMattias Wallin };
926e098adedSMattias Wallin 
92744f72e53SVirupax Sadashivpetimath static struct resource __devinitdata ab8505_iddet_resources[] = {
92844f72e53SVirupax Sadashivpetimath 	{
92944f72e53SVirupax Sadashivpetimath 		.name  = "KeyDeglitch",
93044f72e53SVirupax Sadashivpetimath 		.start = AB8505_INT_KEYDEGLITCH,
93144f72e53SVirupax Sadashivpetimath 		.end   = AB8505_INT_KEYDEGLITCH,
93244f72e53SVirupax Sadashivpetimath 		.flags = IORESOURCE_IRQ,
93344f72e53SVirupax Sadashivpetimath 	},
93444f72e53SVirupax Sadashivpetimath 	{
93544f72e53SVirupax Sadashivpetimath 		.name  = "KP",
93644f72e53SVirupax Sadashivpetimath 		.start = AB8505_INT_KP,
93744f72e53SVirupax Sadashivpetimath 		.end   = AB8505_INT_KP,
93844f72e53SVirupax Sadashivpetimath 		.flags = IORESOURCE_IRQ,
93944f72e53SVirupax Sadashivpetimath 	},
94044f72e53SVirupax Sadashivpetimath 	{
94144f72e53SVirupax Sadashivpetimath 		.name  = "IKP",
94244f72e53SVirupax Sadashivpetimath 		.start = AB8505_INT_IKP,
94344f72e53SVirupax Sadashivpetimath 		.end   = AB8505_INT_IKP,
94444f72e53SVirupax Sadashivpetimath 		.flags = IORESOURCE_IRQ,
94544f72e53SVirupax Sadashivpetimath 	},
94644f72e53SVirupax Sadashivpetimath 	{
94744f72e53SVirupax Sadashivpetimath 		.name  = "IKR",
94844f72e53SVirupax Sadashivpetimath 		.start = AB8505_INT_IKR,
94944f72e53SVirupax Sadashivpetimath 		.end   = AB8505_INT_IKR,
95044f72e53SVirupax Sadashivpetimath 		.flags = IORESOURCE_IRQ,
95144f72e53SVirupax Sadashivpetimath 	},
95244f72e53SVirupax Sadashivpetimath 	{
95344f72e53SVirupax Sadashivpetimath 		.name  = "KeyStuck",
95444f72e53SVirupax Sadashivpetimath 		.start = AB8505_INT_KEYSTUCK,
95544f72e53SVirupax Sadashivpetimath 		.end   = AB8505_INT_KEYSTUCK,
95644f72e53SVirupax Sadashivpetimath 		.flags = IORESOURCE_IRQ,
95744f72e53SVirupax Sadashivpetimath 	},
95844f72e53SVirupax Sadashivpetimath };
95944f72e53SVirupax Sadashivpetimath 
9605cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_temp_resources[] = {
961e098adedSMattias Wallin 	{
962e098adedSMattias Wallin 		.name  = "AB8500_TEMP_WARM",
963e098adedSMattias Wallin 		.start = AB8500_INT_TEMP_WARM,
964e098adedSMattias Wallin 		.end   = AB8500_INT_TEMP_WARM,
965e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
966e098adedSMattias Wallin 	},
967e098adedSMattias Wallin };
968e098adedSMattias Wallin 
969d6255529SLinus Walleij static struct mfd_cell __devinitdata abx500_common_devs[] = {
9705814fc35SMattias Wallin #ifdef CONFIG_DEBUG_FS
9715814fc35SMattias Wallin 	{
9725814fc35SMattias Wallin 		.name = "ab8500-debug",
973e098adedSMattias Wallin 		.num_resources = ARRAY_SIZE(ab8500_debug_resources),
974e098adedSMattias Wallin 		.resources = ab8500_debug_resources,
9755814fc35SMattias Wallin 	},
9765814fc35SMattias Wallin #endif
97762579266SRabin Vincent 	{
978e098adedSMattias Wallin 		.name = "ab8500-sysctrl",
979e098adedSMattias Wallin 	},
980e098adedSMattias Wallin 	{
981e098adedSMattias Wallin 		.name = "ab8500-regulator",
982e098adedSMattias Wallin 	},
983e098adedSMattias Wallin 	{
98462579266SRabin Vincent 		.name = "ab8500-gpadc",
98562579266SRabin Vincent 		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
98662579266SRabin Vincent 		.resources = ab8500_gpadc_resources,
98762579266SRabin Vincent 	},
98862579266SRabin Vincent 	{
98962579266SRabin Vincent 		.name = "ab8500-rtc",
99062579266SRabin Vincent 		.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
99162579266SRabin Vincent 		.resources = ab8500_rtc_resources,
99262579266SRabin Vincent 	},
993f0f05b1cSArun Murthy 	{
9946af75ecdSLinus Walleij 		.name = "ab8500-acc-det",
9956af75ecdSLinus Walleij 		.num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
9966af75ecdSLinus Walleij 		.resources = ab8500_av_acc_detect_resources,
9976af75ecdSLinus Walleij 	},
9986af75ecdSLinus Walleij 	{
999e098adedSMattias Wallin 		.name = "ab8500-poweron-key",
1000e098adedSMattias Wallin 		.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
1001e098adedSMattias Wallin 		.resources = ab8500_poweronkey_db_resources,
1002e098adedSMattias Wallin 	},
1003e098adedSMattias Wallin 	{
1004f0f05b1cSArun Murthy 		.name = "ab8500-pwm",
1005f0f05b1cSArun Murthy 		.id = 1,
1006f0f05b1cSArun Murthy 	},
1007f0f05b1cSArun Murthy 	{
1008f0f05b1cSArun Murthy 		.name = "ab8500-pwm",
1009f0f05b1cSArun Murthy 		.id = 2,
1010f0f05b1cSArun Murthy 	},
1011f0f05b1cSArun Murthy 	{
1012f0f05b1cSArun Murthy 		.name = "ab8500-pwm",
1013f0f05b1cSArun Murthy 		.id = 3,
1014f0f05b1cSArun Murthy 	},
1015e098adedSMattias Wallin 	{ .name = "ab8500-leds", },
101677686517SSundar R Iyer 	{
1017e098adedSMattias Wallin 		.name = "ab8500-denc",
1018e098adedSMattias Wallin 	},
1019e098adedSMattias Wallin 	{
1020e098adedSMattias Wallin 		.name = "ab8500-temp",
1021e098adedSMattias Wallin 		.num_resources = ARRAY_SIZE(ab8500_temp_resources),
1022e098adedSMattias Wallin 		.resources = ab8500_temp_resources,
102377686517SSundar R Iyer 	},
102462579266SRabin Vincent };
102562579266SRabin Vincent 
10266ef9418cSRickard Andersson static struct mfd_cell __devinitdata ab8500_bm_devs[] = {
10276ef9418cSRickard Andersson 	{
10286ef9418cSRickard Andersson 		.name = "ab8500-charger",
10296ef9418cSRickard Andersson 		.num_resources = ARRAY_SIZE(ab8500_charger_resources),
10306ef9418cSRickard Andersson 		.resources = ab8500_charger_resources,
10316ef9418cSRickard Andersson 	},
10326ef9418cSRickard Andersson 	{
10336ef9418cSRickard Andersson 		.name = "ab8500-btemp",
10346ef9418cSRickard Andersson 		.num_resources = ARRAY_SIZE(ab8500_btemp_resources),
10356ef9418cSRickard Andersson 		.resources = ab8500_btemp_resources,
10366ef9418cSRickard Andersson 	},
10376ef9418cSRickard Andersson 	{
10386ef9418cSRickard Andersson 		.name = "ab8500-fg",
10396ef9418cSRickard Andersson 		.num_resources = ARRAY_SIZE(ab8500_fg_resources),
10406ef9418cSRickard Andersson 		.resources = ab8500_fg_resources,
10416ef9418cSRickard Andersson 	},
10426ef9418cSRickard Andersson 	{
10436ef9418cSRickard Andersson 		.name = "ab8500-chargalg",
10446ef9418cSRickard Andersson 		.num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
10456ef9418cSRickard Andersson 		.resources = ab8500_chargalg_resources,
10466ef9418cSRickard Andersson 	},
10476ef9418cSRickard Andersson };
10486ef9418cSRickard Andersson 
1049d6255529SLinus Walleij static struct mfd_cell __devinitdata ab8500_devs[] = {
1050d6255529SLinus Walleij 	{
1051d6255529SLinus Walleij 		.name = "ab8500-gpio",
1052d6255529SLinus Walleij 		.num_resources = ARRAY_SIZE(ab8500_gpio_resources),
1053d6255529SLinus Walleij 		.resources = ab8500_gpio_resources,
1054d6255529SLinus Walleij 	},
1055d6255529SLinus Walleij 	{
1056d6255529SLinus Walleij 		.name = "ab8500-usb",
1057d6255529SLinus Walleij 		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
1058d6255529SLinus Walleij 		.resources = ab8500_usb_resources,
1059d6255529SLinus Walleij 	},
106044f72e53SVirupax Sadashivpetimath 	{
106144f72e53SVirupax Sadashivpetimath 		.name = "ab8500-codec",
106244f72e53SVirupax Sadashivpetimath 	},
1063d6255529SLinus Walleij };
1064d6255529SLinus Walleij 
1065d6255529SLinus Walleij static struct mfd_cell __devinitdata ab9540_devs[] = {
1066d6255529SLinus Walleij 	{
1067d6255529SLinus Walleij 		.name = "ab8500-gpio",
1068d6255529SLinus Walleij 		.num_resources = ARRAY_SIZE(ab9540_gpio_resources),
1069d6255529SLinus Walleij 		.resources = ab9540_gpio_resources,
1070d6255529SLinus Walleij 	},
1071d6255529SLinus Walleij 	{
1072d6255529SLinus Walleij 		.name = "ab9540-usb",
1073d6255529SLinus Walleij 		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
1074d6255529SLinus Walleij 		.resources = ab8500_usb_resources,
1075d6255529SLinus Walleij 	},
107644f72e53SVirupax Sadashivpetimath 	{
107744f72e53SVirupax Sadashivpetimath 		.name = "ab9540-codec",
107844f72e53SVirupax Sadashivpetimath 	},
107944f72e53SVirupax Sadashivpetimath };
108044f72e53SVirupax Sadashivpetimath 
108144f72e53SVirupax Sadashivpetimath /* Device list common to ab9540 and ab8505 */
108244f72e53SVirupax Sadashivpetimath static struct mfd_cell __devinitdata ab9540_ab8505_devs[] = {
108344f72e53SVirupax Sadashivpetimath 	{
108444f72e53SVirupax Sadashivpetimath 		.name = "ab-iddet",
108544f72e53SVirupax Sadashivpetimath 		.num_resources = ARRAY_SIZE(ab8505_iddet_resources),
108644f72e53SVirupax Sadashivpetimath 		.resources = ab8505_iddet_resources,
108744f72e53SVirupax Sadashivpetimath 	},
1088d6255529SLinus Walleij };
1089d6255529SLinus Walleij 
1090cca69b67SMattias Wallin static ssize_t show_chip_id(struct device *dev,
1091cca69b67SMattias Wallin 				struct device_attribute *attr, char *buf)
1092cca69b67SMattias Wallin {
1093cca69b67SMattias Wallin 	struct ab8500 *ab8500;
1094cca69b67SMattias Wallin 
1095cca69b67SMattias Wallin 	ab8500 = dev_get_drvdata(dev);
1096cca69b67SMattias Wallin 	return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
1097cca69b67SMattias Wallin }
1098cca69b67SMattias Wallin 
1099e5c238c3SMattias Wallin /*
1100e5c238c3SMattias Wallin  * ab8500 has switched off due to (SWITCH_OFF_STATUS):
1101e5c238c3SMattias Wallin  * 0x01 Swoff bit programming
1102e5c238c3SMattias Wallin  * 0x02 Thermal protection activation
1103e5c238c3SMattias Wallin  * 0x04 Vbat lower then BattOk falling threshold
1104e5c238c3SMattias Wallin  * 0x08 Watchdog expired
1105e5c238c3SMattias Wallin  * 0x10 Non presence of 32kHz clock
1106e5c238c3SMattias Wallin  * 0x20 Battery level lower than power on reset threshold
1107e5c238c3SMattias Wallin  * 0x40 Power on key 1 pressed longer than 10 seconds
1108e5c238c3SMattias Wallin  * 0x80 DB8500 thermal shutdown
1109e5c238c3SMattias Wallin  */
1110e5c238c3SMattias Wallin static ssize_t show_switch_off_status(struct device *dev,
1111e5c238c3SMattias Wallin 				struct device_attribute *attr, char *buf)
1112e5c238c3SMattias Wallin {
1113e5c238c3SMattias Wallin 	int ret;
1114e5c238c3SMattias Wallin 	u8 value;
1115e5c238c3SMattias Wallin 	struct ab8500 *ab8500;
1116e5c238c3SMattias Wallin 
1117e5c238c3SMattias Wallin 	ab8500 = dev_get_drvdata(dev);
1118e5c238c3SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_RTC,
1119e5c238c3SMattias Wallin 		AB8500_SWITCH_OFF_STATUS, &value);
1120e5c238c3SMattias Wallin 	if (ret < 0)
1121e5c238c3SMattias Wallin 		return ret;
1122e5c238c3SMattias Wallin 	return sprintf(buf, "%#x\n", value);
1123e5c238c3SMattias Wallin }
1124e5c238c3SMattias Wallin 
1125b4a31037SAndrew Lynn /*
1126b4a31037SAndrew Lynn  * ab8500 has turned on due to (TURN_ON_STATUS):
1127b4a31037SAndrew Lynn  * 0x01 PORnVbat
1128b4a31037SAndrew Lynn  * 0x02 PonKey1dbF
1129b4a31037SAndrew Lynn  * 0x04 PonKey2dbF
1130b4a31037SAndrew Lynn  * 0x08 RTCAlarm
1131b4a31037SAndrew Lynn  * 0x10 MainChDet
1132b4a31037SAndrew Lynn  * 0x20 VbusDet
1133b4a31037SAndrew Lynn  * 0x40 UsbIDDetect
1134b4a31037SAndrew Lynn  * 0x80 Reserved
1135b4a31037SAndrew Lynn  */
1136b4a31037SAndrew Lynn static ssize_t show_turn_on_status(struct device *dev,
1137b4a31037SAndrew Lynn 				struct device_attribute *attr, char *buf)
1138b4a31037SAndrew Lynn {
1139b4a31037SAndrew Lynn 	int ret;
1140b4a31037SAndrew Lynn 	u8 value;
1141b4a31037SAndrew Lynn 	struct ab8500 *ab8500;
1142b4a31037SAndrew Lynn 
1143b4a31037SAndrew Lynn 	ab8500 = dev_get_drvdata(dev);
1144b4a31037SAndrew Lynn 	ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
1145b4a31037SAndrew Lynn 		AB8500_TURN_ON_STATUS, &value);
1146b4a31037SAndrew Lynn 	if (ret < 0)
1147b4a31037SAndrew Lynn 		return ret;
1148b4a31037SAndrew Lynn 	return sprintf(buf, "%#x\n", value);
1149b4a31037SAndrew Lynn }
1150b4a31037SAndrew Lynn 
1151d6255529SLinus Walleij static ssize_t show_ab9540_dbbrstn(struct device *dev,
1152d6255529SLinus Walleij 				struct device_attribute *attr, char *buf)
1153d6255529SLinus Walleij {
1154d6255529SLinus Walleij 	struct ab8500 *ab8500;
1155d6255529SLinus Walleij 	int ret;
1156d6255529SLinus Walleij 	u8 value;
1157d6255529SLinus Walleij 
1158d6255529SLinus Walleij 	ab8500 = dev_get_drvdata(dev);
1159d6255529SLinus Walleij 
1160d6255529SLinus Walleij 	ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2,
1161d6255529SLinus Walleij 		AB9540_MODEM_CTRL2_REG, &value);
1162d6255529SLinus Walleij 	if (ret < 0)
1163d6255529SLinus Walleij 		return ret;
1164d6255529SLinus Walleij 
1165d6255529SLinus Walleij 	return sprintf(buf, "%d\n",
1166d6255529SLinus Walleij 			(value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0);
1167d6255529SLinus Walleij }
1168d6255529SLinus Walleij 
1169d6255529SLinus Walleij static ssize_t store_ab9540_dbbrstn(struct device *dev,
1170d6255529SLinus Walleij 	struct device_attribute *attr, const char *buf, size_t count)
1171d6255529SLinus Walleij {
1172d6255529SLinus Walleij 	struct ab8500 *ab8500;
1173d6255529SLinus Walleij 	int ret = count;
1174d6255529SLinus Walleij 	int err;
1175d6255529SLinus Walleij 	u8 bitvalues;
1176d6255529SLinus Walleij 
1177d6255529SLinus Walleij 	ab8500 = dev_get_drvdata(dev);
1178d6255529SLinus Walleij 
1179d6255529SLinus Walleij 	if (count > 0) {
1180d6255529SLinus Walleij 		switch (buf[0]) {
1181d6255529SLinus Walleij 		case '0':
1182d6255529SLinus Walleij 			bitvalues = 0;
1183d6255529SLinus Walleij 			break;
1184d6255529SLinus Walleij 		case '1':
1185d6255529SLinus Walleij 			bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT;
1186d6255529SLinus Walleij 			break;
1187d6255529SLinus Walleij 		default:
1188d6255529SLinus Walleij 			goto exit;
1189d6255529SLinus Walleij 		}
1190d6255529SLinus Walleij 
1191d6255529SLinus Walleij 		err = mask_and_set_register_interruptible(ab8500,
1192d6255529SLinus Walleij 			AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG,
1193d6255529SLinus Walleij 			AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues);
1194d6255529SLinus Walleij 		if (err)
1195d6255529SLinus Walleij 			dev_info(ab8500->dev,
1196d6255529SLinus Walleij 				"Failed to set DBBRSTN %c, err %#x\n",
1197d6255529SLinus Walleij 				buf[0], err);
1198d6255529SLinus Walleij 	}
1199d6255529SLinus Walleij 
1200d6255529SLinus Walleij exit:
1201d6255529SLinus Walleij 	return ret;
1202d6255529SLinus Walleij }
1203d6255529SLinus Walleij 
1204cca69b67SMattias Wallin static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
1205e5c238c3SMattias Wallin static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
1206b4a31037SAndrew Lynn static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
1207d6255529SLinus Walleij static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR,
1208d6255529SLinus Walleij 			show_ab9540_dbbrstn, store_ab9540_dbbrstn);
1209cca69b67SMattias Wallin 
1210cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = {
1211cca69b67SMattias Wallin 	&dev_attr_chip_id.attr,
1212e5c238c3SMattias Wallin 	&dev_attr_switch_off_status.attr,
1213b4a31037SAndrew Lynn 	&dev_attr_turn_on_status.attr,
1214cca69b67SMattias Wallin 	NULL,
1215cca69b67SMattias Wallin };
1216cca69b67SMattias Wallin 
1217d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = {
1218d6255529SLinus Walleij 	&dev_attr_chip_id.attr,
1219d6255529SLinus Walleij 	&dev_attr_switch_off_status.attr,
1220d6255529SLinus Walleij 	&dev_attr_turn_on_status.attr,
1221d6255529SLinus Walleij 	&dev_attr_dbbrstn.attr,
1222d6255529SLinus Walleij 	NULL,
1223d6255529SLinus Walleij };
1224d6255529SLinus Walleij 
1225cca69b67SMattias Wallin static struct attribute_group ab8500_attr_group = {
1226cca69b67SMattias Wallin 	.attrs	= ab8500_sysfs_entries,
1227cca69b67SMattias Wallin };
1228cca69b67SMattias Wallin 
1229d6255529SLinus Walleij static struct attribute_group ab9540_attr_group = {
1230d6255529SLinus Walleij 	.attrs	= ab9540_sysfs_entries,
1231d6255529SLinus Walleij };
1232d6255529SLinus Walleij 
12336bc4a568SLee Jones static const struct of_device_id ab8500_match[] = {
12346bc4a568SLee Jones 	{
12356bc4a568SLee Jones 		.compatible = "stericsson,ab8500",
12366bc4a568SLee Jones 		.data = (void *)AB8500_VERSION_AB8500,
12376bc4a568SLee Jones 	},
12386bc4a568SLee Jones 	{},
12396bc4a568SLee Jones };
12406bc4a568SLee Jones 
1241d28f1db8SLee Jones static int __devinit ab8500_probe(struct platform_device *pdev)
124262579266SRabin Vincent {
1243d28f1db8SLee Jones 	struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev);
1244d28f1db8SLee Jones 	const struct platform_device_id *platid = platform_get_device_id(pdev);
12456bc4a568SLee Jones 	enum ab8500_version version = AB8500_VERSION_UNDEFINED;
12466bc4a568SLee Jones 	struct device_node *np = pdev->dev.of_node;
1247d28f1db8SLee Jones 	struct ab8500 *ab8500;
1248d28f1db8SLee Jones 	struct resource *resource;
124962579266SRabin Vincent 	int ret;
125062579266SRabin Vincent 	int i;
125147c16975SMattias Wallin 	u8 value;
125262579266SRabin Vincent 
1253d28f1db8SLee Jones 	ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL);
1254d28f1db8SLee Jones 	if (!ab8500)
1255d28f1db8SLee Jones 		return -ENOMEM;
1256d28f1db8SLee Jones 
125762579266SRabin Vincent 	if (plat)
125862579266SRabin Vincent 		ab8500->irq_base = plat->irq_base;
125962579266SRabin Vincent 
1260d28f1db8SLee Jones 	ab8500->dev = &pdev->dev;
1261d28f1db8SLee Jones 
1262d28f1db8SLee Jones 	resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1263d28f1db8SLee Jones 	if (!resource) {
1264d28f1db8SLee Jones 		ret = -ENODEV;
1265d28f1db8SLee Jones 		goto out_free_ab8500;
1266d28f1db8SLee Jones 	}
1267d28f1db8SLee Jones 
1268d28f1db8SLee Jones 	ab8500->irq = resource->start;
1269d28f1db8SLee Jones 
1270*822672a7SLee Jones 	ab8500->read = ab8500_prcmu_read;
1271*822672a7SLee Jones 	ab8500->write = ab8500_prcmu_write;
1272*822672a7SLee Jones 	ab8500->write_masked = ab8500_prcmu_write_masked;
1273d28f1db8SLee Jones 
127462579266SRabin Vincent 	mutex_init(&ab8500->lock);
127562579266SRabin Vincent 	mutex_init(&ab8500->irq_lock);
1276112a80d2SJonas Aaberg 	atomic_set(&ab8500->transfer_ongoing, 0);
127762579266SRabin Vincent 
1278d28f1db8SLee Jones 	platform_set_drvdata(pdev, ab8500);
1279d28f1db8SLee Jones 
12806bc4a568SLee Jones 	if (platid)
12816bc4a568SLee Jones 		version = platid->driver_data;
12826bc4a568SLee Jones 	else if (np)
12836bc4a568SLee Jones 		version = (unsigned int)
12846bc4a568SLee Jones 			of_match_device(ab8500_match, &pdev->dev)->data;
12856bc4a568SLee Jones 
12860f620837SLinus Walleij 	if (version != AB8500_VERSION_UNDEFINED)
12870f620837SLinus Walleij 		ab8500->version = version;
12880f620837SLinus Walleij 	else {
12890f620837SLinus Walleij 		ret = get_register_interruptible(ab8500, AB8500_MISC,
12900f620837SLinus Walleij 			AB8500_IC_NAME_REG, &value);
12910f620837SLinus Walleij 		if (ret < 0)
1292d28f1db8SLee Jones 			goto out_free_ab8500;
12930f620837SLinus Walleij 
12940f620837SLinus Walleij 		ab8500->version = value;
12950f620837SLinus Walleij 	}
12960f620837SLinus Walleij 
129747c16975SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_MISC,
129847c16975SMattias Wallin 		AB8500_REV_REG, &value);
129962579266SRabin Vincent 	if (ret < 0)
1300d28f1db8SLee Jones 		goto out_free_ab8500;
130162579266SRabin Vincent 
130247c16975SMattias Wallin 	ab8500->chip_id = value;
130362579266SRabin Vincent 
13040f620837SLinus Walleij 	dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n",
13050f620837SLinus Walleij 			ab8500_version_str[ab8500->version],
13060f620837SLinus Walleij 			ab8500->chip_id >> 4,
13070f620837SLinus Walleij 			ab8500->chip_id & 0x0F);
13080f620837SLinus Walleij 
1309d6255529SLinus Walleij 	/* Configure AB8500 or AB9540 IRQ */
1310a982362cSBengt Jonsson 	if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
1311d6255529SLinus Walleij 		ab8500->mask_size = AB9540_NUM_IRQ_REGS;
1312d6255529SLinus Walleij 		ab8500->irq_reg_offset = ab9540_irq_regoffset;
1313d6255529SLinus Walleij 	} else {
13142ced445eSLinus Walleij 		ab8500->mask_size = AB8500_NUM_IRQ_REGS;
13152ced445eSLinus Walleij 		ab8500->irq_reg_offset = ab8500_irq_regoffset;
1316d6255529SLinus Walleij 	}
13172ced445eSLinus Walleij 	ab8500->mask = kzalloc(ab8500->mask_size, GFP_KERNEL);
13182ced445eSLinus Walleij 	if (!ab8500->mask)
13192ced445eSLinus Walleij 		return -ENOMEM;
13202ced445eSLinus Walleij 	ab8500->oldmask = kzalloc(ab8500->mask_size, GFP_KERNEL);
13212ced445eSLinus Walleij 	if (!ab8500->oldmask) {
13222ced445eSLinus Walleij 		ret = -ENOMEM;
13232ced445eSLinus Walleij 		goto out_freemask;
13242ced445eSLinus Walleij 	}
1325e5c238c3SMattias Wallin 	/*
1326e5c238c3SMattias Wallin 	 * ab8500 has switched off due to (SWITCH_OFF_STATUS):
1327e5c238c3SMattias Wallin 	 * 0x01 Swoff bit programming
1328e5c238c3SMattias Wallin 	 * 0x02 Thermal protection activation
1329e5c238c3SMattias Wallin 	 * 0x04 Vbat lower then BattOk falling threshold
1330e5c238c3SMattias Wallin 	 * 0x08 Watchdog expired
1331e5c238c3SMattias Wallin 	 * 0x10 Non presence of 32kHz clock
1332e5c238c3SMattias Wallin 	 * 0x20 Battery level lower than power on reset threshold
1333e5c238c3SMattias Wallin 	 * 0x40 Power on key 1 pressed longer than 10 seconds
1334e5c238c3SMattias Wallin 	 * 0x80 DB8500 thermal shutdown
1335e5c238c3SMattias Wallin 	 */
1336e5c238c3SMattias Wallin 
1337e5c238c3SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_RTC,
1338e5c238c3SMattias Wallin 		AB8500_SWITCH_OFF_STATUS, &value);
1339e5c238c3SMattias Wallin 	if (ret < 0)
1340e5c238c3SMattias Wallin 		return ret;
134106e589efSLee Jones 	dev_info(ab8500->dev, "switch off status: %#x\n", value);
1342e5c238c3SMattias Wallin 
134362579266SRabin Vincent 	if (plat && plat->init)
134462579266SRabin Vincent 		plat->init(ab8500);
134562579266SRabin Vincent 
134662579266SRabin Vincent 	/* Clear and mask all interrupts */
13472ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++) {
13480f620837SLinus Walleij 		/*
13490f620837SLinus Walleij 		 * Interrupt register 12 doesn't exist prior to AB8500 version
13500f620837SLinus Walleij 		 * 2.0
13510f620837SLinus Walleij 		 */
13520f620837SLinus Walleij 		if (ab8500->irq_reg_offset[i] == 11 &&
13530f620837SLinus Walleij 				is_ab8500_1p1_or_earlier(ab8500))
135492d50a41SMattias Wallin 			continue;
135562579266SRabin Vincent 
135647c16975SMattias Wallin 		get_register_interruptible(ab8500, AB8500_INTERRUPT,
13572ced445eSLinus Walleij 			AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
135892d50a41SMattias Wallin 			&value);
135947c16975SMattias Wallin 		set_register_interruptible(ab8500, AB8500_INTERRUPT,
13602ced445eSLinus Walleij 			AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff);
136162579266SRabin Vincent 	}
136262579266SRabin Vincent 
136347c16975SMattias Wallin 	ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
136447c16975SMattias Wallin 	if (ret)
13652ced445eSLinus Walleij 		goto out_freeoldmask;
136647c16975SMattias Wallin 
13672ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++)
136862579266SRabin Vincent 		ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
136962579266SRabin Vincent 
137006e589efSLee Jones 	ret = ab8500_irq_init(ab8500, np);
137162579266SRabin Vincent 	if (ret)
13722ced445eSLinus Walleij 		goto out_freeoldmask;
137362579266SRabin Vincent 
13747ccfe9b1SMichel JAOUEN 	/*  Activate this feature only in ab9540 */
13757ccfe9b1SMichel JAOUEN 	/*  till tests are done on ab8500 1p2 or later*/
137606e589efSLee Jones 	if (is_ab9540(ab8500)) {
13777ccfe9b1SMichel JAOUEN 		ret = request_threaded_irq(ab8500->irq, NULL,
13787ccfe9b1SMichel JAOUEN 					ab8500_hierarchical_irq,
13797ccfe9b1SMichel JAOUEN 					IRQF_ONESHOT | IRQF_NO_SUSPEND,
13807ccfe9b1SMichel JAOUEN 					"ab8500", ab8500);
138106e589efSLee Jones 	}
138206e589efSLee Jones 	else {
13837ccfe9b1SMichel JAOUEN 		ret = request_threaded_irq(ab8500->irq, NULL,
13847ccfe9b1SMichel JAOUEN 					ab8500_irq,
13854f079985SMattias Wallin 					IRQF_ONESHOT | IRQF_NO_SUSPEND,
13864f079985SMattias Wallin 					"ab8500", ab8500);
138762579266SRabin Vincent 		if (ret)
138806e589efSLee Jones 			goto out_freeoldmask;
138962579266SRabin Vincent 	}
139062579266SRabin Vincent 
13916bc4a568SLee Jones 	if (!np) {
1392d6255529SLinus Walleij 		ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
1393d6255529SLinus Walleij 				ARRAY_SIZE(abx500_common_devs), NULL,
1394d6255529SLinus Walleij 				ab8500->irq_base);
1395d6255529SLinus Walleij 
1396d6255529SLinus Walleij 		if (ret)
1397d6255529SLinus Walleij 			goto out_freeirq;
1398d6255529SLinus Walleij 
1399d6255529SLinus Walleij 		if (is_ab9540(ab8500))
1400d6255529SLinus Walleij 			ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
1401d6255529SLinus Walleij 					ARRAY_SIZE(ab9540_devs), NULL,
1402d6255529SLinus Walleij 					ab8500->irq_base);
1403d6255529SLinus Walleij 		else
1404549931f9SSundar R Iyer 			ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
140544f72e53SVirupax Sadashivpetimath 					ARRAY_SIZE(ab8500_devs), NULL,
140662579266SRabin Vincent 					ab8500->irq_base);
14076bc4a568SLee Jones 		if (ret)
14086bc4a568SLee Jones 			goto out_freeirq;
140944f72e53SVirupax Sadashivpetimath 
141044f72e53SVirupax Sadashivpetimath 		if (is_ab9540(ab8500) || is_ab8505(ab8500))
141144f72e53SVirupax Sadashivpetimath 			ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs,
141244f72e53SVirupax Sadashivpetimath 					ARRAY_SIZE(ab9540_ab8505_devs), NULL,
141344f72e53SVirupax Sadashivpetimath 					ab8500->irq_base);
141462579266SRabin Vincent 		if (ret)
141562579266SRabin Vincent 			goto out_freeirq;
14166bc4a568SLee Jones 	}
141762579266SRabin Vincent 
14186ef9418cSRickard Andersson 	if (!no_bm) {
14196ef9418cSRickard Andersson 		/* Add battery management devices */
14206ef9418cSRickard Andersson 		ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
14216ef9418cSRickard Andersson 				      ARRAY_SIZE(ab8500_bm_devs), NULL,
14226ef9418cSRickard Andersson 				      ab8500->irq_base);
14236ef9418cSRickard Andersson 		if (ret)
14246ef9418cSRickard Andersson 			dev_err(ab8500->dev, "error adding bm devices\n");
14256ef9418cSRickard Andersson 	}
14266ef9418cSRickard Andersson 
1427d6255529SLinus Walleij 	if (is_ab9540(ab8500))
1428d6255529SLinus Walleij 		ret = sysfs_create_group(&ab8500->dev->kobj,
1429d6255529SLinus Walleij 					&ab9540_attr_group);
1430d6255529SLinus Walleij 	else
1431d6255529SLinus Walleij 		ret = sysfs_create_group(&ab8500->dev->kobj,
1432d6255529SLinus Walleij 					&ab8500_attr_group);
1433cca69b67SMattias Wallin 	if (ret)
1434cca69b67SMattias Wallin 		dev_err(ab8500->dev, "error creating sysfs entries\n");
143506e589efSLee Jones 
143662579266SRabin Vincent 	return ret;
143762579266SRabin Vincent 
143862579266SRabin Vincent out_freeirq:
143962579266SRabin Vincent 	free_irq(ab8500->irq, ab8500);
14402ced445eSLinus Walleij out_freeoldmask:
14412ced445eSLinus Walleij 	kfree(ab8500->oldmask);
14422ced445eSLinus Walleij out_freemask:
14432ced445eSLinus Walleij 	kfree(ab8500->mask);
1444d28f1db8SLee Jones out_free_ab8500:
1445d28f1db8SLee Jones 	kfree(ab8500);
14466d95b7fdSLinus Walleij 
144762579266SRabin Vincent 	return ret;
144862579266SRabin Vincent }
144962579266SRabin Vincent 
1450d28f1db8SLee Jones static int __devexit ab8500_remove(struct platform_device *pdev)
145162579266SRabin Vincent {
1452d28f1db8SLee Jones 	struct ab8500 *ab8500 = platform_get_drvdata(pdev);
1453d28f1db8SLee Jones 
1454d6255529SLinus Walleij 	if (is_ab9540(ab8500))
1455d6255529SLinus Walleij 		sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
1456d6255529SLinus Walleij 	else
1457cca69b67SMattias Wallin 		sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
145806e589efSLee Jones 
145962579266SRabin Vincent 	mfd_remove_devices(ab8500->dev);
146062579266SRabin Vincent 	free_irq(ab8500->irq, ab8500);
146106e589efSLee Jones 
14622ced445eSLinus Walleij 	kfree(ab8500->oldmask);
14632ced445eSLinus Walleij 	kfree(ab8500->mask);
1464d28f1db8SLee Jones 	kfree(ab8500);
146562579266SRabin Vincent 
146662579266SRabin Vincent 	return 0;
146762579266SRabin Vincent }
146862579266SRabin Vincent 
1469d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = {
1470d28f1db8SLee Jones 	{ "ab8500-core", AB8500_VERSION_AB8500 },
1471d28f1db8SLee Jones 	{ "ab8505-i2c", AB8500_VERSION_AB8505 },
1472d28f1db8SLee Jones 	{ "ab9540-i2c", AB8500_VERSION_AB9540 },
1473d28f1db8SLee Jones 	{ "ab8540-i2c", AB8500_VERSION_AB8540 },
1474d28f1db8SLee Jones 	{ }
1475d28f1db8SLee Jones };
1476d28f1db8SLee Jones 
1477d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = {
1478d28f1db8SLee Jones 	.driver = {
1479d28f1db8SLee Jones 		.name = "ab8500-core",
1480d28f1db8SLee Jones 		.owner = THIS_MODULE,
14816bc4a568SLee Jones 		.of_match_table = ab8500_match,
1482d28f1db8SLee Jones 	},
1483d28f1db8SLee Jones 	.probe	= ab8500_probe,
1484d28f1db8SLee Jones 	.remove	= __devexit_p(ab8500_remove),
1485d28f1db8SLee Jones 	.id_table = ab8500_id,
1486d28f1db8SLee Jones };
1487d28f1db8SLee Jones 
1488d28f1db8SLee Jones static int __init ab8500_core_init(void)
1489d28f1db8SLee Jones {
1490d28f1db8SLee Jones 	return platform_driver_register(&ab8500_core_driver);
1491d28f1db8SLee Jones }
1492d28f1db8SLee Jones 
1493d28f1db8SLee Jones static void __exit ab8500_core_exit(void)
1494d28f1db8SLee Jones {
1495d28f1db8SLee Jones 	platform_driver_unregister(&ab8500_core_driver);
1496d28f1db8SLee Jones }
1497d28f1db8SLee Jones arch_initcall(ab8500_core_init);
1498d28f1db8SLee Jones module_exit(ab8500_core_exit);
1499d28f1db8SLee Jones 
1500adceed62SMattias Wallin MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent");
150162579266SRabin Vincent MODULE_DESCRIPTION("AB8500 MFD core");
150262579266SRabin Vincent MODULE_LICENSE("GPL v2");
1503