xref: /openbmc/linux/drivers/mfd/ab8500-core.c (revision d28f1db8187dd1ddc1fa6f380ff0402cf8e4d44d)
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>
1462579266SRabin Vincent #include <linux/delay.h>
1562579266SRabin Vincent #include <linux/interrupt.h>
1662579266SRabin Vincent #include <linux/module.h>
1762579266SRabin Vincent #include <linux/platform_device.h>
1862579266SRabin Vincent #include <linux/mfd/core.h>
1947c16975SMattias Wallin #include <linux/mfd/abx500.h>
20ee66e653SLinus Walleij #include <linux/mfd/abx500/ab8500.h>
21*d28f1db8SLee Jones #include <linux/mfd/dbx500-prcmu.h>
22549931f9SSundar R Iyer #include <linux/regulator/ab8500.h>
2362579266SRabin Vincent 
2462579266SRabin Vincent /*
2562579266SRabin Vincent  * Interrupt register offsets
2662579266SRabin Vincent  * Bank : 0x0E
2762579266SRabin Vincent  */
2847c16975SMattias Wallin #define AB8500_IT_SOURCE1_REG		0x00
2947c16975SMattias Wallin #define AB8500_IT_SOURCE2_REG		0x01
3047c16975SMattias Wallin #define AB8500_IT_SOURCE3_REG		0x02
3147c16975SMattias Wallin #define AB8500_IT_SOURCE4_REG		0x03
3247c16975SMattias Wallin #define AB8500_IT_SOURCE5_REG		0x04
3347c16975SMattias Wallin #define AB8500_IT_SOURCE6_REG		0x05
3447c16975SMattias Wallin #define AB8500_IT_SOURCE7_REG		0x06
3547c16975SMattias Wallin #define AB8500_IT_SOURCE8_REG		0x07
36d6255529SLinus Walleij #define AB9540_IT_SOURCE13_REG		0x0C
3747c16975SMattias Wallin #define AB8500_IT_SOURCE19_REG		0x12
3847c16975SMattias Wallin #define AB8500_IT_SOURCE20_REG		0x13
3947c16975SMattias Wallin #define AB8500_IT_SOURCE21_REG		0x14
4047c16975SMattias Wallin #define AB8500_IT_SOURCE22_REG		0x15
4147c16975SMattias Wallin #define AB8500_IT_SOURCE23_REG		0x16
4247c16975SMattias Wallin #define AB8500_IT_SOURCE24_REG		0x17
4362579266SRabin Vincent 
4462579266SRabin Vincent /*
4562579266SRabin Vincent  * latch registers
4662579266SRabin Vincent  */
4747c16975SMattias Wallin #define AB8500_IT_LATCH1_REG		0x20
4847c16975SMattias Wallin #define AB8500_IT_LATCH2_REG		0x21
4947c16975SMattias Wallin #define AB8500_IT_LATCH3_REG		0x22
5047c16975SMattias Wallin #define AB8500_IT_LATCH4_REG		0x23
5147c16975SMattias Wallin #define AB8500_IT_LATCH5_REG		0x24
5247c16975SMattias Wallin #define AB8500_IT_LATCH6_REG		0x25
5347c16975SMattias Wallin #define AB8500_IT_LATCH7_REG		0x26
5447c16975SMattias Wallin #define AB8500_IT_LATCH8_REG		0x27
5547c16975SMattias Wallin #define AB8500_IT_LATCH9_REG		0x28
5647c16975SMattias Wallin #define AB8500_IT_LATCH10_REG		0x29
5792d50a41SMattias Wallin #define AB8500_IT_LATCH12_REG		0x2B
58d6255529SLinus Walleij #define AB9540_IT_LATCH13_REG		0x2C
5947c16975SMattias Wallin #define AB8500_IT_LATCH19_REG		0x32
6047c16975SMattias Wallin #define AB8500_IT_LATCH20_REG		0x33
6147c16975SMattias Wallin #define AB8500_IT_LATCH21_REG		0x34
6247c16975SMattias Wallin #define AB8500_IT_LATCH22_REG		0x35
6347c16975SMattias Wallin #define AB8500_IT_LATCH23_REG		0x36
6447c16975SMattias Wallin #define AB8500_IT_LATCH24_REG		0x37
6562579266SRabin Vincent 
6662579266SRabin Vincent /*
6762579266SRabin Vincent  * mask registers
6862579266SRabin Vincent  */
6962579266SRabin Vincent 
7047c16975SMattias Wallin #define AB8500_IT_MASK1_REG		0x40
7147c16975SMattias Wallin #define AB8500_IT_MASK2_REG		0x41
7247c16975SMattias Wallin #define AB8500_IT_MASK3_REG		0x42
7347c16975SMattias Wallin #define AB8500_IT_MASK4_REG		0x43
7447c16975SMattias Wallin #define AB8500_IT_MASK5_REG		0x44
7547c16975SMattias Wallin #define AB8500_IT_MASK6_REG		0x45
7647c16975SMattias Wallin #define AB8500_IT_MASK7_REG		0x46
7747c16975SMattias Wallin #define AB8500_IT_MASK8_REG		0x47
7847c16975SMattias Wallin #define AB8500_IT_MASK9_REG		0x48
7947c16975SMattias Wallin #define AB8500_IT_MASK10_REG		0x49
8047c16975SMattias Wallin #define AB8500_IT_MASK11_REG		0x4A
8147c16975SMattias Wallin #define AB8500_IT_MASK12_REG		0x4B
8247c16975SMattias Wallin #define AB8500_IT_MASK13_REG		0x4C
8347c16975SMattias Wallin #define AB8500_IT_MASK14_REG		0x4D
8447c16975SMattias Wallin #define AB8500_IT_MASK15_REG		0x4E
8547c16975SMattias Wallin #define AB8500_IT_MASK16_REG		0x4F
8647c16975SMattias Wallin #define AB8500_IT_MASK17_REG		0x50
8747c16975SMattias Wallin #define AB8500_IT_MASK18_REG		0x51
8847c16975SMattias Wallin #define AB8500_IT_MASK19_REG		0x52
8947c16975SMattias Wallin #define AB8500_IT_MASK20_REG		0x53
9047c16975SMattias Wallin #define AB8500_IT_MASK21_REG		0x54
9147c16975SMattias Wallin #define AB8500_IT_MASK22_REG		0x55
9247c16975SMattias Wallin #define AB8500_IT_MASK23_REG		0x56
9347c16975SMattias Wallin #define AB8500_IT_MASK24_REG		0x57
9462579266SRabin Vincent 
957ccfe9b1SMichel JAOUEN /*
967ccfe9b1SMichel JAOUEN  * latch hierarchy registers
977ccfe9b1SMichel JAOUEN  */
987ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER1_REG	0x60
997ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER2_REG	0x61
1007ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER3_REG	0x62
1017ccfe9b1SMichel JAOUEN 
1027ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER_NUM		3
1037ccfe9b1SMichel JAOUEN 
10447c16975SMattias Wallin #define AB8500_REV_REG			0x80
1050f620837SLinus Walleij #define AB8500_IC_NAME_REG		0x82
106e5c238c3SMattias Wallin #define AB8500_SWITCH_OFF_STATUS	0x00
10762579266SRabin Vincent 
108b4a31037SAndrew Lynn #define AB8500_TURN_ON_STATUS		0x00
109b4a31037SAndrew Lynn 
1106ef9418cSRickard Andersson static bool no_bm; /* No battery management */
1116ef9418cSRickard Andersson module_param(no_bm, bool, S_IRUGO);
1126ef9418cSRickard Andersson 
113d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_REG			0x23
114d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT	BIT(2)
115d6255529SLinus Walleij 
11662579266SRabin Vincent /*
11762579266SRabin Vincent  * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
1182ced445eSLinus Walleij  * numbers are indexed into this array with (num / 8). The interupts are
1192ced445eSLinus Walleij  * defined in linux/mfd/ab8500.h
12062579266SRabin Vincent  *
12162579266SRabin Vincent  * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
12262579266SRabin Vincent  * offset 0.
12362579266SRabin Vincent  */
1242ced445eSLinus Walleij /* AB8500 support */
12562579266SRabin Vincent static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
12692d50a41SMattias Wallin 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
12762579266SRabin Vincent };
12862579266SRabin Vincent 
129d6255529SLinus Walleij /* AB9540 support */
130d6255529SLinus Walleij static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
131d6255529SLinus Walleij 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24,
132d6255529SLinus Walleij };
133d6255529SLinus Walleij 
1340f620837SLinus Walleij static const char ab8500_version_str[][7] = {
1350f620837SLinus Walleij 	[AB8500_VERSION_AB8500] = "AB8500",
1360f620837SLinus Walleij 	[AB8500_VERSION_AB8505] = "AB8505",
1370f620837SLinus Walleij 	[AB8500_VERSION_AB9540] = "AB9540",
1380f620837SLinus Walleij 	[AB8500_VERSION_AB8540] = "AB8540",
1390f620837SLinus Walleij };
1400f620837SLinus Walleij 
141*d28f1db8SLee Jones static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
142*d28f1db8SLee Jones {
143*d28f1db8SLee Jones 	int ret;
144*d28f1db8SLee Jones 
145*d28f1db8SLee Jones 	ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
146*d28f1db8SLee Jones 	if (ret < 0)
147*d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
148*d28f1db8SLee Jones 	return ret;
149*d28f1db8SLee Jones }
150*d28f1db8SLee Jones 
151*d28f1db8SLee Jones static int ab8500_i2c_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
152*d28f1db8SLee Jones 	u8 data)
153*d28f1db8SLee Jones {
154*d28f1db8SLee Jones 	int ret;
155*d28f1db8SLee Jones 
156*d28f1db8SLee Jones 	ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data,
157*d28f1db8SLee Jones 		&mask, 1);
158*d28f1db8SLee Jones 	if (ret < 0)
159*d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
160*d28f1db8SLee Jones 	return ret;
161*d28f1db8SLee Jones }
162*d28f1db8SLee Jones 
163*d28f1db8SLee Jones static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
164*d28f1db8SLee Jones {
165*d28f1db8SLee Jones 	int ret;
166*d28f1db8SLee Jones 	u8 data;
167*d28f1db8SLee Jones 
168*d28f1db8SLee Jones 	ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
169*d28f1db8SLee Jones 	if (ret < 0) {
170*d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
171*d28f1db8SLee Jones 		return ret;
172*d28f1db8SLee Jones 	}
173*d28f1db8SLee Jones 	return (int)data;
174*d28f1db8SLee Jones }
175*d28f1db8SLee Jones 
17647c16975SMattias Wallin static int ab8500_get_chip_id(struct device *dev)
17747c16975SMattias Wallin {
1786bce7bf1SMattias Wallin 	struct ab8500 *ab8500;
1796bce7bf1SMattias Wallin 
1806bce7bf1SMattias Wallin 	if (!dev)
1816bce7bf1SMattias Wallin 		return -EINVAL;
1826bce7bf1SMattias Wallin 	ab8500 = dev_get_drvdata(dev->parent);
1836bce7bf1SMattias Wallin 	return ab8500 ? (int)ab8500->chip_id : -EINVAL;
18447c16975SMattias Wallin }
18547c16975SMattias Wallin 
18647c16975SMattias Wallin static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
18747c16975SMattias Wallin 	u8 reg, u8 data)
18862579266SRabin Vincent {
18962579266SRabin Vincent 	int ret;
19047c16975SMattias Wallin 	/*
19147c16975SMattias Wallin 	 * Put the u8 bank and u8 register together into a an u16.
19247c16975SMattias Wallin 	 * The bank on higher 8 bits and register in lower 8 bits.
19347c16975SMattias Wallin 	 * */
19447c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
19562579266SRabin Vincent 
19662579266SRabin Vincent 	dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
19762579266SRabin Vincent 
198392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
19947c16975SMattias Wallin 
20047c16975SMattias Wallin 	ret = ab8500->write(ab8500, addr, data);
20147c16975SMattias Wallin 	if (ret < 0)
20247c16975SMattias Wallin 		dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
20347c16975SMattias Wallin 			addr, ret);
20447c16975SMattias Wallin 	mutex_unlock(&ab8500->lock);
20547c16975SMattias Wallin 
20647c16975SMattias Wallin 	return ret;
20747c16975SMattias Wallin }
20847c16975SMattias Wallin 
20947c16975SMattias Wallin static int ab8500_set_register(struct device *dev, u8 bank,
21047c16975SMattias Wallin 	u8 reg, u8 value)
21147c16975SMattias Wallin {
212112a80d2SJonas Aaberg 	int ret;
21347c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
21447c16975SMattias Wallin 
215112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
216112a80d2SJonas Aaberg 	ret = set_register_interruptible(ab8500, bank, reg, value);
217112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
218112a80d2SJonas Aaberg 	return ret;
21947c16975SMattias Wallin }
22047c16975SMattias Wallin 
22147c16975SMattias Wallin static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
22247c16975SMattias Wallin 	u8 reg, u8 *value)
22347c16975SMattias Wallin {
22447c16975SMattias Wallin 	int ret;
22547c16975SMattias Wallin 	/* put the u8 bank and u8 reg together into a an u16.
22647c16975SMattias Wallin 	 * bank on higher 8 bits and reg in lower */
22747c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
22847c16975SMattias Wallin 
229392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
23047c16975SMattias Wallin 
23147c16975SMattias Wallin 	ret = ab8500->read(ab8500, addr);
23247c16975SMattias Wallin 	if (ret < 0)
23347c16975SMattias Wallin 		dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
23447c16975SMattias Wallin 			addr, ret);
23547c16975SMattias Wallin 	else
23647c16975SMattias Wallin 		*value = ret;
23747c16975SMattias Wallin 
23847c16975SMattias Wallin 	mutex_unlock(&ab8500->lock);
23947c16975SMattias Wallin 	dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret);
24047c16975SMattias Wallin 
24147c16975SMattias Wallin 	return ret;
24247c16975SMattias Wallin }
24347c16975SMattias Wallin 
24447c16975SMattias Wallin static int ab8500_get_register(struct device *dev, u8 bank,
24547c16975SMattias Wallin 	u8 reg, u8 *value)
24647c16975SMattias Wallin {
247112a80d2SJonas Aaberg 	int ret;
24847c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
24947c16975SMattias Wallin 
250112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
251112a80d2SJonas Aaberg 	ret = get_register_interruptible(ab8500, bank, reg, value);
252112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
253112a80d2SJonas Aaberg 	return ret;
25447c16975SMattias Wallin }
25547c16975SMattias Wallin 
25647c16975SMattias Wallin static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
25747c16975SMattias Wallin 	u8 reg, u8 bitmask, u8 bitvalues)
25847c16975SMattias Wallin {
25947c16975SMattias Wallin 	int ret;
26047c16975SMattias Wallin 	/* put the u8 bank and u8 reg together into a an u16.
26147c16975SMattias Wallin 	 * bank on higher 8 bits and reg in lower */
26247c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
26347c16975SMattias Wallin 
264392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
26547c16975SMattias Wallin 
266bc628fd1SMattias Nilsson 	if (ab8500->write_masked == NULL) {
267bc628fd1SMattias Nilsson 		u8 data;
268bc628fd1SMattias Nilsson 
26947c16975SMattias Wallin 		ret = ab8500->read(ab8500, addr);
27047c16975SMattias Wallin 		if (ret < 0) {
27147c16975SMattias Wallin 			dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
27247c16975SMattias Wallin 				addr, ret);
27347c16975SMattias Wallin 			goto out;
27447c16975SMattias Wallin 		}
27547c16975SMattias Wallin 
27647c16975SMattias Wallin 		data = (u8)ret;
27747c16975SMattias Wallin 		data = (~bitmask & data) | (bitmask & bitvalues);
27847c16975SMattias Wallin 
27962579266SRabin Vincent 		ret = ab8500->write(ab8500, addr, data);
28062579266SRabin Vincent 		if (ret < 0)
28162579266SRabin Vincent 			dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
28262579266SRabin Vincent 				addr, ret);
28362579266SRabin Vincent 
284bc628fd1SMattias Nilsson 		dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr,
285bc628fd1SMattias Nilsson 			data);
286bc628fd1SMattias Nilsson 		goto out;
287bc628fd1SMattias Nilsson 	}
288bc628fd1SMattias Nilsson 	ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues);
289bc628fd1SMattias Nilsson 	if (ret < 0)
290bc628fd1SMattias Nilsson 		dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr,
291bc628fd1SMattias Nilsson 			ret);
29262579266SRabin Vincent out:
29362579266SRabin Vincent 	mutex_unlock(&ab8500->lock);
29462579266SRabin Vincent 	return ret;
29562579266SRabin Vincent }
29647c16975SMattias Wallin 
29747c16975SMattias Wallin static int ab8500_mask_and_set_register(struct device *dev,
29847c16975SMattias Wallin 	u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
29947c16975SMattias Wallin {
300112a80d2SJonas Aaberg 	int ret;
30147c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
30247c16975SMattias Wallin 
303112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
304112a80d2SJonas Aaberg 	ret= mask_and_set_register_interruptible(ab8500, bank, reg,
30547c16975SMattias Wallin 						 bitmask, bitvalues);
306112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
307112a80d2SJonas Aaberg 	return ret;
30847c16975SMattias Wallin }
30947c16975SMattias Wallin 
31047c16975SMattias Wallin static struct abx500_ops ab8500_ops = {
31147c16975SMattias Wallin 	.get_chip_id = ab8500_get_chip_id,
31247c16975SMattias Wallin 	.get_register = ab8500_get_register,
31347c16975SMattias Wallin 	.set_register = ab8500_set_register,
31447c16975SMattias Wallin 	.get_register_page = NULL,
31547c16975SMattias Wallin 	.set_register_page = NULL,
31647c16975SMattias Wallin 	.mask_and_set_register = ab8500_mask_and_set_register,
31747c16975SMattias Wallin 	.event_registers_startup_state_get = NULL,
31847c16975SMattias Wallin 	.startup_irq_enabled = NULL,
31947c16975SMattias Wallin };
32062579266SRabin Vincent 
3219505a0a0SMark Brown static void ab8500_irq_lock(struct irq_data *data)
32262579266SRabin Vincent {
3239505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
32462579266SRabin Vincent 
32562579266SRabin Vincent 	mutex_lock(&ab8500->irq_lock);
326112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
32762579266SRabin Vincent }
32862579266SRabin Vincent 
3299505a0a0SMark Brown static void ab8500_irq_sync_unlock(struct irq_data *data)
33062579266SRabin Vincent {
3319505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
33262579266SRabin Vincent 	int i;
33362579266SRabin Vincent 
3342ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++) {
33562579266SRabin Vincent 		u8 old = ab8500->oldmask[i];
33662579266SRabin Vincent 		u8 new = ab8500->mask[i];
33762579266SRabin Vincent 		int reg;
33862579266SRabin Vincent 
33962579266SRabin Vincent 		if (new == old)
34062579266SRabin Vincent 			continue;
34162579266SRabin Vincent 
3420f620837SLinus Walleij 		/*
3430f620837SLinus Walleij 		 * Interrupt register 12 doesn't exist prior to AB8500 version
3440f620837SLinus Walleij 		 * 2.0
3450f620837SLinus Walleij 		 */
3460f620837SLinus Walleij 		if (ab8500->irq_reg_offset[i] == 11 &&
3470f620837SLinus Walleij 			is_ab8500_1p1_or_earlier(ab8500))
34892d50a41SMattias Wallin 			continue;
34992d50a41SMattias Wallin 
35062579266SRabin Vincent 		ab8500->oldmask[i] = new;
35162579266SRabin Vincent 
3522ced445eSLinus Walleij 		reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
35347c16975SMattias Wallin 		set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
35462579266SRabin Vincent 	}
355112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
35662579266SRabin Vincent 	mutex_unlock(&ab8500->irq_lock);
35762579266SRabin Vincent }
35862579266SRabin Vincent 
3599505a0a0SMark Brown static void ab8500_irq_mask(struct irq_data *data)
36062579266SRabin Vincent {
3619505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
3629505a0a0SMark Brown 	int offset = data->irq - ab8500->irq_base;
36362579266SRabin Vincent 	int index = offset / 8;
36462579266SRabin Vincent 	int mask = 1 << (offset % 8);
36562579266SRabin Vincent 
36662579266SRabin Vincent 	ab8500->mask[index] |= mask;
36762579266SRabin Vincent }
36862579266SRabin Vincent 
3699505a0a0SMark Brown static void ab8500_irq_unmask(struct irq_data *data)
37062579266SRabin Vincent {
3719505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
3729505a0a0SMark Brown 	int offset = data->irq - ab8500->irq_base;
37362579266SRabin Vincent 	int index = offset / 8;
37462579266SRabin Vincent 	int mask = 1 << (offset % 8);
37562579266SRabin Vincent 
37662579266SRabin Vincent 	ab8500->mask[index] &= ~mask;
37762579266SRabin Vincent }
37862579266SRabin Vincent 
37962579266SRabin Vincent static struct irq_chip ab8500_irq_chip = {
38062579266SRabin Vincent 	.name			= "ab8500",
3819505a0a0SMark Brown 	.irq_bus_lock		= ab8500_irq_lock,
3829505a0a0SMark Brown 	.irq_bus_sync_unlock	= ab8500_irq_sync_unlock,
3839505a0a0SMark Brown 	.irq_mask		= ab8500_irq_mask,
384e6f9306eSVirupax Sadashivpetimath 	.irq_disable		= ab8500_irq_mask,
3859505a0a0SMark Brown 	.irq_unmask		= ab8500_irq_unmask,
38662579266SRabin Vincent };
38762579266SRabin Vincent 
3887ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
3897ccfe9b1SMichel JAOUEN 					int latch_offset, u8 latch_val)
3907ccfe9b1SMichel JAOUEN {
3917ccfe9b1SMichel JAOUEN 	int int_bit = __ffs(latch_val);
3927ccfe9b1SMichel JAOUEN 	int line, i;
3937ccfe9b1SMichel JAOUEN 
3947ccfe9b1SMichel JAOUEN 	do {
3957ccfe9b1SMichel JAOUEN 		int_bit = __ffs(latch_val);
3967ccfe9b1SMichel JAOUEN 
3977ccfe9b1SMichel JAOUEN 		for (i = 0; i < ab8500->mask_size; i++)
3987ccfe9b1SMichel JAOUEN 			if (ab8500->irq_reg_offset[i] == latch_offset)
3997ccfe9b1SMichel JAOUEN 				break;
4007ccfe9b1SMichel JAOUEN 
4017ccfe9b1SMichel JAOUEN 		if (i >= ab8500->mask_size) {
4027ccfe9b1SMichel JAOUEN 			dev_err(ab8500->dev, "Register offset 0x%2x not declared\n",
4037ccfe9b1SMichel JAOUEN 					latch_offset);
4047ccfe9b1SMichel JAOUEN 			return -ENXIO;
4057ccfe9b1SMichel JAOUEN 		}
4067ccfe9b1SMichel JAOUEN 
4077ccfe9b1SMichel JAOUEN 		line = (i << 3) + int_bit;
4087ccfe9b1SMichel JAOUEN 		latch_val &= ~(1 << int_bit);
4097ccfe9b1SMichel JAOUEN 
4107ccfe9b1SMichel JAOUEN 		handle_nested_irq(ab8500->irq_base + line);
4117ccfe9b1SMichel JAOUEN 	} while (latch_val);
4127ccfe9b1SMichel JAOUEN 
4137ccfe9b1SMichel JAOUEN 	return 0;
4147ccfe9b1SMichel JAOUEN }
4157ccfe9b1SMichel JAOUEN 
4167ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500,
4177ccfe9b1SMichel JAOUEN 					int hier_offset, u8 hier_val)
4187ccfe9b1SMichel JAOUEN {
4197ccfe9b1SMichel JAOUEN 	int latch_bit, status;
4207ccfe9b1SMichel JAOUEN 	u8 latch_offset, latch_val;
4217ccfe9b1SMichel JAOUEN 
4227ccfe9b1SMichel JAOUEN 	do {
4237ccfe9b1SMichel JAOUEN 		latch_bit = __ffs(hier_val);
4247ccfe9b1SMichel JAOUEN 		latch_offset = (hier_offset << 3) + latch_bit;
4257ccfe9b1SMichel JAOUEN 
4267ccfe9b1SMichel JAOUEN 		/* Fix inconsistent ITFromLatch25 bit mapping... */
4277ccfe9b1SMichel JAOUEN 		if (unlikely(latch_offset == 17))
4287ccfe9b1SMichel JAOUEN 			latch_offset = 24;
4297ccfe9b1SMichel JAOUEN 
4307ccfe9b1SMichel JAOUEN 		status = get_register_interruptible(ab8500,
4317ccfe9b1SMichel JAOUEN 				AB8500_INTERRUPT,
4327ccfe9b1SMichel JAOUEN 				AB8500_IT_LATCH1_REG + latch_offset,
4337ccfe9b1SMichel JAOUEN 				&latch_val);
4347ccfe9b1SMichel JAOUEN 		if (status < 0 || latch_val == 0)
4357ccfe9b1SMichel JAOUEN 			goto discard;
4367ccfe9b1SMichel JAOUEN 
4377ccfe9b1SMichel JAOUEN 		status = ab8500_handle_hierarchical_line(ab8500,
4387ccfe9b1SMichel JAOUEN 				latch_offset, latch_val);
4397ccfe9b1SMichel JAOUEN 		if (status < 0)
4407ccfe9b1SMichel JAOUEN 			return status;
4417ccfe9b1SMichel JAOUEN discard:
4427ccfe9b1SMichel JAOUEN 		hier_val &= ~(1 << latch_bit);
4437ccfe9b1SMichel JAOUEN 	} while (hier_val);
4447ccfe9b1SMichel JAOUEN 
4457ccfe9b1SMichel JAOUEN 	return 0;
4467ccfe9b1SMichel JAOUEN }
4477ccfe9b1SMichel JAOUEN 
4487ccfe9b1SMichel JAOUEN static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev)
4497ccfe9b1SMichel JAOUEN {
4507ccfe9b1SMichel JAOUEN 	struct ab8500 *ab8500 = dev;
4517ccfe9b1SMichel JAOUEN 	u8 i;
4527ccfe9b1SMichel JAOUEN 
4537ccfe9b1SMichel JAOUEN 	dev_vdbg(ab8500->dev, "interrupt\n");
4547ccfe9b1SMichel JAOUEN 
4557ccfe9b1SMichel JAOUEN 	/*  Hierarchical interrupt version */
4567ccfe9b1SMichel JAOUEN 	for (i = 0; i < AB8500_IT_LATCHHIER_NUM; i++) {
4577ccfe9b1SMichel JAOUEN 		int status;
4587ccfe9b1SMichel JAOUEN 		u8 hier_val;
4597ccfe9b1SMichel JAOUEN 
4607ccfe9b1SMichel JAOUEN 		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
4617ccfe9b1SMichel JAOUEN 			AB8500_IT_LATCHHIER1_REG + i, &hier_val);
4627ccfe9b1SMichel JAOUEN 		if (status < 0 || hier_val == 0)
4637ccfe9b1SMichel JAOUEN 			continue;
4647ccfe9b1SMichel JAOUEN 
4657ccfe9b1SMichel JAOUEN 		status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val);
4667ccfe9b1SMichel JAOUEN 		if (status < 0)
4677ccfe9b1SMichel JAOUEN 			break;
4687ccfe9b1SMichel JAOUEN 	}
4697ccfe9b1SMichel JAOUEN 	return IRQ_HANDLED;
4707ccfe9b1SMichel JAOUEN }
4717ccfe9b1SMichel JAOUEN 
47262579266SRabin Vincent static irqreturn_t ab8500_irq(int irq, void *dev)
47362579266SRabin Vincent {
47462579266SRabin Vincent 	struct ab8500 *ab8500 = dev;
47562579266SRabin Vincent 	int i;
47662579266SRabin Vincent 
47762579266SRabin Vincent 	dev_vdbg(ab8500->dev, "interrupt\n");
47862579266SRabin Vincent 
479112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
480112a80d2SJonas Aaberg 
4812ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++) {
4822ced445eSLinus Walleij 		int regoffset = ab8500->irq_reg_offset[i];
48362579266SRabin Vincent 		int status;
48447c16975SMattias Wallin 		u8 value;
48562579266SRabin Vincent 
4860f620837SLinus Walleij 		/*
4870f620837SLinus Walleij 		 * Interrupt register 12 doesn't exist prior to AB8500 version
4880f620837SLinus Walleij 		 * 2.0
4890f620837SLinus Walleij 		 */
4900f620837SLinus Walleij 		if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500))
49192d50a41SMattias Wallin 			continue;
49292d50a41SMattias Wallin 
49347c16975SMattias Wallin 		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
49447c16975SMattias Wallin 			AB8500_IT_LATCH1_REG + regoffset, &value);
49547c16975SMattias Wallin 		if (status < 0 || value == 0)
49662579266SRabin Vincent 			continue;
49762579266SRabin Vincent 
49862579266SRabin Vincent 		do {
49988aec4f7SMattias Wallin 			int bit = __ffs(value);
50062579266SRabin Vincent 			int line = i * 8 + bit;
50162579266SRabin Vincent 
50262579266SRabin Vincent 			handle_nested_irq(ab8500->irq_base + line);
50347c16975SMattias Wallin 			value &= ~(1 << bit);
504112a80d2SJonas Aaberg 
50547c16975SMattias Wallin 		} while (value);
50662579266SRabin Vincent 	}
507112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
50862579266SRabin Vincent 	return IRQ_HANDLED;
50962579266SRabin Vincent }
51062579266SRabin Vincent 
51162579266SRabin Vincent static int ab8500_irq_init(struct ab8500 *ab8500)
51262579266SRabin Vincent {
51362579266SRabin Vincent 	int base = ab8500->irq_base;
51462579266SRabin Vincent 	int irq;
5152ced445eSLinus Walleij 	int num_irqs;
51662579266SRabin Vincent 
517d6255529SLinus Walleij 	if (is_ab9540(ab8500))
518d6255529SLinus Walleij 		num_irqs = AB9540_NR_IRQS;
519a982362cSBengt Jonsson 	else if (is_ab8505(ab8500))
520a982362cSBengt Jonsson 		num_irqs = AB8505_NR_IRQS;
521d6255529SLinus Walleij 	else
5222ced445eSLinus Walleij 		num_irqs = AB8500_NR_IRQS;
5232ced445eSLinus Walleij 
5242ced445eSLinus Walleij 	for (irq = base; irq < base + num_irqs; irq++) {
525d5bb1221SThomas Gleixner 		irq_set_chip_data(irq, ab8500);
526d5bb1221SThomas Gleixner 		irq_set_chip_and_handler(irq, &ab8500_irq_chip,
52762579266SRabin Vincent 					 handle_simple_irq);
528d5bb1221SThomas Gleixner 		irq_set_nested_thread(irq, 1);
52962579266SRabin Vincent #ifdef CONFIG_ARM
53062579266SRabin Vincent 		set_irq_flags(irq, IRQF_VALID);
53162579266SRabin Vincent #else
532d5bb1221SThomas Gleixner 		irq_set_noprobe(irq);
53362579266SRabin Vincent #endif
53462579266SRabin Vincent 	}
53562579266SRabin Vincent 
53662579266SRabin Vincent 	return 0;
53762579266SRabin Vincent }
53862579266SRabin Vincent 
53962579266SRabin Vincent static void ab8500_irq_remove(struct ab8500 *ab8500)
54062579266SRabin Vincent {
54162579266SRabin Vincent 	int base = ab8500->irq_base;
54262579266SRabin Vincent 	int irq;
5432ced445eSLinus Walleij 	int num_irqs;
54462579266SRabin Vincent 
545d6255529SLinus Walleij 	if (is_ab9540(ab8500))
546d6255529SLinus Walleij 		num_irqs = AB9540_NR_IRQS;
547a982362cSBengt Jonsson 	else if (is_ab8505(ab8500))
548a982362cSBengt Jonsson 		num_irqs = AB8505_NR_IRQS;
549d6255529SLinus Walleij 	else
5502ced445eSLinus Walleij 		num_irqs = AB8500_NR_IRQS;
5512ced445eSLinus Walleij 
5522ced445eSLinus Walleij 	for (irq = base; irq < base + num_irqs; irq++) {
55362579266SRabin Vincent #ifdef CONFIG_ARM
55462579266SRabin Vincent 		set_irq_flags(irq, 0);
55562579266SRabin Vincent #endif
556d5bb1221SThomas Gleixner 		irq_set_chip_and_handler(irq, NULL, NULL);
557d5bb1221SThomas Gleixner 		irq_set_chip_data(irq, NULL);
55862579266SRabin Vincent 	}
55962579266SRabin Vincent }
56062579266SRabin Vincent 
561112a80d2SJonas Aaberg int ab8500_suspend(struct ab8500 *ab8500)
562112a80d2SJonas Aaberg {
563112a80d2SJonas Aaberg 	if (atomic_read(&ab8500->transfer_ongoing))
564112a80d2SJonas Aaberg 		return -EINVAL;
565112a80d2SJonas Aaberg 	else
566112a80d2SJonas Aaberg 		return 0;
567112a80d2SJonas Aaberg }
568112a80d2SJonas Aaberg 
569d6255529SLinus Walleij /* AB8500 GPIO Resources */
5705cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_gpio_resources[] = {
5710cb3fcd7SBibek Basu 	{
5720cb3fcd7SBibek Basu 		.name	= "GPIO_INT6",
5730cb3fcd7SBibek Basu 		.start	= AB8500_INT_GPIO6R,
5740cb3fcd7SBibek Basu 		.end	= AB8500_INT_GPIO41F,
5750cb3fcd7SBibek Basu 		.flags	= IORESOURCE_IRQ,
5760cb3fcd7SBibek Basu 	}
5770cb3fcd7SBibek Basu };
5780cb3fcd7SBibek Basu 
579d6255529SLinus Walleij /* AB9540 GPIO Resources */
580d6255529SLinus Walleij static struct resource __devinitdata ab9540_gpio_resources[] = {
581d6255529SLinus Walleij 	{
582d6255529SLinus Walleij 		.name	= "GPIO_INT6",
583d6255529SLinus Walleij 		.start	= AB8500_INT_GPIO6R,
584d6255529SLinus Walleij 		.end	= AB8500_INT_GPIO41F,
585d6255529SLinus Walleij 		.flags	= IORESOURCE_IRQ,
586d6255529SLinus Walleij 	},
587d6255529SLinus Walleij 	{
588d6255529SLinus Walleij 		.name	= "GPIO_INT14",
589d6255529SLinus Walleij 		.start	= AB9540_INT_GPIO50R,
590d6255529SLinus Walleij 		.end	= AB9540_INT_GPIO54R,
591d6255529SLinus Walleij 		.flags	= IORESOURCE_IRQ,
592d6255529SLinus Walleij 	},
593d6255529SLinus Walleij 	{
594d6255529SLinus Walleij 		.name	= "GPIO_INT15",
595d6255529SLinus Walleij 		.start	= AB9540_INT_GPIO50F,
596d6255529SLinus Walleij 		.end	= AB9540_INT_GPIO54F,
597d6255529SLinus Walleij 		.flags	= IORESOURCE_IRQ,
598d6255529SLinus Walleij 	}
599d6255529SLinus Walleij };
600d6255529SLinus Walleij 
6015cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_gpadc_resources[] = {
60262579266SRabin Vincent 	{
60362579266SRabin Vincent 		.name	= "HW_CONV_END",
60462579266SRabin Vincent 		.start	= AB8500_INT_GP_HW_ADC_CONV_END,
60562579266SRabin Vincent 		.end	= AB8500_INT_GP_HW_ADC_CONV_END,
60662579266SRabin Vincent 		.flags	= IORESOURCE_IRQ,
60762579266SRabin Vincent 	},
60862579266SRabin Vincent 	{
60962579266SRabin Vincent 		.name	= "SW_CONV_END",
61062579266SRabin Vincent 		.start	= AB8500_INT_GP_SW_ADC_CONV_END,
61162579266SRabin Vincent 		.end	= AB8500_INT_GP_SW_ADC_CONV_END,
61262579266SRabin Vincent 		.flags	= IORESOURCE_IRQ,
61362579266SRabin Vincent 	},
61462579266SRabin Vincent };
61562579266SRabin Vincent 
6165cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_rtc_resources[] = {
61762579266SRabin Vincent 	{
61862579266SRabin Vincent 		.name	= "60S",
61962579266SRabin Vincent 		.start	= AB8500_INT_RTC_60S,
62062579266SRabin Vincent 		.end	= AB8500_INT_RTC_60S,
62162579266SRabin Vincent 		.flags	= IORESOURCE_IRQ,
62262579266SRabin Vincent 	},
62362579266SRabin Vincent 	{
62462579266SRabin Vincent 		.name	= "ALARM",
62562579266SRabin Vincent 		.start	= AB8500_INT_RTC_ALARM,
62662579266SRabin Vincent 		.end	= AB8500_INT_RTC_ALARM,
62762579266SRabin Vincent 		.flags	= IORESOURCE_IRQ,
62862579266SRabin Vincent 	},
62962579266SRabin Vincent };
63062579266SRabin Vincent 
6315cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_poweronkey_db_resources[] = {
63277686517SSundar R Iyer 	{
63377686517SSundar R Iyer 		.name	= "ONKEY_DBF",
63477686517SSundar R Iyer 		.start	= AB8500_INT_PON_KEY1DB_F,
63577686517SSundar R Iyer 		.end	= AB8500_INT_PON_KEY1DB_F,
63677686517SSundar R Iyer 		.flags	= IORESOURCE_IRQ,
63777686517SSundar R Iyer 	},
63877686517SSundar R Iyer 	{
63977686517SSundar R Iyer 		.name	= "ONKEY_DBR",
64077686517SSundar R Iyer 		.start	= AB8500_INT_PON_KEY1DB_R,
64177686517SSundar R Iyer 		.end	= AB8500_INT_PON_KEY1DB_R,
64277686517SSundar R Iyer 		.flags	= IORESOURCE_IRQ,
64377686517SSundar R Iyer 	},
64477686517SSundar R Iyer };
64577686517SSundar R Iyer 
6466af75ecdSLinus Walleij static struct resource __devinitdata ab8500_av_acc_detect_resources[] = {
647e098adedSMattias Wallin 	{
6486af75ecdSLinus Walleij 	       .name = "ACC_DETECT_1DB_F",
6496af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_1DB_F,
6506af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_1DB_F,
651e098adedSMattias Wallin 	       .flags = IORESOURCE_IRQ,
652e098adedSMattias Wallin 	},
653e098adedSMattias Wallin 	{
6546af75ecdSLinus Walleij 	       .name = "ACC_DETECT_1DB_R",
6556af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_1DB_R,
6566af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_1DB_R,
657e098adedSMattias Wallin 	       .flags = IORESOURCE_IRQ,
658e098adedSMattias Wallin 	},
659e098adedSMattias Wallin 	{
6606af75ecdSLinus Walleij 	       .name = "ACC_DETECT_21DB_F",
6616af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_21DB_F,
6626af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_21DB_F,
6636af75ecdSLinus Walleij 	       .flags = IORESOURCE_IRQ,
6646af75ecdSLinus Walleij 	},
6656af75ecdSLinus Walleij 	{
6666af75ecdSLinus Walleij 	       .name = "ACC_DETECT_21DB_R",
6676af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_21DB_R,
6686af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_21DB_R,
6696af75ecdSLinus Walleij 	       .flags = IORESOURCE_IRQ,
6706af75ecdSLinus Walleij 	},
6716af75ecdSLinus Walleij 	{
6726af75ecdSLinus Walleij 	       .name = "ACC_DETECT_22DB_F",
6736af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_22DB_F,
6746af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_22DB_F,
6756af75ecdSLinus Walleij 	       .flags = IORESOURCE_IRQ,
6766af75ecdSLinus Walleij 	},
6776af75ecdSLinus Walleij 	{
6786af75ecdSLinus Walleij 	       .name = "ACC_DETECT_22DB_R",
6796af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_22DB_R,
6806af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_22DB_R,
6816af75ecdSLinus Walleij 	       .flags = IORESOURCE_IRQ,
6826af75ecdSLinus Walleij 	},
6836af75ecdSLinus Walleij };
6846af75ecdSLinus Walleij 
6856af75ecdSLinus Walleij static struct resource __devinitdata ab8500_charger_resources[] = {
6866af75ecdSLinus Walleij 	{
687e098adedSMattias Wallin 		.name = "MAIN_CH_UNPLUG_DET",
688e098adedSMattias Wallin 		.start = AB8500_INT_MAIN_CH_UNPLUG_DET,
689e098adedSMattias Wallin 		.end = AB8500_INT_MAIN_CH_UNPLUG_DET,
690e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
691e098adedSMattias Wallin 	},
692e098adedSMattias Wallin 	{
693e098adedSMattias Wallin 		.name = "MAIN_CHARGE_PLUG_DET",
694e098adedSMattias Wallin 		.start = AB8500_INT_MAIN_CH_PLUG_DET,
695e098adedSMattias Wallin 		.end = AB8500_INT_MAIN_CH_PLUG_DET,
696e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
697e098adedSMattias Wallin 	},
698e098adedSMattias Wallin 	{
699e098adedSMattias Wallin 		.name = "VBUS_DET_R",
700e098adedSMattias Wallin 		.start = AB8500_INT_VBUS_DET_R,
701e098adedSMattias Wallin 		.end = AB8500_INT_VBUS_DET_R,
702e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
703e098adedSMattias Wallin 	},
704e098adedSMattias Wallin 	{
7056af75ecdSLinus Walleij 		.name = "VBUS_DET_F",
7066af75ecdSLinus Walleij 		.start = AB8500_INT_VBUS_DET_F,
7076af75ecdSLinus Walleij 		.end = AB8500_INT_VBUS_DET_F,
708e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
709e098adedSMattias Wallin 	},
710e098adedSMattias Wallin 	{
7116af75ecdSLinus Walleij 		.name = "USB_LINK_STATUS",
7126af75ecdSLinus Walleij 		.start = AB8500_INT_USB_LINK_STATUS,
7136af75ecdSLinus Walleij 		.end = AB8500_INT_USB_LINK_STATUS,
7146af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
7156af75ecdSLinus Walleij 	},
7166af75ecdSLinus Walleij 	{
717e098adedSMattias Wallin 		.name = "VBUS_OVV",
718e098adedSMattias Wallin 		.start = AB8500_INT_VBUS_OVV,
719e098adedSMattias Wallin 		.end = AB8500_INT_VBUS_OVV,
720e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
721e098adedSMattias Wallin 	},
722e098adedSMattias Wallin 	{
7236af75ecdSLinus Walleij 		.name = "USB_CH_TH_PROT_R",
7246af75ecdSLinus Walleij 		.start = AB8500_INT_USB_CH_TH_PROT_R,
7256af75ecdSLinus Walleij 		.end = AB8500_INT_USB_CH_TH_PROT_R,
726e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
727e098adedSMattias Wallin 	},
728e098adedSMattias Wallin 	{
7296af75ecdSLinus Walleij 		.name = "USB_CH_TH_PROT_F",
7306af75ecdSLinus Walleij 		.start = AB8500_INT_USB_CH_TH_PROT_F,
7316af75ecdSLinus Walleij 		.end = AB8500_INT_USB_CH_TH_PROT_F,
732e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
733e098adedSMattias Wallin 	},
734e098adedSMattias Wallin 	{
7356af75ecdSLinus Walleij 		.name = "MAIN_EXT_CH_NOT_OK",
7366af75ecdSLinus Walleij 		.start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
7376af75ecdSLinus Walleij 		.end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
7386af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
7396af75ecdSLinus Walleij 	},
7406af75ecdSLinus Walleij 	{
7416af75ecdSLinus Walleij 		.name = "MAIN_CH_TH_PROT_R",
7426af75ecdSLinus Walleij 		.start = AB8500_INT_MAIN_CH_TH_PROT_R,
7436af75ecdSLinus Walleij 		.end = AB8500_INT_MAIN_CH_TH_PROT_R,
7446af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
7456af75ecdSLinus Walleij 	},
7466af75ecdSLinus Walleij 	{
7476af75ecdSLinus Walleij 		.name = "MAIN_CH_TH_PROT_F",
7486af75ecdSLinus Walleij 		.start = AB8500_INT_MAIN_CH_TH_PROT_F,
7496af75ecdSLinus Walleij 		.end = AB8500_INT_MAIN_CH_TH_PROT_F,
7506af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
7516af75ecdSLinus Walleij 	},
7526af75ecdSLinus Walleij 	{
7536af75ecdSLinus Walleij 		.name = "USB_CHARGER_NOT_OKR",
754a982362cSBengt Jonsson 		.start = AB8500_INT_USB_CHARGER_NOT_OKR,
755a982362cSBengt Jonsson 		.end = AB8500_INT_USB_CHARGER_NOT_OKR,
7566af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
7576af75ecdSLinus Walleij 	},
7586af75ecdSLinus Walleij 	{
7596af75ecdSLinus Walleij 		.name = "CH_WD_EXP",
7606af75ecdSLinus Walleij 		.start = AB8500_INT_CH_WD_EXP,
7616af75ecdSLinus Walleij 		.end = AB8500_INT_CH_WD_EXP,
7626af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
7636af75ecdSLinus Walleij 	},
7646af75ecdSLinus Walleij };
7656af75ecdSLinus Walleij 
7666af75ecdSLinus Walleij static struct resource __devinitdata ab8500_btemp_resources[] = {
7676af75ecdSLinus Walleij 	{
7686af75ecdSLinus Walleij 		.name = "BAT_CTRL_INDB",
7696af75ecdSLinus Walleij 		.start = AB8500_INT_BAT_CTRL_INDB,
7706af75ecdSLinus Walleij 		.end = AB8500_INT_BAT_CTRL_INDB,
771e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
772e098adedSMattias Wallin 	},
773e098adedSMattias Wallin 	{
774e098adedSMattias Wallin 		.name = "BTEMP_LOW",
775e098adedSMattias Wallin 		.start = AB8500_INT_BTEMP_LOW,
776e098adedSMattias Wallin 		.end = AB8500_INT_BTEMP_LOW,
777e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
778e098adedSMattias Wallin 	},
779e098adedSMattias Wallin 	{
780e098adedSMattias Wallin 		.name = "BTEMP_HIGH",
781e098adedSMattias Wallin 		.start = AB8500_INT_BTEMP_HIGH,
782e098adedSMattias Wallin 		.end = AB8500_INT_BTEMP_HIGH,
783e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
784e098adedSMattias Wallin 	},
785e098adedSMattias Wallin 	{
7866af75ecdSLinus Walleij 		.name = "BTEMP_LOW_MEDIUM",
7876af75ecdSLinus Walleij 		.start = AB8500_INT_BTEMP_LOW_MEDIUM,
7886af75ecdSLinus Walleij 		.end = AB8500_INT_BTEMP_LOW_MEDIUM,
789e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
790e098adedSMattias Wallin 	},
791e098adedSMattias Wallin 	{
7926af75ecdSLinus Walleij 		.name = "BTEMP_MEDIUM_HIGH",
7936af75ecdSLinus Walleij 		.start = AB8500_INT_BTEMP_MEDIUM_HIGH,
7946af75ecdSLinus Walleij 		.end = AB8500_INT_BTEMP_MEDIUM_HIGH,
795e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
796e098adedSMattias Wallin 	},
797e098adedSMattias Wallin };
798e098adedSMattias Wallin 
7996af75ecdSLinus Walleij static struct resource __devinitdata ab8500_fg_resources[] = {
8006af75ecdSLinus Walleij 	{
8016af75ecdSLinus Walleij 		.name = "NCONV_ACCU",
8026af75ecdSLinus Walleij 		.start = AB8500_INT_CCN_CONV_ACC,
8036af75ecdSLinus Walleij 		.end = AB8500_INT_CCN_CONV_ACC,
8046af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8056af75ecdSLinus Walleij 	},
8066af75ecdSLinus Walleij 	{
8076af75ecdSLinus Walleij 		.name = "BATT_OVV",
8086af75ecdSLinus Walleij 		.start = AB8500_INT_BATT_OVV,
8096af75ecdSLinus Walleij 		.end = AB8500_INT_BATT_OVV,
8106af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8116af75ecdSLinus Walleij 	},
8126af75ecdSLinus Walleij 	{
8136af75ecdSLinus Walleij 		.name = "LOW_BAT_F",
8146af75ecdSLinus Walleij 		.start = AB8500_INT_LOW_BAT_F,
8156af75ecdSLinus Walleij 		.end = AB8500_INT_LOW_BAT_F,
8166af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8176af75ecdSLinus Walleij 	},
8186af75ecdSLinus Walleij 	{
8196af75ecdSLinus Walleij 		.name = "LOW_BAT_R",
8206af75ecdSLinus Walleij 		.start = AB8500_INT_LOW_BAT_R,
8216af75ecdSLinus Walleij 		.end = AB8500_INT_LOW_BAT_R,
8226af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8236af75ecdSLinus Walleij 	},
8246af75ecdSLinus Walleij 	{
8256af75ecdSLinus Walleij 		.name = "CC_INT_CALIB",
8266af75ecdSLinus Walleij 		.start = AB8500_INT_CC_INT_CALIB,
8276af75ecdSLinus Walleij 		.end = AB8500_INT_CC_INT_CALIB,
8286af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8296af75ecdSLinus Walleij 	},
830a982362cSBengt Jonsson 	{
831a982362cSBengt Jonsson 		.name = "CCEOC",
832a982362cSBengt Jonsson 		.start = AB8500_INT_CCEOC,
833a982362cSBengt Jonsson 		.end = AB8500_INT_CCEOC,
834a982362cSBengt Jonsson 		.flags = IORESOURCE_IRQ,
835a982362cSBengt Jonsson 	},
8366af75ecdSLinus Walleij };
8376af75ecdSLinus Walleij 
8386af75ecdSLinus Walleij static struct resource __devinitdata ab8500_chargalg_resources[] = {};
8396af75ecdSLinus Walleij 
840df720647SAxel Lin #ifdef CONFIG_DEBUG_FS
8415cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_debug_resources[] = {
842e098adedSMattias Wallin 	{
843e098adedSMattias Wallin 		.name	= "IRQ_FIRST",
844e098adedSMattias Wallin 		.start	= AB8500_INT_MAIN_EXT_CH_NOT_OK,
845e098adedSMattias Wallin 		.end	= AB8500_INT_MAIN_EXT_CH_NOT_OK,
846e098adedSMattias Wallin 		.flags	= IORESOURCE_IRQ,
847e098adedSMattias Wallin 	},
848e098adedSMattias Wallin 	{
849e098adedSMattias Wallin 		.name	= "IRQ_LAST",
850a982362cSBengt Jonsson 		.start	= AB8500_INT_XTAL32K_KO,
851a982362cSBengt Jonsson 		.end	= AB8500_INT_XTAL32K_KO,
852e098adedSMattias Wallin 		.flags	= IORESOURCE_IRQ,
853e098adedSMattias Wallin 	},
854e098adedSMattias Wallin };
855df720647SAxel Lin #endif
856e098adedSMattias Wallin 
8575cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_usb_resources[] = {
858e098adedSMattias Wallin 	{
859e098adedSMattias Wallin 		.name = "ID_WAKEUP_R",
860e098adedSMattias Wallin 		.start = AB8500_INT_ID_WAKEUP_R,
861e098adedSMattias Wallin 		.end = AB8500_INT_ID_WAKEUP_R,
862e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
863e098adedSMattias Wallin 	},
864e098adedSMattias Wallin 	{
865e098adedSMattias Wallin 		.name = "ID_WAKEUP_F",
866e098adedSMattias Wallin 		.start = AB8500_INT_ID_WAKEUP_F,
867e098adedSMattias Wallin 		.end = AB8500_INT_ID_WAKEUP_F,
868e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
869e098adedSMattias Wallin 	},
870e098adedSMattias Wallin 	{
871e098adedSMattias Wallin 		.name = "VBUS_DET_F",
872e098adedSMattias Wallin 		.start = AB8500_INT_VBUS_DET_F,
873e098adedSMattias Wallin 		.end = AB8500_INT_VBUS_DET_F,
874e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
875e098adedSMattias Wallin 	},
876e098adedSMattias Wallin 	{
877e098adedSMattias Wallin 		.name = "VBUS_DET_R",
878e098adedSMattias Wallin 		.start = AB8500_INT_VBUS_DET_R,
879e098adedSMattias Wallin 		.end = AB8500_INT_VBUS_DET_R,
880e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
881e098adedSMattias Wallin 	},
88292d50a41SMattias Wallin 	{
88392d50a41SMattias Wallin 		.name = "USB_LINK_STATUS",
88492d50a41SMattias Wallin 		.start = AB8500_INT_USB_LINK_STATUS,
88592d50a41SMattias Wallin 		.end = AB8500_INT_USB_LINK_STATUS,
88692d50a41SMattias Wallin 		.flags = IORESOURCE_IRQ,
88792d50a41SMattias Wallin 	},
8886af75ecdSLinus Walleij 	{
8896af75ecdSLinus Walleij 		.name = "USB_ADP_PROBE_PLUG",
8906af75ecdSLinus Walleij 		.start = AB8500_INT_ADP_PROBE_PLUG,
8916af75ecdSLinus Walleij 		.end = AB8500_INT_ADP_PROBE_PLUG,
8926af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8936af75ecdSLinus Walleij 	},
8946af75ecdSLinus Walleij 	{
8956af75ecdSLinus Walleij 		.name = "USB_ADP_PROBE_UNPLUG",
8966af75ecdSLinus Walleij 		.start = AB8500_INT_ADP_PROBE_UNPLUG,
8976af75ecdSLinus Walleij 		.end = AB8500_INT_ADP_PROBE_UNPLUG,
8986af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8996af75ecdSLinus Walleij 	},
900e098adedSMattias Wallin };
901e098adedSMattias Wallin 
90244f72e53SVirupax Sadashivpetimath static struct resource __devinitdata ab8505_iddet_resources[] = {
90344f72e53SVirupax Sadashivpetimath 	{
90444f72e53SVirupax Sadashivpetimath 		.name  = "KeyDeglitch",
90544f72e53SVirupax Sadashivpetimath 		.start = AB8505_INT_KEYDEGLITCH,
90644f72e53SVirupax Sadashivpetimath 		.end   = AB8505_INT_KEYDEGLITCH,
90744f72e53SVirupax Sadashivpetimath 		.flags = IORESOURCE_IRQ,
90844f72e53SVirupax Sadashivpetimath 	},
90944f72e53SVirupax Sadashivpetimath 	{
91044f72e53SVirupax Sadashivpetimath 		.name  = "KP",
91144f72e53SVirupax Sadashivpetimath 		.start = AB8505_INT_KP,
91244f72e53SVirupax Sadashivpetimath 		.end   = AB8505_INT_KP,
91344f72e53SVirupax Sadashivpetimath 		.flags = IORESOURCE_IRQ,
91444f72e53SVirupax Sadashivpetimath 	},
91544f72e53SVirupax Sadashivpetimath 	{
91644f72e53SVirupax Sadashivpetimath 		.name  = "IKP",
91744f72e53SVirupax Sadashivpetimath 		.start = AB8505_INT_IKP,
91844f72e53SVirupax Sadashivpetimath 		.end   = AB8505_INT_IKP,
91944f72e53SVirupax Sadashivpetimath 		.flags = IORESOURCE_IRQ,
92044f72e53SVirupax Sadashivpetimath 	},
92144f72e53SVirupax Sadashivpetimath 	{
92244f72e53SVirupax Sadashivpetimath 		.name  = "IKR",
92344f72e53SVirupax Sadashivpetimath 		.start = AB8505_INT_IKR,
92444f72e53SVirupax Sadashivpetimath 		.end   = AB8505_INT_IKR,
92544f72e53SVirupax Sadashivpetimath 		.flags = IORESOURCE_IRQ,
92644f72e53SVirupax Sadashivpetimath 	},
92744f72e53SVirupax Sadashivpetimath 	{
92844f72e53SVirupax Sadashivpetimath 		.name  = "KeyStuck",
92944f72e53SVirupax Sadashivpetimath 		.start = AB8505_INT_KEYSTUCK,
93044f72e53SVirupax Sadashivpetimath 		.end   = AB8505_INT_KEYSTUCK,
93144f72e53SVirupax Sadashivpetimath 		.flags = IORESOURCE_IRQ,
93244f72e53SVirupax Sadashivpetimath 	},
93344f72e53SVirupax Sadashivpetimath };
93444f72e53SVirupax Sadashivpetimath 
9355cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_temp_resources[] = {
936e098adedSMattias Wallin 	{
937e098adedSMattias Wallin 		.name  = "AB8500_TEMP_WARM",
938e098adedSMattias Wallin 		.start = AB8500_INT_TEMP_WARM,
939e098adedSMattias Wallin 		.end   = AB8500_INT_TEMP_WARM,
940e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
941e098adedSMattias Wallin 	},
942e098adedSMattias Wallin };
943e098adedSMattias Wallin 
944d6255529SLinus Walleij static struct mfd_cell __devinitdata abx500_common_devs[] = {
9455814fc35SMattias Wallin #ifdef CONFIG_DEBUG_FS
9465814fc35SMattias Wallin 	{
9475814fc35SMattias Wallin 		.name = "ab8500-debug",
948e098adedSMattias Wallin 		.num_resources = ARRAY_SIZE(ab8500_debug_resources),
949e098adedSMattias Wallin 		.resources = ab8500_debug_resources,
9505814fc35SMattias Wallin 	},
9515814fc35SMattias Wallin #endif
95262579266SRabin Vincent 	{
953e098adedSMattias Wallin 		.name = "ab8500-sysctrl",
954e098adedSMattias Wallin 	},
955e098adedSMattias Wallin 	{
956e098adedSMattias Wallin 		.name = "ab8500-regulator",
957e098adedSMattias Wallin 	},
958e098adedSMattias Wallin 	{
95962579266SRabin Vincent 		.name = "ab8500-gpadc",
96062579266SRabin Vincent 		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
96162579266SRabin Vincent 		.resources = ab8500_gpadc_resources,
96262579266SRabin Vincent 	},
96362579266SRabin Vincent 	{
96462579266SRabin Vincent 		.name = "ab8500-rtc",
96562579266SRabin Vincent 		.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
96662579266SRabin Vincent 		.resources = ab8500_rtc_resources,
96762579266SRabin Vincent 	},
968f0f05b1cSArun Murthy 	{
9696af75ecdSLinus Walleij 		.name = "ab8500-acc-det",
9706af75ecdSLinus Walleij 		.num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
9716af75ecdSLinus Walleij 		.resources = ab8500_av_acc_detect_resources,
9726af75ecdSLinus Walleij 	},
9736af75ecdSLinus Walleij 	{
974e098adedSMattias Wallin 		.name = "ab8500-poweron-key",
975e098adedSMattias Wallin 		.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
976e098adedSMattias Wallin 		.resources = ab8500_poweronkey_db_resources,
977e098adedSMattias Wallin 	},
978e098adedSMattias Wallin 	{
979f0f05b1cSArun Murthy 		.name = "ab8500-pwm",
980f0f05b1cSArun Murthy 		.id = 1,
981f0f05b1cSArun Murthy 	},
982f0f05b1cSArun Murthy 	{
983f0f05b1cSArun Murthy 		.name = "ab8500-pwm",
984f0f05b1cSArun Murthy 		.id = 2,
985f0f05b1cSArun Murthy 	},
986f0f05b1cSArun Murthy 	{
987f0f05b1cSArun Murthy 		.name = "ab8500-pwm",
988f0f05b1cSArun Murthy 		.id = 3,
989f0f05b1cSArun Murthy 	},
990e098adedSMattias Wallin 	{ .name = "ab8500-leds", },
99177686517SSundar R Iyer 	{
992e098adedSMattias Wallin 		.name = "ab8500-denc",
993e098adedSMattias Wallin 	},
994e098adedSMattias Wallin 	{
995e098adedSMattias Wallin 		.name = "ab8500-temp",
996e098adedSMattias Wallin 		.num_resources = ARRAY_SIZE(ab8500_temp_resources),
997e098adedSMattias Wallin 		.resources = ab8500_temp_resources,
99877686517SSundar R Iyer 	},
99962579266SRabin Vincent };
100062579266SRabin Vincent 
10016ef9418cSRickard Andersson static struct mfd_cell __devinitdata ab8500_bm_devs[] = {
10026ef9418cSRickard Andersson 	{
10036ef9418cSRickard Andersson 		.name = "ab8500-charger",
10046ef9418cSRickard Andersson 		.num_resources = ARRAY_SIZE(ab8500_charger_resources),
10056ef9418cSRickard Andersson 		.resources = ab8500_charger_resources,
10066ef9418cSRickard Andersson 	},
10076ef9418cSRickard Andersson 	{
10086ef9418cSRickard Andersson 		.name = "ab8500-btemp",
10096ef9418cSRickard Andersson 		.num_resources = ARRAY_SIZE(ab8500_btemp_resources),
10106ef9418cSRickard Andersson 		.resources = ab8500_btemp_resources,
10116ef9418cSRickard Andersson 	},
10126ef9418cSRickard Andersson 	{
10136ef9418cSRickard Andersson 		.name = "ab8500-fg",
10146ef9418cSRickard Andersson 		.num_resources = ARRAY_SIZE(ab8500_fg_resources),
10156ef9418cSRickard Andersson 		.resources = ab8500_fg_resources,
10166ef9418cSRickard Andersson 	},
10176ef9418cSRickard Andersson 	{
10186ef9418cSRickard Andersson 		.name = "ab8500-chargalg",
10196ef9418cSRickard Andersson 		.num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
10206ef9418cSRickard Andersson 		.resources = ab8500_chargalg_resources,
10216ef9418cSRickard Andersson 	},
10226ef9418cSRickard Andersson };
10236ef9418cSRickard Andersson 
1024d6255529SLinus Walleij static struct mfd_cell __devinitdata ab8500_devs[] = {
1025d6255529SLinus Walleij 	{
1026d6255529SLinus Walleij 		.name = "ab8500-gpio",
1027d6255529SLinus Walleij 		.num_resources = ARRAY_SIZE(ab8500_gpio_resources),
1028d6255529SLinus Walleij 		.resources = ab8500_gpio_resources,
1029d6255529SLinus Walleij 	},
1030d6255529SLinus Walleij 	{
1031d6255529SLinus Walleij 		.name = "ab8500-usb",
1032d6255529SLinus Walleij 		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
1033d6255529SLinus Walleij 		.resources = ab8500_usb_resources,
1034d6255529SLinus Walleij 	},
103544f72e53SVirupax Sadashivpetimath 	{
103644f72e53SVirupax Sadashivpetimath 		.name = "ab8500-codec",
103744f72e53SVirupax Sadashivpetimath 	},
1038d6255529SLinus Walleij };
1039d6255529SLinus Walleij 
1040d6255529SLinus Walleij static struct mfd_cell __devinitdata ab9540_devs[] = {
1041d6255529SLinus Walleij 	{
1042d6255529SLinus Walleij 		.name = "ab8500-gpio",
1043d6255529SLinus Walleij 		.num_resources = ARRAY_SIZE(ab9540_gpio_resources),
1044d6255529SLinus Walleij 		.resources = ab9540_gpio_resources,
1045d6255529SLinus Walleij 	},
1046d6255529SLinus Walleij 	{
1047d6255529SLinus Walleij 		.name = "ab9540-usb",
1048d6255529SLinus Walleij 		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
1049d6255529SLinus Walleij 		.resources = ab8500_usb_resources,
1050d6255529SLinus Walleij 	},
105144f72e53SVirupax Sadashivpetimath 	{
105244f72e53SVirupax Sadashivpetimath 		.name = "ab9540-codec",
105344f72e53SVirupax Sadashivpetimath 	},
105444f72e53SVirupax Sadashivpetimath };
105544f72e53SVirupax Sadashivpetimath 
105644f72e53SVirupax Sadashivpetimath /* Device list common to ab9540 and ab8505 */
105744f72e53SVirupax Sadashivpetimath static struct mfd_cell __devinitdata ab9540_ab8505_devs[] = {
105844f72e53SVirupax Sadashivpetimath 	{
105944f72e53SVirupax Sadashivpetimath 		.name = "ab-iddet",
106044f72e53SVirupax Sadashivpetimath 		.num_resources = ARRAY_SIZE(ab8505_iddet_resources),
106144f72e53SVirupax Sadashivpetimath 		.resources = ab8505_iddet_resources,
106244f72e53SVirupax Sadashivpetimath 	},
1063d6255529SLinus Walleij };
1064d6255529SLinus Walleij 
1065cca69b67SMattias Wallin static ssize_t show_chip_id(struct device *dev,
1066cca69b67SMattias Wallin 				struct device_attribute *attr, char *buf)
1067cca69b67SMattias Wallin {
1068cca69b67SMattias Wallin 	struct ab8500 *ab8500;
1069cca69b67SMattias Wallin 
1070cca69b67SMattias Wallin 	ab8500 = dev_get_drvdata(dev);
1071cca69b67SMattias Wallin 	return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
1072cca69b67SMattias Wallin }
1073cca69b67SMattias Wallin 
1074e5c238c3SMattias Wallin /*
1075e5c238c3SMattias Wallin  * ab8500 has switched off due to (SWITCH_OFF_STATUS):
1076e5c238c3SMattias Wallin  * 0x01 Swoff bit programming
1077e5c238c3SMattias Wallin  * 0x02 Thermal protection activation
1078e5c238c3SMattias Wallin  * 0x04 Vbat lower then BattOk falling threshold
1079e5c238c3SMattias Wallin  * 0x08 Watchdog expired
1080e5c238c3SMattias Wallin  * 0x10 Non presence of 32kHz clock
1081e5c238c3SMattias Wallin  * 0x20 Battery level lower than power on reset threshold
1082e5c238c3SMattias Wallin  * 0x40 Power on key 1 pressed longer than 10 seconds
1083e5c238c3SMattias Wallin  * 0x80 DB8500 thermal shutdown
1084e5c238c3SMattias Wallin  */
1085e5c238c3SMattias Wallin static ssize_t show_switch_off_status(struct device *dev,
1086e5c238c3SMattias Wallin 				struct device_attribute *attr, char *buf)
1087e5c238c3SMattias Wallin {
1088e5c238c3SMattias Wallin 	int ret;
1089e5c238c3SMattias Wallin 	u8 value;
1090e5c238c3SMattias Wallin 	struct ab8500 *ab8500;
1091e5c238c3SMattias Wallin 
1092e5c238c3SMattias Wallin 	ab8500 = dev_get_drvdata(dev);
1093e5c238c3SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_RTC,
1094e5c238c3SMattias Wallin 		AB8500_SWITCH_OFF_STATUS, &value);
1095e5c238c3SMattias Wallin 	if (ret < 0)
1096e5c238c3SMattias Wallin 		return ret;
1097e5c238c3SMattias Wallin 	return sprintf(buf, "%#x\n", value);
1098e5c238c3SMattias Wallin }
1099e5c238c3SMattias Wallin 
1100b4a31037SAndrew Lynn /*
1101b4a31037SAndrew Lynn  * ab8500 has turned on due to (TURN_ON_STATUS):
1102b4a31037SAndrew Lynn  * 0x01 PORnVbat
1103b4a31037SAndrew Lynn  * 0x02 PonKey1dbF
1104b4a31037SAndrew Lynn  * 0x04 PonKey2dbF
1105b4a31037SAndrew Lynn  * 0x08 RTCAlarm
1106b4a31037SAndrew Lynn  * 0x10 MainChDet
1107b4a31037SAndrew Lynn  * 0x20 VbusDet
1108b4a31037SAndrew Lynn  * 0x40 UsbIDDetect
1109b4a31037SAndrew Lynn  * 0x80 Reserved
1110b4a31037SAndrew Lynn  */
1111b4a31037SAndrew Lynn static ssize_t show_turn_on_status(struct device *dev,
1112b4a31037SAndrew Lynn 				struct device_attribute *attr, char *buf)
1113b4a31037SAndrew Lynn {
1114b4a31037SAndrew Lynn 	int ret;
1115b4a31037SAndrew Lynn 	u8 value;
1116b4a31037SAndrew Lynn 	struct ab8500 *ab8500;
1117b4a31037SAndrew Lynn 
1118b4a31037SAndrew Lynn 	ab8500 = dev_get_drvdata(dev);
1119b4a31037SAndrew Lynn 	ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
1120b4a31037SAndrew Lynn 		AB8500_TURN_ON_STATUS, &value);
1121b4a31037SAndrew Lynn 	if (ret < 0)
1122b4a31037SAndrew Lynn 		return ret;
1123b4a31037SAndrew Lynn 	return sprintf(buf, "%#x\n", value);
1124b4a31037SAndrew Lynn }
1125b4a31037SAndrew Lynn 
1126d6255529SLinus Walleij static ssize_t show_ab9540_dbbrstn(struct device *dev,
1127d6255529SLinus Walleij 				struct device_attribute *attr, char *buf)
1128d6255529SLinus Walleij {
1129d6255529SLinus Walleij 	struct ab8500 *ab8500;
1130d6255529SLinus Walleij 	int ret;
1131d6255529SLinus Walleij 	u8 value;
1132d6255529SLinus Walleij 
1133d6255529SLinus Walleij 	ab8500 = dev_get_drvdata(dev);
1134d6255529SLinus Walleij 
1135d6255529SLinus Walleij 	ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2,
1136d6255529SLinus Walleij 		AB9540_MODEM_CTRL2_REG, &value);
1137d6255529SLinus Walleij 	if (ret < 0)
1138d6255529SLinus Walleij 		return ret;
1139d6255529SLinus Walleij 
1140d6255529SLinus Walleij 	return sprintf(buf, "%d\n",
1141d6255529SLinus Walleij 			(value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0);
1142d6255529SLinus Walleij }
1143d6255529SLinus Walleij 
1144d6255529SLinus Walleij static ssize_t store_ab9540_dbbrstn(struct device *dev,
1145d6255529SLinus Walleij 	struct device_attribute *attr, const char *buf, size_t count)
1146d6255529SLinus Walleij {
1147d6255529SLinus Walleij 	struct ab8500 *ab8500;
1148d6255529SLinus Walleij 	int ret = count;
1149d6255529SLinus Walleij 	int err;
1150d6255529SLinus Walleij 	u8 bitvalues;
1151d6255529SLinus Walleij 
1152d6255529SLinus Walleij 	ab8500 = dev_get_drvdata(dev);
1153d6255529SLinus Walleij 
1154d6255529SLinus Walleij 	if (count > 0) {
1155d6255529SLinus Walleij 		switch (buf[0]) {
1156d6255529SLinus Walleij 		case '0':
1157d6255529SLinus Walleij 			bitvalues = 0;
1158d6255529SLinus Walleij 			break;
1159d6255529SLinus Walleij 		case '1':
1160d6255529SLinus Walleij 			bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT;
1161d6255529SLinus Walleij 			break;
1162d6255529SLinus Walleij 		default:
1163d6255529SLinus Walleij 			goto exit;
1164d6255529SLinus Walleij 		}
1165d6255529SLinus Walleij 
1166d6255529SLinus Walleij 		err = mask_and_set_register_interruptible(ab8500,
1167d6255529SLinus Walleij 			AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG,
1168d6255529SLinus Walleij 			AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues);
1169d6255529SLinus Walleij 		if (err)
1170d6255529SLinus Walleij 			dev_info(ab8500->dev,
1171d6255529SLinus Walleij 				"Failed to set DBBRSTN %c, err %#x\n",
1172d6255529SLinus Walleij 				buf[0], err);
1173d6255529SLinus Walleij 	}
1174d6255529SLinus Walleij 
1175d6255529SLinus Walleij exit:
1176d6255529SLinus Walleij 	return ret;
1177d6255529SLinus Walleij }
1178d6255529SLinus Walleij 
1179cca69b67SMattias Wallin static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
1180e5c238c3SMattias Wallin static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
1181b4a31037SAndrew Lynn static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
1182d6255529SLinus Walleij static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR,
1183d6255529SLinus Walleij 			show_ab9540_dbbrstn, store_ab9540_dbbrstn);
1184cca69b67SMattias Wallin 
1185cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = {
1186cca69b67SMattias Wallin 	&dev_attr_chip_id.attr,
1187e5c238c3SMattias Wallin 	&dev_attr_switch_off_status.attr,
1188b4a31037SAndrew Lynn 	&dev_attr_turn_on_status.attr,
1189cca69b67SMattias Wallin 	NULL,
1190cca69b67SMattias Wallin };
1191cca69b67SMattias Wallin 
1192d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = {
1193d6255529SLinus Walleij 	&dev_attr_chip_id.attr,
1194d6255529SLinus Walleij 	&dev_attr_switch_off_status.attr,
1195d6255529SLinus Walleij 	&dev_attr_turn_on_status.attr,
1196d6255529SLinus Walleij 	&dev_attr_dbbrstn.attr,
1197d6255529SLinus Walleij 	NULL,
1198d6255529SLinus Walleij };
1199d6255529SLinus Walleij 
1200cca69b67SMattias Wallin static struct attribute_group ab8500_attr_group = {
1201cca69b67SMattias Wallin 	.attrs	= ab8500_sysfs_entries,
1202cca69b67SMattias Wallin };
1203cca69b67SMattias Wallin 
1204d6255529SLinus Walleij static struct attribute_group ab9540_attr_group = {
1205d6255529SLinus Walleij 	.attrs	= ab9540_sysfs_entries,
1206d6255529SLinus Walleij };
1207d6255529SLinus Walleij 
1208*d28f1db8SLee Jones static int __devinit ab8500_probe(struct platform_device *pdev)
120962579266SRabin Vincent {
1210*d28f1db8SLee Jones 	struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev);
1211*d28f1db8SLee Jones 	const struct platform_device_id *platid = platform_get_device_id(pdev);
1212*d28f1db8SLee Jones 	enum ab8500_version version = platid->driver_data;
1213*d28f1db8SLee Jones 	struct ab8500 *ab8500;
1214*d28f1db8SLee Jones 	struct resource *resource;
121562579266SRabin Vincent 	int ret;
121662579266SRabin Vincent 	int i;
121747c16975SMattias Wallin 	u8 value;
121862579266SRabin Vincent 
1219*d28f1db8SLee Jones 	ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL);
1220*d28f1db8SLee Jones 	if (!ab8500)
1221*d28f1db8SLee Jones 		return -ENOMEM;
1222*d28f1db8SLee Jones 
122362579266SRabin Vincent 	if (plat)
122462579266SRabin Vincent 		ab8500->irq_base = plat->irq_base;
122562579266SRabin Vincent 
1226*d28f1db8SLee Jones 	ab8500->dev = &pdev->dev;
1227*d28f1db8SLee Jones 
1228*d28f1db8SLee Jones 	resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1229*d28f1db8SLee Jones 	if (!resource) {
1230*d28f1db8SLee Jones 		ret = -ENODEV;
1231*d28f1db8SLee Jones 		goto out_free_ab8500;
1232*d28f1db8SLee Jones 	}
1233*d28f1db8SLee Jones 
1234*d28f1db8SLee Jones 	ab8500->irq = resource->start;
1235*d28f1db8SLee Jones 
1236*d28f1db8SLee Jones 	ab8500->read = ab8500_i2c_read;
1237*d28f1db8SLee Jones 	ab8500->write = ab8500_i2c_write;
1238*d28f1db8SLee Jones 	ab8500->write_masked = ab8500_i2c_write_masked;
1239*d28f1db8SLee Jones 
124062579266SRabin Vincent 	mutex_init(&ab8500->lock);
124162579266SRabin Vincent 	mutex_init(&ab8500->irq_lock);
1242112a80d2SJonas Aaberg 	atomic_set(&ab8500->transfer_ongoing, 0);
124362579266SRabin Vincent 
1244*d28f1db8SLee Jones 	platform_set_drvdata(pdev, ab8500);
1245*d28f1db8SLee Jones 
12460f620837SLinus Walleij 	if (version != AB8500_VERSION_UNDEFINED)
12470f620837SLinus Walleij 		ab8500->version = version;
12480f620837SLinus Walleij 	else {
12490f620837SLinus Walleij 		ret = get_register_interruptible(ab8500, AB8500_MISC,
12500f620837SLinus Walleij 			AB8500_IC_NAME_REG, &value);
12510f620837SLinus Walleij 		if (ret < 0)
1252*d28f1db8SLee Jones 			goto out_free_ab8500;
12530f620837SLinus Walleij 
12540f620837SLinus Walleij 		ab8500->version = value;
12550f620837SLinus Walleij 	}
12560f620837SLinus Walleij 
125747c16975SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_MISC,
125847c16975SMattias Wallin 		AB8500_REV_REG, &value);
125962579266SRabin Vincent 	if (ret < 0)
1260*d28f1db8SLee Jones 		goto out_free_ab8500;
126162579266SRabin Vincent 
126247c16975SMattias Wallin 	ab8500->chip_id = value;
126362579266SRabin Vincent 
12640f620837SLinus Walleij 	dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n",
12650f620837SLinus Walleij 			ab8500_version_str[ab8500->version],
12660f620837SLinus Walleij 			ab8500->chip_id >> 4,
12670f620837SLinus Walleij 			ab8500->chip_id & 0x0F);
12680f620837SLinus Walleij 
1269d6255529SLinus Walleij 	/* Configure AB8500 or AB9540 IRQ */
1270a982362cSBengt Jonsson 	if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
1271d6255529SLinus Walleij 		ab8500->mask_size = AB9540_NUM_IRQ_REGS;
1272d6255529SLinus Walleij 		ab8500->irq_reg_offset = ab9540_irq_regoffset;
1273d6255529SLinus Walleij 	} else {
12742ced445eSLinus Walleij 		ab8500->mask_size = AB8500_NUM_IRQ_REGS;
12752ced445eSLinus Walleij 		ab8500->irq_reg_offset = ab8500_irq_regoffset;
1276d6255529SLinus Walleij 	}
12772ced445eSLinus Walleij 	ab8500->mask = kzalloc(ab8500->mask_size, GFP_KERNEL);
12782ced445eSLinus Walleij 	if (!ab8500->mask)
12792ced445eSLinus Walleij 		return -ENOMEM;
12802ced445eSLinus Walleij 	ab8500->oldmask = kzalloc(ab8500->mask_size, GFP_KERNEL);
12812ced445eSLinus Walleij 	if (!ab8500->oldmask) {
12822ced445eSLinus Walleij 		ret = -ENOMEM;
12832ced445eSLinus Walleij 		goto out_freemask;
12842ced445eSLinus Walleij 	}
1285e5c238c3SMattias Wallin 	/*
1286e5c238c3SMattias Wallin 	 * ab8500 has switched off due to (SWITCH_OFF_STATUS):
1287e5c238c3SMattias Wallin 	 * 0x01 Swoff bit programming
1288e5c238c3SMattias Wallin 	 * 0x02 Thermal protection activation
1289e5c238c3SMattias Wallin 	 * 0x04 Vbat lower then BattOk falling threshold
1290e5c238c3SMattias Wallin 	 * 0x08 Watchdog expired
1291e5c238c3SMattias Wallin 	 * 0x10 Non presence of 32kHz clock
1292e5c238c3SMattias Wallin 	 * 0x20 Battery level lower than power on reset threshold
1293e5c238c3SMattias Wallin 	 * 0x40 Power on key 1 pressed longer than 10 seconds
1294e5c238c3SMattias Wallin 	 * 0x80 DB8500 thermal shutdown
1295e5c238c3SMattias Wallin 	 */
1296e5c238c3SMattias Wallin 
1297e5c238c3SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_RTC,
1298e5c238c3SMattias Wallin 		AB8500_SWITCH_OFF_STATUS, &value);
1299e5c238c3SMattias Wallin 	if (ret < 0)
1300e5c238c3SMattias Wallin 		return ret;
1301e5c238c3SMattias Wallin 	dev_info(ab8500->dev, "switch off status: %#x", value);
1302e5c238c3SMattias Wallin 
130362579266SRabin Vincent 	if (plat && plat->init)
130462579266SRabin Vincent 		plat->init(ab8500);
130562579266SRabin Vincent 
130662579266SRabin Vincent 	/* Clear and mask all interrupts */
13072ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++) {
13080f620837SLinus Walleij 		/*
13090f620837SLinus Walleij 		 * Interrupt register 12 doesn't exist prior to AB8500 version
13100f620837SLinus Walleij 		 * 2.0
13110f620837SLinus Walleij 		 */
13120f620837SLinus Walleij 		if (ab8500->irq_reg_offset[i] == 11 &&
13130f620837SLinus Walleij 				is_ab8500_1p1_or_earlier(ab8500))
131492d50a41SMattias Wallin 			continue;
131562579266SRabin Vincent 
131647c16975SMattias Wallin 		get_register_interruptible(ab8500, AB8500_INTERRUPT,
13172ced445eSLinus Walleij 			AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
131892d50a41SMattias Wallin 			&value);
131947c16975SMattias Wallin 		set_register_interruptible(ab8500, AB8500_INTERRUPT,
13202ced445eSLinus Walleij 			AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff);
132162579266SRabin Vincent 	}
132262579266SRabin Vincent 
132347c16975SMattias Wallin 	ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
132447c16975SMattias Wallin 	if (ret)
13252ced445eSLinus Walleij 		goto out_freeoldmask;
132647c16975SMattias Wallin 
13272ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++)
132862579266SRabin Vincent 		ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
132962579266SRabin Vincent 
133062579266SRabin Vincent 	if (ab8500->irq_base) {
133162579266SRabin Vincent 		ret = ab8500_irq_init(ab8500);
133262579266SRabin Vincent 		if (ret)
13332ced445eSLinus Walleij 			goto out_freeoldmask;
133462579266SRabin Vincent 
13357ccfe9b1SMichel JAOUEN 		/*  Activate this feature only in ab9540 */
13367ccfe9b1SMichel JAOUEN 		/*  till tests are done on ab8500 1p2 or later*/
13377ccfe9b1SMichel JAOUEN 		if (is_ab9540(ab8500))
13387ccfe9b1SMichel JAOUEN 			ret = request_threaded_irq(ab8500->irq, NULL,
13397ccfe9b1SMichel JAOUEN 					ab8500_hierarchical_irq,
13407ccfe9b1SMichel JAOUEN 					IRQF_ONESHOT | IRQF_NO_SUSPEND,
13417ccfe9b1SMichel JAOUEN 					"ab8500", ab8500);
13427ccfe9b1SMichel JAOUEN 		else
13437ccfe9b1SMichel JAOUEN 			ret = request_threaded_irq(ab8500->irq, NULL,
13447ccfe9b1SMichel JAOUEN 					ab8500_irq,
13454f079985SMattias Wallin 					IRQF_ONESHOT | IRQF_NO_SUSPEND,
13464f079985SMattias Wallin 					"ab8500", ab8500);
134762579266SRabin Vincent 		if (ret)
134862579266SRabin Vincent 			goto out_removeirq;
134962579266SRabin Vincent 	}
135062579266SRabin Vincent 
1351d6255529SLinus Walleij 	ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
1352d6255529SLinus Walleij 			      ARRAY_SIZE(abx500_common_devs), NULL,
1353d6255529SLinus Walleij 			      ab8500->irq_base);
1354d6255529SLinus Walleij 
1355d6255529SLinus Walleij 	if (ret)
1356d6255529SLinus Walleij 		goto out_freeirq;
1357d6255529SLinus Walleij 
1358d6255529SLinus Walleij 	if (is_ab9540(ab8500))
1359d6255529SLinus Walleij 		ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
1360d6255529SLinus Walleij 			      ARRAY_SIZE(ab9540_devs), NULL,
1361d6255529SLinus Walleij 			      ab8500->irq_base);
1362d6255529SLinus Walleij 	else
1363549931f9SSundar R Iyer 		ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
136444f72e53SVirupax Sadashivpetimath 			      ARRAY_SIZE(ab8500_devs), NULL,
136562579266SRabin Vincent 			      ab8500->irq_base);
136644f72e53SVirupax Sadashivpetimath 
136744f72e53SVirupax Sadashivpetimath 	if (is_ab9540(ab8500) || is_ab8505(ab8500))
136844f72e53SVirupax Sadashivpetimath 		ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs,
136944f72e53SVirupax Sadashivpetimath 			      ARRAY_SIZE(ab9540_ab8505_devs), NULL,
137044f72e53SVirupax Sadashivpetimath 			      ab8500->irq_base);
137144f72e53SVirupax Sadashivpetimath 
137262579266SRabin Vincent 	if (ret)
137362579266SRabin Vincent 		goto out_freeirq;
137462579266SRabin Vincent 
13756ef9418cSRickard Andersson 	if (!no_bm) {
13766ef9418cSRickard Andersson 		/* Add battery management devices */
13776ef9418cSRickard Andersson 		ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
13786ef9418cSRickard Andersson 				      ARRAY_SIZE(ab8500_bm_devs), NULL,
13796ef9418cSRickard Andersson 				      ab8500->irq_base);
13806ef9418cSRickard Andersson 		if (ret)
13816ef9418cSRickard Andersson 			dev_err(ab8500->dev, "error adding bm devices\n");
13826ef9418cSRickard Andersson 	}
13836ef9418cSRickard Andersson 
1384d6255529SLinus Walleij 	if (is_ab9540(ab8500))
1385d6255529SLinus Walleij 		ret = sysfs_create_group(&ab8500->dev->kobj,
1386d6255529SLinus Walleij 					&ab9540_attr_group);
1387d6255529SLinus Walleij 	else
1388d6255529SLinus Walleij 		ret = sysfs_create_group(&ab8500->dev->kobj,
1389d6255529SLinus Walleij 					&ab8500_attr_group);
1390cca69b67SMattias Wallin 	if (ret)
1391cca69b67SMattias Wallin 		dev_err(ab8500->dev, "error creating sysfs entries\n");
1392d6255529SLinus Walleij 	else
139362579266SRabin Vincent 		return ret;
139462579266SRabin Vincent 
139562579266SRabin Vincent out_freeirq:
13966d95b7fdSLinus Walleij 	if (ab8500->irq_base)
139762579266SRabin Vincent 		free_irq(ab8500->irq, ab8500);
139862579266SRabin Vincent out_removeirq:
13996d95b7fdSLinus Walleij 	if (ab8500->irq_base)
140062579266SRabin Vincent 		ab8500_irq_remove(ab8500);
14012ced445eSLinus Walleij out_freeoldmask:
14022ced445eSLinus Walleij 	kfree(ab8500->oldmask);
14032ced445eSLinus Walleij out_freemask:
14042ced445eSLinus Walleij 	kfree(ab8500->mask);
1405*d28f1db8SLee Jones out_free_ab8500:
1406*d28f1db8SLee Jones 	kfree(ab8500);
14076d95b7fdSLinus Walleij 
140862579266SRabin Vincent 	return ret;
140962579266SRabin Vincent }
141062579266SRabin Vincent 
1411*d28f1db8SLee Jones static int __devexit ab8500_remove(struct platform_device *pdev)
141262579266SRabin Vincent {
1413*d28f1db8SLee Jones 	struct ab8500 *ab8500 = platform_get_drvdata(pdev);
1414*d28f1db8SLee Jones 
1415d6255529SLinus Walleij 	if (is_ab9540(ab8500))
1416d6255529SLinus Walleij 		sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
1417d6255529SLinus Walleij 	else
1418cca69b67SMattias Wallin 		sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
141962579266SRabin Vincent 	mfd_remove_devices(ab8500->dev);
142062579266SRabin Vincent 	if (ab8500->irq_base) {
142162579266SRabin Vincent 		free_irq(ab8500->irq, ab8500);
142262579266SRabin Vincent 		ab8500_irq_remove(ab8500);
142362579266SRabin Vincent 	}
14242ced445eSLinus Walleij 	kfree(ab8500->oldmask);
14252ced445eSLinus Walleij 	kfree(ab8500->mask);
1426*d28f1db8SLee Jones 	kfree(ab8500);
142762579266SRabin Vincent 
142862579266SRabin Vincent 	return 0;
142962579266SRabin Vincent }
143062579266SRabin Vincent 
1431*d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = {
1432*d28f1db8SLee Jones 	{ "ab8500-core", AB8500_VERSION_AB8500 },
1433*d28f1db8SLee Jones 	{ "ab8505-i2c", AB8500_VERSION_AB8505 },
1434*d28f1db8SLee Jones 	{ "ab9540-i2c", AB8500_VERSION_AB9540 },
1435*d28f1db8SLee Jones 	{ "ab8540-i2c", AB8500_VERSION_AB8540 },
1436*d28f1db8SLee Jones 	{ }
1437*d28f1db8SLee Jones };
1438*d28f1db8SLee Jones 
1439*d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = {
1440*d28f1db8SLee Jones 	.driver = {
1441*d28f1db8SLee Jones 		.name = "ab8500-core",
1442*d28f1db8SLee Jones 		.owner = THIS_MODULE,
1443*d28f1db8SLee Jones 	},
1444*d28f1db8SLee Jones 	.probe	= ab8500_probe,
1445*d28f1db8SLee Jones 	.remove	= __devexit_p(ab8500_remove),
1446*d28f1db8SLee Jones 	.id_table = ab8500_id,
1447*d28f1db8SLee Jones };
1448*d28f1db8SLee Jones 
1449*d28f1db8SLee Jones static int __init ab8500_core_init(void)
1450*d28f1db8SLee Jones {
1451*d28f1db8SLee Jones 	return platform_driver_register(&ab8500_core_driver);
1452*d28f1db8SLee Jones }
1453*d28f1db8SLee Jones 
1454*d28f1db8SLee Jones static void __exit ab8500_core_exit(void)
1455*d28f1db8SLee Jones {
1456*d28f1db8SLee Jones 	platform_driver_unregister(&ab8500_core_driver);
1457*d28f1db8SLee Jones }
1458*d28f1db8SLee Jones arch_initcall(ab8500_core_init);
1459*d28f1db8SLee Jones module_exit(ab8500_core_exit);
1460*d28f1db8SLee Jones 
1461adceed62SMattias Wallin MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent");
146262579266SRabin Vincent MODULE_DESCRIPTION("AB8500 MFD core");
146362579266SRabin Vincent MODULE_LICENSE("GPL v2");
1464