xref: /openbmc/linux/drivers/mfd/ab8500-core.c (revision 10628e3ecf544fa2e4e24f8e112d95c37884dc98)
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>
1731cbae22SPaul Gortmaker #include <linux/moduleparam.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
98a29264b6SLee Jones #define AB8500_IT_MASK25_REG		0x58
9962579266SRabin Vincent 
1007ccfe9b1SMichel JAOUEN /*
1017ccfe9b1SMichel JAOUEN  * latch hierarchy registers
1027ccfe9b1SMichel JAOUEN  */
1037ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER1_REG	0x60
1047ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER2_REG	0x61
1057ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER3_REG	0x62
1063e1a498fSLee Jones #define AB8540_IT_LATCHHIER4_REG	0x63
1077ccfe9b1SMichel JAOUEN 
1087ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER_NUM		3
1093e1a498fSLee Jones #define AB8540_IT_LATCHHIER_NUM		4
1107ccfe9b1SMichel JAOUEN 
11147c16975SMattias Wallin #define AB8500_REV_REG			0x80
1120f620837SLinus Walleij #define AB8500_IC_NAME_REG		0x82
113e5c238c3SMattias Wallin #define AB8500_SWITCH_OFF_STATUS	0x00
11462579266SRabin Vincent 
115b4a31037SAndrew Lynn #define AB8500_TURN_ON_STATUS		0x00
11693ff722eSLee Jones #define AB8505_TURN_ON_STATUS_2		0x04
117b4a31037SAndrew Lynn 
118f04a9d8aSRajkumar Kasirajan #define AB8500_CH_USBCH_STAT1_REG	0x02
119f04a9d8aSRajkumar Kasirajan #define VBUS_DET_DBNC100		0x02
120f04a9d8aSRajkumar Kasirajan #define VBUS_DET_DBNC1			0x01
121f04a9d8aSRajkumar Kasirajan 
122f04a9d8aSRajkumar Kasirajan static DEFINE_SPINLOCK(on_stat_lock);
123f04a9d8aSRajkumar Kasirajan static u8 turn_on_stat_mask = 0xFF;
124f04a9d8aSRajkumar Kasirajan static u8 turn_on_stat_set;
1256ef9418cSRickard Andersson static bool no_bm; /* No battery management */
12631cbae22SPaul Gortmaker /*
12731cbae22SPaul Gortmaker  * not really modular, but the easiest way to keep compat with existing
12831cbae22SPaul Gortmaker  * bootargs behaviour is to continue using module_param here.
12931cbae22SPaul Gortmaker  */
1306ef9418cSRickard Andersson module_param(no_bm, bool, S_IRUGO);
1316ef9418cSRickard Andersson 
132d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_REG			0x23
133d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT	BIT(2)
134d6255529SLinus Walleij 
13562579266SRabin Vincent /*
13662579266SRabin Vincent  * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
1372ced445eSLinus Walleij  * numbers are indexed into this array with (num / 8). The interupts are
1382ced445eSLinus Walleij  * defined in linux/mfd/ab8500.h
13962579266SRabin Vincent  *
14062579266SRabin Vincent  * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
14162579266SRabin Vincent  * offset 0.
14262579266SRabin Vincent  */
1432ced445eSLinus Walleij /* AB8500 support */
14462579266SRabin Vincent static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
14592d50a41SMattias Wallin 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
14662579266SRabin Vincent };
14762579266SRabin Vincent 
148a29264b6SLee Jones /* AB9540 / AB8505 support */
149d6255529SLinus Walleij static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
150a29264b6SLee Jones 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23
151d6255529SLinus Walleij };
152d6255529SLinus Walleij 
1533e1a498fSLee Jones /* AB8540 support */
1543e1a498fSLee Jones static const int ab8540_irq_regoffset[AB8540_NUM_IRQ_REGS] = {
1557ccf40b1SLee Jones 	0, 1, 2, 3, 4, -1, -1, -1, -1, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22,
1567ccf40b1SLee Jones 	23, 25, 26, 27, 28, 29, 30, 31,
1573e1a498fSLee Jones };
1583e1a498fSLee Jones 
1590f620837SLinus Walleij static const char ab8500_version_str[][7] = {
1600f620837SLinus Walleij 	[AB8500_VERSION_AB8500] = "AB8500",
1610f620837SLinus Walleij 	[AB8500_VERSION_AB8505] = "AB8505",
1620f620837SLinus Walleij 	[AB8500_VERSION_AB9540] = "AB9540",
1630f620837SLinus Walleij 	[AB8500_VERSION_AB8540] = "AB8540",
1640f620837SLinus Walleij };
1650f620837SLinus Walleij 
166822672a7SLee Jones static int ab8500_prcmu_write(struct ab8500 *ab8500, u16 addr, u8 data)
167d28f1db8SLee Jones {
168d28f1db8SLee Jones 	int ret;
169d28f1db8SLee Jones 
170d28f1db8SLee Jones 	ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
171d28f1db8SLee Jones 	if (ret < 0)
172d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
173d28f1db8SLee Jones 	return ret;
174d28f1db8SLee Jones }
175d28f1db8SLee Jones 
176822672a7SLee Jones static int ab8500_prcmu_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
177d28f1db8SLee Jones 	u8 data)
178d28f1db8SLee Jones {
179d28f1db8SLee Jones 	int ret;
180d28f1db8SLee Jones 
181d28f1db8SLee Jones 	ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data,
182d28f1db8SLee Jones 		&mask, 1);
183d28f1db8SLee Jones 	if (ret < 0)
184d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
185d28f1db8SLee Jones 	return ret;
186d28f1db8SLee Jones }
187d28f1db8SLee Jones 
188822672a7SLee Jones static int ab8500_prcmu_read(struct ab8500 *ab8500, u16 addr)
189d28f1db8SLee Jones {
190d28f1db8SLee Jones 	int ret;
191d28f1db8SLee Jones 	u8 data;
192d28f1db8SLee Jones 
193d28f1db8SLee Jones 	ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
194d28f1db8SLee Jones 	if (ret < 0) {
195d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
196d28f1db8SLee Jones 		return ret;
197d28f1db8SLee Jones 	}
198d28f1db8SLee Jones 	return (int)data;
199d28f1db8SLee Jones }
200d28f1db8SLee Jones 
20147c16975SMattias Wallin static int ab8500_get_chip_id(struct device *dev)
20247c16975SMattias Wallin {
2036bce7bf1SMattias Wallin 	struct ab8500 *ab8500;
2046bce7bf1SMattias Wallin 
2056bce7bf1SMattias Wallin 	if (!dev)
2066bce7bf1SMattias Wallin 		return -EINVAL;
2076bce7bf1SMattias Wallin 	ab8500 = dev_get_drvdata(dev->parent);
2086bce7bf1SMattias Wallin 	return ab8500 ? (int)ab8500->chip_id : -EINVAL;
20947c16975SMattias Wallin }
21047c16975SMattias Wallin 
21147c16975SMattias Wallin static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
21247c16975SMattias Wallin 	u8 reg, u8 data)
21362579266SRabin Vincent {
21462579266SRabin Vincent 	int ret;
21547c16975SMattias Wallin 	/*
21647c16975SMattias Wallin 	 * Put the u8 bank and u8 register together into a an u16.
21747c16975SMattias Wallin 	 * The bank on higher 8 bits and register in lower 8 bits.
218500e69a1SLee Jones 	 */
21947c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
22062579266SRabin Vincent 
22162579266SRabin Vincent 	dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
22262579266SRabin Vincent 
223392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
22447c16975SMattias Wallin 
22547c16975SMattias Wallin 	ret = ab8500->write(ab8500, addr, data);
22647c16975SMattias Wallin 	if (ret < 0)
22747c16975SMattias Wallin 		dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
22847c16975SMattias Wallin 			addr, ret);
22947c16975SMattias Wallin 	mutex_unlock(&ab8500->lock);
23047c16975SMattias Wallin 
23147c16975SMattias Wallin 	return ret;
23247c16975SMattias Wallin }
23347c16975SMattias Wallin 
23447c16975SMattias Wallin static int ab8500_set_register(struct device *dev, u8 bank,
23547c16975SMattias Wallin 	u8 reg, u8 value)
23647c16975SMattias Wallin {
237112a80d2SJonas Aaberg 	int ret;
23847c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
23947c16975SMattias Wallin 
240112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
241112a80d2SJonas Aaberg 	ret = set_register_interruptible(ab8500, bank, reg, value);
242112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
243112a80d2SJonas Aaberg 	return ret;
24447c16975SMattias Wallin }
24547c16975SMattias Wallin 
24647c16975SMattias Wallin static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
24747c16975SMattias Wallin 	u8 reg, u8 *value)
24847c16975SMattias Wallin {
24947c16975SMattias Wallin 	int ret;
25047c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
25147c16975SMattias Wallin 
252392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
25347c16975SMattias Wallin 
25447c16975SMattias Wallin 	ret = ab8500->read(ab8500, addr);
25547c16975SMattias Wallin 	if (ret < 0)
25647c16975SMattias Wallin 		dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
25747c16975SMattias Wallin 			addr, ret);
25847c16975SMattias Wallin 	else
25947c16975SMattias Wallin 		*value = ret;
26047c16975SMattias Wallin 
26147c16975SMattias Wallin 	mutex_unlock(&ab8500->lock);
26247c16975SMattias Wallin 	dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret);
26347c16975SMattias Wallin 
264*10628e3eSDan Carpenter 	return (ret < 0) ? ret : 0;
26547c16975SMattias Wallin }
26647c16975SMattias Wallin 
26747c16975SMattias Wallin static int ab8500_get_register(struct device *dev, u8 bank,
26847c16975SMattias Wallin 	u8 reg, u8 *value)
26947c16975SMattias Wallin {
270112a80d2SJonas Aaberg 	int ret;
27147c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
27247c16975SMattias Wallin 
273112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
274112a80d2SJonas Aaberg 	ret = get_register_interruptible(ab8500, bank, reg, value);
275112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
276112a80d2SJonas Aaberg 	return ret;
27747c16975SMattias Wallin }
27847c16975SMattias Wallin 
27947c16975SMattias Wallin static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
28047c16975SMattias Wallin 	u8 reg, u8 bitmask, u8 bitvalues)
28147c16975SMattias Wallin {
28247c16975SMattias Wallin 	int ret;
28347c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
28447c16975SMattias Wallin 
285392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
28647c16975SMattias Wallin 
287bc628fd1SMattias Nilsson 	if (ab8500->write_masked == NULL) {
288bc628fd1SMattias Nilsson 		u8 data;
289bc628fd1SMattias Nilsson 
29047c16975SMattias Wallin 		ret = ab8500->read(ab8500, addr);
29147c16975SMattias Wallin 		if (ret < 0) {
29247c16975SMattias Wallin 			dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
29347c16975SMattias Wallin 				addr, ret);
29447c16975SMattias Wallin 			goto out;
29547c16975SMattias Wallin 		}
29647c16975SMattias Wallin 
29747c16975SMattias Wallin 		data = (u8)ret;
29847c16975SMattias Wallin 		data = (~bitmask & data) | (bitmask & bitvalues);
29947c16975SMattias Wallin 
30062579266SRabin Vincent 		ret = ab8500->write(ab8500, addr, data);
30162579266SRabin Vincent 		if (ret < 0)
30262579266SRabin Vincent 			dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
30362579266SRabin Vincent 				addr, ret);
30462579266SRabin Vincent 
305bc628fd1SMattias Nilsson 		dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr,
306bc628fd1SMattias Nilsson 			data);
307bc628fd1SMattias Nilsson 		goto out;
308bc628fd1SMattias Nilsson 	}
309bc628fd1SMattias Nilsson 	ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues);
310bc628fd1SMattias Nilsson 	if (ret < 0)
311bc628fd1SMattias Nilsson 		dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr,
312bc628fd1SMattias Nilsson 			ret);
31362579266SRabin Vincent out:
31462579266SRabin Vincent 	mutex_unlock(&ab8500->lock);
31562579266SRabin Vincent 	return ret;
31662579266SRabin Vincent }
31747c16975SMattias Wallin 
31847c16975SMattias Wallin static int ab8500_mask_and_set_register(struct device *dev,
31947c16975SMattias Wallin 	u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
32047c16975SMattias Wallin {
321112a80d2SJonas Aaberg 	int ret;
32247c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
32347c16975SMattias Wallin 
324112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
325112a80d2SJonas Aaberg 	ret = mask_and_set_register_interruptible(ab8500, bank, reg,
32647c16975SMattias Wallin 						 bitmask, bitvalues);
327112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
328112a80d2SJonas Aaberg 	return ret;
32947c16975SMattias Wallin }
33047c16975SMattias Wallin 
33147c16975SMattias Wallin static struct abx500_ops ab8500_ops = {
33247c16975SMattias Wallin 	.get_chip_id = ab8500_get_chip_id,
33347c16975SMattias Wallin 	.get_register = ab8500_get_register,
33447c16975SMattias Wallin 	.set_register = ab8500_set_register,
33547c16975SMattias Wallin 	.get_register_page = NULL,
33647c16975SMattias Wallin 	.set_register_page = NULL,
33747c16975SMattias Wallin 	.mask_and_set_register = ab8500_mask_and_set_register,
33847c16975SMattias Wallin 	.event_registers_startup_state_get = NULL,
33947c16975SMattias Wallin 	.startup_irq_enabled = NULL,
3401d843a6cSMian Yousaf Kaukab 	.dump_all_banks = ab8500_dump_all_banks,
34147c16975SMattias Wallin };
34262579266SRabin Vincent 
3439505a0a0SMark Brown static void ab8500_irq_lock(struct irq_data *data)
34462579266SRabin Vincent {
3459505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
34662579266SRabin Vincent 
34762579266SRabin Vincent 	mutex_lock(&ab8500->irq_lock);
348112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
34962579266SRabin Vincent }
35062579266SRabin Vincent 
3519505a0a0SMark Brown static void ab8500_irq_sync_unlock(struct irq_data *data)
35262579266SRabin Vincent {
3539505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
35462579266SRabin Vincent 	int i;
35562579266SRabin Vincent 
3562ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++) {
35762579266SRabin Vincent 		u8 old = ab8500->oldmask[i];
35862579266SRabin Vincent 		u8 new = ab8500->mask[i];
35962579266SRabin Vincent 		int reg;
36062579266SRabin Vincent 
36162579266SRabin Vincent 		if (new == old)
36262579266SRabin Vincent 			continue;
36362579266SRabin Vincent 
3640f620837SLinus Walleij 		/*
3650f620837SLinus Walleij 		 * Interrupt register 12 doesn't exist prior to AB8500 version
3660f620837SLinus Walleij 		 * 2.0
3670f620837SLinus Walleij 		 */
3680f620837SLinus Walleij 		if (ab8500->irq_reg_offset[i] == 11 &&
3690f620837SLinus Walleij 			is_ab8500_1p1_or_earlier(ab8500))
37092d50a41SMattias Wallin 			continue;
37192d50a41SMattias Wallin 
3723e1a498fSLee Jones 		if (ab8500->irq_reg_offset[i] < 0)
3733e1a498fSLee Jones 			continue;
3743e1a498fSLee Jones 
37562579266SRabin Vincent 		ab8500->oldmask[i] = new;
37662579266SRabin Vincent 
3772ced445eSLinus Walleij 		reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
37847c16975SMattias Wallin 		set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
37962579266SRabin Vincent 	}
380112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
38162579266SRabin Vincent 	mutex_unlock(&ab8500->irq_lock);
38262579266SRabin Vincent }
38362579266SRabin Vincent 
3849505a0a0SMark Brown static void ab8500_irq_mask(struct irq_data *data)
38562579266SRabin Vincent {
3869505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
38706e589efSLee Jones 	int offset = data->hwirq;
38862579266SRabin Vincent 	int index = offset / 8;
38962579266SRabin Vincent 	int mask = 1 << (offset % 8);
39062579266SRabin Vincent 
39162579266SRabin Vincent 	ab8500->mask[index] |= mask;
3929c677b9bSLee Jones 
3939c677b9bSLee Jones 	/* The AB8500 GPIOs have two interrupts each (rising & falling). */
3949c677b9bSLee Jones 	if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
3959c677b9bSLee Jones 		ab8500->mask[index + 2] |= mask;
3969c677b9bSLee Jones 	if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R)
3979c677b9bSLee Jones 		ab8500->mask[index + 1] |= mask;
3989c677b9bSLee Jones 	if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R)
399e2ddf46aSLinus Walleij 		/* Here the falling IRQ is one bit lower */
400e2ddf46aSLinus Walleij 		ab8500->mask[index] |= (mask << 1);
40162579266SRabin Vincent }
40262579266SRabin Vincent 
4039505a0a0SMark Brown static void ab8500_irq_unmask(struct irq_data *data)
40462579266SRabin Vincent {
4059505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
4069c677b9bSLee Jones 	unsigned int type = irqd_get_trigger_type(data);
40706e589efSLee Jones 	int offset = data->hwirq;
40862579266SRabin Vincent 	int index = offset / 8;
40962579266SRabin Vincent 	int mask = 1 << (offset % 8);
41062579266SRabin Vincent 
4119c677b9bSLee Jones 	if (type & IRQ_TYPE_EDGE_RISING)
41262579266SRabin Vincent 		ab8500->mask[index] &= ~mask;
4139c677b9bSLee Jones 
4149c677b9bSLee Jones 	/* The AB8500 GPIOs have two interrupts each (rising & falling). */
4159c677b9bSLee Jones 	if (type & IRQ_TYPE_EDGE_FALLING) {
4169c677b9bSLee Jones 		if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
4179c677b9bSLee Jones 			ab8500->mask[index + 2] &= ~mask;
4187ccf40b1SLee Jones 		else if (offset >= AB9540_INT_GPIO50R &&
4197ccf40b1SLee Jones 			 offset <= AB9540_INT_GPIO54R)
4209c677b9bSLee Jones 			ab8500->mask[index + 1] &= ~mask;
4217ccf40b1SLee Jones 		else if (offset == AB8540_INT_GPIO43R ||
4227ccf40b1SLee Jones 			 offset == AB8540_INT_GPIO44R)
423e2ddf46aSLinus Walleij 			/* Here the falling IRQ is one bit lower */
424e2ddf46aSLinus Walleij 			ab8500->mask[index] &= ~(mask << 1);
4259c677b9bSLee Jones 		else
4269c677b9bSLee Jones 			ab8500->mask[index] &= ~mask;
427e2ddf46aSLinus Walleij 	} else {
4289c677b9bSLee Jones 		/* Satisfies the case where type is not set. */
42962579266SRabin Vincent 		ab8500->mask[index] &= ~mask;
43062579266SRabin Vincent 	}
431e2ddf46aSLinus Walleij }
43262579266SRabin Vincent 
43340f6e5a2SLee Jones static int ab8500_irq_set_type(struct irq_data *data, unsigned int type)
43440f6e5a2SLee Jones {
43540f6e5a2SLee Jones 	return 0;
43662579266SRabin Vincent }
43762579266SRabin Vincent 
43862579266SRabin Vincent static struct irq_chip ab8500_irq_chip = {
43962579266SRabin Vincent 	.name			= "ab8500",
4409505a0a0SMark Brown 	.irq_bus_lock		= ab8500_irq_lock,
4419505a0a0SMark Brown 	.irq_bus_sync_unlock	= ab8500_irq_sync_unlock,
4429505a0a0SMark Brown 	.irq_mask		= ab8500_irq_mask,
443e6f9306eSVirupax Sadashivpetimath 	.irq_disable		= ab8500_irq_mask,
4449505a0a0SMark Brown 	.irq_unmask		= ab8500_irq_unmask,
44540f6e5a2SLee Jones 	.irq_set_type		= ab8500_irq_set_type,
44662579266SRabin Vincent };
44762579266SRabin Vincent 
4483e1a498fSLee Jones static void update_latch_offset(u8 *offset, int i)
4493e1a498fSLee Jones {
4503e1a498fSLee Jones 	/* Fix inconsistent ITFromLatch25 bit mapping... */
4513e1a498fSLee Jones 	if (unlikely(*offset == 17))
4523e1a498fSLee Jones 		*offset = 24;
4533e1a498fSLee Jones 	/* Fix inconsistent ab8540 bit mapping... */
4543e1a498fSLee Jones 	if (unlikely(*offset == 16))
4553e1a498fSLee Jones 		*offset = 25;
4563e1a498fSLee Jones 	if ((i == 3) && (*offset >= 24))
4573e1a498fSLee Jones 		*offset += 2;
4583e1a498fSLee Jones }
4593e1a498fSLee Jones 
4607ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
4617ccfe9b1SMichel JAOUEN 					int latch_offset, u8 latch_val)
4627ccfe9b1SMichel JAOUEN {
4637a93fb37SFabio Baltieri 	int int_bit, line, i;
4647ccfe9b1SMichel JAOUEN 
4657ccfe9b1SMichel JAOUEN 	for (i = 0; i < ab8500->mask_size; i++)
4667ccfe9b1SMichel JAOUEN 		if (ab8500->irq_reg_offset[i] == latch_offset)
4677ccfe9b1SMichel JAOUEN 			break;
4687ccfe9b1SMichel JAOUEN 
4697ccfe9b1SMichel JAOUEN 	if (i >= ab8500->mask_size) {
4707ccfe9b1SMichel JAOUEN 		dev_err(ab8500->dev, "Register offset 0x%2x not declared\n",
4717ccfe9b1SMichel JAOUEN 				latch_offset);
4727ccfe9b1SMichel JAOUEN 		return -ENXIO;
4737ccfe9b1SMichel JAOUEN 	}
4747ccfe9b1SMichel JAOUEN 
4757a93fb37SFabio Baltieri 	/* ignore masked out interrupts */
4767a93fb37SFabio Baltieri 	latch_val &= ~ab8500->mask[i];
4777a93fb37SFabio Baltieri 
4787a93fb37SFabio Baltieri 	while (latch_val) {
4797a93fb37SFabio Baltieri 		int_bit = __ffs(latch_val);
4807ccfe9b1SMichel JAOUEN 		line = (i << 3) + int_bit;
4817ccfe9b1SMichel JAOUEN 		latch_val &= ~(1 << int_bit);
4827ccfe9b1SMichel JAOUEN 
483e2ddf46aSLinus Walleij 		/*
484e2ddf46aSLinus Walleij 		 * This handles the falling edge hwirqs from the GPIO
485e2ddf46aSLinus Walleij 		 * lines. Route them back to the line registered for the
486e2ddf46aSLinus Walleij 		 * rising IRQ, as this is merely a flag for the same IRQ
487e2ddf46aSLinus Walleij 		 * in linux terms.
488e2ddf46aSLinus Walleij 		 */
489e2ddf46aSLinus Walleij 		if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F)
490e2ddf46aSLinus Walleij 			line -= 16;
491e2ddf46aSLinus Walleij 		if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F)
492e2ddf46aSLinus Walleij 			line -= 8;
493e2ddf46aSLinus Walleij 		if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F)
494e2ddf46aSLinus Walleij 			line += 1;
495e2ddf46aSLinus Walleij 
496ed83d301SLinus Walleij 		handle_nested_irq(irq_create_mapping(ab8500->domain, line));
4977a93fb37SFabio Baltieri 	}
4987ccfe9b1SMichel JAOUEN 
4997ccfe9b1SMichel JAOUEN 	return 0;
5007ccfe9b1SMichel JAOUEN }
5017ccfe9b1SMichel JAOUEN 
5027ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500,
5037ccfe9b1SMichel JAOUEN 					int hier_offset, u8 hier_val)
5047ccfe9b1SMichel JAOUEN {
5057ccfe9b1SMichel JAOUEN 	int latch_bit, status;
5067ccfe9b1SMichel JAOUEN 	u8 latch_offset, latch_val;
5077ccfe9b1SMichel JAOUEN 
5087ccfe9b1SMichel JAOUEN 	do {
5097ccfe9b1SMichel JAOUEN 		latch_bit = __ffs(hier_val);
5107ccfe9b1SMichel JAOUEN 		latch_offset = (hier_offset << 3) + latch_bit;
5117ccfe9b1SMichel JAOUEN 
5123e1a498fSLee Jones 		update_latch_offset(&latch_offset, hier_offset);
5137ccfe9b1SMichel JAOUEN 
5147ccfe9b1SMichel JAOUEN 		status = get_register_interruptible(ab8500,
5157ccfe9b1SMichel JAOUEN 				AB8500_INTERRUPT,
5167ccfe9b1SMichel JAOUEN 				AB8500_IT_LATCH1_REG + latch_offset,
5177ccfe9b1SMichel JAOUEN 				&latch_val);
5187ccfe9b1SMichel JAOUEN 		if (status < 0 || latch_val == 0)
5197ccfe9b1SMichel JAOUEN 			goto discard;
5207ccfe9b1SMichel JAOUEN 
5217ccfe9b1SMichel JAOUEN 		status = ab8500_handle_hierarchical_line(ab8500,
5227ccfe9b1SMichel JAOUEN 				latch_offset, latch_val);
5237ccfe9b1SMichel JAOUEN 		if (status < 0)
5247ccfe9b1SMichel JAOUEN 			return status;
5257ccfe9b1SMichel JAOUEN discard:
5267ccfe9b1SMichel JAOUEN 		hier_val &= ~(1 << latch_bit);
5277ccfe9b1SMichel JAOUEN 	} while (hier_val);
5287ccfe9b1SMichel JAOUEN 
5297ccfe9b1SMichel JAOUEN 	return 0;
5307ccfe9b1SMichel JAOUEN }
5317ccfe9b1SMichel JAOUEN 
5327ccfe9b1SMichel JAOUEN static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev)
5337ccfe9b1SMichel JAOUEN {
5347ccfe9b1SMichel JAOUEN 	struct ab8500 *ab8500 = dev;
5357ccfe9b1SMichel JAOUEN 	u8 i;
5367ccfe9b1SMichel JAOUEN 
5377ccfe9b1SMichel JAOUEN 	dev_vdbg(ab8500->dev, "interrupt\n");
5387ccfe9b1SMichel JAOUEN 
5397ccfe9b1SMichel JAOUEN 	/*  Hierarchical interrupt version */
5403e1a498fSLee Jones 	for (i = 0; i < (ab8500->it_latchhier_num); i++) {
5417ccfe9b1SMichel JAOUEN 		int status;
5427ccfe9b1SMichel JAOUEN 		u8 hier_val;
5437ccfe9b1SMichel JAOUEN 
5447ccfe9b1SMichel JAOUEN 		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
5457ccfe9b1SMichel JAOUEN 			AB8500_IT_LATCHHIER1_REG + i, &hier_val);
5467ccfe9b1SMichel JAOUEN 		if (status < 0 || hier_val == 0)
5477ccfe9b1SMichel JAOUEN 			continue;
5487ccfe9b1SMichel JAOUEN 
5497ccfe9b1SMichel JAOUEN 		status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val);
5507ccfe9b1SMichel JAOUEN 		if (status < 0)
5517ccfe9b1SMichel JAOUEN 			break;
5527ccfe9b1SMichel JAOUEN 	}
5537ccfe9b1SMichel JAOUEN 	return IRQ_HANDLED;
5547ccfe9b1SMichel JAOUEN }
5557ccfe9b1SMichel JAOUEN 
55606e589efSLee Jones static int ab8500_irq_map(struct irq_domain *d, unsigned int virq,
55706e589efSLee Jones 				irq_hw_number_t hwirq)
55806e589efSLee Jones {
55906e589efSLee Jones 	struct ab8500 *ab8500 = d->host_data;
56006e589efSLee Jones 
56106e589efSLee Jones 	if (!ab8500)
56206e589efSLee Jones 		return -EINVAL;
56306e589efSLee Jones 
56406e589efSLee Jones 	irq_set_chip_data(virq, ab8500);
56506e589efSLee Jones 	irq_set_chip_and_handler(virq, &ab8500_irq_chip,
56606e589efSLee Jones 				handle_simple_irq);
56706e589efSLee Jones 	irq_set_nested_thread(virq, 1);
56806e589efSLee Jones 	irq_set_noprobe(virq);
56962579266SRabin Vincent 
57062579266SRabin Vincent 	return 0;
57162579266SRabin Vincent }
57262579266SRabin Vincent 
5737ce7b26fSKrzysztof Kozlowski static const struct irq_domain_ops ab8500_irq_ops = {
57406e589efSLee Jones 	.map    = ab8500_irq_map,
57506e589efSLee Jones 	.xlate  = irq_domain_xlate_twocell,
57606e589efSLee Jones };
57706e589efSLee Jones 
57806e589efSLee Jones static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np)
57962579266SRabin Vincent {
5802ced445eSLinus Walleij 	int num_irqs;
58162579266SRabin Vincent 
5823e1a498fSLee Jones 	if (is_ab8540(ab8500))
5833e1a498fSLee Jones 		num_irqs = AB8540_NR_IRQS;
5843e1a498fSLee Jones 	else if (is_ab9540(ab8500))
585d6255529SLinus Walleij 		num_irqs = AB9540_NR_IRQS;
586a982362cSBengt Jonsson 	else if (is_ab8505(ab8500))
587a982362cSBengt Jonsson 		num_irqs = AB8505_NR_IRQS;
588d6255529SLinus Walleij 	else
5892ced445eSLinus Walleij 		num_irqs = AB8500_NR_IRQS;
5902ced445eSLinus Walleij 
591f1d11f39SLinus Walleij 	/* If ->irq_base is zero this will give a linear mapping */
5927602e05dSGrygorii Strashko 	ab8500->domain = irq_domain_add_simple(ab8500->dev->of_node,
593f864c46aSLinus Walleij 					       num_irqs, 0,
594f1d11f39SLinus Walleij 					       &ab8500_irq_ops, ab8500);
59506e589efSLee Jones 
59606e589efSLee Jones 	if (!ab8500->domain) {
59706e589efSLee Jones 		dev_err(ab8500->dev, "Failed to create irqdomain\n");
598500e69a1SLee Jones 		return -ENODEV;
59906e589efSLee Jones 	}
60006e589efSLee Jones 
60106e589efSLee Jones 	return 0;
60262579266SRabin Vincent }
60362579266SRabin Vincent 
604112a80d2SJonas Aaberg int ab8500_suspend(struct ab8500 *ab8500)
605112a80d2SJonas Aaberg {
606112a80d2SJonas Aaberg 	if (atomic_read(&ab8500->transfer_ongoing))
607112a80d2SJonas Aaberg 		return -EINVAL;
608f3556302SLee Jones 
609112a80d2SJonas Aaberg 	return 0;
610112a80d2SJonas Aaberg }
611112a80d2SJonas Aaberg 
6125ac98553SGeert Uytterhoeven static const struct mfd_cell ab8500_bm_devs[] = {
6136ef9418cSRickard Andersson 	{
6146ef9418cSRickard Andersson 		.name = "ab8500-charger",
6154aef72dbSRajanikanth H.V 		.of_compatible = "stericsson,ab8500-charger",
6164aef72dbSRajanikanth H.V 		.platform_data = &ab8500_bm_data,
6174aef72dbSRajanikanth H.V 		.pdata_size = sizeof(ab8500_bm_data),
6186ef9418cSRickard Andersson 	},
6196ef9418cSRickard Andersson 	{
6206ef9418cSRickard Andersson 		.name = "ab8500-btemp",
621bd9e8ab2SRajanikanth H.V 		.of_compatible = "stericsson,ab8500-btemp",
622bd9e8ab2SRajanikanth H.V 		.platform_data = &ab8500_bm_data,
623bd9e8ab2SRajanikanth H.V 		.pdata_size = sizeof(ab8500_bm_data),
6246ef9418cSRickard Andersson 	},
6256ef9418cSRickard Andersson 	{
6266ef9418cSRickard Andersson 		.name = "ab8500-fg",
627e0f1abebSRajanikanth H.V 		.of_compatible = "stericsson,ab8500-fg",
628e0f1abebSRajanikanth H.V 		.platform_data = &ab8500_bm_data,
629e0f1abebSRajanikanth H.V 		.pdata_size = sizeof(ab8500_bm_data),
6306ef9418cSRickard Andersson 	},
6316ef9418cSRickard Andersson 	{
6326ef9418cSRickard Andersson 		.name = "ab8500-chargalg",
633a12810abSRajanikanth H.V 		.of_compatible = "stericsson,ab8500-chargalg",
634a12810abSRajanikanth H.V 		.platform_data = &ab8500_bm_data,
635a12810abSRajanikanth H.V 		.pdata_size = sizeof(ab8500_bm_data),
6366ef9418cSRickard Andersson 	},
6376ef9418cSRickard Andersson };
6386ef9418cSRickard Andersson 
6395ac98553SGeert Uytterhoeven static const struct mfd_cell ab8500_devs[] = {
6404b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS
641d6255529SLinus Walleij 	{
6424b106fb9SLee Jones 		.name = "ab8500-debug",
6434b106fb9SLee Jones 		.of_compatible = "stericsson,ab8500-debug",
6444b106fb9SLee Jones 	},
6454b106fb9SLee Jones #endif
6464b106fb9SLee Jones 	{
6474b106fb9SLee Jones 		.name = "ab8500-sysctrl",
6484b106fb9SLee Jones 		.of_compatible = "stericsson,ab8500-sysctrl",
6494b106fb9SLee Jones 	},
6504b106fb9SLee Jones 	{
65153f325beSLee Jones 		.name = "ab8500-ext-regulator",
65253f325beSLee Jones 		.of_compatible = "stericsson,ab8500-ext-regulator",
65353f325beSLee Jones 	},
65453f325beSLee Jones 	{
6554b106fb9SLee Jones 		.name = "ab8500-regulator",
6564b106fb9SLee Jones 		.of_compatible = "stericsson,ab8500-regulator",
6574b106fb9SLee Jones 	},
6584b106fb9SLee Jones 	{
65991549e87SLinus Walleij 		.name = "ab8500-clk",
66091549e87SLinus Walleij 		.of_compatible = "stericsson,ab8500-clk",
6614b106fb9SLee Jones 	},
6624b106fb9SLee Jones 	{
6634b106fb9SLee Jones 		.name = "ab8500-gpadc",
664955de2eaSLee Jones 		.of_compatible = "stericsson,ab8500-gpadc",
6654b106fb9SLee Jones 	},
6664b106fb9SLee Jones 	{
6674b106fb9SLee Jones 		.name = "ab8500-rtc",
6684b106fb9SLee Jones 		.of_compatible = "stericsson,ab8500-rtc",
6694b106fb9SLee Jones 	},
6704b106fb9SLee Jones 	{
6714b106fb9SLee Jones 		.name = "ab8500-acc-det",
6724b106fb9SLee Jones 		.of_compatible = "stericsson,ab8500-acc-det",
6734b106fb9SLee Jones 	},
6744b106fb9SLee Jones 	{
6754b106fb9SLee Jones 
6764b106fb9SLee Jones 		.name = "ab8500-poweron-key",
6774b106fb9SLee Jones 		.of_compatible = "stericsson,ab8500-poweron-key",
6784b106fb9SLee Jones 	},
6794b106fb9SLee Jones 	{
6804b106fb9SLee Jones 		.name = "ab8500-pwm",
6814b106fb9SLee Jones 		.of_compatible = "stericsson,ab8500-pwm",
6824b106fb9SLee Jones 		.id = 1,
6834b106fb9SLee Jones 	},
6844b106fb9SLee Jones 	{
6854b106fb9SLee Jones 		.name = "ab8500-pwm",
6864b106fb9SLee Jones 		.of_compatible = "stericsson,ab8500-pwm",
6874b106fb9SLee Jones 		.id = 2,
6884b106fb9SLee Jones 	},
6894b106fb9SLee Jones 	{
6904b106fb9SLee Jones 		.name = "ab8500-pwm",
6914b106fb9SLee Jones 		.of_compatible = "stericsson,ab8500-pwm",
6924b106fb9SLee Jones 		.id = 3,
6934b106fb9SLee Jones 	},
6944b106fb9SLee Jones 	{
6954b106fb9SLee Jones 		.name = "ab8500-denc",
6964b106fb9SLee Jones 		.of_compatible = "stericsson,ab8500-denc",
6974b106fb9SLee Jones 	},
6984b106fb9SLee Jones 	{
699eb696c31SLee Jones 		.name = "pinctrl-ab8500",
700bad76991SLee Jones 		.of_compatible = "stericsson,ab8500-gpio",
701d6255529SLinus Walleij 	},
702d6255529SLinus Walleij 	{
7034b106fb9SLee Jones 		.name = "abx500-temp",
7044b106fb9SLee Jones 		.of_compatible = "stericsson,abx500-temp",
7054b106fb9SLee Jones 	},
7064b106fb9SLee Jones 	{
707d6255529SLinus Walleij 		.name = "ab8500-usb",
708f201f730SFabio Baltieri 		.of_compatible = "stericsson,ab8500-usb",
709d6255529SLinus Walleij 	},
71044f72e53SVirupax Sadashivpetimath 	{
71144f72e53SVirupax Sadashivpetimath 		.name = "ab8500-codec",
712fccf14adSFabio Baltieri 		.of_compatible = "stericsson,ab8500-codec",
7134b106fb9SLee Jones 	},
7144b106fb9SLee Jones };
7154b106fb9SLee Jones 
7165ac98553SGeert Uytterhoeven static const struct mfd_cell ab9540_devs[] = {
7174b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS
7184b106fb9SLee Jones 	{
7194b106fb9SLee Jones 		.name = "ab8500-debug",
7204b106fb9SLee Jones 	},
7214b106fb9SLee Jones #endif
7224b106fb9SLee Jones 	{
7234b106fb9SLee Jones 		.name = "ab8500-sysctrl",
7244b106fb9SLee Jones 	},
7254b106fb9SLee Jones 	{
72653f325beSLee Jones 		.name = "ab8500-ext-regulator",
72753f325beSLee Jones 	},
72853f325beSLee Jones 	{
7294b106fb9SLee Jones 		.name = "ab8500-regulator",
73044f72e53SVirupax Sadashivpetimath 	},
731c0eda9aeSLee Jones 	{
7329ee17676SUlf Hansson 		.name = "abx500-clk",
7339ee17676SUlf Hansson 		.of_compatible = "stericsson,abx500-clk",
7349ee17676SUlf Hansson 	},
7359ee17676SUlf Hansson 	{
736c0eda9aeSLee Jones 		.name = "ab8500-gpadc",
737c0eda9aeSLee Jones 		.of_compatible = "stericsson,ab8500-gpadc",
738c0eda9aeSLee Jones 	},
7394b106fb9SLee Jones 	{
7404b106fb9SLee Jones 		.name = "ab8500-rtc",
7414b106fb9SLee Jones 	},
7424b106fb9SLee Jones 	{
7434b106fb9SLee Jones 		.name = "ab8500-acc-det",
7444b106fb9SLee Jones 	},
7454b106fb9SLee Jones 	{
7464b106fb9SLee Jones 		.name = "ab8500-poweron-key",
7474b106fb9SLee Jones 	},
7484b106fb9SLee Jones 	{
7494b106fb9SLee Jones 		.name = "ab8500-pwm",
7504b106fb9SLee Jones 		.id = 1,
7514b106fb9SLee Jones 	},
7524b106fb9SLee Jones 	{
7534b106fb9SLee Jones 		.name = "abx500-temp",
7544b106fb9SLee Jones 	},
755d6255529SLinus Walleij 	{
756e64d905eSLee Jones 		.name = "pinctrl-ab9540",
757e64d905eSLee Jones 		.of_compatible = "stericsson,ab9540-gpio",
758d6255529SLinus Walleij 	},
759d6255529SLinus Walleij 	{
760d6255529SLinus Walleij 		.name = "ab9540-usb",
761d6255529SLinus Walleij 	},
76244f72e53SVirupax Sadashivpetimath 	{
76344f72e53SVirupax Sadashivpetimath 		.name = "ab9540-codec",
76444f72e53SVirupax Sadashivpetimath 	},
765c0eda9aeSLee Jones 	{
766c0eda9aeSLee Jones 		.name = "ab-iddet",
767c0eda9aeSLee Jones 	},
76844f72e53SVirupax Sadashivpetimath };
76944f72e53SVirupax Sadashivpetimath 
770c0eda9aeSLee Jones /* Device list for ab8505  */
7715ac98553SGeert Uytterhoeven static const struct mfd_cell ab8505_devs[] = {
7724b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS
7734b106fb9SLee Jones 	{
7744b106fb9SLee Jones 		.name = "ab8500-debug",
7754b106fb9SLee Jones 	},
7764b106fb9SLee Jones #endif
7774b106fb9SLee Jones 	{
7784b106fb9SLee Jones 		.name = "ab8500-sysctrl",
7794b106fb9SLee Jones 	},
7804b106fb9SLee Jones 	{
7814b106fb9SLee Jones 		.name = "ab8500-regulator",
7824b106fb9SLee Jones 	},
7834b106fb9SLee Jones 	{
7849ee17676SUlf Hansson 		.name = "abx500-clk",
7859ee17676SUlf Hansson 		.of_compatible = "stericsson,abx500-clk",
7869ee17676SUlf Hansson 	},
7879ee17676SUlf Hansson 	{
7884b106fb9SLee Jones 		.name = "ab8500-gpadc",
789955de2eaSLee Jones 		.of_compatible = "stericsson,ab8500-gpadc",
7904b106fb9SLee Jones 	},
7914b106fb9SLee Jones 	{
7924b106fb9SLee Jones 		.name = "ab8500-rtc",
7934b106fb9SLee Jones 	},
7944b106fb9SLee Jones 	{
7954b106fb9SLee Jones 		.name = "ab8500-acc-det",
7964b106fb9SLee Jones 	},
7974b106fb9SLee Jones 	{
7984b106fb9SLee Jones 		.name = "ab8500-poweron-key",
7994b106fb9SLee Jones 	},
8004b106fb9SLee Jones 	{
8014b106fb9SLee Jones 		.name = "ab8500-pwm",
8024b106fb9SLee Jones 		.id = 1,
8034b106fb9SLee Jones 	},
8044b106fb9SLee Jones 	{
805eb696c31SLee Jones 		.name = "pinctrl-ab8505",
8064b106fb9SLee Jones 	},
8074b106fb9SLee Jones 	{
8084b106fb9SLee Jones 		.name = "ab8500-usb",
8094b106fb9SLee Jones 	},
8104b106fb9SLee Jones 	{
8114b106fb9SLee Jones 		.name = "ab8500-codec",
8124b106fb9SLee Jones 	},
813c0eda9aeSLee Jones 	{
814c0eda9aeSLee Jones 		.name = "ab-iddet",
815c0eda9aeSLee Jones 	},
816c0eda9aeSLee Jones };
817c0eda9aeSLee Jones 
8185ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_devs[] = {
8194b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS
8204b106fb9SLee Jones 	{
8214b106fb9SLee Jones 		.name = "ab8500-debug",
8224b106fb9SLee Jones 	},
8234b106fb9SLee Jones #endif
8244b106fb9SLee Jones 	{
8254b106fb9SLee Jones 		.name = "ab8500-sysctrl",
8264b106fb9SLee Jones 	},
8274b106fb9SLee Jones 	{
82853f325beSLee Jones 		.name = "ab8500-ext-regulator",
82953f325beSLee Jones 	},
83053f325beSLee Jones 	{
8314b106fb9SLee Jones 		.name = "ab8500-regulator",
8324b106fb9SLee Jones 	},
8334b106fb9SLee Jones 	{
8349ee17676SUlf Hansson 		.name = "abx500-clk",
8359ee17676SUlf Hansson 		.of_compatible = "stericsson,abx500-clk",
8369ee17676SUlf Hansson 	},
8379ee17676SUlf Hansson 	{
8384b106fb9SLee Jones 		.name = "ab8500-gpadc",
839955de2eaSLee Jones 		.of_compatible = "stericsson,ab8500-gpadc",
8404b106fb9SLee Jones 	},
8414b106fb9SLee Jones 	{
8424b106fb9SLee Jones 		.name = "ab8500-acc-det",
8434b106fb9SLee Jones 	},
8444b106fb9SLee Jones 	{
8454b106fb9SLee Jones 		.name = "ab8500-poweron-key",
8464b106fb9SLee Jones 	},
8474b106fb9SLee Jones 	{
8484b106fb9SLee Jones 		.name = "ab8500-pwm",
8494b106fb9SLee Jones 		.id = 1,
8504b106fb9SLee Jones 	},
8514b106fb9SLee Jones 	{
8524b106fb9SLee Jones 		.name = "abx500-temp",
8534b106fb9SLee Jones 	},
854c0eda9aeSLee Jones 	{
855eb696c31SLee Jones 		.name = "pinctrl-ab8540",
856c0eda9aeSLee Jones 	},
857c0eda9aeSLee Jones 	{
858c0eda9aeSLee Jones 		.name = "ab8540-usb",
859c0eda9aeSLee Jones 	},
860c0eda9aeSLee Jones 	{
861c0eda9aeSLee Jones 		.name = "ab8540-codec",
862c0eda9aeSLee Jones 	},
863c0eda9aeSLee Jones 	{
86444f72e53SVirupax Sadashivpetimath 		.name = "ab-iddet",
86544f72e53SVirupax Sadashivpetimath 	},
866d6255529SLinus Walleij };
867d6255529SLinus Walleij 
8685ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_cut1_devs[] = {
8699c717cf3SAlexandre Torgue 	{
8709c717cf3SAlexandre Torgue 		.name = "ab8500-rtc",
8719c717cf3SAlexandre Torgue 		.of_compatible = "stericsson,ab8500-rtc",
8729c717cf3SAlexandre Torgue 	},
8739c717cf3SAlexandre Torgue };
8749c717cf3SAlexandre Torgue 
8755ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_cut2_devs[] = {
8769c717cf3SAlexandre Torgue 	{
8779c717cf3SAlexandre Torgue 		.name = "ab8540-rtc",
8789c717cf3SAlexandre Torgue 		.of_compatible = "stericsson,ab8540-rtc",
8799c717cf3SAlexandre Torgue 	},
8809c717cf3SAlexandre Torgue };
8819c717cf3SAlexandre Torgue 
882cca69b67SMattias Wallin static ssize_t show_chip_id(struct device *dev,
883cca69b67SMattias Wallin 				struct device_attribute *attr, char *buf)
884cca69b67SMattias Wallin {
885cca69b67SMattias Wallin 	struct ab8500 *ab8500;
886cca69b67SMattias Wallin 
887cca69b67SMattias Wallin 	ab8500 = dev_get_drvdata(dev);
888e436ddffSLee Jones 
889cca69b67SMattias Wallin 	return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
890cca69b67SMattias Wallin }
891cca69b67SMattias Wallin 
892e5c238c3SMattias Wallin /*
893e5c238c3SMattias Wallin  * ab8500 has switched off due to (SWITCH_OFF_STATUS):
894e5c238c3SMattias Wallin  * 0x01 Swoff bit programming
895e5c238c3SMattias Wallin  * 0x02 Thermal protection activation
896e5c238c3SMattias Wallin  * 0x04 Vbat lower then BattOk falling threshold
897e5c238c3SMattias Wallin  * 0x08 Watchdog expired
898e5c238c3SMattias Wallin  * 0x10 Non presence of 32kHz clock
899e5c238c3SMattias Wallin  * 0x20 Battery level lower than power on reset threshold
900e5c238c3SMattias Wallin  * 0x40 Power on key 1 pressed longer than 10 seconds
901e5c238c3SMattias Wallin  * 0x80 DB8500 thermal shutdown
902e5c238c3SMattias Wallin  */
903e5c238c3SMattias Wallin static ssize_t show_switch_off_status(struct device *dev,
904e5c238c3SMattias Wallin 				struct device_attribute *attr, char *buf)
905e5c238c3SMattias Wallin {
906e5c238c3SMattias Wallin 	int ret;
907e5c238c3SMattias Wallin 	u8 value;
908e5c238c3SMattias Wallin 	struct ab8500 *ab8500;
909e5c238c3SMattias Wallin 
910e5c238c3SMattias Wallin 	ab8500 = dev_get_drvdata(dev);
911e5c238c3SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_RTC,
912e5c238c3SMattias Wallin 		AB8500_SWITCH_OFF_STATUS, &value);
913e5c238c3SMattias Wallin 	if (ret < 0)
914e5c238c3SMattias Wallin 		return ret;
915e5c238c3SMattias Wallin 	return sprintf(buf, "%#x\n", value);
916e5c238c3SMattias Wallin }
917e5c238c3SMattias Wallin 
918f04a9d8aSRajkumar Kasirajan /* use mask and set to override the register turn_on_stat value */
919f04a9d8aSRajkumar Kasirajan void ab8500_override_turn_on_stat(u8 mask, u8 set)
920f04a9d8aSRajkumar Kasirajan {
921f04a9d8aSRajkumar Kasirajan 	spin_lock(&on_stat_lock);
922f04a9d8aSRajkumar Kasirajan 	turn_on_stat_mask = mask;
923f04a9d8aSRajkumar Kasirajan 	turn_on_stat_set = set;
924f04a9d8aSRajkumar Kasirajan 	spin_unlock(&on_stat_lock);
925f04a9d8aSRajkumar Kasirajan }
926f04a9d8aSRajkumar Kasirajan 
927b4a31037SAndrew Lynn /*
928b4a31037SAndrew Lynn  * ab8500 has turned on due to (TURN_ON_STATUS):
929b4a31037SAndrew Lynn  * 0x01 PORnVbat
930b4a31037SAndrew Lynn  * 0x02 PonKey1dbF
931b4a31037SAndrew Lynn  * 0x04 PonKey2dbF
932b4a31037SAndrew Lynn  * 0x08 RTCAlarm
933b4a31037SAndrew Lynn  * 0x10 MainChDet
934b4a31037SAndrew Lynn  * 0x20 VbusDet
935b4a31037SAndrew Lynn  * 0x40 UsbIDDetect
936b4a31037SAndrew Lynn  * 0x80 Reserved
937b4a31037SAndrew Lynn  */
938b4a31037SAndrew Lynn static ssize_t show_turn_on_status(struct device *dev,
939b4a31037SAndrew Lynn 				struct device_attribute *attr, char *buf)
940b4a31037SAndrew Lynn {
941b4a31037SAndrew Lynn 	int ret;
942b4a31037SAndrew Lynn 	u8 value;
943b4a31037SAndrew Lynn 	struct ab8500 *ab8500;
944b4a31037SAndrew Lynn 
945b4a31037SAndrew Lynn 	ab8500 = dev_get_drvdata(dev);
946b4a31037SAndrew Lynn 	ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
947b4a31037SAndrew Lynn 		AB8500_TURN_ON_STATUS, &value);
948b4a31037SAndrew Lynn 	if (ret < 0)
949b4a31037SAndrew Lynn 		return ret;
950f04a9d8aSRajkumar Kasirajan 
951f04a9d8aSRajkumar Kasirajan 	/*
952f04a9d8aSRajkumar Kasirajan 	 * In L9540, turn_on_status register is not updated correctly if
953f04a9d8aSRajkumar Kasirajan 	 * the device is rebooted with AC/USB charger connected. Due to
954f04a9d8aSRajkumar Kasirajan 	 * this, the device boots android instead of entering into charge
955f04a9d8aSRajkumar Kasirajan 	 * only mode. Read the AC/USB status register to detect the charger
956f04a9d8aSRajkumar Kasirajan 	 * presence and update the turn on status manually.
957f04a9d8aSRajkumar Kasirajan 	 */
958f04a9d8aSRajkumar Kasirajan 	if (is_ab9540(ab8500)) {
959f04a9d8aSRajkumar Kasirajan 		spin_lock(&on_stat_lock);
960f04a9d8aSRajkumar Kasirajan 		value = (value & turn_on_stat_mask) | turn_on_stat_set;
961f04a9d8aSRajkumar Kasirajan 		spin_unlock(&on_stat_lock);
962f04a9d8aSRajkumar Kasirajan 	}
963f04a9d8aSRajkumar Kasirajan 
964b4a31037SAndrew Lynn 	return sprintf(buf, "%#x\n", value);
965b4a31037SAndrew Lynn }
966b4a31037SAndrew Lynn 
96793ff722eSLee Jones static ssize_t show_turn_on_status_2(struct device *dev,
96893ff722eSLee Jones 				struct device_attribute *attr, char *buf)
96993ff722eSLee Jones {
97093ff722eSLee Jones 	int ret;
97193ff722eSLee Jones 	u8 value;
97293ff722eSLee Jones 	struct ab8500 *ab8500;
97393ff722eSLee Jones 
97493ff722eSLee Jones 	ab8500 = dev_get_drvdata(dev);
97593ff722eSLee Jones 	ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
97693ff722eSLee Jones 		AB8505_TURN_ON_STATUS_2, &value);
97793ff722eSLee Jones 	if (ret < 0)
97893ff722eSLee Jones 		return ret;
97993ff722eSLee Jones 	return sprintf(buf, "%#x\n", (value & 0x1));
98093ff722eSLee Jones }
98193ff722eSLee Jones 
982d6255529SLinus Walleij static ssize_t show_ab9540_dbbrstn(struct device *dev,
983d6255529SLinus Walleij 				struct device_attribute *attr, char *buf)
984d6255529SLinus Walleij {
985d6255529SLinus Walleij 	struct ab8500 *ab8500;
986d6255529SLinus Walleij 	int ret;
987d6255529SLinus Walleij 	u8 value;
988d6255529SLinus Walleij 
989d6255529SLinus Walleij 	ab8500 = dev_get_drvdata(dev);
990d6255529SLinus Walleij 
991d6255529SLinus Walleij 	ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2,
992d6255529SLinus Walleij 		AB9540_MODEM_CTRL2_REG, &value);
993d6255529SLinus Walleij 	if (ret < 0)
994d6255529SLinus Walleij 		return ret;
995d6255529SLinus Walleij 
996d6255529SLinus Walleij 	return sprintf(buf, "%d\n",
997d6255529SLinus Walleij 			(value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0);
998d6255529SLinus Walleij }
999d6255529SLinus Walleij 
1000d6255529SLinus Walleij static ssize_t store_ab9540_dbbrstn(struct device *dev,
1001d6255529SLinus Walleij 	struct device_attribute *attr, const char *buf, size_t count)
1002d6255529SLinus Walleij {
1003d6255529SLinus Walleij 	struct ab8500 *ab8500;
1004d6255529SLinus Walleij 	int ret = count;
1005d6255529SLinus Walleij 	int err;
1006d6255529SLinus Walleij 	u8 bitvalues;
1007d6255529SLinus Walleij 
1008d6255529SLinus Walleij 	ab8500 = dev_get_drvdata(dev);
1009d6255529SLinus Walleij 
1010d6255529SLinus Walleij 	if (count > 0) {
1011d6255529SLinus Walleij 		switch (buf[0]) {
1012d6255529SLinus Walleij 		case '0':
1013d6255529SLinus Walleij 			bitvalues = 0;
1014d6255529SLinus Walleij 			break;
1015d6255529SLinus Walleij 		case '1':
1016d6255529SLinus Walleij 			bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT;
1017d6255529SLinus Walleij 			break;
1018d6255529SLinus Walleij 		default:
1019d6255529SLinus Walleij 			goto exit;
1020d6255529SLinus Walleij 		}
1021d6255529SLinus Walleij 
1022d6255529SLinus Walleij 		err = mask_and_set_register_interruptible(ab8500,
1023d6255529SLinus Walleij 			AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG,
1024d6255529SLinus Walleij 			AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues);
1025d6255529SLinus Walleij 		if (err)
1026d6255529SLinus Walleij 			dev_info(ab8500->dev,
1027d6255529SLinus Walleij 				"Failed to set DBBRSTN %c, err %#x\n",
1028d6255529SLinus Walleij 				buf[0], err);
1029d6255529SLinus Walleij 	}
1030d6255529SLinus Walleij 
1031d6255529SLinus Walleij exit:
1032d6255529SLinus Walleij 	return ret;
1033d6255529SLinus Walleij }
1034d6255529SLinus Walleij 
1035cca69b67SMattias Wallin static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
1036e5c238c3SMattias Wallin static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
1037b4a31037SAndrew Lynn static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
103893ff722eSLee Jones static DEVICE_ATTR(turn_on_status_2, S_IRUGO, show_turn_on_status_2, NULL);
1039d6255529SLinus Walleij static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR,
1040d6255529SLinus Walleij 			show_ab9540_dbbrstn, store_ab9540_dbbrstn);
1041cca69b67SMattias Wallin 
1042cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = {
1043cca69b67SMattias Wallin 	&dev_attr_chip_id.attr,
1044e5c238c3SMattias Wallin 	&dev_attr_switch_off_status.attr,
1045b4a31037SAndrew Lynn 	&dev_attr_turn_on_status.attr,
1046cca69b67SMattias Wallin 	NULL,
1047cca69b67SMattias Wallin };
1048cca69b67SMattias Wallin 
104993ff722eSLee Jones static struct attribute *ab8505_sysfs_entries[] = {
105093ff722eSLee Jones 	&dev_attr_turn_on_status_2.attr,
105193ff722eSLee Jones 	NULL,
105293ff722eSLee Jones };
105393ff722eSLee Jones 
1054d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = {
1055d6255529SLinus Walleij 	&dev_attr_chip_id.attr,
1056d6255529SLinus Walleij 	&dev_attr_switch_off_status.attr,
1057d6255529SLinus Walleij 	&dev_attr_turn_on_status.attr,
1058d6255529SLinus Walleij 	&dev_attr_dbbrstn.attr,
1059d6255529SLinus Walleij 	NULL,
1060d6255529SLinus Walleij };
1061d6255529SLinus Walleij 
106252557dc6SArvind Yadav static const struct attribute_group ab8500_attr_group = {
1063cca69b67SMattias Wallin 	.attrs	= ab8500_sysfs_entries,
1064cca69b67SMattias Wallin };
1065cca69b67SMattias Wallin 
106652557dc6SArvind Yadav static const struct attribute_group ab8505_attr_group = {
106793ff722eSLee Jones 	.attrs	= ab8505_sysfs_entries,
106893ff722eSLee Jones };
106993ff722eSLee Jones 
107052557dc6SArvind Yadav static const struct attribute_group ab9540_attr_group = {
1071d6255529SLinus Walleij 	.attrs	= ab9540_sysfs_entries,
1072d6255529SLinus Walleij };
1073d6255529SLinus Walleij 
1074f791be49SBill Pemberton static int ab8500_probe(struct platform_device *pdev)
107562579266SRabin Vincent {
1076500e69a1SLee Jones 	static const char * const switch_off_status[] = {
1077b04c530cSJonas Aaberg 		"Swoff bit programming",
1078b04c530cSJonas Aaberg 		"Thermal protection activation",
1079b04c530cSJonas Aaberg 		"Vbat lower then BattOk falling threshold",
1080b04c530cSJonas Aaberg 		"Watchdog expired",
1081b04c530cSJonas Aaberg 		"Non presence of 32kHz clock",
1082b04c530cSJonas Aaberg 		"Battery level lower than power on reset threshold",
1083b04c530cSJonas Aaberg 		"Power on key 1 pressed longer than 10 seconds",
1084b04c530cSJonas Aaberg 		"DB8500 thermal shutdown"};
1085500e69a1SLee Jones 	static const char * const turn_on_status[] = {
1086abee26cdSMattias Wallin 		"Battery rising (Vbat)",
1087abee26cdSMattias Wallin 		"Power On Key 1 dbF",
1088abee26cdSMattias Wallin 		"Power On Key 2 dbF",
1089abee26cdSMattias Wallin 		"RTC Alarm",
1090abee26cdSMattias Wallin 		"Main Charger Detect",
1091abee26cdSMattias Wallin 		"Vbus Detect (USB)",
1092abee26cdSMattias Wallin 		"USB ID Detect",
1093abee26cdSMattias Wallin 		"UART Factory Mode Detect"};
1094d28f1db8SLee Jones 	const struct platform_device_id *platid = platform_get_device_id(pdev);
10956bc4a568SLee Jones 	enum ab8500_version version = AB8500_VERSION_UNDEFINED;
10966bc4a568SLee Jones 	struct device_node *np = pdev->dev.of_node;
1097d28f1db8SLee Jones 	struct ab8500 *ab8500;
1098d28f1db8SLee Jones 	struct resource *resource;
109962579266SRabin Vincent 	int ret;
110062579266SRabin Vincent 	int i;
110147c16975SMattias Wallin 	u8 value;
110262579266SRabin Vincent 
11037ccf40b1SLee Jones 	ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL);
1104d28f1db8SLee Jones 	if (!ab8500)
1105d28f1db8SLee Jones 		return -ENOMEM;
1106d28f1db8SLee Jones 
1107d28f1db8SLee Jones 	ab8500->dev = &pdev->dev;
1108d28f1db8SLee Jones 
1109d28f1db8SLee Jones 	resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1110f864c46aSLinus Walleij 	if (!resource) {
1111f864c46aSLinus Walleij 		dev_err(&pdev->dev, "no IRQ resource\n");
11128c4203cbSLee Jones 		return -ENODEV;
1113f864c46aSLinus Walleij 	}
1114d28f1db8SLee Jones 
1115d28f1db8SLee Jones 	ab8500->irq = resource->start;
1116d28f1db8SLee Jones 
1117822672a7SLee Jones 	ab8500->read = ab8500_prcmu_read;
1118822672a7SLee Jones 	ab8500->write = ab8500_prcmu_write;
1119822672a7SLee Jones 	ab8500->write_masked = ab8500_prcmu_write_masked;
1120d28f1db8SLee Jones 
112162579266SRabin Vincent 	mutex_init(&ab8500->lock);
112262579266SRabin Vincent 	mutex_init(&ab8500->irq_lock);
1123112a80d2SJonas Aaberg 	atomic_set(&ab8500->transfer_ongoing, 0);
112462579266SRabin Vincent 
1125d28f1db8SLee Jones 	platform_set_drvdata(pdev, ab8500);
1126d28f1db8SLee Jones 
11276bc4a568SLee Jones 	if (platid)
11286bc4a568SLee Jones 		version = platid->driver_data;
11296bc4a568SLee Jones 
11300f620837SLinus Walleij 	if (version != AB8500_VERSION_UNDEFINED)
11310f620837SLinus Walleij 		ab8500->version = version;
11320f620837SLinus Walleij 	else {
11330f620837SLinus Walleij 		ret = get_register_interruptible(ab8500, AB8500_MISC,
11340f620837SLinus Walleij 			AB8500_IC_NAME_REG, &value);
1135f864c46aSLinus Walleij 		if (ret < 0) {
1136f864c46aSLinus Walleij 			dev_err(&pdev->dev, "could not probe HW\n");
11378c4203cbSLee Jones 			return ret;
1138f864c46aSLinus Walleij 		}
11390f620837SLinus Walleij 
11400f620837SLinus Walleij 		ab8500->version = value;
11410f620837SLinus Walleij 	}
11420f620837SLinus Walleij 
114347c16975SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_MISC,
114447c16975SMattias Wallin 		AB8500_REV_REG, &value);
114562579266SRabin Vincent 	if (ret < 0)
11468c4203cbSLee Jones 		return ret;
114762579266SRabin Vincent 
114847c16975SMattias Wallin 	ab8500->chip_id = value;
114962579266SRabin Vincent 
11500f620837SLinus Walleij 	dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n",
11510f620837SLinus Walleij 			ab8500_version_str[ab8500->version],
11520f620837SLinus Walleij 			ab8500->chip_id >> 4,
11530f620837SLinus Walleij 			ab8500->chip_id & 0x0F);
11540f620837SLinus Walleij 
11553e1a498fSLee Jones 	/* Configure AB8540 */
11563e1a498fSLee Jones 	if (is_ab8540(ab8500)) {
11573e1a498fSLee Jones 		ab8500->mask_size = AB8540_NUM_IRQ_REGS;
11583e1a498fSLee Jones 		ab8500->irq_reg_offset = ab8540_irq_regoffset;
11593e1a498fSLee Jones 		ab8500->it_latchhier_num = AB8540_IT_LATCHHIER_NUM;
11603e1a498fSLee Jones 	} /* Configure AB8500 or AB9540 IRQ */
11613e1a498fSLee Jones 	else if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
1162d6255529SLinus Walleij 		ab8500->mask_size = AB9540_NUM_IRQ_REGS;
1163d6255529SLinus Walleij 		ab8500->irq_reg_offset = ab9540_irq_regoffset;
11643e1a498fSLee Jones 		ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM;
1165d6255529SLinus Walleij 	} else {
11662ced445eSLinus Walleij 		ab8500->mask_size = AB8500_NUM_IRQ_REGS;
11672ced445eSLinus Walleij 		ab8500->irq_reg_offset = ab8500_irq_regoffset;
11683e1a498fSLee Jones 		ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM;
1169d6255529SLinus Walleij 	}
11707ccf40b1SLee Jones 	ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size,
11717ccf40b1SLee Jones 				    GFP_KERNEL);
11722ced445eSLinus Walleij 	if (!ab8500->mask)
11732ced445eSLinus Walleij 		return -ENOMEM;
11747ccf40b1SLee Jones 	ab8500->oldmask = devm_kzalloc(&pdev->dev, ab8500->mask_size,
11757ccf40b1SLee Jones 				       GFP_KERNEL);
11768c4203cbSLee Jones 	if (!ab8500->oldmask)
11778c4203cbSLee Jones 		return -ENOMEM;
11788c4203cbSLee Jones 
1179e5c238c3SMattias Wallin 	/*
1180e5c238c3SMattias Wallin 	 * ab8500 has switched off due to (SWITCH_OFF_STATUS):
1181e5c238c3SMattias Wallin 	 * 0x01 Swoff bit programming
1182e5c238c3SMattias Wallin 	 * 0x02 Thermal protection activation
1183e5c238c3SMattias Wallin 	 * 0x04 Vbat lower then BattOk falling threshold
1184e5c238c3SMattias Wallin 	 * 0x08 Watchdog expired
1185e5c238c3SMattias Wallin 	 * 0x10 Non presence of 32kHz clock
1186e5c238c3SMattias Wallin 	 * 0x20 Battery level lower than power on reset threshold
1187e5c238c3SMattias Wallin 	 * 0x40 Power on key 1 pressed longer than 10 seconds
1188e5c238c3SMattias Wallin 	 * 0x80 DB8500 thermal shutdown
1189e5c238c3SMattias Wallin 	 */
1190e5c238c3SMattias Wallin 
1191e5c238c3SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_RTC,
1192e5c238c3SMattias Wallin 		AB8500_SWITCH_OFF_STATUS, &value);
1193e5c238c3SMattias Wallin 	if (ret < 0)
1194e5c238c3SMattias Wallin 		return ret;
1195b04c530cSJonas Aaberg 	dev_info(ab8500->dev, "switch off cause(s) (%#x): ", value);
1196b04c530cSJonas Aaberg 
1197b04c530cSJonas Aaberg 	if (value) {
1198b04c530cSJonas Aaberg 		for (i = 0; i < ARRAY_SIZE(switch_off_status); i++) {
1199b04c530cSJonas Aaberg 			if (value & 1)
12007ccf40b1SLee Jones 				pr_cont(" \"%s\"", switch_off_status[i]);
1201b04c530cSJonas Aaberg 			value = value >> 1;
1202b04c530cSJonas Aaberg 
1203b04c530cSJonas Aaberg 		}
12047ccf40b1SLee Jones 		pr_cont("\n");
1205b04c530cSJonas Aaberg 	} else {
12067ccf40b1SLee Jones 		pr_cont(" None\n");
1207b04c530cSJonas Aaberg 	}
1208abee26cdSMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
1209abee26cdSMattias Wallin 		AB8500_TURN_ON_STATUS, &value);
1210abee26cdSMattias Wallin 	if (ret < 0)
1211abee26cdSMattias Wallin 		return ret;
1212abee26cdSMattias Wallin 	dev_info(ab8500->dev, "turn on reason(s) (%#x): ", value);
1213abee26cdSMattias Wallin 
1214abee26cdSMattias Wallin 	if (value) {
1215abee26cdSMattias Wallin 		for (i = 0; i < ARRAY_SIZE(turn_on_status); i++) {
1216abee26cdSMattias Wallin 			if (value & 1)
12177ccf40b1SLee Jones 				pr_cont("\"%s\" ", turn_on_status[i]);
1218abee26cdSMattias Wallin 			value = value >> 1;
1219abee26cdSMattias Wallin 		}
12207ccf40b1SLee Jones 		pr_cont("\n");
1221abee26cdSMattias Wallin 	} else {
12227ccf40b1SLee Jones 		pr_cont("None\n");
1223abee26cdSMattias Wallin 	}
1224e5c238c3SMattias Wallin 
1225f04a9d8aSRajkumar Kasirajan 	if (is_ab9540(ab8500)) {
1226f04a9d8aSRajkumar Kasirajan 		ret = get_register_interruptible(ab8500, AB8500_CHARGER,
1227f04a9d8aSRajkumar Kasirajan 			AB8500_CH_USBCH_STAT1_REG, &value);
1228f04a9d8aSRajkumar Kasirajan 		if (ret < 0)
1229f04a9d8aSRajkumar Kasirajan 			return ret;
1230f04a9d8aSRajkumar Kasirajan 		if ((value & VBUS_DET_DBNC1) && (value & VBUS_DET_DBNC100))
1231f04a9d8aSRajkumar Kasirajan 			ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON,
1232f04a9d8aSRajkumar Kasirajan 						     AB8500_VBUS_DET);
1233f04a9d8aSRajkumar Kasirajan 	}
123462579266SRabin Vincent 
123562579266SRabin Vincent 	/* Clear and mask all interrupts */
12362ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++) {
12370f620837SLinus Walleij 		/*
12380f620837SLinus Walleij 		 * Interrupt register 12 doesn't exist prior to AB8500 version
12390f620837SLinus Walleij 		 * 2.0
12400f620837SLinus Walleij 		 */
12410f620837SLinus Walleij 		if (ab8500->irq_reg_offset[i] == 11 &&
12420f620837SLinus Walleij 				is_ab8500_1p1_or_earlier(ab8500))
124392d50a41SMattias Wallin 			continue;
124462579266SRabin Vincent 
12453e1a498fSLee Jones 		if (ab8500->irq_reg_offset[i] < 0)
12463e1a498fSLee Jones 			continue;
12473e1a498fSLee Jones 
124847c16975SMattias Wallin 		get_register_interruptible(ab8500, AB8500_INTERRUPT,
12492ced445eSLinus Walleij 			AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
125092d50a41SMattias Wallin 			&value);
125147c16975SMattias Wallin 		set_register_interruptible(ab8500, AB8500_INTERRUPT,
12522ced445eSLinus Walleij 			AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff);
125362579266SRabin Vincent 	}
125462579266SRabin Vincent 
125547c16975SMattias Wallin 	ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
125647c16975SMattias Wallin 	if (ret)
12578c4203cbSLee Jones 		return ret;
125847c16975SMattias Wallin 
12592ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++)
126062579266SRabin Vincent 		ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
126162579266SRabin Vincent 
126206e589efSLee Jones 	ret = ab8500_irq_init(ab8500, np);
126362579266SRabin Vincent 	if (ret)
12648c4203cbSLee Jones 		return ret;
126562579266SRabin Vincent 
12668c4203cbSLee Jones 	ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL,
12677ccfe9b1SMichel JAOUEN 			ab8500_hierarchical_irq,
12687ccfe9b1SMichel JAOUEN 			IRQF_ONESHOT | IRQF_NO_SUSPEND,
12697ccfe9b1SMichel JAOUEN 			"ab8500", ab8500);
127062579266SRabin Vincent 	if (ret)
12718c4203cbSLee Jones 		return ret;
127262579266SRabin Vincent 
1273d6255529SLinus Walleij 	if (is_ab9540(ab8500))
1274d6255529SLinus Walleij 		ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
1275d6255529SLinus Walleij 				ARRAY_SIZE(ab9540_devs), NULL,
1276f864c46aSLinus Walleij 				0, ab8500->domain);
12779c717cf3SAlexandre Torgue 	else if (is_ab8540(ab8500)) {
1278c0eda9aeSLee Jones 		ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs,
1279c0eda9aeSLee Jones 			      ARRAY_SIZE(ab8540_devs), NULL,
1280f864c46aSLinus Walleij 			      0, ab8500->domain);
12819c717cf3SAlexandre Torgue 		if (ret)
12829c717cf3SAlexandre Torgue 			return ret;
12839c717cf3SAlexandre Torgue 
12849c717cf3SAlexandre Torgue 		if (is_ab8540_1p2_or_earlier(ab8500))
12859c717cf3SAlexandre Torgue 			ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut1_devs,
12869c717cf3SAlexandre Torgue 			      ARRAY_SIZE(ab8540_cut1_devs), NULL,
1287f864c46aSLinus Walleij 			      0, ab8500->domain);
12889c717cf3SAlexandre Torgue 		else /* ab8540 >= cut2 */
12899c717cf3SAlexandre Torgue 			ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut2_devs,
12909c717cf3SAlexandre Torgue 			      ARRAY_SIZE(ab8540_cut2_devs), NULL,
1291f864c46aSLinus Walleij 			      0, ab8500->domain);
12929c717cf3SAlexandre Torgue 	} else if (is_ab8505(ab8500))
1293c0eda9aeSLee Jones 		ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs,
1294c0eda9aeSLee Jones 			      ARRAY_SIZE(ab8505_devs), NULL,
1295f864c46aSLinus Walleij 			      0, ab8500->domain);
1296d6255529SLinus Walleij 	else
1297549931f9SSundar R Iyer 		ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
129844f72e53SVirupax Sadashivpetimath 				ARRAY_SIZE(ab8500_devs), NULL,
1299f864c46aSLinus Walleij 				0, ab8500->domain);
13006bc4a568SLee Jones 	if (ret)
13018c4203cbSLee Jones 		return ret;
130244f72e53SVirupax Sadashivpetimath 
13036ef9418cSRickard Andersson 	if (!no_bm) {
13046ef9418cSRickard Andersson 		/* Add battery management devices */
13056ef9418cSRickard Andersson 		ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
13066ef9418cSRickard Andersson 				      ARRAY_SIZE(ab8500_bm_devs), NULL,
1307f864c46aSLinus Walleij 				      0, ab8500->domain);
13086ef9418cSRickard Andersson 		if (ret)
13096ef9418cSRickard Andersson 			dev_err(ab8500->dev, "error adding bm devices\n");
13106ef9418cSRickard Andersson 	}
13116ef9418cSRickard Andersson 
1312e436ddffSLee Jones 	if (((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
1313e436ddffSLee Jones 			ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500))
1314d6255529SLinus Walleij 		ret = sysfs_create_group(&ab8500->dev->kobj,
1315d6255529SLinus Walleij 					&ab9540_attr_group);
1316d6255529SLinus Walleij 	else
1317d6255529SLinus Walleij 		ret = sysfs_create_group(&ab8500->dev->kobj,
1318d6255529SLinus Walleij 					&ab8500_attr_group);
131993ff722eSLee Jones 
132093ff722eSLee Jones 	if ((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
132193ff722eSLee Jones 			ab8500->chip_id >= AB8500_CUT2P0)
132293ff722eSLee Jones 		ret = sysfs_create_group(&ab8500->dev->kobj,
132393ff722eSLee Jones 					 &ab8505_attr_group);
132493ff722eSLee Jones 
1325cca69b67SMattias Wallin 	if (ret)
1326cca69b67SMattias Wallin 		dev_err(ab8500->dev, "error creating sysfs entries\n");
132706e589efSLee Jones 
132862579266SRabin Vincent 	return ret;
132962579266SRabin Vincent }
133062579266SRabin Vincent 
1331d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = {
1332d28f1db8SLee Jones 	{ "ab8500-core", AB8500_VERSION_AB8500 },
1333d28f1db8SLee Jones 	{ "ab8505-i2c", AB8500_VERSION_AB8505 },
1334d28f1db8SLee Jones 	{ "ab9540-i2c", AB8500_VERSION_AB9540 },
1335d28f1db8SLee Jones 	{ "ab8540-i2c", AB8500_VERSION_AB8540 },
1336d28f1db8SLee Jones 	{ }
1337d28f1db8SLee Jones };
1338d28f1db8SLee Jones 
1339d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = {
1340d28f1db8SLee Jones 	.driver = {
1341d28f1db8SLee Jones 		.name = "ab8500-core",
134231cbae22SPaul Gortmaker 		.suppress_bind_attrs = true,
1343d28f1db8SLee Jones 	},
1344d28f1db8SLee Jones 	.probe	= ab8500_probe,
1345d28f1db8SLee Jones 	.id_table = ab8500_id,
1346d28f1db8SLee Jones };
1347d28f1db8SLee Jones 
1348d28f1db8SLee Jones static int __init ab8500_core_init(void)
1349d28f1db8SLee Jones {
1350d28f1db8SLee Jones 	return platform_driver_register(&ab8500_core_driver);
1351d28f1db8SLee Jones }
1352ba7cbc3eSLee Jones core_initcall(ab8500_core_init);
1353