xref: /openbmc/linux/drivers/mfd/ab8500-core.c (revision f04a9d8a)
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>
2200441b5eSLee Jones #include <linux/mfd/abx500/ab8500-bm.h>
23d28f1db8SLee Jones #include <linux/mfd/dbx500-prcmu.h>
24549931f9SSundar R Iyer #include <linux/regulator/ab8500.h>
256bc4a568SLee Jones #include <linux/of.h>
266bc4a568SLee Jones #include <linux/of_device.h>
2762579266SRabin Vincent 
2862579266SRabin Vincent /*
2962579266SRabin Vincent  * Interrupt register offsets
3062579266SRabin Vincent  * Bank : 0x0E
3162579266SRabin Vincent  */
3247c16975SMattias Wallin #define AB8500_IT_SOURCE1_REG		0x00
3347c16975SMattias Wallin #define AB8500_IT_SOURCE2_REG		0x01
3447c16975SMattias Wallin #define AB8500_IT_SOURCE3_REG		0x02
3547c16975SMattias Wallin #define AB8500_IT_SOURCE4_REG		0x03
3647c16975SMattias Wallin #define AB8500_IT_SOURCE5_REG		0x04
3747c16975SMattias Wallin #define AB8500_IT_SOURCE6_REG		0x05
3847c16975SMattias Wallin #define AB8500_IT_SOURCE7_REG		0x06
3947c16975SMattias Wallin #define AB8500_IT_SOURCE8_REG		0x07
40d6255529SLinus Walleij #define AB9540_IT_SOURCE13_REG		0x0C
4147c16975SMattias Wallin #define AB8500_IT_SOURCE19_REG		0x12
4247c16975SMattias Wallin #define AB8500_IT_SOURCE20_REG		0x13
4347c16975SMattias Wallin #define AB8500_IT_SOURCE21_REG		0x14
4447c16975SMattias Wallin #define AB8500_IT_SOURCE22_REG		0x15
4547c16975SMattias Wallin #define AB8500_IT_SOURCE23_REG		0x16
4647c16975SMattias Wallin #define AB8500_IT_SOURCE24_REG		0x17
4762579266SRabin Vincent 
4862579266SRabin Vincent /*
4962579266SRabin Vincent  * latch registers
5062579266SRabin Vincent  */
5147c16975SMattias Wallin #define AB8500_IT_LATCH1_REG		0x20
5247c16975SMattias Wallin #define AB8500_IT_LATCH2_REG		0x21
5347c16975SMattias Wallin #define AB8500_IT_LATCH3_REG		0x22
5447c16975SMattias Wallin #define AB8500_IT_LATCH4_REG		0x23
5547c16975SMattias Wallin #define AB8500_IT_LATCH5_REG		0x24
5647c16975SMattias Wallin #define AB8500_IT_LATCH6_REG		0x25
5747c16975SMattias Wallin #define AB8500_IT_LATCH7_REG		0x26
5847c16975SMattias Wallin #define AB8500_IT_LATCH8_REG		0x27
5947c16975SMattias Wallin #define AB8500_IT_LATCH9_REG		0x28
6047c16975SMattias Wallin #define AB8500_IT_LATCH10_REG		0x29
6192d50a41SMattias Wallin #define AB8500_IT_LATCH12_REG		0x2B
62d6255529SLinus Walleij #define AB9540_IT_LATCH13_REG		0x2C
6347c16975SMattias Wallin #define AB8500_IT_LATCH19_REG		0x32
6447c16975SMattias Wallin #define AB8500_IT_LATCH20_REG		0x33
6547c16975SMattias Wallin #define AB8500_IT_LATCH21_REG		0x34
6647c16975SMattias Wallin #define AB8500_IT_LATCH22_REG		0x35
6747c16975SMattias Wallin #define AB8500_IT_LATCH23_REG		0x36
6847c16975SMattias Wallin #define AB8500_IT_LATCH24_REG		0x37
6962579266SRabin Vincent 
7062579266SRabin Vincent /*
7162579266SRabin Vincent  * mask registers
7262579266SRabin Vincent  */
7362579266SRabin Vincent 
7447c16975SMattias Wallin #define AB8500_IT_MASK1_REG		0x40
7547c16975SMattias Wallin #define AB8500_IT_MASK2_REG		0x41
7647c16975SMattias Wallin #define AB8500_IT_MASK3_REG		0x42
7747c16975SMattias Wallin #define AB8500_IT_MASK4_REG		0x43
7847c16975SMattias Wallin #define AB8500_IT_MASK5_REG		0x44
7947c16975SMattias Wallin #define AB8500_IT_MASK6_REG		0x45
8047c16975SMattias Wallin #define AB8500_IT_MASK7_REG		0x46
8147c16975SMattias Wallin #define AB8500_IT_MASK8_REG		0x47
8247c16975SMattias Wallin #define AB8500_IT_MASK9_REG		0x48
8347c16975SMattias Wallin #define AB8500_IT_MASK10_REG		0x49
8447c16975SMattias Wallin #define AB8500_IT_MASK11_REG		0x4A
8547c16975SMattias Wallin #define AB8500_IT_MASK12_REG		0x4B
8647c16975SMattias Wallin #define AB8500_IT_MASK13_REG		0x4C
8747c16975SMattias Wallin #define AB8500_IT_MASK14_REG		0x4D
8847c16975SMattias Wallin #define AB8500_IT_MASK15_REG		0x4E
8947c16975SMattias Wallin #define AB8500_IT_MASK16_REG		0x4F
9047c16975SMattias Wallin #define AB8500_IT_MASK17_REG		0x50
9147c16975SMattias Wallin #define AB8500_IT_MASK18_REG		0x51
9247c16975SMattias Wallin #define AB8500_IT_MASK19_REG		0x52
9347c16975SMattias Wallin #define AB8500_IT_MASK20_REG		0x53
9447c16975SMattias Wallin #define AB8500_IT_MASK21_REG		0x54
9547c16975SMattias Wallin #define AB8500_IT_MASK22_REG		0x55
9647c16975SMattias Wallin #define AB8500_IT_MASK23_REG		0x56
9747c16975SMattias Wallin #define AB8500_IT_MASK24_REG		0x57
9862579266SRabin Vincent 
997ccfe9b1SMichel JAOUEN /*
1007ccfe9b1SMichel JAOUEN  * latch hierarchy registers
1017ccfe9b1SMichel JAOUEN  */
1027ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER1_REG	0x60
1037ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER2_REG	0x61
1047ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER3_REG	0x62
1057ccfe9b1SMichel JAOUEN 
1067ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER_NUM		3
1077ccfe9b1SMichel JAOUEN 
10847c16975SMattias Wallin #define AB8500_REV_REG			0x80
1090f620837SLinus Walleij #define AB8500_IC_NAME_REG		0x82
110e5c238c3SMattias Wallin #define AB8500_SWITCH_OFF_STATUS	0x00
11162579266SRabin Vincent 
112b4a31037SAndrew Lynn #define AB8500_TURN_ON_STATUS		0x00
113b4a31037SAndrew Lynn 
114f04a9d8aSRajkumar Kasirajan #define AB8500_CH_USBCH_STAT1_REG	0x02
115f04a9d8aSRajkumar Kasirajan #define VBUS_DET_DBNC100		0x02
116f04a9d8aSRajkumar Kasirajan #define VBUS_DET_DBNC1			0x01
117f04a9d8aSRajkumar Kasirajan 
118f04a9d8aSRajkumar Kasirajan static DEFINE_SPINLOCK(on_stat_lock);
119f04a9d8aSRajkumar Kasirajan static u8 turn_on_stat_mask = 0xFF;
120f04a9d8aSRajkumar Kasirajan static u8 turn_on_stat_set;
1216ef9418cSRickard Andersson static bool no_bm; /* No battery management */
1226ef9418cSRickard Andersson module_param(no_bm, bool, S_IRUGO);
1236ef9418cSRickard Andersson 
124d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_REG			0x23
125d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT	BIT(2)
126d6255529SLinus Walleij 
12762579266SRabin Vincent /*
12862579266SRabin Vincent  * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
1292ced445eSLinus Walleij  * numbers are indexed into this array with (num / 8). The interupts are
1302ced445eSLinus Walleij  * defined in linux/mfd/ab8500.h
13162579266SRabin Vincent  *
13262579266SRabin Vincent  * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
13362579266SRabin Vincent  * offset 0.
13462579266SRabin Vincent  */
1352ced445eSLinus Walleij /* AB8500 support */
13662579266SRabin Vincent static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
13792d50a41SMattias Wallin 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
13862579266SRabin Vincent };
13962579266SRabin Vincent 
140d6255529SLinus Walleij /* AB9540 support */
141d6255529SLinus Walleij static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
142d6255529SLinus Walleij 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24,
143d6255529SLinus Walleij };
144d6255529SLinus Walleij 
1450f620837SLinus Walleij static const char ab8500_version_str[][7] = {
1460f620837SLinus Walleij 	[AB8500_VERSION_AB8500] = "AB8500",
1470f620837SLinus Walleij 	[AB8500_VERSION_AB8505] = "AB8505",
1480f620837SLinus Walleij 	[AB8500_VERSION_AB9540] = "AB9540",
1490f620837SLinus Walleij 	[AB8500_VERSION_AB8540] = "AB8540",
1500f620837SLinus Walleij };
1510f620837SLinus Walleij 
152822672a7SLee Jones static int ab8500_prcmu_write(struct ab8500 *ab8500, u16 addr, u8 data)
153d28f1db8SLee Jones {
154d28f1db8SLee Jones 	int ret;
155d28f1db8SLee Jones 
156d28f1db8SLee Jones 	ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
157d28f1db8SLee Jones 	if (ret < 0)
158d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
159d28f1db8SLee Jones 	return ret;
160d28f1db8SLee Jones }
161d28f1db8SLee Jones 
162822672a7SLee Jones static int ab8500_prcmu_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
163d28f1db8SLee Jones 	u8 data)
164d28f1db8SLee Jones {
165d28f1db8SLee Jones 	int ret;
166d28f1db8SLee Jones 
167d28f1db8SLee Jones 	ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data,
168d28f1db8SLee Jones 		&mask, 1);
169d28f1db8SLee Jones 	if (ret < 0)
170d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
171d28f1db8SLee Jones 	return ret;
172d28f1db8SLee Jones }
173d28f1db8SLee Jones 
174822672a7SLee Jones static int ab8500_prcmu_read(struct ab8500 *ab8500, u16 addr)
175d28f1db8SLee Jones {
176d28f1db8SLee Jones 	int ret;
177d28f1db8SLee Jones 	u8 data;
178d28f1db8SLee Jones 
179d28f1db8SLee Jones 	ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
180d28f1db8SLee Jones 	if (ret < 0) {
181d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
182d28f1db8SLee Jones 		return ret;
183d28f1db8SLee Jones 	}
184d28f1db8SLee Jones 	return (int)data;
185d28f1db8SLee Jones }
186d28f1db8SLee Jones 
18747c16975SMattias Wallin static int ab8500_get_chip_id(struct device *dev)
18847c16975SMattias Wallin {
1896bce7bf1SMattias Wallin 	struct ab8500 *ab8500;
1906bce7bf1SMattias Wallin 
1916bce7bf1SMattias Wallin 	if (!dev)
1926bce7bf1SMattias Wallin 		return -EINVAL;
1936bce7bf1SMattias Wallin 	ab8500 = dev_get_drvdata(dev->parent);
1946bce7bf1SMattias Wallin 	return ab8500 ? (int)ab8500->chip_id : -EINVAL;
19547c16975SMattias Wallin }
19647c16975SMattias Wallin 
19747c16975SMattias Wallin static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
19847c16975SMattias Wallin 	u8 reg, u8 data)
19962579266SRabin Vincent {
20062579266SRabin Vincent 	int ret;
20147c16975SMattias Wallin 	/*
20247c16975SMattias Wallin 	 * Put the u8 bank and u8 register together into a an u16.
20347c16975SMattias Wallin 	 * The bank on higher 8 bits and register in lower 8 bits.
20447c16975SMattias Wallin 	 * */
20547c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
20662579266SRabin Vincent 
20762579266SRabin Vincent 	dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
20862579266SRabin Vincent 
209392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
21047c16975SMattias Wallin 
21147c16975SMattias Wallin 	ret = ab8500->write(ab8500, addr, data);
21247c16975SMattias Wallin 	if (ret < 0)
21347c16975SMattias Wallin 		dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
21447c16975SMattias Wallin 			addr, ret);
21547c16975SMattias Wallin 	mutex_unlock(&ab8500->lock);
21647c16975SMattias Wallin 
21747c16975SMattias Wallin 	return ret;
21847c16975SMattias Wallin }
21947c16975SMattias Wallin 
22047c16975SMattias Wallin static int ab8500_set_register(struct device *dev, u8 bank,
22147c16975SMattias Wallin 	u8 reg, u8 value)
22247c16975SMattias Wallin {
223112a80d2SJonas Aaberg 	int ret;
22447c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
22547c16975SMattias Wallin 
226112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
227112a80d2SJonas Aaberg 	ret = set_register_interruptible(ab8500, bank, reg, value);
228112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
229112a80d2SJonas Aaberg 	return ret;
23047c16975SMattias Wallin }
23147c16975SMattias Wallin 
23247c16975SMattias Wallin static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
23347c16975SMattias Wallin 	u8 reg, u8 *value)
23447c16975SMattias Wallin {
23547c16975SMattias Wallin 	int ret;
23647c16975SMattias Wallin 	/* put the u8 bank and u8 reg together into a an u16.
23747c16975SMattias Wallin 	 * bank on higher 8 bits and reg in lower */
23847c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
23947c16975SMattias Wallin 
240392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
24147c16975SMattias Wallin 
24247c16975SMattias Wallin 	ret = ab8500->read(ab8500, addr);
24347c16975SMattias Wallin 	if (ret < 0)
24447c16975SMattias Wallin 		dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
24547c16975SMattias Wallin 			addr, ret);
24647c16975SMattias Wallin 	else
24747c16975SMattias Wallin 		*value = ret;
24847c16975SMattias Wallin 
24947c16975SMattias Wallin 	mutex_unlock(&ab8500->lock);
25047c16975SMattias Wallin 	dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret);
25147c16975SMattias Wallin 
25247c16975SMattias Wallin 	return ret;
25347c16975SMattias Wallin }
25447c16975SMattias Wallin 
25547c16975SMattias Wallin static int ab8500_get_register(struct device *dev, u8 bank,
25647c16975SMattias Wallin 	u8 reg, u8 *value)
25747c16975SMattias Wallin {
258112a80d2SJonas Aaberg 	int ret;
25947c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
26047c16975SMattias Wallin 
261112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
262112a80d2SJonas Aaberg 	ret = get_register_interruptible(ab8500, bank, reg, value);
263112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
264112a80d2SJonas Aaberg 	return ret;
26547c16975SMattias Wallin }
26647c16975SMattias Wallin 
26747c16975SMattias Wallin static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
26847c16975SMattias Wallin 	u8 reg, u8 bitmask, u8 bitvalues)
26947c16975SMattias Wallin {
27047c16975SMattias Wallin 	int ret;
27147c16975SMattias Wallin 	/* put the u8 bank and u8 reg together into a an u16.
27247c16975SMattias Wallin 	 * bank on higher 8 bits and reg in lower */
27347c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
27447c16975SMattias Wallin 
275392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
27647c16975SMattias Wallin 
277bc628fd1SMattias Nilsson 	if (ab8500->write_masked == NULL) {
278bc628fd1SMattias Nilsson 		u8 data;
279bc628fd1SMattias Nilsson 
28047c16975SMattias Wallin 		ret = ab8500->read(ab8500, addr);
28147c16975SMattias Wallin 		if (ret < 0) {
28247c16975SMattias Wallin 			dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
28347c16975SMattias Wallin 				addr, ret);
28447c16975SMattias Wallin 			goto out;
28547c16975SMattias Wallin 		}
28647c16975SMattias Wallin 
28747c16975SMattias Wallin 		data = (u8)ret;
28847c16975SMattias Wallin 		data = (~bitmask & data) | (bitmask & bitvalues);
28947c16975SMattias Wallin 
29062579266SRabin Vincent 		ret = ab8500->write(ab8500, addr, data);
29162579266SRabin Vincent 		if (ret < 0)
29262579266SRabin Vincent 			dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
29362579266SRabin Vincent 				addr, ret);
29462579266SRabin Vincent 
295bc628fd1SMattias Nilsson 		dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr,
296bc628fd1SMattias Nilsson 			data);
297bc628fd1SMattias Nilsson 		goto out;
298bc628fd1SMattias Nilsson 	}
299bc628fd1SMattias Nilsson 	ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues);
300bc628fd1SMattias Nilsson 	if (ret < 0)
301bc628fd1SMattias Nilsson 		dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr,
302bc628fd1SMattias Nilsson 			ret);
30362579266SRabin Vincent out:
30462579266SRabin Vincent 	mutex_unlock(&ab8500->lock);
30562579266SRabin Vincent 	return ret;
30662579266SRabin Vincent }
30747c16975SMattias Wallin 
30847c16975SMattias Wallin static int ab8500_mask_and_set_register(struct device *dev,
30947c16975SMattias Wallin 	u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
31047c16975SMattias Wallin {
311112a80d2SJonas Aaberg 	int ret;
31247c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
31347c16975SMattias Wallin 
314112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
315112a80d2SJonas Aaberg 	ret= mask_and_set_register_interruptible(ab8500, bank, reg,
31647c16975SMattias Wallin 						 bitmask, bitvalues);
317112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
318112a80d2SJonas Aaberg 	return ret;
31947c16975SMattias Wallin }
32047c16975SMattias Wallin 
32147c16975SMattias Wallin static struct abx500_ops ab8500_ops = {
32247c16975SMattias Wallin 	.get_chip_id = ab8500_get_chip_id,
32347c16975SMattias Wallin 	.get_register = ab8500_get_register,
32447c16975SMattias Wallin 	.set_register = ab8500_set_register,
32547c16975SMattias Wallin 	.get_register_page = NULL,
32647c16975SMattias Wallin 	.set_register_page = NULL,
32747c16975SMattias Wallin 	.mask_and_set_register = ab8500_mask_and_set_register,
32847c16975SMattias Wallin 	.event_registers_startup_state_get = NULL,
32947c16975SMattias Wallin 	.startup_irq_enabled = NULL,
3301d843a6cSMian Yousaf Kaukab 	.dump_all_banks = ab8500_dump_all_banks,
33147c16975SMattias Wallin };
33262579266SRabin Vincent 
3339505a0a0SMark Brown static void ab8500_irq_lock(struct irq_data *data)
33462579266SRabin Vincent {
3359505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
33662579266SRabin Vincent 
33762579266SRabin Vincent 	mutex_lock(&ab8500->irq_lock);
338112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
33962579266SRabin Vincent }
34062579266SRabin Vincent 
3419505a0a0SMark Brown static void ab8500_irq_sync_unlock(struct irq_data *data)
34262579266SRabin Vincent {
3439505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
34462579266SRabin Vincent 	int i;
34562579266SRabin Vincent 
3462ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++) {
34762579266SRabin Vincent 		u8 old = ab8500->oldmask[i];
34862579266SRabin Vincent 		u8 new = ab8500->mask[i];
34962579266SRabin Vincent 		int reg;
35062579266SRabin Vincent 
35162579266SRabin Vincent 		if (new == old)
35262579266SRabin Vincent 			continue;
35362579266SRabin Vincent 
3540f620837SLinus Walleij 		/*
3550f620837SLinus Walleij 		 * Interrupt register 12 doesn't exist prior to AB8500 version
3560f620837SLinus Walleij 		 * 2.0
3570f620837SLinus Walleij 		 */
3580f620837SLinus Walleij 		if (ab8500->irq_reg_offset[i] == 11 &&
3590f620837SLinus Walleij 			is_ab8500_1p1_or_earlier(ab8500))
36092d50a41SMattias Wallin 			continue;
36192d50a41SMattias Wallin 
36262579266SRabin Vincent 		ab8500->oldmask[i] = new;
36362579266SRabin Vincent 
3642ced445eSLinus Walleij 		reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
36547c16975SMattias Wallin 		set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
36662579266SRabin Vincent 	}
367112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
36862579266SRabin Vincent 	mutex_unlock(&ab8500->irq_lock);
36962579266SRabin Vincent }
37062579266SRabin Vincent 
3719505a0a0SMark Brown static void ab8500_irq_mask(struct irq_data *data)
37262579266SRabin Vincent {
3739505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
37406e589efSLee Jones 	int offset = data->hwirq;
37562579266SRabin Vincent 	int index = offset / 8;
37662579266SRabin Vincent 	int mask = 1 << (offset % 8);
37762579266SRabin Vincent 
37862579266SRabin Vincent 	ab8500->mask[index] |= mask;
3799c677b9bSLee Jones 
3809c677b9bSLee Jones 	/* The AB8500 GPIOs have two interrupts each (rising & falling). */
3819c677b9bSLee Jones 	if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
3829c677b9bSLee Jones 		ab8500->mask[index + 2] |= mask;
3839c677b9bSLee Jones 	if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R)
3849c677b9bSLee Jones 		ab8500->mask[index + 1] |= mask;
3859c677b9bSLee Jones 	if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R)
386e2ddf46aSLinus Walleij 		/* Here the falling IRQ is one bit lower */
387e2ddf46aSLinus Walleij 		ab8500->mask[index] |= (mask << 1);
38862579266SRabin Vincent }
38962579266SRabin Vincent 
3909505a0a0SMark Brown static void ab8500_irq_unmask(struct irq_data *data)
39162579266SRabin Vincent {
3929505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
3939c677b9bSLee Jones 	unsigned int type = irqd_get_trigger_type(data);
39406e589efSLee Jones 	int offset = data->hwirq;
39562579266SRabin Vincent 	int index = offset / 8;
39662579266SRabin Vincent 	int mask = 1 << (offset % 8);
39762579266SRabin Vincent 
3989c677b9bSLee Jones 	if (type & IRQ_TYPE_EDGE_RISING)
39962579266SRabin Vincent 		ab8500->mask[index] &= ~mask;
4009c677b9bSLee Jones 
4019c677b9bSLee Jones 	/* The AB8500 GPIOs have two interrupts each (rising & falling). */
4029c677b9bSLee Jones 	if (type & IRQ_TYPE_EDGE_FALLING) {
4039c677b9bSLee Jones 		if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
4049c677b9bSLee Jones 			ab8500->mask[index + 2] &= ~mask;
4059c677b9bSLee Jones 		else if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R)
4069c677b9bSLee Jones 			ab8500->mask[index + 1] &= ~mask;
4079c677b9bSLee Jones 		else if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R)
408e2ddf46aSLinus Walleij 			/* Here the falling IRQ is one bit lower */
409e2ddf46aSLinus Walleij 			ab8500->mask[index] &= ~(mask << 1);
4109c677b9bSLee Jones 		else
4119c677b9bSLee Jones 			ab8500->mask[index] &= ~mask;
412e2ddf46aSLinus Walleij 	} else {
4139c677b9bSLee Jones 		/* Satisfies the case where type is not set. */
41462579266SRabin Vincent 		ab8500->mask[index] &= ~mask;
41562579266SRabin Vincent 	}
416e2ddf46aSLinus Walleij }
41762579266SRabin Vincent 
41840f6e5a2SLee Jones static int ab8500_irq_set_type(struct irq_data *data, unsigned int type)
41940f6e5a2SLee Jones {
42040f6e5a2SLee Jones 	return 0;
42162579266SRabin Vincent }
42262579266SRabin Vincent 
42362579266SRabin Vincent static struct irq_chip ab8500_irq_chip = {
42462579266SRabin Vincent 	.name			= "ab8500",
4259505a0a0SMark Brown 	.irq_bus_lock		= ab8500_irq_lock,
4269505a0a0SMark Brown 	.irq_bus_sync_unlock	= ab8500_irq_sync_unlock,
4279505a0a0SMark Brown 	.irq_mask		= ab8500_irq_mask,
428e6f9306eSVirupax Sadashivpetimath 	.irq_disable		= ab8500_irq_mask,
4299505a0a0SMark Brown 	.irq_unmask		= ab8500_irq_unmask,
43040f6e5a2SLee Jones 	.irq_set_type		= ab8500_irq_set_type,
43162579266SRabin Vincent };
43262579266SRabin Vincent 
4337ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
4347ccfe9b1SMichel JAOUEN 					int latch_offset, u8 latch_val)
4357ccfe9b1SMichel JAOUEN {
4367ccfe9b1SMichel JAOUEN 	int int_bit = __ffs(latch_val);
4377ccfe9b1SMichel JAOUEN 	int line, i;
4387ccfe9b1SMichel JAOUEN 
4397ccfe9b1SMichel JAOUEN 	do {
4407ccfe9b1SMichel JAOUEN 		int_bit = __ffs(latch_val);
4417ccfe9b1SMichel JAOUEN 
4427ccfe9b1SMichel JAOUEN 		for (i = 0; i < ab8500->mask_size; i++)
4437ccfe9b1SMichel JAOUEN 			if (ab8500->irq_reg_offset[i] == latch_offset)
4447ccfe9b1SMichel JAOUEN 				break;
4457ccfe9b1SMichel JAOUEN 
4467ccfe9b1SMichel JAOUEN 		if (i >= ab8500->mask_size) {
4477ccfe9b1SMichel JAOUEN 			dev_err(ab8500->dev, "Register offset 0x%2x not declared\n",
4487ccfe9b1SMichel JAOUEN 					latch_offset);
4497ccfe9b1SMichel JAOUEN 			return -ENXIO;
4507ccfe9b1SMichel JAOUEN 		}
4517ccfe9b1SMichel JAOUEN 
4527ccfe9b1SMichel JAOUEN 		line = (i << 3) + int_bit;
4537ccfe9b1SMichel JAOUEN 		latch_val &= ~(1 << int_bit);
4547ccfe9b1SMichel JAOUEN 
455e2ddf46aSLinus Walleij 		/*
456e2ddf46aSLinus Walleij 		 * This handles the falling edge hwirqs from the GPIO
457e2ddf46aSLinus Walleij 		 * lines. Route them back to the line registered for the
458e2ddf46aSLinus Walleij 		 * rising IRQ, as this is merely a flag for the same IRQ
459e2ddf46aSLinus Walleij 		 * in linux terms.
460e2ddf46aSLinus Walleij 		 */
461e2ddf46aSLinus Walleij 		if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F)
462e2ddf46aSLinus Walleij 			line -= 16;
463e2ddf46aSLinus Walleij 		if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F)
464e2ddf46aSLinus Walleij 			line -= 8;
465e2ddf46aSLinus Walleij 		if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F)
466e2ddf46aSLinus Walleij 			line += 1;
467e2ddf46aSLinus Walleij 
4687ccfe9b1SMichel JAOUEN 		handle_nested_irq(ab8500->irq_base + line);
4697ccfe9b1SMichel JAOUEN 	} while (latch_val);
4707ccfe9b1SMichel JAOUEN 
4717ccfe9b1SMichel JAOUEN 	return 0;
4727ccfe9b1SMichel JAOUEN }
4737ccfe9b1SMichel JAOUEN 
4747ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500,
4757ccfe9b1SMichel JAOUEN 					int hier_offset, u8 hier_val)
4767ccfe9b1SMichel JAOUEN {
4777ccfe9b1SMichel JAOUEN 	int latch_bit, status;
4787ccfe9b1SMichel JAOUEN 	u8 latch_offset, latch_val;
4797ccfe9b1SMichel JAOUEN 
4807ccfe9b1SMichel JAOUEN 	do {
4817ccfe9b1SMichel JAOUEN 		latch_bit = __ffs(hier_val);
4827ccfe9b1SMichel JAOUEN 		latch_offset = (hier_offset << 3) + latch_bit;
4837ccfe9b1SMichel JAOUEN 
4847ccfe9b1SMichel JAOUEN 		/* Fix inconsistent ITFromLatch25 bit mapping... */
4857ccfe9b1SMichel JAOUEN 		if (unlikely(latch_offset == 17))
4867ccfe9b1SMichel JAOUEN 			latch_offset = 24;
4877ccfe9b1SMichel JAOUEN 
4887ccfe9b1SMichel JAOUEN 		status = get_register_interruptible(ab8500,
4897ccfe9b1SMichel JAOUEN 				AB8500_INTERRUPT,
4907ccfe9b1SMichel JAOUEN 				AB8500_IT_LATCH1_REG + latch_offset,
4917ccfe9b1SMichel JAOUEN 				&latch_val);
4927ccfe9b1SMichel JAOUEN 		if (status < 0 || latch_val == 0)
4937ccfe9b1SMichel JAOUEN 			goto discard;
4947ccfe9b1SMichel JAOUEN 
4957ccfe9b1SMichel JAOUEN 		status = ab8500_handle_hierarchical_line(ab8500,
4967ccfe9b1SMichel JAOUEN 				latch_offset, latch_val);
4977ccfe9b1SMichel JAOUEN 		if (status < 0)
4987ccfe9b1SMichel JAOUEN 			return status;
4997ccfe9b1SMichel JAOUEN discard:
5007ccfe9b1SMichel JAOUEN 		hier_val &= ~(1 << latch_bit);
5017ccfe9b1SMichel JAOUEN 	} while (hier_val);
5027ccfe9b1SMichel JAOUEN 
5037ccfe9b1SMichel JAOUEN 	return 0;
5047ccfe9b1SMichel JAOUEN }
5057ccfe9b1SMichel JAOUEN 
5067ccfe9b1SMichel JAOUEN static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev)
5077ccfe9b1SMichel JAOUEN {
5087ccfe9b1SMichel JAOUEN 	struct ab8500 *ab8500 = dev;
5097ccfe9b1SMichel JAOUEN 	u8 i;
5107ccfe9b1SMichel JAOUEN 
5117ccfe9b1SMichel JAOUEN 	dev_vdbg(ab8500->dev, "interrupt\n");
5127ccfe9b1SMichel JAOUEN 
5137ccfe9b1SMichel JAOUEN 	/*  Hierarchical interrupt version */
5147ccfe9b1SMichel JAOUEN 	for (i = 0; i < AB8500_IT_LATCHHIER_NUM; i++) {
5157ccfe9b1SMichel JAOUEN 		int status;
5167ccfe9b1SMichel JAOUEN 		u8 hier_val;
5177ccfe9b1SMichel JAOUEN 
5187ccfe9b1SMichel JAOUEN 		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
5197ccfe9b1SMichel JAOUEN 			AB8500_IT_LATCHHIER1_REG + i, &hier_val);
5207ccfe9b1SMichel JAOUEN 		if (status < 0 || hier_val == 0)
5217ccfe9b1SMichel JAOUEN 			continue;
5227ccfe9b1SMichel JAOUEN 
5237ccfe9b1SMichel JAOUEN 		status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val);
5247ccfe9b1SMichel JAOUEN 		if (status < 0)
5257ccfe9b1SMichel JAOUEN 			break;
5267ccfe9b1SMichel JAOUEN 	}
5277ccfe9b1SMichel JAOUEN 	return IRQ_HANDLED;
5287ccfe9b1SMichel JAOUEN }
5297ccfe9b1SMichel JAOUEN 
53080633f05SLee Jones /**
53180633f05SLee Jones  * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
53280633f05SLee Jones  *
53380633f05SLee Jones  * @ab8500: ab8500_irq controller to operate on.
53480633f05SLee Jones  * @irq: index of the interrupt requested in the chip IRQs
53580633f05SLee Jones  *
53680633f05SLee Jones  * Useful for drivers to request their own IRQs.
53780633f05SLee Jones  */
53880633f05SLee Jones static int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq)
53980633f05SLee Jones {
54080633f05SLee Jones 	if (!ab8500)
54180633f05SLee Jones 		return -EINVAL;
54280633f05SLee Jones 
54380633f05SLee Jones 	return irq_create_mapping(ab8500->domain, irq);
54480633f05SLee Jones }
54580633f05SLee Jones 
54662579266SRabin Vincent static irqreturn_t ab8500_irq(int irq, void *dev)
54762579266SRabin Vincent {
54862579266SRabin Vincent 	struct ab8500 *ab8500 = dev;
54962579266SRabin Vincent 	int i;
55062579266SRabin Vincent 
55162579266SRabin Vincent 	dev_vdbg(ab8500->dev, "interrupt\n");
55262579266SRabin Vincent 
553112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
554112a80d2SJonas Aaberg 
5552ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++) {
5562ced445eSLinus Walleij 		int regoffset = ab8500->irq_reg_offset[i];
55762579266SRabin Vincent 		int status;
55847c16975SMattias Wallin 		u8 value;
55962579266SRabin Vincent 
5600f620837SLinus Walleij 		/*
5610f620837SLinus Walleij 		 * Interrupt register 12 doesn't exist prior to AB8500 version
5620f620837SLinus Walleij 		 * 2.0
5630f620837SLinus Walleij 		 */
5640f620837SLinus Walleij 		if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500))
56592d50a41SMattias Wallin 			continue;
56692d50a41SMattias Wallin 
56747c16975SMattias Wallin 		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
56847c16975SMattias Wallin 			AB8500_IT_LATCH1_REG + regoffset, &value);
56947c16975SMattias Wallin 		if (status < 0 || value == 0)
57062579266SRabin Vincent 			continue;
57162579266SRabin Vincent 
57262579266SRabin Vincent 		do {
57388aec4f7SMattias Wallin 			int bit = __ffs(value);
57462579266SRabin Vincent 			int line = i * 8 + bit;
5750a37fc56SLee Jones 			int virq = ab8500_irq_get_virq(ab8500, line);
57662579266SRabin Vincent 
5770a37fc56SLee Jones 			handle_nested_irq(virq);
5788f0eb43bSBengt Jonsson 			ab8500_debug_register_interrupt(line);
57947c16975SMattias Wallin 			value &= ~(1 << bit);
580112a80d2SJonas Aaberg 
58147c16975SMattias Wallin 		} while (value);
58262579266SRabin Vincent 	}
583112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
58462579266SRabin Vincent 	return IRQ_HANDLED;
58562579266SRabin Vincent }
58662579266SRabin Vincent 
58706e589efSLee Jones static int ab8500_irq_map(struct irq_domain *d, unsigned int virq,
58806e589efSLee Jones 				irq_hw_number_t hwirq)
58906e589efSLee Jones {
59006e589efSLee Jones 	struct ab8500 *ab8500 = d->host_data;
59106e589efSLee Jones 
59206e589efSLee Jones 	if (!ab8500)
59306e589efSLee Jones 		return -EINVAL;
59406e589efSLee Jones 
59506e589efSLee Jones 	irq_set_chip_data(virq, ab8500);
59606e589efSLee Jones 	irq_set_chip_and_handler(virq, &ab8500_irq_chip,
59706e589efSLee Jones 				handle_simple_irq);
59806e589efSLee Jones 	irq_set_nested_thread(virq, 1);
59906e589efSLee Jones #ifdef CONFIG_ARM
60006e589efSLee Jones 	set_irq_flags(virq, IRQF_VALID);
60106e589efSLee Jones #else
60206e589efSLee Jones 	irq_set_noprobe(virq);
60306e589efSLee Jones #endif
60462579266SRabin Vincent 
60562579266SRabin Vincent 	return 0;
60662579266SRabin Vincent }
60762579266SRabin Vincent 
60806e589efSLee Jones static struct irq_domain_ops ab8500_irq_ops = {
60906e589efSLee Jones         .map    = ab8500_irq_map,
61006e589efSLee Jones         .xlate  = irq_domain_xlate_twocell,
61106e589efSLee Jones };
61206e589efSLee Jones 
61306e589efSLee Jones static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np)
61462579266SRabin Vincent {
6152ced445eSLinus Walleij 	int num_irqs;
61662579266SRabin Vincent 
617d6255529SLinus Walleij 	if (is_ab9540(ab8500))
618d6255529SLinus Walleij 		num_irqs = AB9540_NR_IRQS;
619a982362cSBengt Jonsson 	else if (is_ab8505(ab8500))
620a982362cSBengt Jonsson 		num_irqs = AB8505_NR_IRQS;
621d6255529SLinus Walleij 	else
6222ced445eSLinus Walleij 		num_irqs = AB8500_NR_IRQS;
6232ced445eSLinus Walleij 
624f1d11f39SLinus Walleij 	/* If ->irq_base is zero this will give a linear mapping */
625f1d11f39SLinus Walleij 	ab8500->domain = irq_domain_add_simple(NULL,
626f1d11f39SLinus Walleij 			num_irqs, ab8500->irq_base,
627f1d11f39SLinus Walleij 			&ab8500_irq_ops, ab8500);
62806e589efSLee Jones 
62906e589efSLee Jones 	if (!ab8500->domain) {
63006e589efSLee Jones 		dev_err(ab8500->dev, "Failed to create irqdomain\n");
63106e589efSLee Jones 		return -ENOSYS;
63206e589efSLee Jones 	}
63306e589efSLee Jones 
63406e589efSLee Jones 	return 0;
63562579266SRabin Vincent }
63662579266SRabin Vincent 
637112a80d2SJonas Aaberg int ab8500_suspend(struct ab8500 *ab8500)
638112a80d2SJonas Aaberg {
639112a80d2SJonas Aaberg 	if (atomic_read(&ab8500->transfer_ongoing))
640112a80d2SJonas Aaberg 		return -EINVAL;
641112a80d2SJonas Aaberg 	else
642112a80d2SJonas Aaberg 		return 0;
643112a80d2SJonas Aaberg }
644112a80d2SJonas Aaberg 
645a9e9ce4cSBill Pemberton static struct resource ab8500_gpadc_resources[] = {
64662579266SRabin Vincent 	{
64762579266SRabin Vincent 		.name	= "HW_CONV_END",
64862579266SRabin Vincent 		.start	= AB8500_INT_GP_HW_ADC_CONV_END,
64962579266SRabin Vincent 		.end	= AB8500_INT_GP_HW_ADC_CONV_END,
65062579266SRabin Vincent 		.flags	= IORESOURCE_IRQ,
65162579266SRabin Vincent 	},
65262579266SRabin Vincent 	{
65362579266SRabin Vincent 		.name	= "SW_CONV_END",
65462579266SRabin Vincent 		.start	= AB8500_INT_GP_SW_ADC_CONV_END,
65562579266SRabin Vincent 		.end	= AB8500_INT_GP_SW_ADC_CONV_END,
65662579266SRabin Vincent 		.flags	= IORESOURCE_IRQ,
65762579266SRabin Vincent 	},
65862579266SRabin Vincent };
65962579266SRabin Vincent 
660a9e9ce4cSBill Pemberton static struct resource ab8500_rtc_resources[] = {
66162579266SRabin Vincent 	{
66262579266SRabin Vincent 		.name	= "60S",
66362579266SRabin Vincent 		.start	= AB8500_INT_RTC_60S,
66462579266SRabin Vincent 		.end	= AB8500_INT_RTC_60S,
66562579266SRabin Vincent 		.flags	= IORESOURCE_IRQ,
66662579266SRabin Vincent 	},
66762579266SRabin Vincent 	{
66862579266SRabin Vincent 		.name	= "ALARM",
66962579266SRabin Vincent 		.start	= AB8500_INT_RTC_ALARM,
67062579266SRabin Vincent 		.end	= AB8500_INT_RTC_ALARM,
67162579266SRabin Vincent 		.flags	= IORESOURCE_IRQ,
67262579266SRabin Vincent 	},
67362579266SRabin Vincent };
67462579266SRabin Vincent 
675a9e9ce4cSBill Pemberton static struct resource ab8500_poweronkey_db_resources[] = {
67677686517SSundar R Iyer 	{
67777686517SSundar R Iyer 		.name	= "ONKEY_DBF",
67877686517SSundar R Iyer 		.start	= AB8500_INT_PON_KEY1DB_F,
67977686517SSundar R Iyer 		.end	= AB8500_INT_PON_KEY1DB_F,
68077686517SSundar R Iyer 		.flags	= IORESOURCE_IRQ,
68177686517SSundar R Iyer 	},
68277686517SSundar R Iyer 	{
68377686517SSundar R Iyer 		.name	= "ONKEY_DBR",
68477686517SSundar R Iyer 		.start	= AB8500_INT_PON_KEY1DB_R,
68577686517SSundar R Iyer 		.end	= AB8500_INT_PON_KEY1DB_R,
68677686517SSundar R Iyer 		.flags	= IORESOURCE_IRQ,
68777686517SSundar R Iyer 	},
68877686517SSundar R Iyer };
68977686517SSundar R Iyer 
690a9e9ce4cSBill Pemberton static struct resource ab8500_av_acc_detect_resources[] = {
691e098adedSMattias Wallin 	{
6926af75ecdSLinus Walleij 	       .name = "ACC_DETECT_1DB_F",
6936af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_1DB_F,
6946af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_1DB_F,
695e098adedSMattias Wallin 	       .flags = IORESOURCE_IRQ,
696e098adedSMattias Wallin 	},
697e098adedSMattias Wallin 	{
6986af75ecdSLinus Walleij 	       .name = "ACC_DETECT_1DB_R",
6996af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_1DB_R,
7006af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_1DB_R,
701e098adedSMattias Wallin 	       .flags = IORESOURCE_IRQ,
702e098adedSMattias Wallin 	},
703e098adedSMattias Wallin 	{
7046af75ecdSLinus Walleij 	       .name = "ACC_DETECT_21DB_F",
7056af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_21DB_F,
7066af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_21DB_F,
7076af75ecdSLinus Walleij 	       .flags = IORESOURCE_IRQ,
7086af75ecdSLinus Walleij 	},
7096af75ecdSLinus Walleij 	{
7106af75ecdSLinus Walleij 	       .name = "ACC_DETECT_21DB_R",
7116af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_21DB_R,
7126af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_21DB_R,
7136af75ecdSLinus Walleij 	       .flags = IORESOURCE_IRQ,
7146af75ecdSLinus Walleij 	},
7156af75ecdSLinus Walleij 	{
7166af75ecdSLinus Walleij 	       .name = "ACC_DETECT_22DB_F",
7176af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_22DB_F,
7186af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_22DB_F,
7196af75ecdSLinus Walleij 	       .flags = IORESOURCE_IRQ,
7206af75ecdSLinus Walleij 	},
7216af75ecdSLinus Walleij 	{
7226af75ecdSLinus Walleij 	       .name = "ACC_DETECT_22DB_R",
7236af75ecdSLinus Walleij 	       .start = AB8500_INT_ACC_DETECT_22DB_R,
7246af75ecdSLinus Walleij 	       .end = AB8500_INT_ACC_DETECT_22DB_R,
7256af75ecdSLinus Walleij 	       .flags = IORESOURCE_IRQ,
7266af75ecdSLinus Walleij 	},
7276af75ecdSLinus Walleij };
7286af75ecdSLinus Walleij 
729a9e9ce4cSBill Pemberton static struct resource ab8500_charger_resources[] = {
7306af75ecdSLinus Walleij 	{
731e098adedSMattias Wallin 		.name = "MAIN_CH_UNPLUG_DET",
732e098adedSMattias Wallin 		.start = AB8500_INT_MAIN_CH_UNPLUG_DET,
733e098adedSMattias Wallin 		.end = AB8500_INT_MAIN_CH_UNPLUG_DET,
734e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
735e098adedSMattias Wallin 	},
736e098adedSMattias Wallin 	{
737e098adedSMattias Wallin 		.name = "MAIN_CHARGE_PLUG_DET",
738e098adedSMattias Wallin 		.start = AB8500_INT_MAIN_CH_PLUG_DET,
739e098adedSMattias Wallin 		.end = AB8500_INT_MAIN_CH_PLUG_DET,
740e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
741e098adedSMattias Wallin 	},
742e098adedSMattias Wallin 	{
743e098adedSMattias Wallin 		.name = "VBUS_DET_R",
744e098adedSMattias Wallin 		.start = AB8500_INT_VBUS_DET_R,
745e098adedSMattias Wallin 		.end = AB8500_INT_VBUS_DET_R,
746e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
747e098adedSMattias Wallin 	},
748e098adedSMattias Wallin 	{
7496af75ecdSLinus Walleij 		.name = "VBUS_DET_F",
7506af75ecdSLinus Walleij 		.start = AB8500_INT_VBUS_DET_F,
7516af75ecdSLinus Walleij 		.end = AB8500_INT_VBUS_DET_F,
752e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
753e098adedSMattias Wallin 	},
754e098adedSMattias Wallin 	{
7556af75ecdSLinus Walleij 		.name = "USB_LINK_STATUS",
7566af75ecdSLinus Walleij 		.start = AB8500_INT_USB_LINK_STATUS,
7576af75ecdSLinus Walleij 		.end = AB8500_INT_USB_LINK_STATUS,
7586af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
7596af75ecdSLinus Walleij 	},
7606af75ecdSLinus Walleij 	{
761e098adedSMattias Wallin 		.name = "VBUS_OVV",
762e098adedSMattias Wallin 		.start = AB8500_INT_VBUS_OVV,
763e098adedSMattias Wallin 		.end = AB8500_INT_VBUS_OVV,
764e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
765e098adedSMattias Wallin 	},
766e098adedSMattias Wallin 	{
7676af75ecdSLinus Walleij 		.name = "USB_CH_TH_PROT_R",
7686af75ecdSLinus Walleij 		.start = AB8500_INT_USB_CH_TH_PROT_R,
7696af75ecdSLinus Walleij 		.end = AB8500_INT_USB_CH_TH_PROT_R,
770e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
771e098adedSMattias Wallin 	},
772e098adedSMattias Wallin 	{
7736af75ecdSLinus Walleij 		.name = "USB_CH_TH_PROT_F",
7746af75ecdSLinus Walleij 		.start = AB8500_INT_USB_CH_TH_PROT_F,
7756af75ecdSLinus Walleij 		.end = AB8500_INT_USB_CH_TH_PROT_F,
776e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
777e098adedSMattias Wallin 	},
778e098adedSMattias Wallin 	{
7796af75ecdSLinus Walleij 		.name = "MAIN_EXT_CH_NOT_OK",
7806af75ecdSLinus Walleij 		.start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
7816af75ecdSLinus Walleij 		.end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
7826af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
7836af75ecdSLinus Walleij 	},
7846af75ecdSLinus Walleij 	{
7856af75ecdSLinus Walleij 		.name = "MAIN_CH_TH_PROT_R",
7866af75ecdSLinus Walleij 		.start = AB8500_INT_MAIN_CH_TH_PROT_R,
7876af75ecdSLinus Walleij 		.end = AB8500_INT_MAIN_CH_TH_PROT_R,
7886af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
7896af75ecdSLinus Walleij 	},
7906af75ecdSLinus Walleij 	{
7916af75ecdSLinus Walleij 		.name = "MAIN_CH_TH_PROT_F",
7926af75ecdSLinus Walleij 		.start = AB8500_INT_MAIN_CH_TH_PROT_F,
7936af75ecdSLinus Walleij 		.end = AB8500_INT_MAIN_CH_TH_PROT_F,
7946af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
7956af75ecdSLinus Walleij 	},
7966af75ecdSLinus Walleij 	{
7976af75ecdSLinus Walleij 		.name = "USB_CHARGER_NOT_OKR",
798a982362cSBengt Jonsson 		.start = AB8500_INT_USB_CHARGER_NOT_OKR,
799a982362cSBengt Jonsson 		.end = AB8500_INT_USB_CHARGER_NOT_OKR,
8006af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8016af75ecdSLinus Walleij 	},
8026af75ecdSLinus Walleij 	{
8036af75ecdSLinus Walleij 		.name = "CH_WD_EXP",
8046af75ecdSLinus Walleij 		.start = AB8500_INT_CH_WD_EXP,
8056af75ecdSLinus Walleij 		.end = AB8500_INT_CH_WD_EXP,
8066af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8076af75ecdSLinus Walleij 	},
80834c11a70SPaer-Olof Haakansson 	{
80934c11a70SPaer-Olof Haakansson 		.name = "VBUS_CH_DROP_END",
81034c11a70SPaer-Olof Haakansson 		.start = AB8500_INT_VBUS_CH_DROP_END,
81134c11a70SPaer-Olof Haakansson 		.end = AB8500_INT_VBUS_CH_DROP_END,
81234c11a70SPaer-Olof Haakansson 		.flags = IORESOURCE_IRQ,
81334c11a70SPaer-Olof Haakansson 	},
8146af75ecdSLinus Walleij };
8156af75ecdSLinus Walleij 
816a9e9ce4cSBill Pemberton static struct resource ab8500_btemp_resources[] = {
8176af75ecdSLinus Walleij 	{
8186af75ecdSLinus Walleij 		.name = "BAT_CTRL_INDB",
8196af75ecdSLinus Walleij 		.start = AB8500_INT_BAT_CTRL_INDB,
8206af75ecdSLinus Walleij 		.end = AB8500_INT_BAT_CTRL_INDB,
821e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
822e098adedSMattias Wallin 	},
823e098adedSMattias Wallin 	{
824e098adedSMattias Wallin 		.name = "BTEMP_LOW",
825e098adedSMattias Wallin 		.start = AB8500_INT_BTEMP_LOW,
826e098adedSMattias Wallin 		.end = AB8500_INT_BTEMP_LOW,
827e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
828e098adedSMattias Wallin 	},
829e098adedSMattias Wallin 	{
830e098adedSMattias Wallin 		.name = "BTEMP_HIGH",
831e098adedSMattias Wallin 		.start = AB8500_INT_BTEMP_HIGH,
832e098adedSMattias Wallin 		.end = AB8500_INT_BTEMP_HIGH,
833e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
834e098adedSMattias Wallin 	},
835e098adedSMattias Wallin 	{
8366af75ecdSLinus Walleij 		.name = "BTEMP_LOW_MEDIUM",
8376af75ecdSLinus Walleij 		.start = AB8500_INT_BTEMP_LOW_MEDIUM,
8386af75ecdSLinus Walleij 		.end = AB8500_INT_BTEMP_LOW_MEDIUM,
839e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
840e098adedSMattias Wallin 	},
841e098adedSMattias Wallin 	{
8426af75ecdSLinus Walleij 		.name = "BTEMP_MEDIUM_HIGH",
8436af75ecdSLinus Walleij 		.start = AB8500_INT_BTEMP_MEDIUM_HIGH,
8446af75ecdSLinus Walleij 		.end = AB8500_INT_BTEMP_MEDIUM_HIGH,
845e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
846e098adedSMattias Wallin 	},
847e098adedSMattias Wallin };
848e098adedSMattias Wallin 
849a9e9ce4cSBill Pemberton static struct resource ab8500_fg_resources[] = {
8506af75ecdSLinus Walleij 	{
8516af75ecdSLinus Walleij 		.name = "NCONV_ACCU",
8526af75ecdSLinus Walleij 		.start = AB8500_INT_CCN_CONV_ACC,
8536af75ecdSLinus Walleij 		.end = AB8500_INT_CCN_CONV_ACC,
8546af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8556af75ecdSLinus Walleij 	},
8566af75ecdSLinus Walleij 	{
8576af75ecdSLinus Walleij 		.name = "BATT_OVV",
8586af75ecdSLinus Walleij 		.start = AB8500_INT_BATT_OVV,
8596af75ecdSLinus Walleij 		.end = AB8500_INT_BATT_OVV,
8606af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8616af75ecdSLinus Walleij 	},
8626af75ecdSLinus Walleij 	{
8636af75ecdSLinus Walleij 		.name = "LOW_BAT_F",
8646af75ecdSLinus Walleij 		.start = AB8500_INT_LOW_BAT_F,
8656af75ecdSLinus Walleij 		.end = AB8500_INT_LOW_BAT_F,
8666af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8676af75ecdSLinus Walleij 	},
8686af75ecdSLinus Walleij 	{
8696af75ecdSLinus Walleij 		.name = "LOW_BAT_R",
8706af75ecdSLinus Walleij 		.start = AB8500_INT_LOW_BAT_R,
8716af75ecdSLinus Walleij 		.end = AB8500_INT_LOW_BAT_R,
8726af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8736af75ecdSLinus Walleij 	},
8746af75ecdSLinus Walleij 	{
8756af75ecdSLinus Walleij 		.name = "CC_INT_CALIB",
8766af75ecdSLinus Walleij 		.start = AB8500_INT_CC_INT_CALIB,
8776af75ecdSLinus Walleij 		.end = AB8500_INT_CC_INT_CALIB,
8786af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
8796af75ecdSLinus Walleij 	},
880a982362cSBengt Jonsson 	{
881a982362cSBengt Jonsson 		.name = "CCEOC",
882a982362cSBengt Jonsson 		.start = AB8500_INT_CCEOC,
883a982362cSBengt Jonsson 		.end = AB8500_INT_CCEOC,
884a982362cSBengt Jonsson 		.flags = IORESOURCE_IRQ,
885a982362cSBengt Jonsson 	},
8866af75ecdSLinus Walleij };
8876af75ecdSLinus Walleij 
888a9e9ce4cSBill Pemberton static struct resource ab8500_chargalg_resources[] = {};
8896af75ecdSLinus Walleij 
890df720647SAxel Lin #ifdef CONFIG_DEBUG_FS
891a9e9ce4cSBill Pemberton static struct resource ab8500_debug_resources[] = {
892e098adedSMattias Wallin 	{
893e098adedSMattias Wallin 		.name	= "IRQ_FIRST",
894e098adedSMattias Wallin 		.start	= AB8500_INT_MAIN_EXT_CH_NOT_OK,
895e098adedSMattias Wallin 		.end	= AB8500_INT_MAIN_EXT_CH_NOT_OK,
896e098adedSMattias Wallin 		.flags	= IORESOURCE_IRQ,
897e098adedSMattias Wallin 	},
898e098adedSMattias Wallin 	{
899e098adedSMattias Wallin 		.name	= "IRQ_LAST",
900a982362cSBengt Jonsson 		.start	= AB8500_INT_XTAL32K_KO,
901a982362cSBengt Jonsson 		.end	= AB8500_INT_XTAL32K_KO,
902e098adedSMattias Wallin 		.flags	= IORESOURCE_IRQ,
903e098adedSMattias Wallin 	},
904e098adedSMattias Wallin };
905df720647SAxel Lin #endif
906e098adedSMattias Wallin 
907a9e9ce4cSBill Pemberton static struct resource ab8500_usb_resources[] = {
908e098adedSMattias Wallin 	{
909e098adedSMattias Wallin 		.name = "ID_WAKEUP_R",
910e098adedSMattias Wallin 		.start = AB8500_INT_ID_WAKEUP_R,
911e098adedSMattias Wallin 		.end = AB8500_INT_ID_WAKEUP_R,
912e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
913e098adedSMattias Wallin 	},
914e098adedSMattias Wallin 	{
915e098adedSMattias Wallin 		.name = "ID_WAKEUP_F",
916e098adedSMattias Wallin 		.start = AB8500_INT_ID_WAKEUP_F,
917e098adedSMattias Wallin 		.end = AB8500_INT_ID_WAKEUP_F,
918e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
919e098adedSMattias Wallin 	},
920e098adedSMattias Wallin 	{
921e098adedSMattias Wallin 		.name = "VBUS_DET_F",
922e098adedSMattias Wallin 		.start = AB8500_INT_VBUS_DET_F,
923e098adedSMattias Wallin 		.end = AB8500_INT_VBUS_DET_F,
924e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
925e098adedSMattias Wallin 	},
926e098adedSMattias Wallin 	{
927e098adedSMattias Wallin 		.name = "VBUS_DET_R",
928e098adedSMattias Wallin 		.start = AB8500_INT_VBUS_DET_R,
929e098adedSMattias Wallin 		.end = AB8500_INT_VBUS_DET_R,
930e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
931e098adedSMattias Wallin 	},
93292d50a41SMattias Wallin 	{
93392d50a41SMattias Wallin 		.name = "USB_LINK_STATUS",
93492d50a41SMattias Wallin 		.start = AB8500_INT_USB_LINK_STATUS,
93592d50a41SMattias Wallin 		.end = AB8500_INT_USB_LINK_STATUS,
93692d50a41SMattias Wallin 		.flags = IORESOURCE_IRQ,
93792d50a41SMattias Wallin 	},
9386af75ecdSLinus Walleij 	{
9396af75ecdSLinus Walleij 		.name = "USB_ADP_PROBE_PLUG",
9406af75ecdSLinus Walleij 		.start = AB8500_INT_ADP_PROBE_PLUG,
9416af75ecdSLinus Walleij 		.end = AB8500_INT_ADP_PROBE_PLUG,
9426af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
9436af75ecdSLinus Walleij 	},
9446af75ecdSLinus Walleij 	{
9456af75ecdSLinus Walleij 		.name = "USB_ADP_PROBE_UNPLUG",
9466af75ecdSLinus Walleij 		.start = AB8500_INT_ADP_PROBE_UNPLUG,
9476af75ecdSLinus Walleij 		.end = AB8500_INT_ADP_PROBE_UNPLUG,
9486af75ecdSLinus Walleij 		.flags = IORESOURCE_IRQ,
9496af75ecdSLinus Walleij 	},
950e098adedSMattias Wallin };
951e098adedSMattias Wallin 
952a9e9ce4cSBill Pemberton static struct resource ab8505_iddet_resources[] = {
95344f72e53SVirupax Sadashivpetimath 	{
95444f72e53SVirupax Sadashivpetimath 		.name  = "KeyDeglitch",
95544f72e53SVirupax Sadashivpetimath 		.start = AB8505_INT_KEYDEGLITCH,
95644f72e53SVirupax Sadashivpetimath 		.end   = AB8505_INT_KEYDEGLITCH,
95744f72e53SVirupax Sadashivpetimath 		.flags = IORESOURCE_IRQ,
95844f72e53SVirupax Sadashivpetimath 	},
95944f72e53SVirupax Sadashivpetimath 	{
96044f72e53SVirupax Sadashivpetimath 		.name  = "KP",
96144f72e53SVirupax Sadashivpetimath 		.start = AB8505_INT_KP,
96244f72e53SVirupax Sadashivpetimath 		.end   = AB8505_INT_KP,
96344f72e53SVirupax Sadashivpetimath 		.flags = IORESOURCE_IRQ,
96444f72e53SVirupax Sadashivpetimath 	},
96544f72e53SVirupax Sadashivpetimath 	{
96644f72e53SVirupax Sadashivpetimath 		.name  = "IKP",
96744f72e53SVirupax Sadashivpetimath 		.start = AB8505_INT_IKP,
96844f72e53SVirupax Sadashivpetimath 		.end   = AB8505_INT_IKP,
96944f72e53SVirupax Sadashivpetimath 		.flags = IORESOURCE_IRQ,
97044f72e53SVirupax Sadashivpetimath 	},
97144f72e53SVirupax Sadashivpetimath 	{
97244f72e53SVirupax Sadashivpetimath 		.name  = "IKR",
97344f72e53SVirupax Sadashivpetimath 		.start = AB8505_INT_IKR,
97444f72e53SVirupax Sadashivpetimath 		.end   = AB8505_INT_IKR,
97544f72e53SVirupax Sadashivpetimath 		.flags = IORESOURCE_IRQ,
97644f72e53SVirupax Sadashivpetimath 	},
97744f72e53SVirupax Sadashivpetimath 	{
97844f72e53SVirupax Sadashivpetimath 		.name  = "KeyStuck",
97944f72e53SVirupax Sadashivpetimath 		.start = AB8505_INT_KEYSTUCK,
98044f72e53SVirupax Sadashivpetimath 		.end   = AB8505_INT_KEYSTUCK,
98144f72e53SVirupax Sadashivpetimath 		.flags = IORESOURCE_IRQ,
98244f72e53SVirupax Sadashivpetimath 	},
98344f72e53SVirupax Sadashivpetimath };
98444f72e53SVirupax Sadashivpetimath 
985a9e9ce4cSBill Pemberton static struct resource ab8500_temp_resources[] = {
986e098adedSMattias Wallin 	{
987151621a7SHongbo Zhang 		.name  = "ABX500_TEMP_WARM",
988e098adedSMattias Wallin 		.start = AB8500_INT_TEMP_WARM,
989e098adedSMattias Wallin 		.end   = AB8500_INT_TEMP_WARM,
990e098adedSMattias Wallin 		.flags = IORESOURCE_IRQ,
991e098adedSMattias Wallin 	},
992e098adedSMattias Wallin };
993e098adedSMattias Wallin 
994a9e9ce4cSBill Pemberton static struct mfd_cell abx500_common_devs[] = {
9955814fc35SMattias Wallin #ifdef CONFIG_DEBUG_FS
9965814fc35SMattias Wallin 	{
9975814fc35SMattias Wallin 		.name = "ab8500-debug",
998bad76991SLee Jones 		.of_compatible = "stericsson,ab8500-debug",
999e098adedSMattias Wallin 		.num_resources = ARRAY_SIZE(ab8500_debug_resources),
1000e098adedSMattias Wallin 		.resources = ab8500_debug_resources,
10015814fc35SMattias Wallin 	},
10025814fc35SMattias Wallin #endif
100362579266SRabin Vincent 	{
1004e098adedSMattias Wallin 		.name = "ab8500-sysctrl",
1005bad76991SLee Jones 		.of_compatible = "stericsson,ab8500-sysctrl",
1006e098adedSMattias Wallin 	},
1007e098adedSMattias Wallin 	{
1008e098adedSMattias Wallin 		.name = "ab8500-regulator",
1009bad76991SLee Jones 		.of_compatible = "stericsson,ab8500-regulator",
1010e098adedSMattias Wallin 	},
1011e098adedSMattias Wallin 	{
1012916a871cSUlf Hansson 		.name = "abx500-clk",
1013916a871cSUlf Hansson 		.of_compatible = "stericsson,abx500-clk",
1014916a871cSUlf Hansson 	},
1015916a871cSUlf Hansson 	{
101662579266SRabin Vincent 		.name = "ab8500-gpadc",
1017bad76991SLee Jones 		.of_compatible = "stericsson,ab8500-gpadc",
101862579266SRabin Vincent 		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
101962579266SRabin Vincent 		.resources = ab8500_gpadc_resources,
102062579266SRabin Vincent 	},
102162579266SRabin Vincent 	{
102262579266SRabin Vincent 		.name = "ab8500-rtc",
1023bad76991SLee Jones 		.of_compatible = "stericsson,ab8500-rtc",
102462579266SRabin Vincent 		.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
102562579266SRabin Vincent 		.resources = ab8500_rtc_resources,
102662579266SRabin Vincent 	},
1027f0f05b1cSArun Murthy 	{
10286af75ecdSLinus Walleij 		.name = "ab8500-acc-det",
1029bad76991SLee Jones 		.of_compatible = "stericsson,ab8500-acc-det",
10306af75ecdSLinus Walleij 		.num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
10316af75ecdSLinus Walleij 		.resources = ab8500_av_acc_detect_resources,
10326af75ecdSLinus Walleij 	},
10336af75ecdSLinus Walleij 	{
1034e098adedSMattias Wallin 		.name = "ab8500-poweron-key",
1035bad76991SLee Jones 		.of_compatible = "stericsson,ab8500-poweron-key",
1036e098adedSMattias Wallin 		.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
1037e098adedSMattias Wallin 		.resources = ab8500_poweronkey_db_resources,
1038e098adedSMattias Wallin 	},
1039e098adedSMattias Wallin 	{
1040f0f05b1cSArun Murthy 		.name = "ab8500-pwm",
1041bad76991SLee Jones 		.of_compatible = "stericsson,ab8500-pwm",
1042f0f05b1cSArun Murthy 		.id = 1,
1043f0f05b1cSArun Murthy 	},
1044f0f05b1cSArun Murthy 	{
1045f0f05b1cSArun Murthy 		.name = "ab8500-pwm",
1046bad76991SLee Jones 		.of_compatible = "stericsson,ab8500-pwm",
1047f0f05b1cSArun Murthy 		.id = 2,
1048f0f05b1cSArun Murthy 	},
1049f0f05b1cSArun Murthy 	{
1050f0f05b1cSArun Murthy 		.name = "ab8500-pwm",
1051bad76991SLee Jones 		.of_compatible = "stericsson,ab8500-pwm",
1052f0f05b1cSArun Murthy 		.id = 3,
1053f0f05b1cSArun Murthy 	},
1054bad76991SLee Jones 	{
1055bad76991SLee Jones 		.name = "ab8500-leds",
1056bad76991SLee Jones 		.of_compatible = "stericsson,ab8500-leds",
1057bad76991SLee Jones 	},
105877686517SSundar R Iyer 	{
1059e098adedSMattias Wallin 		.name = "ab8500-denc",
1060bad76991SLee Jones 		.of_compatible = "stericsson,ab8500-denc",
1061e098adedSMattias Wallin 	},
1062e098adedSMattias Wallin 	{
1063151621a7SHongbo Zhang 		.name = "abx500-temp",
1064151621a7SHongbo Zhang 		.of_compatible = "stericsson,abx500-temp",
1065e098adedSMattias Wallin 		.num_resources = ARRAY_SIZE(ab8500_temp_resources),
1066e098adedSMattias Wallin 		.resources = ab8500_temp_resources,
106777686517SSundar R Iyer 	},
106862579266SRabin Vincent };
106962579266SRabin Vincent 
1070a9e9ce4cSBill Pemberton static struct mfd_cell ab8500_bm_devs[] = {
10716ef9418cSRickard Andersson 	{
10726ef9418cSRickard Andersson 		.name = "ab8500-charger",
10734aef72dbSRajanikanth H.V 		.of_compatible = "stericsson,ab8500-charger",
10746ef9418cSRickard Andersson 		.num_resources = ARRAY_SIZE(ab8500_charger_resources),
10756ef9418cSRickard Andersson 		.resources = ab8500_charger_resources,
10764aef72dbSRajanikanth H.V 		.platform_data = &ab8500_bm_data,
10774aef72dbSRajanikanth H.V 		.pdata_size = sizeof(ab8500_bm_data),
10786ef9418cSRickard Andersson 	},
10796ef9418cSRickard Andersson 	{
10806ef9418cSRickard Andersson 		.name = "ab8500-btemp",
1081bd9e8ab2SRajanikanth H.V 		.of_compatible = "stericsson,ab8500-btemp",
10826ef9418cSRickard Andersson 		.num_resources = ARRAY_SIZE(ab8500_btemp_resources),
10836ef9418cSRickard Andersson 		.resources = ab8500_btemp_resources,
1084bd9e8ab2SRajanikanth H.V 		.platform_data = &ab8500_bm_data,
1085bd9e8ab2SRajanikanth H.V 		.pdata_size = sizeof(ab8500_bm_data),
10866ef9418cSRickard Andersson 	},
10876ef9418cSRickard Andersson 	{
10886ef9418cSRickard Andersson 		.name = "ab8500-fg",
1089e0f1abebSRajanikanth H.V 		.of_compatible = "stericsson,ab8500-fg",
10906ef9418cSRickard Andersson 		.num_resources = ARRAY_SIZE(ab8500_fg_resources),
10916ef9418cSRickard Andersson 		.resources = ab8500_fg_resources,
1092e0f1abebSRajanikanth H.V 		.platform_data = &ab8500_bm_data,
1093e0f1abebSRajanikanth H.V 		.pdata_size = sizeof(ab8500_bm_data),
10946ef9418cSRickard Andersson 	},
10956ef9418cSRickard Andersson 	{
10966ef9418cSRickard Andersson 		.name = "ab8500-chargalg",
1097a12810abSRajanikanth H.V 		.of_compatible = "stericsson,ab8500-chargalg",
10986ef9418cSRickard Andersson 		.num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
10996ef9418cSRickard Andersson 		.resources = ab8500_chargalg_resources,
1100a12810abSRajanikanth H.V 		.platform_data = &ab8500_bm_data,
1101a12810abSRajanikanth H.V 		.pdata_size = sizeof(ab8500_bm_data),
11026ef9418cSRickard Andersson 	},
11036ef9418cSRickard Andersson };
11046ef9418cSRickard Andersson 
1105a9e9ce4cSBill Pemberton static struct mfd_cell ab8500_devs[] = {
1106d6255529SLinus Walleij 	{
11077d56a46eSLee Jones 		.name = "pinctrl-ab8500",
1108bad76991SLee Jones 		.of_compatible = "stericsson,ab8500-gpio",
1109d6255529SLinus Walleij 	},
1110d6255529SLinus Walleij 	{
1111d6255529SLinus Walleij 		.name = "ab8500-usb",
1112bad76991SLee Jones 		.of_compatible = "stericsson,ab8500-usb",
1113d6255529SLinus Walleij 		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
1114d6255529SLinus Walleij 		.resources = ab8500_usb_resources,
1115d6255529SLinus Walleij 	},
111644f72e53SVirupax Sadashivpetimath 	{
111744f72e53SVirupax Sadashivpetimath 		.name = "ab8500-codec",
111881a21cddSLee Jones 		.of_compatible = "stericsson,ab8500-codec",
111944f72e53SVirupax Sadashivpetimath 	},
1120d6255529SLinus Walleij };
1121d6255529SLinus Walleij 
1122a9e9ce4cSBill Pemberton static struct mfd_cell ab9540_devs[] = {
1123d6255529SLinus Walleij 	{
1124e64d905eSLee Jones 		.name = "pinctrl-ab9540",
1125e64d905eSLee Jones 		.of_compatible = "stericsson,ab9540-gpio",
1126d6255529SLinus Walleij 	},
1127d6255529SLinus Walleij 	{
1128d6255529SLinus Walleij 		.name = "ab9540-usb",
1129d6255529SLinus Walleij 		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
1130d6255529SLinus Walleij 		.resources = ab8500_usb_resources,
1131d6255529SLinus Walleij 	},
113244f72e53SVirupax Sadashivpetimath 	{
113344f72e53SVirupax Sadashivpetimath 		.name = "ab9540-codec",
113444f72e53SVirupax Sadashivpetimath 	},
113544f72e53SVirupax Sadashivpetimath };
113644f72e53SVirupax Sadashivpetimath 
113744f72e53SVirupax Sadashivpetimath /* Device list common to ab9540 and ab8505 */
1138a9e9ce4cSBill Pemberton static struct mfd_cell ab9540_ab8505_devs[] = {
113944f72e53SVirupax Sadashivpetimath 	{
114044f72e53SVirupax Sadashivpetimath 		.name = "ab-iddet",
114144f72e53SVirupax Sadashivpetimath 		.num_resources = ARRAY_SIZE(ab8505_iddet_resources),
114244f72e53SVirupax Sadashivpetimath 		.resources = ab8505_iddet_resources,
114344f72e53SVirupax Sadashivpetimath 	},
1144d6255529SLinus Walleij };
1145d6255529SLinus Walleij 
1146cca69b67SMattias Wallin static ssize_t show_chip_id(struct device *dev,
1147cca69b67SMattias Wallin 				struct device_attribute *attr, char *buf)
1148cca69b67SMattias Wallin {
1149cca69b67SMattias Wallin 	struct ab8500 *ab8500;
1150cca69b67SMattias Wallin 
1151cca69b67SMattias Wallin 	ab8500 = dev_get_drvdata(dev);
1152cca69b67SMattias Wallin 	return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
1153cca69b67SMattias Wallin }
1154cca69b67SMattias Wallin 
1155e5c238c3SMattias Wallin /*
1156e5c238c3SMattias Wallin  * ab8500 has switched off due to (SWITCH_OFF_STATUS):
1157e5c238c3SMattias Wallin  * 0x01 Swoff bit programming
1158e5c238c3SMattias Wallin  * 0x02 Thermal protection activation
1159e5c238c3SMattias Wallin  * 0x04 Vbat lower then BattOk falling threshold
1160e5c238c3SMattias Wallin  * 0x08 Watchdog expired
1161e5c238c3SMattias Wallin  * 0x10 Non presence of 32kHz clock
1162e5c238c3SMattias Wallin  * 0x20 Battery level lower than power on reset threshold
1163e5c238c3SMattias Wallin  * 0x40 Power on key 1 pressed longer than 10 seconds
1164e5c238c3SMattias Wallin  * 0x80 DB8500 thermal shutdown
1165e5c238c3SMattias Wallin  */
1166e5c238c3SMattias Wallin static ssize_t show_switch_off_status(struct device *dev,
1167e5c238c3SMattias Wallin 				struct device_attribute *attr, char *buf)
1168e5c238c3SMattias Wallin {
1169e5c238c3SMattias Wallin 	int ret;
1170e5c238c3SMattias Wallin 	u8 value;
1171e5c238c3SMattias Wallin 	struct ab8500 *ab8500;
1172e5c238c3SMattias Wallin 
1173e5c238c3SMattias Wallin 	ab8500 = dev_get_drvdata(dev);
1174e5c238c3SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_RTC,
1175e5c238c3SMattias Wallin 		AB8500_SWITCH_OFF_STATUS, &value);
1176e5c238c3SMattias Wallin 	if (ret < 0)
1177e5c238c3SMattias Wallin 		return ret;
1178e5c238c3SMattias Wallin 	return sprintf(buf, "%#x\n", value);
1179e5c238c3SMattias Wallin }
1180e5c238c3SMattias Wallin 
1181f04a9d8aSRajkumar Kasirajan /* use mask and set to override the register turn_on_stat value */
1182f04a9d8aSRajkumar Kasirajan void ab8500_override_turn_on_stat(u8 mask, u8 set)
1183f04a9d8aSRajkumar Kasirajan {
1184f04a9d8aSRajkumar Kasirajan 	spin_lock(&on_stat_lock);
1185f04a9d8aSRajkumar Kasirajan 	turn_on_stat_mask = mask;
1186f04a9d8aSRajkumar Kasirajan 	turn_on_stat_set = set;
1187f04a9d8aSRajkumar Kasirajan 	spin_unlock(&on_stat_lock);
1188f04a9d8aSRajkumar Kasirajan }
1189f04a9d8aSRajkumar Kasirajan 
1190b4a31037SAndrew Lynn /*
1191b4a31037SAndrew Lynn  * ab8500 has turned on due to (TURN_ON_STATUS):
1192b4a31037SAndrew Lynn  * 0x01 PORnVbat
1193b4a31037SAndrew Lynn  * 0x02 PonKey1dbF
1194b4a31037SAndrew Lynn  * 0x04 PonKey2dbF
1195b4a31037SAndrew Lynn  * 0x08 RTCAlarm
1196b4a31037SAndrew Lynn  * 0x10 MainChDet
1197b4a31037SAndrew Lynn  * 0x20 VbusDet
1198b4a31037SAndrew Lynn  * 0x40 UsbIDDetect
1199b4a31037SAndrew Lynn  * 0x80 Reserved
1200b4a31037SAndrew Lynn  */
1201b4a31037SAndrew Lynn static ssize_t show_turn_on_status(struct device *dev,
1202b4a31037SAndrew Lynn 				struct device_attribute *attr, char *buf)
1203b4a31037SAndrew Lynn {
1204b4a31037SAndrew Lynn 	int ret;
1205b4a31037SAndrew Lynn 	u8 value;
1206b4a31037SAndrew Lynn 	struct ab8500 *ab8500;
1207b4a31037SAndrew Lynn 
1208b4a31037SAndrew Lynn 	ab8500 = dev_get_drvdata(dev);
1209b4a31037SAndrew Lynn 	ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
1210b4a31037SAndrew Lynn 		AB8500_TURN_ON_STATUS, &value);
1211b4a31037SAndrew Lynn 	if (ret < 0)
1212b4a31037SAndrew Lynn 		return ret;
1213f04a9d8aSRajkumar Kasirajan 
1214f04a9d8aSRajkumar Kasirajan 	/*
1215f04a9d8aSRajkumar Kasirajan 	 * In L9540, turn_on_status register is not updated correctly if
1216f04a9d8aSRajkumar Kasirajan 	 * the device is rebooted with AC/USB charger connected. Due to
1217f04a9d8aSRajkumar Kasirajan 	 * this, the device boots android instead of entering into charge
1218f04a9d8aSRajkumar Kasirajan 	 * only mode. Read the AC/USB status register to detect the charger
1219f04a9d8aSRajkumar Kasirajan 	 * presence and update the turn on status manually.
1220f04a9d8aSRajkumar Kasirajan 	 */
1221f04a9d8aSRajkumar Kasirajan 	if (is_ab9540(ab8500)) {
1222f04a9d8aSRajkumar Kasirajan 		spin_lock(&on_stat_lock);
1223f04a9d8aSRajkumar Kasirajan 		value = (value & turn_on_stat_mask) | turn_on_stat_set;
1224f04a9d8aSRajkumar Kasirajan 		spin_unlock(&on_stat_lock);
1225f04a9d8aSRajkumar Kasirajan 	}
1226f04a9d8aSRajkumar Kasirajan 
1227b4a31037SAndrew Lynn 	return sprintf(buf, "%#x\n", value);
1228b4a31037SAndrew Lynn }
1229b4a31037SAndrew Lynn 
1230d6255529SLinus Walleij static ssize_t show_ab9540_dbbrstn(struct device *dev,
1231d6255529SLinus Walleij 				struct device_attribute *attr, char *buf)
1232d6255529SLinus Walleij {
1233d6255529SLinus Walleij 	struct ab8500 *ab8500;
1234d6255529SLinus Walleij 	int ret;
1235d6255529SLinus Walleij 	u8 value;
1236d6255529SLinus Walleij 
1237d6255529SLinus Walleij 	ab8500 = dev_get_drvdata(dev);
1238d6255529SLinus Walleij 
1239d6255529SLinus Walleij 	ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2,
1240d6255529SLinus Walleij 		AB9540_MODEM_CTRL2_REG, &value);
1241d6255529SLinus Walleij 	if (ret < 0)
1242d6255529SLinus Walleij 		return ret;
1243d6255529SLinus Walleij 
1244d6255529SLinus Walleij 	return sprintf(buf, "%d\n",
1245d6255529SLinus Walleij 			(value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0);
1246d6255529SLinus Walleij }
1247d6255529SLinus Walleij 
1248d6255529SLinus Walleij static ssize_t store_ab9540_dbbrstn(struct device *dev,
1249d6255529SLinus Walleij 	struct device_attribute *attr, const char *buf, size_t count)
1250d6255529SLinus Walleij {
1251d6255529SLinus Walleij 	struct ab8500 *ab8500;
1252d6255529SLinus Walleij 	int ret = count;
1253d6255529SLinus Walleij 	int err;
1254d6255529SLinus Walleij 	u8 bitvalues;
1255d6255529SLinus Walleij 
1256d6255529SLinus Walleij 	ab8500 = dev_get_drvdata(dev);
1257d6255529SLinus Walleij 
1258d6255529SLinus Walleij 	if (count > 0) {
1259d6255529SLinus Walleij 		switch (buf[0]) {
1260d6255529SLinus Walleij 		case '0':
1261d6255529SLinus Walleij 			bitvalues = 0;
1262d6255529SLinus Walleij 			break;
1263d6255529SLinus Walleij 		case '1':
1264d6255529SLinus Walleij 			bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT;
1265d6255529SLinus Walleij 			break;
1266d6255529SLinus Walleij 		default:
1267d6255529SLinus Walleij 			goto exit;
1268d6255529SLinus Walleij 		}
1269d6255529SLinus Walleij 
1270d6255529SLinus Walleij 		err = mask_and_set_register_interruptible(ab8500,
1271d6255529SLinus Walleij 			AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG,
1272d6255529SLinus Walleij 			AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues);
1273d6255529SLinus Walleij 		if (err)
1274d6255529SLinus Walleij 			dev_info(ab8500->dev,
1275d6255529SLinus Walleij 				"Failed to set DBBRSTN %c, err %#x\n",
1276d6255529SLinus Walleij 				buf[0], err);
1277d6255529SLinus Walleij 	}
1278d6255529SLinus Walleij 
1279d6255529SLinus Walleij exit:
1280d6255529SLinus Walleij 	return ret;
1281d6255529SLinus Walleij }
1282d6255529SLinus Walleij 
1283cca69b67SMattias Wallin static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
1284e5c238c3SMattias Wallin static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
1285b4a31037SAndrew Lynn static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
1286d6255529SLinus Walleij static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR,
1287d6255529SLinus Walleij 			show_ab9540_dbbrstn, store_ab9540_dbbrstn);
1288cca69b67SMattias Wallin 
1289cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = {
1290cca69b67SMattias Wallin 	&dev_attr_chip_id.attr,
1291e5c238c3SMattias Wallin 	&dev_attr_switch_off_status.attr,
1292b4a31037SAndrew Lynn 	&dev_attr_turn_on_status.attr,
1293cca69b67SMattias Wallin 	NULL,
1294cca69b67SMattias Wallin };
1295cca69b67SMattias Wallin 
1296d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = {
1297d6255529SLinus Walleij 	&dev_attr_chip_id.attr,
1298d6255529SLinus Walleij 	&dev_attr_switch_off_status.attr,
1299d6255529SLinus Walleij 	&dev_attr_turn_on_status.attr,
1300d6255529SLinus Walleij 	&dev_attr_dbbrstn.attr,
1301d6255529SLinus Walleij 	NULL,
1302d6255529SLinus Walleij };
1303d6255529SLinus Walleij 
1304cca69b67SMattias Wallin static struct attribute_group ab8500_attr_group = {
1305cca69b67SMattias Wallin 	.attrs	= ab8500_sysfs_entries,
1306cca69b67SMattias Wallin };
1307cca69b67SMattias Wallin 
1308d6255529SLinus Walleij static struct attribute_group ab9540_attr_group = {
1309d6255529SLinus Walleij 	.attrs	= ab9540_sysfs_entries,
1310d6255529SLinus Walleij };
1311d6255529SLinus Walleij 
1312f791be49SBill Pemberton static int ab8500_probe(struct platform_device *pdev)
131362579266SRabin Vincent {
1314b04c530cSJonas Aaberg 	static char *switch_off_status[] = {
1315b04c530cSJonas Aaberg 		"Swoff bit programming",
1316b04c530cSJonas Aaberg 		"Thermal protection activation",
1317b04c530cSJonas Aaberg 		"Vbat lower then BattOk falling threshold",
1318b04c530cSJonas Aaberg 		"Watchdog expired",
1319b04c530cSJonas Aaberg 		"Non presence of 32kHz clock",
1320b04c530cSJonas Aaberg 		"Battery level lower than power on reset threshold",
1321b04c530cSJonas Aaberg 		"Power on key 1 pressed longer than 10 seconds",
1322b04c530cSJonas Aaberg 		"DB8500 thermal shutdown"};
1323d28f1db8SLee Jones 	struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev);
1324d28f1db8SLee Jones 	const struct platform_device_id *platid = platform_get_device_id(pdev);
13256bc4a568SLee Jones 	enum ab8500_version version = AB8500_VERSION_UNDEFINED;
13266bc4a568SLee Jones 	struct device_node *np = pdev->dev.of_node;
1327d28f1db8SLee Jones 	struct ab8500 *ab8500;
1328d28f1db8SLee Jones 	struct resource *resource;
132962579266SRabin Vincent 	int ret;
133062579266SRabin Vincent 	int i;
133147c16975SMattias Wallin 	u8 value;
133262579266SRabin Vincent 
13338c4203cbSLee Jones 	ab8500 = devm_kzalloc(&pdev->dev, sizeof *ab8500, GFP_KERNEL);
1334d28f1db8SLee Jones 	if (!ab8500)
1335d28f1db8SLee Jones 		return -ENOMEM;
1336d28f1db8SLee Jones 
133762579266SRabin Vincent 	if (plat)
133862579266SRabin Vincent 		ab8500->irq_base = plat->irq_base;
133962579266SRabin Vincent 
1340d28f1db8SLee Jones 	ab8500->dev = &pdev->dev;
1341d28f1db8SLee Jones 
1342d28f1db8SLee Jones 	resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
13438c4203cbSLee Jones 	if (!resource)
13448c4203cbSLee Jones 		return -ENODEV;
1345d28f1db8SLee Jones 
1346d28f1db8SLee Jones 	ab8500->irq = resource->start;
1347d28f1db8SLee Jones 
1348822672a7SLee Jones 	ab8500->read = ab8500_prcmu_read;
1349822672a7SLee Jones 	ab8500->write = ab8500_prcmu_write;
1350822672a7SLee Jones 	ab8500->write_masked = ab8500_prcmu_write_masked;
1351d28f1db8SLee Jones 
135262579266SRabin Vincent 	mutex_init(&ab8500->lock);
135362579266SRabin Vincent 	mutex_init(&ab8500->irq_lock);
1354112a80d2SJonas Aaberg 	atomic_set(&ab8500->transfer_ongoing, 0);
135562579266SRabin Vincent 
1356d28f1db8SLee Jones 	platform_set_drvdata(pdev, ab8500);
1357d28f1db8SLee Jones 
13586bc4a568SLee Jones 	if (platid)
13596bc4a568SLee Jones 		version = platid->driver_data;
13606bc4a568SLee Jones 
13610f620837SLinus Walleij 	if (version != AB8500_VERSION_UNDEFINED)
13620f620837SLinus Walleij 		ab8500->version = version;
13630f620837SLinus Walleij 	else {
13640f620837SLinus Walleij 		ret = get_register_interruptible(ab8500, AB8500_MISC,
13650f620837SLinus Walleij 			AB8500_IC_NAME_REG, &value);
13660f620837SLinus Walleij 		if (ret < 0)
13678c4203cbSLee Jones 			return ret;
13680f620837SLinus Walleij 
13690f620837SLinus Walleij 		ab8500->version = value;
13700f620837SLinus Walleij 	}
13710f620837SLinus Walleij 
137247c16975SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_MISC,
137347c16975SMattias Wallin 		AB8500_REV_REG, &value);
137462579266SRabin Vincent 	if (ret < 0)
13758c4203cbSLee Jones 		return ret;
137662579266SRabin Vincent 
137747c16975SMattias Wallin 	ab8500->chip_id = value;
137862579266SRabin Vincent 
13790f620837SLinus Walleij 	dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n",
13800f620837SLinus Walleij 			ab8500_version_str[ab8500->version],
13810f620837SLinus Walleij 			ab8500->chip_id >> 4,
13820f620837SLinus Walleij 			ab8500->chip_id & 0x0F);
13830f620837SLinus Walleij 
1384d6255529SLinus Walleij 	/* Configure AB8500 or AB9540 IRQ */
1385a982362cSBengt Jonsson 	if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
1386d6255529SLinus Walleij 		ab8500->mask_size = AB9540_NUM_IRQ_REGS;
1387d6255529SLinus Walleij 		ab8500->irq_reg_offset = ab9540_irq_regoffset;
1388d6255529SLinus Walleij 	} else {
13892ced445eSLinus Walleij 		ab8500->mask_size = AB8500_NUM_IRQ_REGS;
13902ced445eSLinus Walleij 		ab8500->irq_reg_offset = ab8500_irq_regoffset;
1391d6255529SLinus Walleij 	}
13928c4203cbSLee Jones 	ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size, GFP_KERNEL);
13932ced445eSLinus Walleij 	if (!ab8500->mask)
13942ced445eSLinus Walleij 		return -ENOMEM;
13958c4203cbSLee Jones 	ab8500->oldmask = devm_kzalloc(&pdev->dev, ab8500->mask_size, GFP_KERNEL);
13968c4203cbSLee Jones 	if (!ab8500->oldmask)
13978c4203cbSLee Jones 		return -ENOMEM;
13988c4203cbSLee Jones 
1399e5c238c3SMattias Wallin 	/*
1400e5c238c3SMattias Wallin 	 * ab8500 has switched off due to (SWITCH_OFF_STATUS):
1401e5c238c3SMattias Wallin 	 * 0x01 Swoff bit programming
1402e5c238c3SMattias Wallin 	 * 0x02 Thermal protection activation
1403e5c238c3SMattias Wallin 	 * 0x04 Vbat lower then BattOk falling threshold
1404e5c238c3SMattias Wallin 	 * 0x08 Watchdog expired
1405e5c238c3SMattias Wallin 	 * 0x10 Non presence of 32kHz clock
1406e5c238c3SMattias Wallin 	 * 0x20 Battery level lower than power on reset threshold
1407e5c238c3SMattias Wallin 	 * 0x40 Power on key 1 pressed longer than 10 seconds
1408e5c238c3SMattias Wallin 	 * 0x80 DB8500 thermal shutdown
1409e5c238c3SMattias Wallin 	 */
1410e5c238c3SMattias Wallin 
1411e5c238c3SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_RTC,
1412e5c238c3SMattias Wallin 		AB8500_SWITCH_OFF_STATUS, &value);
1413e5c238c3SMattias Wallin 	if (ret < 0)
1414e5c238c3SMattias Wallin 		return ret;
1415b04c530cSJonas Aaberg 	dev_info(ab8500->dev, "switch off cause(s) (%#x): ", value);
1416b04c530cSJonas Aaberg 
1417b04c530cSJonas Aaberg 	if (value) {
1418b04c530cSJonas Aaberg 		for (i = 0; i < ARRAY_SIZE(switch_off_status); i++) {
1419b04c530cSJonas Aaberg 			if (value & 1)
1420b04c530cSJonas Aaberg 				printk(KERN_CONT " \"%s\"",
1421b04c530cSJonas Aaberg 				       switch_off_status[i]);
1422b04c530cSJonas Aaberg 			value = value >> 1;
1423b04c530cSJonas Aaberg 
1424b04c530cSJonas Aaberg 		}
1425b04c530cSJonas Aaberg 		printk(KERN_CONT "\n");
1426b04c530cSJonas Aaberg 	} else {
1427b04c530cSJonas Aaberg 		printk(KERN_CONT " None\n");
1428b04c530cSJonas Aaberg 	}
1429e5c238c3SMattias Wallin 
143062579266SRabin Vincent 	if (plat && plat->init)
143162579266SRabin Vincent 		plat->init(ab8500);
1432f04a9d8aSRajkumar Kasirajan 	if (is_ab9540(ab8500)) {
1433f04a9d8aSRajkumar Kasirajan 		ret = get_register_interruptible(ab8500, AB8500_CHARGER,
1434f04a9d8aSRajkumar Kasirajan 			AB8500_CH_USBCH_STAT1_REG, &value);
1435f04a9d8aSRajkumar Kasirajan 		if (ret < 0)
1436f04a9d8aSRajkumar Kasirajan 			return ret;
1437f04a9d8aSRajkumar Kasirajan 		if ((value & VBUS_DET_DBNC1) && (value & VBUS_DET_DBNC100))
1438f04a9d8aSRajkumar Kasirajan 			ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON,
1439f04a9d8aSRajkumar Kasirajan 						     AB8500_VBUS_DET);
1440f04a9d8aSRajkumar Kasirajan 	}
144162579266SRabin Vincent 
144262579266SRabin Vincent 	/* Clear and mask all interrupts */
14432ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++) {
14440f620837SLinus Walleij 		/*
14450f620837SLinus Walleij 		 * Interrupt register 12 doesn't exist prior to AB8500 version
14460f620837SLinus Walleij 		 * 2.0
14470f620837SLinus Walleij 		 */
14480f620837SLinus Walleij 		if (ab8500->irq_reg_offset[i] == 11 &&
14490f620837SLinus Walleij 				is_ab8500_1p1_or_earlier(ab8500))
145092d50a41SMattias Wallin 			continue;
145162579266SRabin Vincent 
145247c16975SMattias Wallin 		get_register_interruptible(ab8500, AB8500_INTERRUPT,
14532ced445eSLinus Walleij 			AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
145492d50a41SMattias Wallin 			&value);
145547c16975SMattias Wallin 		set_register_interruptible(ab8500, AB8500_INTERRUPT,
14562ced445eSLinus Walleij 			AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff);
145762579266SRabin Vincent 	}
145862579266SRabin Vincent 
145947c16975SMattias Wallin 	ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
146047c16975SMattias Wallin 	if (ret)
14618c4203cbSLee Jones 		return ret;
146247c16975SMattias Wallin 
14632ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++)
146462579266SRabin Vincent 		ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
146562579266SRabin Vincent 
146606e589efSLee Jones 	ret = ab8500_irq_init(ab8500, np);
146762579266SRabin Vincent 	if (ret)
14688c4203cbSLee Jones 		return ret;
146962579266SRabin Vincent 
14707ccfe9b1SMichel JAOUEN 	/*  Activate this feature only in ab9540 */
14717ccfe9b1SMichel JAOUEN 	/*  till tests are done on ab8500 1p2 or later*/
147206e589efSLee Jones 	if (is_ab9540(ab8500)) {
14738c4203cbSLee Jones 		ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL,
14747ccfe9b1SMichel JAOUEN 						ab8500_hierarchical_irq,
14757ccfe9b1SMichel JAOUEN 						IRQF_ONESHOT | IRQF_NO_SUSPEND,
14767ccfe9b1SMichel JAOUEN 						"ab8500", ab8500);
147706e589efSLee Jones 	}
147806e589efSLee Jones 	else {
14798c4203cbSLee Jones 		ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL,
14807ccfe9b1SMichel JAOUEN 						ab8500_irq,
14814f079985SMattias Wallin 						IRQF_ONESHOT | IRQF_NO_SUSPEND,
14824f079985SMattias Wallin 						"ab8500", ab8500);
148362579266SRabin Vincent 		if (ret)
14848c4203cbSLee Jones 			return ret;
148562579266SRabin Vincent 	}
148662579266SRabin Vincent 
1487d6255529SLinus Walleij 	ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
1488d6255529SLinus Walleij 			ARRAY_SIZE(abx500_common_devs), NULL,
148955692af5SMark Brown 			ab8500->irq_base, ab8500->domain);
1490d6255529SLinus Walleij 	if (ret)
14918c4203cbSLee Jones 		return ret;
1492d6255529SLinus Walleij 
1493d6255529SLinus Walleij 	if (is_ab9540(ab8500))
1494d6255529SLinus Walleij 		ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
1495d6255529SLinus Walleij 				ARRAY_SIZE(ab9540_devs), NULL,
149655692af5SMark Brown 				ab8500->irq_base, ab8500->domain);
1497d6255529SLinus Walleij 	else
1498549931f9SSundar R Iyer 		ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
149944f72e53SVirupax Sadashivpetimath 				ARRAY_SIZE(ab8500_devs), NULL,
150055692af5SMark Brown 				ab8500->irq_base, ab8500->domain);
15016bc4a568SLee Jones 	if (ret)
15028c4203cbSLee Jones 		return ret;
150344f72e53SVirupax Sadashivpetimath 
150444f72e53SVirupax Sadashivpetimath 	if (is_ab9540(ab8500) || is_ab8505(ab8500))
150544f72e53SVirupax Sadashivpetimath 		ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs,
150644f72e53SVirupax Sadashivpetimath 				ARRAY_SIZE(ab9540_ab8505_devs), NULL,
150755692af5SMark Brown 				ab8500->irq_base, ab8500->domain);
150862579266SRabin Vincent 	if (ret)
15098c4203cbSLee Jones 		return ret;
151062579266SRabin Vincent 
15116ef9418cSRickard Andersson 	if (!no_bm) {
15126ef9418cSRickard Andersson 		/* Add battery management devices */
15136ef9418cSRickard Andersson 		ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
15146ef9418cSRickard Andersson 				      ARRAY_SIZE(ab8500_bm_devs), NULL,
151555692af5SMark Brown 				      ab8500->irq_base, ab8500->domain);
15166ef9418cSRickard Andersson 		if (ret)
15176ef9418cSRickard Andersson 			dev_err(ab8500->dev, "error adding bm devices\n");
15186ef9418cSRickard Andersson 	}
15196ef9418cSRickard Andersson 
1520d6255529SLinus Walleij 	if (is_ab9540(ab8500))
1521d6255529SLinus Walleij 		ret = sysfs_create_group(&ab8500->dev->kobj,
1522d6255529SLinus Walleij 					&ab9540_attr_group);
1523d6255529SLinus Walleij 	else
1524d6255529SLinus Walleij 		ret = sysfs_create_group(&ab8500->dev->kobj,
1525d6255529SLinus Walleij 					&ab8500_attr_group);
1526cca69b67SMattias Wallin 	if (ret)
1527cca69b67SMattias Wallin 		dev_err(ab8500->dev, "error creating sysfs entries\n");
152806e589efSLee Jones 
152962579266SRabin Vincent 	return ret;
153062579266SRabin Vincent }
153162579266SRabin Vincent 
15324740f73fSBill Pemberton static int ab8500_remove(struct platform_device *pdev)
153362579266SRabin Vincent {
1534d28f1db8SLee Jones 	struct ab8500 *ab8500 = platform_get_drvdata(pdev);
1535d28f1db8SLee Jones 
1536d6255529SLinus Walleij 	if (is_ab9540(ab8500))
1537d6255529SLinus Walleij 		sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
1538d6255529SLinus Walleij 	else
1539cca69b67SMattias Wallin 		sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
154006e589efSLee Jones 
154162579266SRabin Vincent 	mfd_remove_devices(ab8500->dev);
154262579266SRabin Vincent 
154362579266SRabin Vincent 	return 0;
154462579266SRabin Vincent }
154562579266SRabin Vincent 
1546d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = {
1547d28f1db8SLee Jones 	{ "ab8500-core", AB8500_VERSION_AB8500 },
1548d28f1db8SLee Jones 	{ "ab8505-i2c", AB8500_VERSION_AB8505 },
1549d28f1db8SLee Jones 	{ "ab9540-i2c", AB8500_VERSION_AB9540 },
1550d28f1db8SLee Jones 	{ "ab8540-i2c", AB8500_VERSION_AB8540 },
1551d28f1db8SLee Jones 	{ }
1552d28f1db8SLee Jones };
1553d28f1db8SLee Jones 
1554d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = {
1555d28f1db8SLee Jones 	.driver = {
1556d28f1db8SLee Jones 		.name = "ab8500-core",
1557d28f1db8SLee Jones 		.owner = THIS_MODULE,
1558d28f1db8SLee Jones 	},
1559d28f1db8SLee Jones 	.probe	= ab8500_probe,
156084449216SBill Pemberton 	.remove	= ab8500_remove,
1561d28f1db8SLee Jones 	.id_table = ab8500_id,
1562d28f1db8SLee Jones };
1563d28f1db8SLee Jones 
1564d28f1db8SLee Jones static int __init ab8500_core_init(void)
1565d28f1db8SLee Jones {
1566d28f1db8SLee Jones 	return platform_driver_register(&ab8500_core_driver);
1567d28f1db8SLee Jones }
1568d28f1db8SLee Jones 
1569d28f1db8SLee Jones static void __exit ab8500_core_exit(void)
1570d28f1db8SLee Jones {
1571d28f1db8SLee Jones 	platform_driver_unregister(&ab8500_core_driver);
1572d28f1db8SLee Jones }
1573ba7cbc3eSLee Jones core_initcall(ab8500_core_init);
1574d28f1db8SLee Jones module_exit(ab8500_core_exit);
1575d28f1db8SLee Jones 
1576adceed62SMattias Wallin MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent");
157762579266SRabin Vincent MODULE_DESCRIPTION("AB8500 MFD core");
157862579266SRabin Vincent MODULE_LICENSE("GPL v2");
1579