xref: /openbmc/linux/drivers/mfd/ab8500-core.c (revision 417c0fc24dd4dbd60d94fa8deb36bf1176930e06)
10376148fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
262579266SRabin Vincent /*
362579266SRabin Vincent  * Copyright (C) ST-Ericsson SA 2010
462579266SRabin Vincent  *
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>
22d28f1db8SLee Jones #include <linux/mfd/dbx500-prcmu.h>
236bc4a568SLee Jones #include <linux/of.h>
246bc4a568SLee Jones #include <linux/of_device.h>
2562579266SRabin Vincent 
2662579266SRabin Vincent /*
2762579266SRabin Vincent  * Interrupt register offsets
2862579266SRabin Vincent  * Bank : 0x0E
2962579266SRabin Vincent  */
3047c16975SMattias Wallin #define AB8500_IT_SOURCE1_REG		0x00
3147c16975SMattias Wallin #define AB8500_IT_SOURCE2_REG		0x01
3247c16975SMattias Wallin #define AB8500_IT_SOURCE3_REG		0x02
3347c16975SMattias Wallin #define AB8500_IT_SOURCE4_REG		0x03
3447c16975SMattias Wallin #define AB8500_IT_SOURCE5_REG		0x04
3547c16975SMattias Wallin #define AB8500_IT_SOURCE6_REG		0x05
3647c16975SMattias Wallin #define AB8500_IT_SOURCE7_REG		0x06
3747c16975SMattias Wallin #define AB8500_IT_SOURCE8_REG		0x07
38d6255529SLinus Walleij #define AB9540_IT_SOURCE13_REG		0x0C
3947c16975SMattias Wallin #define AB8500_IT_SOURCE19_REG		0x12
4047c16975SMattias Wallin #define AB8500_IT_SOURCE20_REG		0x13
4147c16975SMattias Wallin #define AB8500_IT_SOURCE21_REG		0x14
4247c16975SMattias Wallin #define AB8500_IT_SOURCE22_REG		0x15
4347c16975SMattias Wallin #define AB8500_IT_SOURCE23_REG		0x16
4447c16975SMattias Wallin #define AB8500_IT_SOURCE24_REG		0x17
4562579266SRabin Vincent 
4662579266SRabin Vincent /*
4762579266SRabin Vincent  * latch registers
4862579266SRabin Vincent  */
4947c16975SMattias Wallin #define AB8500_IT_LATCH1_REG		0x20
5047c16975SMattias Wallin #define AB8500_IT_LATCH2_REG		0x21
5147c16975SMattias Wallin #define AB8500_IT_LATCH3_REG		0x22
5247c16975SMattias Wallin #define AB8500_IT_LATCH4_REG		0x23
5347c16975SMattias Wallin #define AB8500_IT_LATCH5_REG		0x24
5447c16975SMattias Wallin #define AB8500_IT_LATCH6_REG		0x25
5547c16975SMattias Wallin #define AB8500_IT_LATCH7_REG		0x26
5647c16975SMattias Wallin #define AB8500_IT_LATCH8_REG		0x27
5747c16975SMattias Wallin #define AB8500_IT_LATCH9_REG		0x28
5847c16975SMattias Wallin #define AB8500_IT_LATCH10_REG		0x29
5992d50a41SMattias Wallin #define AB8500_IT_LATCH12_REG		0x2B
60d6255529SLinus Walleij #define AB9540_IT_LATCH13_REG		0x2C
6147c16975SMattias Wallin #define AB8500_IT_LATCH19_REG		0x32
6247c16975SMattias Wallin #define AB8500_IT_LATCH20_REG		0x33
6347c16975SMattias Wallin #define AB8500_IT_LATCH21_REG		0x34
6447c16975SMattias Wallin #define AB8500_IT_LATCH22_REG		0x35
6547c16975SMattias Wallin #define AB8500_IT_LATCH23_REG		0x36
6647c16975SMattias Wallin #define AB8500_IT_LATCH24_REG		0x37
6762579266SRabin Vincent 
6862579266SRabin Vincent /*
6962579266SRabin Vincent  * mask registers
7062579266SRabin Vincent  */
7162579266SRabin Vincent 
7247c16975SMattias Wallin #define AB8500_IT_MASK1_REG		0x40
7347c16975SMattias Wallin #define AB8500_IT_MASK2_REG		0x41
7447c16975SMattias Wallin #define AB8500_IT_MASK3_REG		0x42
7547c16975SMattias Wallin #define AB8500_IT_MASK4_REG		0x43
7647c16975SMattias Wallin #define AB8500_IT_MASK5_REG		0x44
7747c16975SMattias Wallin #define AB8500_IT_MASK6_REG		0x45
7847c16975SMattias Wallin #define AB8500_IT_MASK7_REG		0x46
7947c16975SMattias Wallin #define AB8500_IT_MASK8_REG		0x47
8047c16975SMattias Wallin #define AB8500_IT_MASK9_REG		0x48
8147c16975SMattias Wallin #define AB8500_IT_MASK10_REG		0x49
8247c16975SMattias Wallin #define AB8500_IT_MASK11_REG		0x4A
8347c16975SMattias Wallin #define AB8500_IT_MASK12_REG		0x4B
8447c16975SMattias Wallin #define AB8500_IT_MASK13_REG		0x4C
8547c16975SMattias Wallin #define AB8500_IT_MASK14_REG		0x4D
8647c16975SMattias Wallin #define AB8500_IT_MASK15_REG		0x4E
8747c16975SMattias Wallin #define AB8500_IT_MASK16_REG		0x4F
8847c16975SMattias Wallin #define AB8500_IT_MASK17_REG		0x50
8947c16975SMattias Wallin #define AB8500_IT_MASK18_REG		0x51
9047c16975SMattias Wallin #define AB8500_IT_MASK19_REG		0x52
9147c16975SMattias Wallin #define AB8500_IT_MASK20_REG		0x53
9247c16975SMattias Wallin #define AB8500_IT_MASK21_REG		0x54
9347c16975SMattias Wallin #define AB8500_IT_MASK22_REG		0x55
9447c16975SMattias Wallin #define AB8500_IT_MASK23_REG		0x56
9547c16975SMattias Wallin #define AB8500_IT_MASK24_REG		0x57
96a29264b6SLee Jones #define AB8500_IT_MASK25_REG		0x58
9762579266SRabin Vincent 
987ccfe9b1SMichel JAOUEN /*
997ccfe9b1SMichel JAOUEN  * latch hierarchy registers
1007ccfe9b1SMichel JAOUEN  */
1017ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER1_REG	0x60
1027ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER2_REG	0x61
1037ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER3_REG	0x62
1043e1a498fSLee Jones #define AB8540_IT_LATCHHIER4_REG	0x63
1057ccfe9b1SMichel JAOUEN 
1067ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER_NUM		3
1073e1a498fSLee Jones #define AB8540_IT_LATCHHIER_NUM		4
1087ccfe9b1SMichel JAOUEN 
10947c16975SMattias Wallin #define AB8500_REV_REG			0x80
1100f620837SLinus Walleij #define AB8500_IC_NAME_REG		0x82
111e5c238c3SMattias Wallin #define AB8500_SWITCH_OFF_STATUS	0x00
11262579266SRabin Vincent 
113b4a31037SAndrew Lynn #define AB8500_TURN_ON_STATUS		0x00
11493ff722eSLee Jones #define AB8505_TURN_ON_STATUS_2		0x04
115b4a31037SAndrew Lynn 
116f04a9d8aSRajkumar Kasirajan #define AB8500_CH_USBCH_STAT1_REG	0x02
117f04a9d8aSRajkumar Kasirajan #define VBUS_DET_DBNC100		0x02
118f04a9d8aSRajkumar Kasirajan #define VBUS_DET_DBNC1			0x01
119f04a9d8aSRajkumar Kasirajan 
120f04a9d8aSRajkumar Kasirajan static DEFINE_SPINLOCK(on_stat_lock);
121f04a9d8aSRajkumar Kasirajan static u8 turn_on_stat_mask = 0xFF;
122f04a9d8aSRajkumar Kasirajan static u8 turn_on_stat_set;
1236ef9418cSRickard Andersson static bool no_bm; /* No battery management */
12431cbae22SPaul Gortmaker /*
12531cbae22SPaul Gortmaker  * not really modular, but the easiest way to keep compat with existing
12631cbae22SPaul Gortmaker  * bootargs behaviour is to continue using module_param here.
12731cbae22SPaul Gortmaker  */
1286ef9418cSRickard Andersson module_param(no_bm, bool, S_IRUGO);
1296ef9418cSRickard Andersson 
130d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_REG			0x23
131d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT	BIT(2)
132d6255529SLinus Walleij 
13362579266SRabin Vincent /*
13462579266SRabin Vincent  * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
1352ced445eSLinus Walleij  * numbers are indexed into this array with (num / 8). The interupts are
1362ced445eSLinus Walleij  * defined in linux/mfd/ab8500.h
13762579266SRabin Vincent  *
13862579266SRabin Vincent  * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
13962579266SRabin Vincent  * offset 0.
14062579266SRabin Vincent  */
1412ced445eSLinus Walleij /* AB8500 support */
14262579266SRabin Vincent static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
14392d50a41SMattias Wallin 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
14462579266SRabin Vincent };
14562579266SRabin Vincent 
146a29264b6SLee Jones /* AB9540 / AB8505 support */
147d6255529SLinus Walleij static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
148a29264b6SLee Jones 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23
149d6255529SLinus Walleij };
150d6255529SLinus Walleij 
1513e1a498fSLee Jones /* AB8540 support */
1523e1a498fSLee Jones static const int ab8540_irq_regoffset[AB8540_NUM_IRQ_REGS] = {
1537ccf40b1SLee Jones 	0, 1, 2, 3, 4, -1, -1, -1, -1, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22,
1547ccf40b1SLee Jones 	23, 25, 26, 27, 28, 29, 30, 31,
1553e1a498fSLee Jones };
1563e1a498fSLee Jones 
1570f620837SLinus Walleij static const char ab8500_version_str[][7] = {
1580f620837SLinus Walleij 	[AB8500_VERSION_AB8500] = "AB8500",
1590f620837SLinus Walleij 	[AB8500_VERSION_AB8505] = "AB8505",
1600f620837SLinus Walleij 	[AB8500_VERSION_AB9540] = "AB9540",
1610f620837SLinus Walleij 	[AB8500_VERSION_AB8540] = "AB8540",
1620f620837SLinus Walleij };
1630f620837SLinus Walleij 
164822672a7SLee Jones static int ab8500_prcmu_write(struct ab8500 *ab8500, u16 addr, u8 data)
165d28f1db8SLee Jones {
166d28f1db8SLee Jones 	int ret;
167d28f1db8SLee Jones 
168d28f1db8SLee Jones 	ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 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_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
175d28f1db8SLee Jones 	u8 data)
176d28f1db8SLee Jones {
177d28f1db8SLee Jones 	int ret;
178d28f1db8SLee Jones 
179d28f1db8SLee Jones 	ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data,
180d28f1db8SLee Jones 		&mask, 1);
181d28f1db8SLee Jones 	if (ret < 0)
182d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
183d28f1db8SLee Jones 	return ret;
184d28f1db8SLee Jones }
185d28f1db8SLee Jones 
186822672a7SLee Jones static int ab8500_prcmu_read(struct ab8500 *ab8500, u16 addr)
187d28f1db8SLee Jones {
188d28f1db8SLee Jones 	int ret;
189d28f1db8SLee Jones 	u8 data;
190d28f1db8SLee Jones 
191d28f1db8SLee Jones 	ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
192d28f1db8SLee Jones 	if (ret < 0) {
193d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
194d28f1db8SLee Jones 		return ret;
195d28f1db8SLee Jones 	}
196d28f1db8SLee Jones 	return (int)data;
197d28f1db8SLee Jones }
198d28f1db8SLee Jones 
19947c16975SMattias Wallin static int ab8500_get_chip_id(struct device *dev)
20047c16975SMattias Wallin {
2016bce7bf1SMattias Wallin 	struct ab8500 *ab8500;
2026bce7bf1SMattias Wallin 
2036bce7bf1SMattias Wallin 	if (!dev)
2046bce7bf1SMattias Wallin 		return -EINVAL;
2056bce7bf1SMattias Wallin 	ab8500 = dev_get_drvdata(dev->parent);
2066bce7bf1SMattias Wallin 	return ab8500 ? (int)ab8500->chip_id : -EINVAL;
20747c16975SMattias Wallin }
20847c16975SMattias Wallin 
20947c16975SMattias Wallin static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
21047c16975SMattias Wallin 	u8 reg, u8 data)
21162579266SRabin Vincent {
21262579266SRabin Vincent 	int ret;
21347c16975SMattias Wallin 	/*
21447c16975SMattias Wallin 	 * Put the u8 bank and u8 register together into a an u16.
21547c16975SMattias Wallin 	 * The bank on higher 8 bits and register in lower 8 bits.
216500e69a1SLee Jones 	 */
21747c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
21862579266SRabin Vincent 
21962579266SRabin Vincent 	dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
22062579266SRabin Vincent 
221392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
22247c16975SMattias Wallin 
22347c16975SMattias Wallin 	ret = ab8500->write(ab8500, addr, data);
22447c16975SMattias Wallin 	if (ret < 0)
22547c16975SMattias Wallin 		dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
22647c16975SMattias Wallin 			addr, ret);
22747c16975SMattias Wallin 	mutex_unlock(&ab8500->lock);
22847c16975SMattias Wallin 
22947c16975SMattias Wallin 	return ret;
23047c16975SMattias Wallin }
23147c16975SMattias Wallin 
23247c16975SMattias Wallin static int ab8500_set_register(struct device *dev, u8 bank,
23347c16975SMattias Wallin 	u8 reg, u8 value)
23447c16975SMattias Wallin {
235112a80d2SJonas Aaberg 	int ret;
23647c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
23747c16975SMattias Wallin 
238112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
239112a80d2SJonas Aaberg 	ret = set_register_interruptible(ab8500, bank, reg, value);
240112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
241112a80d2SJonas Aaberg 	return ret;
24247c16975SMattias Wallin }
24347c16975SMattias Wallin 
24447c16975SMattias Wallin static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
24547c16975SMattias Wallin 	u8 reg, u8 *value)
24647c16975SMattias Wallin {
24747c16975SMattias Wallin 	int ret;
24847c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
24947c16975SMattias Wallin 
250392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
25147c16975SMattias Wallin 
25247c16975SMattias Wallin 	ret = ab8500->read(ab8500, addr);
25347c16975SMattias Wallin 	if (ret < 0)
25447c16975SMattias Wallin 		dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
25547c16975SMattias Wallin 			addr, ret);
25647c16975SMattias Wallin 	else
25747c16975SMattias Wallin 		*value = ret;
25847c16975SMattias Wallin 
25947c16975SMattias Wallin 	mutex_unlock(&ab8500->lock);
26047c16975SMattias Wallin 	dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret);
26147c16975SMattias Wallin 
26210628e3eSDan Carpenter 	return (ret < 0) ? ret : 0;
26347c16975SMattias Wallin }
26447c16975SMattias Wallin 
26547c16975SMattias Wallin static int ab8500_get_register(struct device *dev, u8 bank,
26647c16975SMattias Wallin 	u8 reg, u8 *value)
26747c16975SMattias Wallin {
268112a80d2SJonas Aaberg 	int ret;
26947c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
27047c16975SMattias Wallin 
271112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
272112a80d2SJonas Aaberg 	ret = get_register_interruptible(ab8500, bank, reg, value);
273112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
274112a80d2SJonas Aaberg 	return ret;
27547c16975SMattias Wallin }
27647c16975SMattias Wallin 
27747c16975SMattias Wallin static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
27847c16975SMattias Wallin 	u8 reg, u8 bitmask, u8 bitvalues)
27947c16975SMattias Wallin {
28047c16975SMattias Wallin 	int ret;
28147c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
28247c16975SMattias Wallin 
283392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
28447c16975SMattias Wallin 
285bc628fd1SMattias Nilsson 	if (ab8500->write_masked == NULL) {
286bc628fd1SMattias Nilsson 		u8 data;
287bc628fd1SMattias Nilsson 
28847c16975SMattias Wallin 		ret = ab8500->read(ab8500, addr);
28947c16975SMattias Wallin 		if (ret < 0) {
29047c16975SMattias Wallin 			dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
29147c16975SMattias Wallin 				addr, ret);
29247c16975SMattias Wallin 			goto out;
29347c16975SMattias Wallin 		}
29447c16975SMattias Wallin 
29547c16975SMattias Wallin 		data = (u8)ret;
29647c16975SMattias Wallin 		data = (~bitmask & data) | (bitmask & bitvalues);
29747c16975SMattias Wallin 
29862579266SRabin Vincent 		ret = ab8500->write(ab8500, addr, data);
29962579266SRabin Vincent 		if (ret < 0)
30062579266SRabin Vincent 			dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
30162579266SRabin Vincent 				addr, ret);
30262579266SRabin Vincent 
303bc628fd1SMattias Nilsson 		dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr,
304bc628fd1SMattias Nilsson 			data);
305bc628fd1SMattias Nilsson 		goto out;
306bc628fd1SMattias Nilsson 	}
307bc628fd1SMattias Nilsson 	ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues);
308bc628fd1SMattias Nilsson 	if (ret < 0)
309bc628fd1SMattias Nilsson 		dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr,
310bc628fd1SMattias Nilsson 			ret);
31162579266SRabin Vincent out:
31262579266SRabin Vincent 	mutex_unlock(&ab8500->lock);
31362579266SRabin Vincent 	return ret;
31462579266SRabin Vincent }
31547c16975SMattias Wallin 
31647c16975SMattias Wallin static int ab8500_mask_and_set_register(struct device *dev,
31747c16975SMattias Wallin 	u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
31847c16975SMattias Wallin {
319112a80d2SJonas Aaberg 	int ret;
32047c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
32147c16975SMattias Wallin 
322112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
323112a80d2SJonas Aaberg 	ret = mask_and_set_register_interruptible(ab8500, bank, reg,
32447c16975SMattias Wallin 						 bitmask, bitvalues);
325112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
326112a80d2SJonas Aaberg 	return ret;
32747c16975SMattias Wallin }
32847c16975SMattias Wallin 
32947c16975SMattias Wallin static struct abx500_ops ab8500_ops = {
33047c16975SMattias Wallin 	.get_chip_id = ab8500_get_chip_id,
33147c16975SMattias Wallin 	.get_register = ab8500_get_register,
33247c16975SMattias Wallin 	.set_register = ab8500_set_register,
33347c16975SMattias Wallin 	.get_register_page = NULL,
33447c16975SMattias Wallin 	.set_register_page = NULL,
33547c16975SMattias Wallin 	.mask_and_set_register = ab8500_mask_and_set_register,
33647c16975SMattias Wallin 	.event_registers_startup_state_get = NULL,
33747c16975SMattias Wallin 	.startup_irq_enabled = NULL,
3381d843a6cSMian Yousaf Kaukab 	.dump_all_banks = ab8500_dump_all_banks,
33947c16975SMattias Wallin };
34062579266SRabin Vincent 
3419505a0a0SMark Brown static void ab8500_irq_lock(struct irq_data *data)
34262579266SRabin Vincent {
3439505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
34462579266SRabin Vincent 
34562579266SRabin Vincent 	mutex_lock(&ab8500->irq_lock);
346112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
34762579266SRabin Vincent }
34862579266SRabin Vincent 
3499505a0a0SMark Brown static void ab8500_irq_sync_unlock(struct irq_data *data)
35062579266SRabin Vincent {
3519505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
35262579266SRabin Vincent 	int i;
35362579266SRabin Vincent 
3542ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++) {
35562579266SRabin Vincent 		u8 old = ab8500->oldmask[i];
35662579266SRabin Vincent 		u8 new = ab8500->mask[i];
35762579266SRabin Vincent 		int reg;
35862579266SRabin Vincent 
35962579266SRabin Vincent 		if (new == old)
36062579266SRabin Vincent 			continue;
36162579266SRabin Vincent 
3620f620837SLinus Walleij 		/*
3630f620837SLinus Walleij 		 * Interrupt register 12 doesn't exist prior to AB8500 version
3640f620837SLinus Walleij 		 * 2.0
3650f620837SLinus Walleij 		 */
3660f620837SLinus Walleij 		if (ab8500->irq_reg_offset[i] == 11 &&
3670f620837SLinus Walleij 			is_ab8500_1p1_or_earlier(ab8500))
36892d50a41SMattias Wallin 			continue;
36992d50a41SMattias Wallin 
3703e1a498fSLee Jones 		if (ab8500->irq_reg_offset[i] < 0)
3713e1a498fSLee Jones 			continue;
3723e1a498fSLee Jones 
37362579266SRabin Vincent 		ab8500->oldmask[i] = new;
37462579266SRabin Vincent 
3752ced445eSLinus Walleij 		reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
37647c16975SMattias Wallin 		set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
37762579266SRabin Vincent 	}
378112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
37962579266SRabin Vincent 	mutex_unlock(&ab8500->irq_lock);
38062579266SRabin Vincent }
38162579266SRabin Vincent 
3829505a0a0SMark Brown static void ab8500_irq_mask(struct irq_data *data)
38362579266SRabin Vincent {
3849505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
38506e589efSLee Jones 	int offset = data->hwirq;
38662579266SRabin Vincent 	int index = offset / 8;
38762579266SRabin Vincent 	int mask = 1 << (offset % 8);
38862579266SRabin Vincent 
38962579266SRabin Vincent 	ab8500->mask[index] |= mask;
3909c677b9bSLee Jones 
3919c677b9bSLee Jones 	/* The AB8500 GPIOs have two interrupts each (rising & falling). */
3929c677b9bSLee Jones 	if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
3939c677b9bSLee Jones 		ab8500->mask[index + 2] |= mask;
3949c677b9bSLee Jones 	if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R)
3959c677b9bSLee Jones 		ab8500->mask[index + 1] |= mask;
3969c677b9bSLee Jones 	if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R)
397e2ddf46aSLinus Walleij 		/* Here the falling IRQ is one bit lower */
398e2ddf46aSLinus Walleij 		ab8500->mask[index] |= (mask << 1);
39962579266SRabin Vincent }
40062579266SRabin Vincent 
4019505a0a0SMark Brown static void ab8500_irq_unmask(struct irq_data *data)
40262579266SRabin Vincent {
4039505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
4049c677b9bSLee Jones 	unsigned int type = irqd_get_trigger_type(data);
40506e589efSLee Jones 	int offset = data->hwirq;
40662579266SRabin Vincent 	int index = offset / 8;
40762579266SRabin Vincent 	int mask = 1 << (offset % 8);
40862579266SRabin Vincent 
4099c677b9bSLee Jones 	if (type & IRQ_TYPE_EDGE_RISING)
41062579266SRabin Vincent 		ab8500->mask[index] &= ~mask;
4119c677b9bSLee Jones 
4129c677b9bSLee Jones 	/* The AB8500 GPIOs have two interrupts each (rising & falling). */
4139c677b9bSLee Jones 	if (type & IRQ_TYPE_EDGE_FALLING) {
4149c677b9bSLee Jones 		if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
4159c677b9bSLee Jones 			ab8500->mask[index + 2] &= ~mask;
4167ccf40b1SLee Jones 		else if (offset >= AB9540_INT_GPIO50R &&
4177ccf40b1SLee Jones 			 offset <= AB9540_INT_GPIO54R)
4189c677b9bSLee Jones 			ab8500->mask[index + 1] &= ~mask;
4197ccf40b1SLee Jones 		else if (offset == AB8540_INT_GPIO43R ||
4207ccf40b1SLee Jones 			 offset == AB8540_INT_GPIO44R)
421e2ddf46aSLinus Walleij 			/* Here the falling IRQ is one bit lower */
422e2ddf46aSLinus Walleij 			ab8500->mask[index] &= ~(mask << 1);
4239c677b9bSLee Jones 		else
4249c677b9bSLee Jones 			ab8500->mask[index] &= ~mask;
425e2ddf46aSLinus Walleij 	} else {
4269c677b9bSLee Jones 		/* Satisfies the case where type is not set. */
42762579266SRabin Vincent 		ab8500->mask[index] &= ~mask;
42862579266SRabin Vincent 	}
429e2ddf46aSLinus Walleij }
43062579266SRabin Vincent 
43140f6e5a2SLee Jones static int ab8500_irq_set_type(struct irq_data *data, unsigned int type)
43240f6e5a2SLee Jones {
43340f6e5a2SLee Jones 	return 0;
43462579266SRabin Vincent }
43562579266SRabin Vincent 
43662579266SRabin Vincent static struct irq_chip ab8500_irq_chip = {
43762579266SRabin Vincent 	.name			= "ab8500",
4389505a0a0SMark Brown 	.irq_bus_lock		= ab8500_irq_lock,
4399505a0a0SMark Brown 	.irq_bus_sync_unlock	= ab8500_irq_sync_unlock,
4409505a0a0SMark Brown 	.irq_mask		= ab8500_irq_mask,
441e6f9306eSVirupax Sadashivpetimath 	.irq_disable		= ab8500_irq_mask,
4429505a0a0SMark Brown 	.irq_unmask		= ab8500_irq_unmask,
44340f6e5a2SLee Jones 	.irq_set_type		= ab8500_irq_set_type,
44462579266SRabin Vincent };
44562579266SRabin Vincent 
4463e1a498fSLee Jones static void update_latch_offset(u8 *offset, int i)
4473e1a498fSLee Jones {
4483e1a498fSLee Jones 	/* Fix inconsistent ITFromLatch25 bit mapping... */
4493e1a498fSLee Jones 	if (unlikely(*offset == 17))
4503e1a498fSLee Jones 		*offset = 24;
4513e1a498fSLee Jones 	/* Fix inconsistent ab8540 bit mapping... */
4523e1a498fSLee Jones 	if (unlikely(*offset == 16))
4533e1a498fSLee Jones 		*offset = 25;
4543e1a498fSLee Jones 	if ((i == 3) && (*offset >= 24))
4553e1a498fSLee Jones 		*offset += 2;
4563e1a498fSLee Jones }
4573e1a498fSLee Jones 
4587ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
4597ccfe9b1SMichel JAOUEN 					int latch_offset, u8 latch_val)
4607ccfe9b1SMichel JAOUEN {
4617a93fb37SFabio Baltieri 	int int_bit, line, i;
4627ccfe9b1SMichel JAOUEN 
4637ccfe9b1SMichel JAOUEN 	for (i = 0; i < ab8500->mask_size; i++)
4647ccfe9b1SMichel JAOUEN 		if (ab8500->irq_reg_offset[i] == latch_offset)
4657ccfe9b1SMichel JAOUEN 			break;
4667ccfe9b1SMichel JAOUEN 
4677ccfe9b1SMichel JAOUEN 	if (i >= ab8500->mask_size) {
4687ccfe9b1SMichel JAOUEN 		dev_err(ab8500->dev, "Register offset 0x%2x not declared\n",
4697ccfe9b1SMichel JAOUEN 				latch_offset);
4707ccfe9b1SMichel JAOUEN 		return -ENXIO;
4717ccfe9b1SMichel JAOUEN 	}
4727ccfe9b1SMichel JAOUEN 
4737a93fb37SFabio Baltieri 	/* ignore masked out interrupts */
4747a93fb37SFabio Baltieri 	latch_val &= ~ab8500->mask[i];
4757a93fb37SFabio Baltieri 
4767a93fb37SFabio Baltieri 	while (latch_val) {
4777a93fb37SFabio Baltieri 		int_bit = __ffs(latch_val);
4787ccfe9b1SMichel JAOUEN 		line = (i << 3) + int_bit;
4797ccfe9b1SMichel JAOUEN 		latch_val &= ~(1 << int_bit);
4807ccfe9b1SMichel JAOUEN 
481e2ddf46aSLinus Walleij 		/*
482e2ddf46aSLinus Walleij 		 * This handles the falling edge hwirqs from the GPIO
483e2ddf46aSLinus Walleij 		 * lines. Route them back to the line registered for the
484e2ddf46aSLinus Walleij 		 * rising IRQ, as this is merely a flag for the same IRQ
485e2ddf46aSLinus Walleij 		 * in linux terms.
486e2ddf46aSLinus Walleij 		 */
487e2ddf46aSLinus Walleij 		if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F)
488e2ddf46aSLinus Walleij 			line -= 16;
489e2ddf46aSLinus Walleij 		if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F)
490e2ddf46aSLinus Walleij 			line -= 8;
491e2ddf46aSLinus Walleij 		if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F)
492e2ddf46aSLinus Walleij 			line += 1;
493e2ddf46aSLinus Walleij 
494ed83d301SLinus Walleij 		handle_nested_irq(irq_create_mapping(ab8500->domain, line));
4957a93fb37SFabio Baltieri 	}
4967ccfe9b1SMichel JAOUEN 
4977ccfe9b1SMichel JAOUEN 	return 0;
4987ccfe9b1SMichel JAOUEN }
4997ccfe9b1SMichel JAOUEN 
5007ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500,
5017ccfe9b1SMichel JAOUEN 					int hier_offset, u8 hier_val)
5027ccfe9b1SMichel JAOUEN {
5037ccfe9b1SMichel JAOUEN 	int latch_bit, status;
5047ccfe9b1SMichel JAOUEN 	u8 latch_offset, latch_val;
5057ccfe9b1SMichel JAOUEN 
5067ccfe9b1SMichel JAOUEN 	do {
5077ccfe9b1SMichel JAOUEN 		latch_bit = __ffs(hier_val);
5087ccfe9b1SMichel JAOUEN 		latch_offset = (hier_offset << 3) + latch_bit;
5097ccfe9b1SMichel JAOUEN 
5103e1a498fSLee Jones 		update_latch_offset(&latch_offset, hier_offset);
5117ccfe9b1SMichel JAOUEN 
5127ccfe9b1SMichel JAOUEN 		status = get_register_interruptible(ab8500,
5137ccfe9b1SMichel JAOUEN 				AB8500_INTERRUPT,
5147ccfe9b1SMichel JAOUEN 				AB8500_IT_LATCH1_REG + latch_offset,
5157ccfe9b1SMichel JAOUEN 				&latch_val);
5167ccfe9b1SMichel JAOUEN 		if (status < 0 || latch_val == 0)
5177ccfe9b1SMichel JAOUEN 			goto discard;
5187ccfe9b1SMichel JAOUEN 
5197ccfe9b1SMichel JAOUEN 		status = ab8500_handle_hierarchical_line(ab8500,
5207ccfe9b1SMichel JAOUEN 				latch_offset, latch_val);
5217ccfe9b1SMichel JAOUEN 		if (status < 0)
5227ccfe9b1SMichel JAOUEN 			return status;
5237ccfe9b1SMichel JAOUEN discard:
5247ccfe9b1SMichel JAOUEN 		hier_val &= ~(1 << latch_bit);
5257ccfe9b1SMichel JAOUEN 	} while (hier_val);
5267ccfe9b1SMichel JAOUEN 
5277ccfe9b1SMichel JAOUEN 	return 0;
5287ccfe9b1SMichel JAOUEN }
5297ccfe9b1SMichel JAOUEN 
5307ccfe9b1SMichel JAOUEN static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev)
5317ccfe9b1SMichel JAOUEN {
5327ccfe9b1SMichel JAOUEN 	struct ab8500 *ab8500 = dev;
5337ccfe9b1SMichel JAOUEN 	u8 i;
5347ccfe9b1SMichel JAOUEN 
5357ccfe9b1SMichel JAOUEN 	dev_vdbg(ab8500->dev, "interrupt\n");
5367ccfe9b1SMichel JAOUEN 
5377ccfe9b1SMichel JAOUEN 	/*  Hierarchical interrupt version */
5383e1a498fSLee Jones 	for (i = 0; i < (ab8500->it_latchhier_num); i++) {
5397ccfe9b1SMichel JAOUEN 		int status;
5407ccfe9b1SMichel JAOUEN 		u8 hier_val;
5417ccfe9b1SMichel JAOUEN 
5427ccfe9b1SMichel JAOUEN 		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
5437ccfe9b1SMichel JAOUEN 			AB8500_IT_LATCHHIER1_REG + i, &hier_val);
5447ccfe9b1SMichel JAOUEN 		if (status < 0 || hier_val == 0)
5457ccfe9b1SMichel JAOUEN 			continue;
5467ccfe9b1SMichel JAOUEN 
5477ccfe9b1SMichel JAOUEN 		status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val);
5487ccfe9b1SMichel JAOUEN 		if (status < 0)
5497ccfe9b1SMichel JAOUEN 			break;
5507ccfe9b1SMichel JAOUEN 	}
5517ccfe9b1SMichel JAOUEN 	return IRQ_HANDLED;
5527ccfe9b1SMichel JAOUEN }
5537ccfe9b1SMichel JAOUEN 
55406e589efSLee Jones static int ab8500_irq_map(struct irq_domain *d, unsigned int virq,
55506e589efSLee Jones 				irq_hw_number_t hwirq)
55606e589efSLee Jones {
55706e589efSLee Jones 	struct ab8500 *ab8500 = d->host_data;
55806e589efSLee Jones 
55906e589efSLee Jones 	if (!ab8500)
56006e589efSLee Jones 		return -EINVAL;
56106e589efSLee Jones 
56206e589efSLee Jones 	irq_set_chip_data(virq, ab8500);
56306e589efSLee Jones 	irq_set_chip_and_handler(virq, &ab8500_irq_chip,
56406e589efSLee Jones 				handle_simple_irq);
56506e589efSLee Jones 	irq_set_nested_thread(virq, 1);
56606e589efSLee Jones 	irq_set_noprobe(virq);
56762579266SRabin Vincent 
56862579266SRabin Vincent 	return 0;
56962579266SRabin Vincent }
57062579266SRabin Vincent 
5717ce7b26fSKrzysztof Kozlowski static const struct irq_domain_ops ab8500_irq_ops = {
57206e589efSLee Jones 	.map    = ab8500_irq_map,
57306e589efSLee Jones 	.xlate  = irq_domain_xlate_twocell,
57406e589efSLee Jones };
57506e589efSLee Jones 
57606e589efSLee Jones static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np)
57762579266SRabin Vincent {
5782ced445eSLinus Walleij 	int num_irqs;
57962579266SRabin Vincent 
5803e1a498fSLee Jones 	if (is_ab8540(ab8500))
5813e1a498fSLee Jones 		num_irqs = AB8540_NR_IRQS;
5823e1a498fSLee Jones 	else if (is_ab9540(ab8500))
583d6255529SLinus Walleij 		num_irqs = AB9540_NR_IRQS;
584a982362cSBengt Jonsson 	else if (is_ab8505(ab8500))
585a982362cSBengt Jonsson 		num_irqs = AB8505_NR_IRQS;
586d6255529SLinus Walleij 	else
5872ced445eSLinus Walleij 		num_irqs = AB8500_NR_IRQS;
5882ced445eSLinus Walleij 
589f1d11f39SLinus Walleij 	/* If ->irq_base is zero this will give a linear mapping */
5907602e05dSGrygorii Strashko 	ab8500->domain = irq_domain_add_simple(ab8500->dev->of_node,
591f864c46aSLinus Walleij 					       num_irqs, 0,
592f1d11f39SLinus Walleij 					       &ab8500_irq_ops, ab8500);
59306e589efSLee Jones 
59406e589efSLee Jones 	if (!ab8500->domain) {
59506e589efSLee Jones 		dev_err(ab8500->dev, "Failed to create irqdomain\n");
596500e69a1SLee Jones 		return -ENODEV;
59706e589efSLee Jones 	}
59806e589efSLee Jones 
59906e589efSLee Jones 	return 0;
60062579266SRabin Vincent }
60162579266SRabin Vincent 
602112a80d2SJonas Aaberg int ab8500_suspend(struct ab8500 *ab8500)
603112a80d2SJonas Aaberg {
604112a80d2SJonas Aaberg 	if (atomic_read(&ab8500->transfer_ongoing))
605112a80d2SJonas Aaberg 		return -EINVAL;
606f3556302SLee Jones 
607112a80d2SJonas Aaberg 	return 0;
608112a80d2SJonas Aaberg }
609112a80d2SJonas Aaberg 
6105ac98553SGeert Uytterhoeven static const struct mfd_cell ab8500_bm_devs[] = {
611*417c0fc2SLinus Walleij 	MFD_CELL_OF("ab8500-charger", NULL, NULL, 0, 0,
612*417c0fc2SLinus Walleij 		    "stericsson,ab8500-charger"),
613*417c0fc2SLinus Walleij 	MFD_CELL_OF("ab8500-btemp", NULL, NULL, 0, 0,
614*417c0fc2SLinus Walleij 		    "stericsson,ab8500-btemp"),
615*417c0fc2SLinus Walleij 	MFD_CELL_OF("ab8500-fg", NULL, NULL, 0, 0,
616*417c0fc2SLinus Walleij 		    "stericsson,ab8500-fg"),
617*417c0fc2SLinus Walleij 	MFD_CELL_OF("ab8500-chargalg", NULL, NULL, 0, 0,
618*417c0fc2SLinus Walleij 		    "stericsson,ab8500-chargalg"),
6196ef9418cSRickard Andersson };
6206ef9418cSRickard Andersson 
6215ac98553SGeert Uytterhoeven static const struct mfd_cell ab8500_devs[] = {
6224b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS
623db783e76SLee Jones 	MFD_CELL_OF("ab8500-debug",
624f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-debug"),
6254b106fb9SLee Jones #endif
626db783e76SLee Jones 	MFD_CELL_OF("ab8500-sysctrl",
627f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-sysctrl"),
628db783e76SLee Jones 	MFD_CELL_OF("ab8500-ext-regulator",
629f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-ext-regulator"),
630db783e76SLee Jones 	MFD_CELL_OF("ab8500-regulator",
631f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-regulator"),
632db783e76SLee Jones 	MFD_CELL_OF("ab8500-clk",
633702204c2SLinus Walleij 		    NULL, NULL, 0, 0, "stericsson,ab8500-clk"),
634db783e76SLee Jones 	MFD_CELL_OF("ab8500-gpadc",
635f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-gpadc"),
636db783e76SLee Jones 	MFD_CELL_OF("ab8500-rtc",
637f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-rtc"),
638db783e76SLee Jones 	MFD_CELL_OF("ab8500-acc-det",
639f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-acc-det"),
640db783e76SLee Jones 	MFD_CELL_OF("ab8500-poweron-key",
641f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-poweron-key"),
642db783e76SLee Jones 	MFD_CELL_OF("ab8500-pwm",
643f4d41ad8SLee Jones 		    NULL, NULL, 0, 1, "stericsson,ab8500-pwm"),
644db783e76SLee Jones 	MFD_CELL_OF("ab8500-pwm",
645f4d41ad8SLee Jones 		    NULL, NULL, 0, 2, "stericsson,ab8500-pwm"),
646db783e76SLee Jones 	MFD_CELL_OF("ab8500-pwm",
647f4d41ad8SLee Jones 		    NULL, NULL, 0, 3, "stericsson,ab8500-pwm"),
648db783e76SLee Jones 	MFD_CELL_OF("ab8500-denc",
649f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-denc"),
650db783e76SLee Jones 	MFD_CELL_OF("pinctrl-ab8500",
651f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-gpio"),
652db783e76SLee Jones 	MFD_CELL_OF("abx500-temp",
653f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,abx500-temp"),
654db783e76SLee Jones 	MFD_CELL_OF("ab8500-usb",
655f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-usb"),
656db783e76SLee Jones 	MFD_CELL_OF("ab8500-codec",
657f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-codec"),
6584b106fb9SLee Jones };
6594b106fb9SLee Jones 
6605ac98553SGeert Uytterhoeven static const struct mfd_cell ab9540_devs[] = {
6614b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS
6624b106fb9SLee Jones 	{
6634b106fb9SLee Jones 		.name = "ab8500-debug",
6644b106fb9SLee Jones 	},
6654b106fb9SLee Jones #endif
6664b106fb9SLee Jones 	{
6674b106fb9SLee Jones 		.name = "ab8500-sysctrl",
6684b106fb9SLee Jones 	},
6694b106fb9SLee Jones 	{
67053f325beSLee Jones 		.name = "ab8500-ext-regulator",
67153f325beSLee Jones 	},
67253f325beSLee Jones 	{
6734b106fb9SLee Jones 		.name = "ab8500-regulator",
67444f72e53SVirupax Sadashivpetimath 	},
675c0eda9aeSLee Jones 	{
6769ee17676SUlf Hansson 		.name = "abx500-clk",
6779ee17676SUlf Hansson 		.of_compatible = "stericsson,abx500-clk",
6789ee17676SUlf Hansson 	},
6799ee17676SUlf Hansson 	{
680c0eda9aeSLee Jones 		.name = "ab8500-gpadc",
681c0eda9aeSLee Jones 		.of_compatible = "stericsson,ab8500-gpadc",
682c0eda9aeSLee Jones 	},
6834b106fb9SLee Jones 	{
6844b106fb9SLee Jones 		.name = "ab8500-rtc",
6854b106fb9SLee Jones 	},
6864b106fb9SLee Jones 	{
6874b106fb9SLee Jones 		.name = "ab8500-acc-det",
6884b106fb9SLee Jones 	},
6894b106fb9SLee Jones 	{
6904b106fb9SLee Jones 		.name = "ab8500-poweron-key",
6914b106fb9SLee Jones 	},
6924b106fb9SLee Jones 	{
6934b106fb9SLee Jones 		.name = "ab8500-pwm",
6944b106fb9SLee Jones 		.id = 1,
6954b106fb9SLee Jones 	},
6964b106fb9SLee Jones 	{
6974b106fb9SLee Jones 		.name = "abx500-temp",
6984b106fb9SLee Jones 	},
699d6255529SLinus Walleij 	{
700e64d905eSLee Jones 		.name = "pinctrl-ab9540",
701e64d905eSLee Jones 		.of_compatible = "stericsson,ab9540-gpio",
702d6255529SLinus Walleij 	},
703d6255529SLinus Walleij 	{
704d6255529SLinus Walleij 		.name = "ab9540-usb",
705d6255529SLinus Walleij 	},
70644f72e53SVirupax Sadashivpetimath 	{
70744f72e53SVirupax Sadashivpetimath 		.name = "ab9540-codec",
70844f72e53SVirupax Sadashivpetimath 	},
709c0eda9aeSLee Jones 	{
710c0eda9aeSLee Jones 		.name = "ab-iddet",
711c0eda9aeSLee Jones 	},
71244f72e53SVirupax Sadashivpetimath };
71344f72e53SVirupax Sadashivpetimath 
714c0eda9aeSLee Jones /* Device list for ab8505  */
7155ac98553SGeert Uytterhoeven static const struct mfd_cell ab8505_devs[] = {
7164b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS
7174b106fb9SLee Jones 	{
7184b106fb9SLee Jones 		.name = "ab8500-debug",
7191c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-debug",
7204b106fb9SLee Jones 	},
7214b106fb9SLee Jones #endif
7224b106fb9SLee Jones 	{
7234b106fb9SLee Jones 		.name = "ab8500-sysctrl",
7241c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-sysctrl",
7254b106fb9SLee Jones 	},
7264b106fb9SLee Jones 	{
7274b106fb9SLee Jones 		.name = "ab8500-regulator",
7281c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8505-regulator",
7294b106fb9SLee Jones 	},
7304b106fb9SLee Jones 	{
7319ee17676SUlf Hansson 		.name = "abx500-clk",
7321c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-clk",
7339ee17676SUlf Hansson 	},
7349ee17676SUlf Hansson 	{
7354b106fb9SLee Jones 		.name = "ab8500-gpadc",
736955de2eaSLee Jones 		.of_compatible = "stericsson,ab8500-gpadc",
7374b106fb9SLee Jones 	},
7384b106fb9SLee Jones 	{
7394b106fb9SLee Jones 		.name = "ab8500-rtc",
7401c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-rtc",
7414b106fb9SLee Jones 	},
7424b106fb9SLee Jones 	{
7434b106fb9SLee Jones 		.name = "ab8500-acc-det",
7441c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-acc-det",
7454b106fb9SLee Jones 	},
7464b106fb9SLee Jones 	{
7474b106fb9SLee Jones 		.name = "ab8500-poweron-key",
7481c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-poweron-key",
7494b106fb9SLee Jones 	},
7504b106fb9SLee Jones 	{
7514b106fb9SLee Jones 		.name = "ab8500-pwm",
7521c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-pwm",
7534b106fb9SLee Jones 		.id = 1,
7544b106fb9SLee Jones 	},
7554b106fb9SLee Jones 	{
756eb696c31SLee Jones 		.name = "pinctrl-ab8505",
7571c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8505-gpio",
7584b106fb9SLee Jones 	},
7594b106fb9SLee Jones 	{
7604b106fb9SLee Jones 		.name = "ab8500-usb",
7611c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-usb",
7624b106fb9SLee Jones 	},
7634b106fb9SLee Jones 	{
7644b106fb9SLee Jones 		.name = "ab8500-codec",
7651c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-codec",
7664b106fb9SLee Jones 	},
767c0eda9aeSLee Jones 	{
768c0eda9aeSLee Jones 		.name = "ab-iddet",
769c0eda9aeSLee Jones 	},
770c0eda9aeSLee Jones };
771c0eda9aeSLee Jones 
7725ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_devs[] = {
7734b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS
7744b106fb9SLee Jones 	{
7754b106fb9SLee Jones 		.name = "ab8500-debug",
7764b106fb9SLee Jones 	},
7774b106fb9SLee Jones #endif
7784b106fb9SLee Jones 	{
7794b106fb9SLee Jones 		.name = "ab8500-sysctrl",
7804b106fb9SLee Jones 	},
7814b106fb9SLee Jones 	{
78253f325beSLee Jones 		.name = "ab8500-ext-regulator",
78353f325beSLee Jones 	},
78453f325beSLee Jones 	{
7854b106fb9SLee Jones 		.name = "ab8500-regulator",
7864b106fb9SLee Jones 	},
7874b106fb9SLee Jones 	{
7889ee17676SUlf Hansson 		.name = "abx500-clk",
7899ee17676SUlf Hansson 		.of_compatible = "stericsson,abx500-clk",
7909ee17676SUlf Hansson 	},
7919ee17676SUlf Hansson 	{
7924b106fb9SLee Jones 		.name = "ab8500-gpadc",
793955de2eaSLee Jones 		.of_compatible = "stericsson,ab8500-gpadc",
7944b106fb9SLee Jones 	},
7954b106fb9SLee Jones 	{
7964b106fb9SLee Jones 		.name = "ab8500-acc-det",
7974b106fb9SLee Jones 	},
7984b106fb9SLee Jones 	{
7994b106fb9SLee Jones 		.name = "ab8500-poweron-key",
8004b106fb9SLee Jones 	},
8014b106fb9SLee Jones 	{
8024b106fb9SLee Jones 		.name = "ab8500-pwm",
8034b106fb9SLee Jones 		.id = 1,
8044b106fb9SLee Jones 	},
8054b106fb9SLee Jones 	{
8064b106fb9SLee Jones 		.name = "abx500-temp",
8074b106fb9SLee Jones 	},
808c0eda9aeSLee Jones 	{
809eb696c31SLee Jones 		.name = "pinctrl-ab8540",
810c0eda9aeSLee Jones 	},
811c0eda9aeSLee Jones 	{
812c0eda9aeSLee Jones 		.name = "ab8540-usb",
813c0eda9aeSLee Jones 	},
814c0eda9aeSLee Jones 	{
815c0eda9aeSLee Jones 		.name = "ab8540-codec",
816c0eda9aeSLee Jones 	},
817c0eda9aeSLee Jones 	{
81844f72e53SVirupax Sadashivpetimath 		.name = "ab-iddet",
81944f72e53SVirupax Sadashivpetimath 	},
820d6255529SLinus Walleij };
821d6255529SLinus Walleij 
8225ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_cut1_devs[] = {
8239c717cf3SAlexandre Torgue 	{
8249c717cf3SAlexandre Torgue 		.name = "ab8500-rtc",
8259c717cf3SAlexandre Torgue 		.of_compatible = "stericsson,ab8500-rtc",
8269c717cf3SAlexandre Torgue 	},
8279c717cf3SAlexandre Torgue };
8289c717cf3SAlexandre Torgue 
8295ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_cut2_devs[] = {
8309c717cf3SAlexandre Torgue 	{
8319c717cf3SAlexandre Torgue 		.name = "ab8540-rtc",
8329c717cf3SAlexandre Torgue 		.of_compatible = "stericsson,ab8540-rtc",
8339c717cf3SAlexandre Torgue 	},
8349c717cf3SAlexandre Torgue };
8359c717cf3SAlexandre Torgue 
836cca69b67SMattias Wallin static ssize_t show_chip_id(struct device *dev,
837cca69b67SMattias Wallin 				struct device_attribute *attr, char *buf)
838cca69b67SMattias Wallin {
839cca69b67SMattias Wallin 	struct ab8500 *ab8500;
840cca69b67SMattias Wallin 
841cca69b67SMattias Wallin 	ab8500 = dev_get_drvdata(dev);
842e436ddffSLee Jones 
843cca69b67SMattias Wallin 	return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
844cca69b67SMattias Wallin }
845cca69b67SMattias Wallin 
846e5c238c3SMattias Wallin /*
847e5c238c3SMattias Wallin  * ab8500 has switched off due to (SWITCH_OFF_STATUS):
848e5c238c3SMattias Wallin  * 0x01 Swoff bit programming
849e5c238c3SMattias Wallin  * 0x02 Thermal protection activation
850e5c238c3SMattias Wallin  * 0x04 Vbat lower then BattOk falling threshold
851e5c238c3SMattias Wallin  * 0x08 Watchdog expired
852e5c238c3SMattias Wallin  * 0x10 Non presence of 32kHz clock
853e5c238c3SMattias Wallin  * 0x20 Battery level lower than power on reset threshold
854e5c238c3SMattias Wallin  * 0x40 Power on key 1 pressed longer than 10 seconds
855e5c238c3SMattias Wallin  * 0x80 DB8500 thermal shutdown
856e5c238c3SMattias Wallin  */
857e5c238c3SMattias Wallin static ssize_t show_switch_off_status(struct device *dev,
858e5c238c3SMattias Wallin 				struct device_attribute *attr, char *buf)
859e5c238c3SMattias Wallin {
860e5c238c3SMattias Wallin 	int ret;
861e5c238c3SMattias Wallin 	u8 value;
862e5c238c3SMattias Wallin 	struct ab8500 *ab8500;
863e5c238c3SMattias Wallin 
864e5c238c3SMattias Wallin 	ab8500 = dev_get_drvdata(dev);
865e5c238c3SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_RTC,
866e5c238c3SMattias Wallin 		AB8500_SWITCH_OFF_STATUS, &value);
867e5c238c3SMattias Wallin 	if (ret < 0)
868e5c238c3SMattias Wallin 		return ret;
869e5c238c3SMattias Wallin 	return sprintf(buf, "%#x\n", value);
870e5c238c3SMattias Wallin }
871e5c238c3SMattias Wallin 
872f04a9d8aSRajkumar Kasirajan /* use mask and set to override the register turn_on_stat value */
873f04a9d8aSRajkumar Kasirajan void ab8500_override_turn_on_stat(u8 mask, u8 set)
874f04a9d8aSRajkumar Kasirajan {
875f04a9d8aSRajkumar Kasirajan 	spin_lock(&on_stat_lock);
876f04a9d8aSRajkumar Kasirajan 	turn_on_stat_mask = mask;
877f04a9d8aSRajkumar Kasirajan 	turn_on_stat_set = set;
878f04a9d8aSRajkumar Kasirajan 	spin_unlock(&on_stat_lock);
879f04a9d8aSRajkumar Kasirajan }
880f04a9d8aSRajkumar Kasirajan 
881b4a31037SAndrew Lynn /*
882b4a31037SAndrew Lynn  * ab8500 has turned on due to (TURN_ON_STATUS):
883b4a31037SAndrew Lynn  * 0x01 PORnVbat
884b4a31037SAndrew Lynn  * 0x02 PonKey1dbF
885b4a31037SAndrew Lynn  * 0x04 PonKey2dbF
886b4a31037SAndrew Lynn  * 0x08 RTCAlarm
887b4a31037SAndrew Lynn  * 0x10 MainChDet
888b4a31037SAndrew Lynn  * 0x20 VbusDet
889b4a31037SAndrew Lynn  * 0x40 UsbIDDetect
890b4a31037SAndrew Lynn  * 0x80 Reserved
891b4a31037SAndrew Lynn  */
892b4a31037SAndrew Lynn static ssize_t show_turn_on_status(struct device *dev,
893b4a31037SAndrew Lynn 				struct device_attribute *attr, char *buf)
894b4a31037SAndrew Lynn {
895b4a31037SAndrew Lynn 	int ret;
896b4a31037SAndrew Lynn 	u8 value;
897b4a31037SAndrew Lynn 	struct ab8500 *ab8500;
898b4a31037SAndrew Lynn 
899b4a31037SAndrew Lynn 	ab8500 = dev_get_drvdata(dev);
900b4a31037SAndrew Lynn 	ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
901b4a31037SAndrew Lynn 		AB8500_TURN_ON_STATUS, &value);
902b4a31037SAndrew Lynn 	if (ret < 0)
903b4a31037SAndrew Lynn 		return ret;
904f04a9d8aSRajkumar Kasirajan 
905f04a9d8aSRajkumar Kasirajan 	/*
906f04a9d8aSRajkumar Kasirajan 	 * In L9540, turn_on_status register is not updated correctly if
907f04a9d8aSRajkumar Kasirajan 	 * the device is rebooted with AC/USB charger connected. Due to
908f04a9d8aSRajkumar Kasirajan 	 * this, the device boots android instead of entering into charge
909f04a9d8aSRajkumar Kasirajan 	 * only mode. Read the AC/USB status register to detect the charger
910f04a9d8aSRajkumar Kasirajan 	 * presence and update the turn on status manually.
911f04a9d8aSRajkumar Kasirajan 	 */
912f04a9d8aSRajkumar Kasirajan 	if (is_ab9540(ab8500)) {
913f04a9d8aSRajkumar Kasirajan 		spin_lock(&on_stat_lock);
914f04a9d8aSRajkumar Kasirajan 		value = (value & turn_on_stat_mask) | turn_on_stat_set;
915f04a9d8aSRajkumar Kasirajan 		spin_unlock(&on_stat_lock);
916f04a9d8aSRajkumar Kasirajan 	}
917f04a9d8aSRajkumar Kasirajan 
918b4a31037SAndrew Lynn 	return sprintf(buf, "%#x\n", value);
919b4a31037SAndrew Lynn }
920b4a31037SAndrew Lynn 
92193ff722eSLee Jones static ssize_t show_turn_on_status_2(struct device *dev,
92293ff722eSLee Jones 				struct device_attribute *attr, char *buf)
92393ff722eSLee Jones {
92493ff722eSLee Jones 	int ret;
92593ff722eSLee Jones 	u8 value;
92693ff722eSLee Jones 	struct ab8500 *ab8500;
92793ff722eSLee Jones 
92893ff722eSLee Jones 	ab8500 = dev_get_drvdata(dev);
92993ff722eSLee Jones 	ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
93093ff722eSLee Jones 		AB8505_TURN_ON_STATUS_2, &value);
93193ff722eSLee Jones 	if (ret < 0)
93293ff722eSLee Jones 		return ret;
93393ff722eSLee Jones 	return sprintf(buf, "%#x\n", (value & 0x1));
93493ff722eSLee Jones }
93593ff722eSLee Jones 
936d6255529SLinus Walleij static ssize_t show_ab9540_dbbrstn(struct device *dev,
937d6255529SLinus Walleij 				struct device_attribute *attr, char *buf)
938d6255529SLinus Walleij {
939d6255529SLinus Walleij 	struct ab8500 *ab8500;
940d6255529SLinus Walleij 	int ret;
941d6255529SLinus Walleij 	u8 value;
942d6255529SLinus Walleij 
943d6255529SLinus Walleij 	ab8500 = dev_get_drvdata(dev);
944d6255529SLinus Walleij 
945d6255529SLinus Walleij 	ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2,
946d6255529SLinus Walleij 		AB9540_MODEM_CTRL2_REG, &value);
947d6255529SLinus Walleij 	if (ret < 0)
948d6255529SLinus Walleij 		return ret;
949d6255529SLinus Walleij 
950d6255529SLinus Walleij 	return sprintf(buf, "%d\n",
951d6255529SLinus Walleij 			(value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0);
952d6255529SLinus Walleij }
953d6255529SLinus Walleij 
954d6255529SLinus Walleij static ssize_t store_ab9540_dbbrstn(struct device *dev,
955d6255529SLinus Walleij 	struct device_attribute *attr, const char *buf, size_t count)
956d6255529SLinus Walleij {
957d6255529SLinus Walleij 	struct ab8500 *ab8500;
958d6255529SLinus Walleij 	int ret = count;
959d6255529SLinus Walleij 	int err;
960d6255529SLinus Walleij 	u8 bitvalues;
961d6255529SLinus Walleij 
962d6255529SLinus Walleij 	ab8500 = dev_get_drvdata(dev);
963d6255529SLinus Walleij 
964d6255529SLinus Walleij 	if (count > 0) {
965d6255529SLinus Walleij 		switch (buf[0]) {
966d6255529SLinus Walleij 		case '0':
967d6255529SLinus Walleij 			bitvalues = 0;
968d6255529SLinus Walleij 			break;
969d6255529SLinus Walleij 		case '1':
970d6255529SLinus Walleij 			bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT;
971d6255529SLinus Walleij 			break;
972d6255529SLinus Walleij 		default:
973d6255529SLinus Walleij 			goto exit;
974d6255529SLinus Walleij 		}
975d6255529SLinus Walleij 
976d6255529SLinus Walleij 		err = mask_and_set_register_interruptible(ab8500,
977d6255529SLinus Walleij 			AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG,
978d6255529SLinus Walleij 			AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues);
979d6255529SLinus Walleij 		if (err)
980d6255529SLinus Walleij 			dev_info(ab8500->dev,
981d6255529SLinus Walleij 				"Failed to set DBBRSTN %c, err %#x\n",
982d6255529SLinus Walleij 				buf[0], err);
983d6255529SLinus Walleij 	}
984d6255529SLinus Walleij 
985d6255529SLinus Walleij exit:
986d6255529SLinus Walleij 	return ret;
987d6255529SLinus Walleij }
988d6255529SLinus Walleij 
989cca69b67SMattias Wallin static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
990e5c238c3SMattias Wallin static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
991b4a31037SAndrew Lynn static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
99293ff722eSLee Jones static DEVICE_ATTR(turn_on_status_2, S_IRUGO, show_turn_on_status_2, NULL);
993d6255529SLinus Walleij static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR,
994d6255529SLinus Walleij 			show_ab9540_dbbrstn, store_ab9540_dbbrstn);
995cca69b67SMattias Wallin 
996cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = {
997cca69b67SMattias Wallin 	&dev_attr_chip_id.attr,
998e5c238c3SMattias Wallin 	&dev_attr_switch_off_status.attr,
999b4a31037SAndrew Lynn 	&dev_attr_turn_on_status.attr,
1000cca69b67SMattias Wallin 	NULL,
1001cca69b67SMattias Wallin };
1002cca69b67SMattias Wallin 
100393ff722eSLee Jones static struct attribute *ab8505_sysfs_entries[] = {
100493ff722eSLee Jones 	&dev_attr_turn_on_status_2.attr,
100593ff722eSLee Jones 	NULL,
100693ff722eSLee Jones };
100793ff722eSLee Jones 
1008d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = {
1009d6255529SLinus Walleij 	&dev_attr_chip_id.attr,
1010d6255529SLinus Walleij 	&dev_attr_switch_off_status.attr,
1011d6255529SLinus Walleij 	&dev_attr_turn_on_status.attr,
1012d6255529SLinus Walleij 	&dev_attr_dbbrstn.attr,
1013d6255529SLinus Walleij 	NULL,
1014d6255529SLinus Walleij };
1015d6255529SLinus Walleij 
101652557dc6SArvind Yadav static const struct attribute_group ab8500_attr_group = {
1017cca69b67SMattias Wallin 	.attrs	= ab8500_sysfs_entries,
1018cca69b67SMattias Wallin };
1019cca69b67SMattias Wallin 
102052557dc6SArvind Yadav static const struct attribute_group ab8505_attr_group = {
102193ff722eSLee Jones 	.attrs	= ab8505_sysfs_entries,
102293ff722eSLee Jones };
102393ff722eSLee Jones 
102452557dc6SArvind Yadav static const struct attribute_group ab9540_attr_group = {
1025d6255529SLinus Walleij 	.attrs	= ab9540_sysfs_entries,
1026d6255529SLinus Walleij };
1027d6255529SLinus Walleij 
1028f791be49SBill Pemberton static int ab8500_probe(struct platform_device *pdev)
102962579266SRabin Vincent {
1030500e69a1SLee Jones 	static const char * const switch_off_status[] = {
1031b04c530cSJonas Aaberg 		"Swoff bit programming",
1032b04c530cSJonas Aaberg 		"Thermal protection activation",
1033b04c530cSJonas Aaberg 		"Vbat lower then BattOk falling threshold",
1034b04c530cSJonas Aaberg 		"Watchdog expired",
1035b04c530cSJonas Aaberg 		"Non presence of 32kHz clock",
1036b04c530cSJonas Aaberg 		"Battery level lower than power on reset threshold",
1037b04c530cSJonas Aaberg 		"Power on key 1 pressed longer than 10 seconds",
1038b04c530cSJonas Aaberg 		"DB8500 thermal shutdown"};
1039500e69a1SLee Jones 	static const char * const turn_on_status[] = {
1040abee26cdSMattias Wallin 		"Battery rising (Vbat)",
1041abee26cdSMattias Wallin 		"Power On Key 1 dbF",
1042abee26cdSMattias Wallin 		"Power On Key 2 dbF",
1043abee26cdSMattias Wallin 		"RTC Alarm",
1044abee26cdSMattias Wallin 		"Main Charger Detect",
1045abee26cdSMattias Wallin 		"Vbus Detect (USB)",
1046abee26cdSMattias Wallin 		"USB ID Detect",
1047abee26cdSMattias Wallin 		"UART Factory Mode Detect"};
1048d28f1db8SLee Jones 	const struct platform_device_id *platid = platform_get_device_id(pdev);
10496bc4a568SLee Jones 	enum ab8500_version version = AB8500_VERSION_UNDEFINED;
10506bc4a568SLee Jones 	struct device_node *np = pdev->dev.of_node;
1051d28f1db8SLee Jones 	struct ab8500 *ab8500;
1052d28f1db8SLee Jones 	struct resource *resource;
105362579266SRabin Vincent 	int ret;
105462579266SRabin Vincent 	int i;
105547c16975SMattias Wallin 	u8 value;
105662579266SRabin Vincent 
10577ccf40b1SLee Jones 	ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL);
1058d28f1db8SLee Jones 	if (!ab8500)
1059d28f1db8SLee Jones 		return -ENOMEM;
1060d28f1db8SLee Jones 
1061d28f1db8SLee Jones 	ab8500->dev = &pdev->dev;
1062d28f1db8SLee Jones 
1063d28f1db8SLee Jones 	resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1064f864c46aSLinus Walleij 	if (!resource) {
1065f864c46aSLinus Walleij 		dev_err(&pdev->dev, "no IRQ resource\n");
10668c4203cbSLee Jones 		return -ENODEV;
1067f864c46aSLinus Walleij 	}
1068d28f1db8SLee Jones 
1069d28f1db8SLee Jones 	ab8500->irq = resource->start;
1070d28f1db8SLee Jones 
1071822672a7SLee Jones 	ab8500->read = ab8500_prcmu_read;
1072822672a7SLee Jones 	ab8500->write = ab8500_prcmu_write;
1073822672a7SLee Jones 	ab8500->write_masked = ab8500_prcmu_write_masked;
1074d28f1db8SLee Jones 
107562579266SRabin Vincent 	mutex_init(&ab8500->lock);
107662579266SRabin Vincent 	mutex_init(&ab8500->irq_lock);
1077112a80d2SJonas Aaberg 	atomic_set(&ab8500->transfer_ongoing, 0);
107862579266SRabin Vincent 
1079d28f1db8SLee Jones 	platform_set_drvdata(pdev, ab8500);
1080d28f1db8SLee Jones 
10816bc4a568SLee Jones 	if (platid)
10826bc4a568SLee Jones 		version = platid->driver_data;
10836bc4a568SLee Jones 
10840f620837SLinus Walleij 	if (version != AB8500_VERSION_UNDEFINED)
10850f620837SLinus Walleij 		ab8500->version = version;
10860f620837SLinus Walleij 	else {
10870f620837SLinus Walleij 		ret = get_register_interruptible(ab8500, AB8500_MISC,
10880f620837SLinus Walleij 			AB8500_IC_NAME_REG, &value);
1089f864c46aSLinus Walleij 		if (ret < 0) {
1090f864c46aSLinus Walleij 			dev_err(&pdev->dev, "could not probe HW\n");
10918c4203cbSLee Jones 			return ret;
1092f864c46aSLinus Walleij 		}
10930f620837SLinus Walleij 
10940f620837SLinus Walleij 		ab8500->version = value;
10950f620837SLinus Walleij 	}
10960f620837SLinus Walleij 
109747c16975SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_MISC,
109847c16975SMattias Wallin 		AB8500_REV_REG, &value);
109962579266SRabin Vincent 	if (ret < 0)
11008c4203cbSLee Jones 		return ret;
110162579266SRabin Vincent 
110247c16975SMattias Wallin 	ab8500->chip_id = value;
110362579266SRabin Vincent 
11040f620837SLinus Walleij 	dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n",
11050f620837SLinus Walleij 			ab8500_version_str[ab8500->version],
11060f620837SLinus Walleij 			ab8500->chip_id >> 4,
11070f620837SLinus Walleij 			ab8500->chip_id & 0x0F);
11080f620837SLinus Walleij 
11093e1a498fSLee Jones 	/* Configure AB8540 */
11103e1a498fSLee Jones 	if (is_ab8540(ab8500)) {
11113e1a498fSLee Jones 		ab8500->mask_size = AB8540_NUM_IRQ_REGS;
11123e1a498fSLee Jones 		ab8500->irq_reg_offset = ab8540_irq_regoffset;
11133e1a498fSLee Jones 		ab8500->it_latchhier_num = AB8540_IT_LATCHHIER_NUM;
11143e1a498fSLee Jones 	} /* Configure AB8500 or AB9540 IRQ */
11153e1a498fSLee Jones 	else if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
1116d6255529SLinus Walleij 		ab8500->mask_size = AB9540_NUM_IRQ_REGS;
1117d6255529SLinus Walleij 		ab8500->irq_reg_offset = ab9540_irq_regoffset;
11183e1a498fSLee Jones 		ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM;
1119d6255529SLinus Walleij 	} else {
11202ced445eSLinus Walleij 		ab8500->mask_size = AB8500_NUM_IRQ_REGS;
11212ced445eSLinus Walleij 		ab8500->irq_reg_offset = ab8500_irq_regoffset;
11223e1a498fSLee Jones 		ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM;
1123d6255529SLinus Walleij 	}
11247ccf40b1SLee Jones 	ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size,
11257ccf40b1SLee Jones 				    GFP_KERNEL);
11262ced445eSLinus Walleij 	if (!ab8500->mask)
11272ced445eSLinus Walleij 		return -ENOMEM;
11287ccf40b1SLee Jones 	ab8500->oldmask = devm_kzalloc(&pdev->dev, ab8500->mask_size,
11297ccf40b1SLee Jones 				       GFP_KERNEL);
11308c4203cbSLee Jones 	if (!ab8500->oldmask)
11318c4203cbSLee Jones 		return -ENOMEM;
11328c4203cbSLee Jones 
1133e5c238c3SMattias Wallin 	/*
1134e5c238c3SMattias Wallin 	 * ab8500 has switched off due to (SWITCH_OFF_STATUS):
1135e5c238c3SMattias Wallin 	 * 0x01 Swoff bit programming
1136e5c238c3SMattias Wallin 	 * 0x02 Thermal protection activation
1137e5c238c3SMattias Wallin 	 * 0x04 Vbat lower then BattOk falling threshold
1138e5c238c3SMattias Wallin 	 * 0x08 Watchdog expired
1139e5c238c3SMattias Wallin 	 * 0x10 Non presence of 32kHz clock
1140e5c238c3SMattias Wallin 	 * 0x20 Battery level lower than power on reset threshold
1141e5c238c3SMattias Wallin 	 * 0x40 Power on key 1 pressed longer than 10 seconds
1142e5c238c3SMattias Wallin 	 * 0x80 DB8500 thermal shutdown
1143e5c238c3SMattias Wallin 	 */
1144e5c238c3SMattias Wallin 
1145e5c238c3SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_RTC,
1146e5c238c3SMattias Wallin 		AB8500_SWITCH_OFF_STATUS, &value);
1147e5c238c3SMattias Wallin 	if (ret < 0)
1148e5c238c3SMattias Wallin 		return ret;
1149b04c530cSJonas Aaberg 	dev_info(ab8500->dev, "switch off cause(s) (%#x): ", value);
1150b04c530cSJonas Aaberg 
1151b04c530cSJonas Aaberg 	if (value) {
1152b04c530cSJonas Aaberg 		for (i = 0; i < ARRAY_SIZE(switch_off_status); i++) {
1153b04c530cSJonas Aaberg 			if (value & 1)
11547ccf40b1SLee Jones 				pr_cont(" \"%s\"", switch_off_status[i]);
1155b04c530cSJonas Aaberg 			value = value >> 1;
1156b04c530cSJonas Aaberg 
1157b04c530cSJonas Aaberg 		}
11587ccf40b1SLee Jones 		pr_cont("\n");
1159b04c530cSJonas Aaberg 	} else {
11607ccf40b1SLee Jones 		pr_cont(" None\n");
1161b04c530cSJonas Aaberg 	}
1162abee26cdSMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
1163abee26cdSMattias Wallin 		AB8500_TURN_ON_STATUS, &value);
1164abee26cdSMattias Wallin 	if (ret < 0)
1165abee26cdSMattias Wallin 		return ret;
1166abee26cdSMattias Wallin 	dev_info(ab8500->dev, "turn on reason(s) (%#x): ", value);
1167abee26cdSMattias Wallin 
1168abee26cdSMattias Wallin 	if (value) {
1169abee26cdSMattias Wallin 		for (i = 0; i < ARRAY_SIZE(turn_on_status); i++) {
1170abee26cdSMattias Wallin 			if (value & 1)
11717ccf40b1SLee Jones 				pr_cont("\"%s\" ", turn_on_status[i]);
1172abee26cdSMattias Wallin 			value = value >> 1;
1173abee26cdSMattias Wallin 		}
11747ccf40b1SLee Jones 		pr_cont("\n");
1175abee26cdSMattias Wallin 	} else {
11767ccf40b1SLee Jones 		pr_cont("None\n");
1177abee26cdSMattias Wallin 	}
1178e5c238c3SMattias Wallin 
1179f04a9d8aSRajkumar Kasirajan 	if (is_ab9540(ab8500)) {
1180f04a9d8aSRajkumar Kasirajan 		ret = get_register_interruptible(ab8500, AB8500_CHARGER,
1181f04a9d8aSRajkumar Kasirajan 			AB8500_CH_USBCH_STAT1_REG, &value);
1182f04a9d8aSRajkumar Kasirajan 		if (ret < 0)
1183f04a9d8aSRajkumar Kasirajan 			return ret;
1184f04a9d8aSRajkumar Kasirajan 		if ((value & VBUS_DET_DBNC1) && (value & VBUS_DET_DBNC100))
1185f04a9d8aSRajkumar Kasirajan 			ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON,
1186f04a9d8aSRajkumar Kasirajan 						     AB8500_VBUS_DET);
1187f04a9d8aSRajkumar Kasirajan 	}
118862579266SRabin Vincent 
118962579266SRabin Vincent 	/* Clear and mask all interrupts */
11902ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++) {
11910f620837SLinus Walleij 		/*
11920f620837SLinus Walleij 		 * Interrupt register 12 doesn't exist prior to AB8500 version
11930f620837SLinus Walleij 		 * 2.0
11940f620837SLinus Walleij 		 */
11950f620837SLinus Walleij 		if (ab8500->irq_reg_offset[i] == 11 &&
11960f620837SLinus Walleij 				is_ab8500_1p1_or_earlier(ab8500))
119792d50a41SMattias Wallin 			continue;
119862579266SRabin Vincent 
11993e1a498fSLee Jones 		if (ab8500->irq_reg_offset[i] < 0)
12003e1a498fSLee Jones 			continue;
12013e1a498fSLee Jones 
120247c16975SMattias Wallin 		get_register_interruptible(ab8500, AB8500_INTERRUPT,
12032ced445eSLinus Walleij 			AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
120492d50a41SMattias Wallin 			&value);
120547c16975SMattias Wallin 		set_register_interruptible(ab8500, AB8500_INTERRUPT,
12062ced445eSLinus Walleij 			AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff);
120762579266SRabin Vincent 	}
120862579266SRabin Vincent 
120947c16975SMattias Wallin 	ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
121047c16975SMattias Wallin 	if (ret)
12118c4203cbSLee Jones 		return ret;
121247c16975SMattias Wallin 
12132ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++)
121462579266SRabin Vincent 		ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
121562579266SRabin Vincent 
121606e589efSLee Jones 	ret = ab8500_irq_init(ab8500, np);
121762579266SRabin Vincent 	if (ret)
12188c4203cbSLee Jones 		return ret;
121962579266SRabin Vincent 
12208c4203cbSLee Jones 	ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL,
12217ccfe9b1SMichel JAOUEN 			ab8500_hierarchical_irq,
12227ccfe9b1SMichel JAOUEN 			IRQF_ONESHOT | IRQF_NO_SUSPEND,
12237ccfe9b1SMichel JAOUEN 			"ab8500", ab8500);
122462579266SRabin Vincent 	if (ret)
12258c4203cbSLee Jones 		return ret;
122662579266SRabin Vincent 
1227d6255529SLinus Walleij 	if (is_ab9540(ab8500))
1228d6255529SLinus Walleij 		ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
1229d6255529SLinus Walleij 				ARRAY_SIZE(ab9540_devs), NULL,
1230f864c46aSLinus Walleij 				0, ab8500->domain);
12319c717cf3SAlexandre Torgue 	else if (is_ab8540(ab8500)) {
1232c0eda9aeSLee Jones 		ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs,
1233c0eda9aeSLee Jones 			      ARRAY_SIZE(ab8540_devs), NULL,
1234f864c46aSLinus Walleij 			      0, ab8500->domain);
12359c717cf3SAlexandre Torgue 		if (ret)
12369c717cf3SAlexandre Torgue 			return ret;
12379c717cf3SAlexandre Torgue 
12389c717cf3SAlexandre Torgue 		if (is_ab8540_1p2_or_earlier(ab8500))
12399c717cf3SAlexandre Torgue 			ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut1_devs,
12409c717cf3SAlexandre Torgue 			      ARRAY_SIZE(ab8540_cut1_devs), NULL,
1241f864c46aSLinus Walleij 			      0, ab8500->domain);
12429c717cf3SAlexandre Torgue 		else /* ab8540 >= cut2 */
12439c717cf3SAlexandre Torgue 			ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut2_devs,
12449c717cf3SAlexandre Torgue 			      ARRAY_SIZE(ab8540_cut2_devs), NULL,
1245f864c46aSLinus Walleij 			      0, ab8500->domain);
12469c717cf3SAlexandre Torgue 	} else if (is_ab8505(ab8500))
1247c0eda9aeSLee Jones 		ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs,
1248c0eda9aeSLee Jones 			      ARRAY_SIZE(ab8505_devs), NULL,
1249f864c46aSLinus Walleij 			      0, ab8500->domain);
1250d6255529SLinus Walleij 	else
1251549931f9SSundar R Iyer 		ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
125244f72e53SVirupax Sadashivpetimath 				ARRAY_SIZE(ab8500_devs), NULL,
1253f864c46aSLinus Walleij 				0, ab8500->domain);
12546bc4a568SLee Jones 	if (ret)
12558c4203cbSLee Jones 		return ret;
125644f72e53SVirupax Sadashivpetimath 
12576ef9418cSRickard Andersson 	if (!no_bm) {
12586ef9418cSRickard Andersson 		/* Add battery management devices */
12596ef9418cSRickard Andersson 		ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
12606ef9418cSRickard Andersson 				      ARRAY_SIZE(ab8500_bm_devs), NULL,
1261f864c46aSLinus Walleij 				      0, ab8500->domain);
12626ef9418cSRickard Andersson 		if (ret)
12636ef9418cSRickard Andersson 			dev_err(ab8500->dev, "error adding bm devices\n");
12646ef9418cSRickard Andersson 	}
12656ef9418cSRickard Andersson 
1266e436ddffSLee Jones 	if (((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
1267e436ddffSLee Jones 			ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500))
1268d6255529SLinus Walleij 		ret = sysfs_create_group(&ab8500->dev->kobj,
1269d6255529SLinus Walleij 					&ab9540_attr_group);
1270d6255529SLinus Walleij 	else
1271d6255529SLinus Walleij 		ret = sysfs_create_group(&ab8500->dev->kobj,
1272d6255529SLinus Walleij 					&ab8500_attr_group);
127393ff722eSLee Jones 
127493ff722eSLee Jones 	if ((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
127593ff722eSLee Jones 			ab8500->chip_id >= AB8500_CUT2P0)
127693ff722eSLee Jones 		ret = sysfs_create_group(&ab8500->dev->kobj,
127793ff722eSLee Jones 					 &ab8505_attr_group);
127893ff722eSLee Jones 
1279cca69b67SMattias Wallin 	if (ret)
1280cca69b67SMattias Wallin 		dev_err(ab8500->dev, "error creating sysfs entries\n");
128106e589efSLee Jones 
128262579266SRabin Vincent 	return ret;
128362579266SRabin Vincent }
128462579266SRabin Vincent 
1285d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = {
1286d28f1db8SLee Jones 	{ "ab8500-core", AB8500_VERSION_AB8500 },
12871c0769d2SStephan Gerhold 	{ "ab8505-core", AB8500_VERSION_AB8505 },
1288d28f1db8SLee Jones 	{ "ab9540-i2c", AB8500_VERSION_AB9540 },
1289d28f1db8SLee Jones 	{ "ab8540-i2c", AB8500_VERSION_AB8540 },
1290d28f1db8SLee Jones 	{ }
1291d28f1db8SLee Jones };
1292d28f1db8SLee Jones 
1293d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = {
1294d28f1db8SLee Jones 	.driver = {
1295d28f1db8SLee Jones 		.name = "ab8500-core",
129631cbae22SPaul Gortmaker 		.suppress_bind_attrs = true,
1297d28f1db8SLee Jones 	},
1298d28f1db8SLee Jones 	.probe	= ab8500_probe,
1299d28f1db8SLee Jones 	.id_table = ab8500_id,
1300d28f1db8SLee Jones };
1301d28f1db8SLee Jones 
1302d28f1db8SLee Jones static int __init ab8500_core_init(void)
1303d28f1db8SLee Jones {
1304d28f1db8SLee Jones 	return platform_driver_register(&ab8500_core_driver);
1305d28f1db8SLee Jones }
1306ba7cbc3eSLee Jones core_initcall(ab8500_core_init);
1307