xref: /openbmc/linux/drivers/mfd/ab8500-core.c (revision afb349c09601fbf1b0f4d9fc6360d1181ba2ed4f)
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 
124d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_REG			0x23
125d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT	BIT(2)
126d6255529SLinus Walleij 
12762579266SRabin Vincent /*
12862579266SRabin Vincent  * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
1292ced445eSLinus Walleij  * numbers are indexed into this array with (num / 8). The interupts are
1302ced445eSLinus Walleij  * defined in linux/mfd/ab8500.h
13162579266SRabin Vincent  *
13262579266SRabin Vincent  * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
13362579266SRabin Vincent  * offset 0.
13462579266SRabin Vincent  */
1352ced445eSLinus Walleij /* AB8500 support */
13662579266SRabin Vincent static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
13792d50a41SMattias Wallin 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
13862579266SRabin Vincent };
13962579266SRabin Vincent 
140a29264b6SLee Jones /* AB9540 / AB8505 support */
141d6255529SLinus Walleij static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
142a29264b6SLee Jones 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23
143d6255529SLinus Walleij };
144d6255529SLinus Walleij 
1453e1a498fSLee Jones /* AB8540 support */
1463e1a498fSLee Jones static const int ab8540_irq_regoffset[AB8540_NUM_IRQ_REGS] = {
1477ccf40b1SLee Jones 	0, 1, 2, 3, 4, -1, -1, -1, -1, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22,
1487ccf40b1SLee Jones 	23, 25, 26, 27, 28, 29, 30, 31,
1493e1a498fSLee Jones };
1503e1a498fSLee Jones 
1510f620837SLinus Walleij static const char ab8500_version_str[][7] = {
1520f620837SLinus Walleij 	[AB8500_VERSION_AB8500] = "AB8500",
1530f620837SLinus Walleij 	[AB8500_VERSION_AB8505] = "AB8505",
1540f620837SLinus Walleij 	[AB8500_VERSION_AB9540] = "AB9540",
1550f620837SLinus Walleij 	[AB8500_VERSION_AB8540] = "AB8540",
1560f620837SLinus Walleij };
1570f620837SLinus Walleij 
158822672a7SLee Jones static int ab8500_prcmu_write(struct ab8500 *ab8500, u16 addr, u8 data)
159d28f1db8SLee Jones {
160d28f1db8SLee Jones 	int ret;
161d28f1db8SLee Jones 
162d28f1db8SLee Jones 	ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
163d28f1db8SLee Jones 	if (ret < 0)
164d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
165d28f1db8SLee Jones 	return ret;
166d28f1db8SLee Jones }
167d28f1db8SLee Jones 
168822672a7SLee Jones static int ab8500_prcmu_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
169d28f1db8SLee Jones 	u8 data)
170d28f1db8SLee Jones {
171d28f1db8SLee Jones 	int ret;
172d28f1db8SLee Jones 
173d28f1db8SLee Jones 	ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data,
174d28f1db8SLee Jones 		&mask, 1);
175d28f1db8SLee Jones 	if (ret < 0)
176d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
177d28f1db8SLee Jones 	return ret;
178d28f1db8SLee Jones }
179d28f1db8SLee Jones 
180822672a7SLee Jones static int ab8500_prcmu_read(struct ab8500 *ab8500, u16 addr)
181d28f1db8SLee Jones {
182d28f1db8SLee Jones 	int ret;
183d28f1db8SLee Jones 	u8 data;
184d28f1db8SLee Jones 
185d28f1db8SLee Jones 	ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
186d28f1db8SLee Jones 	if (ret < 0) {
187d28f1db8SLee Jones 		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
188d28f1db8SLee Jones 		return ret;
189d28f1db8SLee Jones 	}
190d28f1db8SLee Jones 	return (int)data;
191d28f1db8SLee Jones }
192d28f1db8SLee Jones 
19347c16975SMattias Wallin static int ab8500_get_chip_id(struct device *dev)
19447c16975SMattias Wallin {
1956bce7bf1SMattias Wallin 	struct ab8500 *ab8500;
1966bce7bf1SMattias Wallin 
1976bce7bf1SMattias Wallin 	if (!dev)
1986bce7bf1SMattias Wallin 		return -EINVAL;
1996bce7bf1SMattias Wallin 	ab8500 = dev_get_drvdata(dev->parent);
2006bce7bf1SMattias Wallin 	return ab8500 ? (int)ab8500->chip_id : -EINVAL;
20147c16975SMattias Wallin }
20247c16975SMattias Wallin 
20347c16975SMattias Wallin static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
20447c16975SMattias Wallin 	u8 reg, u8 data)
20562579266SRabin Vincent {
20662579266SRabin Vincent 	int ret;
20747c16975SMattias Wallin 	/*
20847c16975SMattias Wallin 	 * Put the u8 bank and u8 register together into a an u16.
20947c16975SMattias Wallin 	 * The bank on higher 8 bits and register in lower 8 bits.
210500e69a1SLee Jones 	 */
21147c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
21262579266SRabin Vincent 
21362579266SRabin Vincent 	dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
21462579266SRabin Vincent 
215392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
21647c16975SMattias Wallin 
21747c16975SMattias Wallin 	ret = ab8500->write(ab8500, addr, data);
21847c16975SMattias Wallin 	if (ret < 0)
21947c16975SMattias Wallin 		dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
22047c16975SMattias Wallin 			addr, ret);
22147c16975SMattias Wallin 	mutex_unlock(&ab8500->lock);
22247c16975SMattias Wallin 
22347c16975SMattias Wallin 	return ret;
22447c16975SMattias Wallin }
22547c16975SMattias Wallin 
22647c16975SMattias Wallin static int ab8500_set_register(struct device *dev, u8 bank,
22747c16975SMattias Wallin 	u8 reg, u8 value)
22847c16975SMattias Wallin {
229112a80d2SJonas Aaberg 	int ret;
23047c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
23147c16975SMattias Wallin 
232112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
233112a80d2SJonas Aaberg 	ret = set_register_interruptible(ab8500, bank, reg, value);
234112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
235112a80d2SJonas Aaberg 	return ret;
23647c16975SMattias Wallin }
23747c16975SMattias Wallin 
23847c16975SMattias Wallin static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
23947c16975SMattias Wallin 	u8 reg, u8 *value)
24047c16975SMattias Wallin {
24147c16975SMattias Wallin 	int ret;
24247c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
24347c16975SMattias Wallin 
244392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
24547c16975SMattias Wallin 
24647c16975SMattias Wallin 	ret = ab8500->read(ab8500, addr);
24747c16975SMattias Wallin 	if (ret < 0)
24847c16975SMattias Wallin 		dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
24947c16975SMattias Wallin 			addr, ret);
25047c16975SMattias Wallin 	else
25147c16975SMattias Wallin 		*value = ret;
25247c16975SMattias Wallin 
25347c16975SMattias Wallin 	mutex_unlock(&ab8500->lock);
25447c16975SMattias Wallin 	dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret);
25547c16975SMattias Wallin 
25610628e3eSDan Carpenter 	return (ret < 0) ? ret : 0;
25747c16975SMattias Wallin }
25847c16975SMattias Wallin 
25947c16975SMattias Wallin static int ab8500_get_register(struct device *dev, u8 bank,
26047c16975SMattias Wallin 	u8 reg, u8 *value)
26147c16975SMattias Wallin {
262112a80d2SJonas Aaberg 	int ret;
26347c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
26447c16975SMattias Wallin 
265112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
266112a80d2SJonas Aaberg 	ret = get_register_interruptible(ab8500, bank, reg, value);
267112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
268112a80d2SJonas Aaberg 	return ret;
26947c16975SMattias Wallin }
27047c16975SMattias Wallin 
27147c16975SMattias Wallin static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
27247c16975SMattias Wallin 	u8 reg, u8 bitmask, u8 bitvalues)
27347c16975SMattias Wallin {
27447c16975SMattias Wallin 	int ret;
27547c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
27647c16975SMattias Wallin 
277392cbd1eSRabin Vincent 	mutex_lock(&ab8500->lock);
27847c16975SMattias Wallin 
279bc628fd1SMattias Nilsson 	if (ab8500->write_masked == NULL) {
280bc628fd1SMattias Nilsson 		u8 data;
281bc628fd1SMattias Nilsson 
28247c16975SMattias Wallin 		ret = ab8500->read(ab8500, addr);
28347c16975SMattias Wallin 		if (ret < 0) {
28447c16975SMattias Wallin 			dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
28547c16975SMattias Wallin 				addr, ret);
28647c16975SMattias Wallin 			goto out;
28747c16975SMattias Wallin 		}
28847c16975SMattias Wallin 
28947c16975SMattias Wallin 		data = (u8)ret;
29047c16975SMattias Wallin 		data = (~bitmask & data) | (bitmask & bitvalues);
29147c16975SMattias Wallin 
29262579266SRabin Vincent 		ret = ab8500->write(ab8500, addr, data);
29362579266SRabin Vincent 		if (ret < 0)
29462579266SRabin Vincent 			dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
29562579266SRabin Vincent 				addr, ret);
29662579266SRabin Vincent 
297bc628fd1SMattias Nilsson 		dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr,
298bc628fd1SMattias Nilsson 			data);
299bc628fd1SMattias Nilsson 		goto out;
300bc628fd1SMattias Nilsson 	}
301bc628fd1SMattias Nilsson 	ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues);
302bc628fd1SMattias Nilsson 	if (ret < 0)
303bc628fd1SMattias Nilsson 		dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr,
304bc628fd1SMattias Nilsson 			ret);
30562579266SRabin Vincent out:
30662579266SRabin Vincent 	mutex_unlock(&ab8500->lock);
30762579266SRabin Vincent 	return ret;
30862579266SRabin Vincent }
30947c16975SMattias Wallin 
31047c16975SMattias Wallin static int ab8500_mask_and_set_register(struct device *dev,
31147c16975SMattias Wallin 	u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
31247c16975SMattias Wallin {
313112a80d2SJonas Aaberg 	int ret;
31447c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
31547c16975SMattias Wallin 
316112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
317112a80d2SJonas Aaberg 	ret = mask_and_set_register_interruptible(ab8500, bank, reg,
31847c16975SMattias Wallin 						 bitmask, bitvalues);
319112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
320112a80d2SJonas Aaberg 	return ret;
32147c16975SMattias Wallin }
32247c16975SMattias Wallin 
32347c16975SMattias Wallin static struct abx500_ops ab8500_ops = {
32447c16975SMattias Wallin 	.get_chip_id = ab8500_get_chip_id,
32547c16975SMattias Wallin 	.get_register = ab8500_get_register,
32647c16975SMattias Wallin 	.set_register = ab8500_set_register,
32747c16975SMattias Wallin 	.get_register_page = NULL,
32847c16975SMattias Wallin 	.set_register_page = NULL,
32947c16975SMattias Wallin 	.mask_and_set_register = ab8500_mask_and_set_register,
33047c16975SMattias Wallin 	.event_registers_startup_state_get = NULL,
33147c16975SMattias Wallin 	.startup_irq_enabled = NULL,
3321d843a6cSMian Yousaf Kaukab 	.dump_all_banks = ab8500_dump_all_banks,
33347c16975SMattias Wallin };
33462579266SRabin Vincent 
3359505a0a0SMark Brown static void ab8500_irq_lock(struct irq_data *data)
33662579266SRabin Vincent {
3379505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
33862579266SRabin Vincent 
33962579266SRabin Vincent 	mutex_lock(&ab8500->irq_lock);
340112a80d2SJonas Aaberg 	atomic_inc(&ab8500->transfer_ongoing);
34162579266SRabin Vincent }
34262579266SRabin Vincent 
3439505a0a0SMark Brown static void ab8500_irq_sync_unlock(struct irq_data *data)
34462579266SRabin Vincent {
3459505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
34662579266SRabin Vincent 	int i;
34762579266SRabin Vincent 
3482ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++) {
34962579266SRabin Vincent 		u8 old = ab8500->oldmask[i];
35062579266SRabin Vincent 		u8 new = ab8500->mask[i];
35162579266SRabin Vincent 		int reg;
35262579266SRabin Vincent 
35362579266SRabin Vincent 		if (new == old)
35462579266SRabin Vincent 			continue;
35562579266SRabin Vincent 
3560f620837SLinus Walleij 		/*
3570f620837SLinus Walleij 		 * Interrupt register 12 doesn't exist prior to AB8500 version
3580f620837SLinus Walleij 		 * 2.0
3590f620837SLinus Walleij 		 */
3600f620837SLinus Walleij 		if (ab8500->irq_reg_offset[i] == 11 &&
3610f620837SLinus Walleij 			is_ab8500_1p1_or_earlier(ab8500))
36292d50a41SMattias Wallin 			continue;
36392d50a41SMattias Wallin 
3643e1a498fSLee Jones 		if (ab8500->irq_reg_offset[i] < 0)
3653e1a498fSLee Jones 			continue;
3663e1a498fSLee Jones 
36762579266SRabin Vincent 		ab8500->oldmask[i] = new;
36862579266SRabin Vincent 
3692ced445eSLinus Walleij 		reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
37047c16975SMattias Wallin 		set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
37162579266SRabin Vincent 	}
372112a80d2SJonas Aaberg 	atomic_dec(&ab8500->transfer_ongoing);
37362579266SRabin Vincent 	mutex_unlock(&ab8500->irq_lock);
37462579266SRabin Vincent }
37562579266SRabin Vincent 
3769505a0a0SMark Brown static void ab8500_irq_mask(struct irq_data *data)
37762579266SRabin Vincent {
3789505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
37906e589efSLee Jones 	int offset = data->hwirq;
38062579266SRabin Vincent 	int index = offset / 8;
38162579266SRabin Vincent 	int mask = 1 << (offset % 8);
38262579266SRabin Vincent 
38362579266SRabin Vincent 	ab8500->mask[index] |= mask;
3849c677b9bSLee Jones 
3859c677b9bSLee Jones 	/* The AB8500 GPIOs have two interrupts each (rising & falling). */
3869c677b9bSLee Jones 	if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
3879c677b9bSLee Jones 		ab8500->mask[index + 2] |= mask;
3889c677b9bSLee Jones 	if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R)
3899c677b9bSLee Jones 		ab8500->mask[index + 1] |= mask;
3909c677b9bSLee Jones 	if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R)
391e2ddf46aSLinus Walleij 		/* Here the falling IRQ is one bit lower */
392e2ddf46aSLinus Walleij 		ab8500->mask[index] |= (mask << 1);
39362579266SRabin Vincent }
39462579266SRabin Vincent 
3959505a0a0SMark Brown static void ab8500_irq_unmask(struct irq_data *data)
39662579266SRabin Vincent {
3979505a0a0SMark Brown 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
3989c677b9bSLee Jones 	unsigned int type = irqd_get_trigger_type(data);
39906e589efSLee Jones 	int offset = data->hwirq;
40062579266SRabin Vincent 	int index = offset / 8;
40162579266SRabin Vincent 	int mask = 1 << (offset % 8);
40262579266SRabin Vincent 
4039c677b9bSLee Jones 	if (type & IRQ_TYPE_EDGE_RISING)
40462579266SRabin Vincent 		ab8500->mask[index] &= ~mask;
4059c677b9bSLee Jones 
4069c677b9bSLee Jones 	/* The AB8500 GPIOs have two interrupts each (rising & falling). */
4079c677b9bSLee Jones 	if (type & IRQ_TYPE_EDGE_FALLING) {
4089c677b9bSLee Jones 		if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
4099c677b9bSLee Jones 			ab8500->mask[index + 2] &= ~mask;
4107ccf40b1SLee Jones 		else if (offset >= AB9540_INT_GPIO50R &&
4117ccf40b1SLee Jones 			 offset <= AB9540_INT_GPIO54R)
4129c677b9bSLee Jones 			ab8500->mask[index + 1] &= ~mask;
4137ccf40b1SLee Jones 		else if (offset == AB8540_INT_GPIO43R ||
4147ccf40b1SLee Jones 			 offset == AB8540_INT_GPIO44R)
415e2ddf46aSLinus Walleij 			/* Here the falling IRQ is one bit lower */
416e2ddf46aSLinus Walleij 			ab8500->mask[index] &= ~(mask << 1);
4179c677b9bSLee Jones 		else
4189c677b9bSLee Jones 			ab8500->mask[index] &= ~mask;
419e2ddf46aSLinus Walleij 	} else {
4209c677b9bSLee Jones 		/* Satisfies the case where type is not set. */
42162579266SRabin Vincent 		ab8500->mask[index] &= ~mask;
42262579266SRabin Vincent 	}
423e2ddf46aSLinus Walleij }
42462579266SRabin Vincent 
42540f6e5a2SLee Jones static int ab8500_irq_set_type(struct irq_data *data, unsigned int type)
42640f6e5a2SLee Jones {
42740f6e5a2SLee Jones 	return 0;
42862579266SRabin Vincent }
42962579266SRabin Vincent 
43062579266SRabin Vincent static struct irq_chip ab8500_irq_chip = {
43162579266SRabin Vincent 	.name			= "ab8500",
4329505a0a0SMark Brown 	.irq_bus_lock		= ab8500_irq_lock,
4339505a0a0SMark Brown 	.irq_bus_sync_unlock	= ab8500_irq_sync_unlock,
4349505a0a0SMark Brown 	.irq_mask		= ab8500_irq_mask,
435e6f9306eSVirupax Sadashivpetimath 	.irq_disable		= ab8500_irq_mask,
4369505a0a0SMark Brown 	.irq_unmask		= ab8500_irq_unmask,
43740f6e5a2SLee Jones 	.irq_set_type		= ab8500_irq_set_type,
43862579266SRabin Vincent };
43962579266SRabin Vincent 
4403e1a498fSLee Jones static void update_latch_offset(u8 *offset, int i)
4413e1a498fSLee Jones {
4423e1a498fSLee Jones 	/* Fix inconsistent ITFromLatch25 bit mapping... */
4433e1a498fSLee Jones 	if (unlikely(*offset == 17))
4443e1a498fSLee Jones 		*offset = 24;
4453e1a498fSLee Jones 	/* Fix inconsistent ab8540 bit mapping... */
4463e1a498fSLee Jones 	if (unlikely(*offset == 16))
4473e1a498fSLee Jones 		*offset = 25;
4483e1a498fSLee Jones 	if ((i == 3) && (*offset >= 24))
4493e1a498fSLee Jones 		*offset += 2;
4503e1a498fSLee Jones }
4513e1a498fSLee Jones 
4527ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
4537ccfe9b1SMichel JAOUEN 					int latch_offset, u8 latch_val)
4547ccfe9b1SMichel JAOUEN {
4557a93fb37SFabio Baltieri 	int int_bit, line, i;
4567ccfe9b1SMichel JAOUEN 
4577ccfe9b1SMichel JAOUEN 	for (i = 0; i < ab8500->mask_size; i++)
4587ccfe9b1SMichel JAOUEN 		if (ab8500->irq_reg_offset[i] == latch_offset)
4597ccfe9b1SMichel JAOUEN 			break;
4607ccfe9b1SMichel JAOUEN 
4617ccfe9b1SMichel JAOUEN 	if (i >= ab8500->mask_size) {
4627ccfe9b1SMichel JAOUEN 		dev_err(ab8500->dev, "Register offset 0x%2x not declared\n",
4637ccfe9b1SMichel JAOUEN 				latch_offset);
4647ccfe9b1SMichel JAOUEN 		return -ENXIO;
4657ccfe9b1SMichel JAOUEN 	}
4667ccfe9b1SMichel JAOUEN 
4677a93fb37SFabio Baltieri 	/* ignore masked out interrupts */
4687a93fb37SFabio Baltieri 	latch_val &= ~ab8500->mask[i];
4697a93fb37SFabio Baltieri 
4707a93fb37SFabio Baltieri 	while (latch_val) {
4717a93fb37SFabio Baltieri 		int_bit = __ffs(latch_val);
4727ccfe9b1SMichel JAOUEN 		line = (i << 3) + int_bit;
4737ccfe9b1SMichel JAOUEN 		latch_val &= ~(1 << int_bit);
4747ccfe9b1SMichel JAOUEN 
475e2ddf46aSLinus Walleij 		/*
476e2ddf46aSLinus Walleij 		 * This handles the falling edge hwirqs from the GPIO
477e2ddf46aSLinus Walleij 		 * lines. Route them back to the line registered for the
478e2ddf46aSLinus Walleij 		 * rising IRQ, as this is merely a flag for the same IRQ
479e2ddf46aSLinus Walleij 		 * in linux terms.
480e2ddf46aSLinus Walleij 		 */
481e2ddf46aSLinus Walleij 		if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F)
482e2ddf46aSLinus Walleij 			line -= 16;
483e2ddf46aSLinus Walleij 		if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F)
484e2ddf46aSLinus Walleij 			line -= 8;
485e2ddf46aSLinus Walleij 		if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F)
486e2ddf46aSLinus Walleij 			line += 1;
487e2ddf46aSLinus Walleij 
488ed83d301SLinus Walleij 		handle_nested_irq(irq_create_mapping(ab8500->domain, line));
4897a93fb37SFabio Baltieri 	}
4907ccfe9b1SMichel JAOUEN 
4917ccfe9b1SMichel JAOUEN 	return 0;
4927ccfe9b1SMichel JAOUEN }
4937ccfe9b1SMichel JAOUEN 
4947ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500,
4957ccfe9b1SMichel JAOUEN 					int hier_offset, u8 hier_val)
4967ccfe9b1SMichel JAOUEN {
4977ccfe9b1SMichel JAOUEN 	int latch_bit, status;
4987ccfe9b1SMichel JAOUEN 	u8 latch_offset, latch_val;
4997ccfe9b1SMichel JAOUEN 
5007ccfe9b1SMichel JAOUEN 	do {
5017ccfe9b1SMichel JAOUEN 		latch_bit = __ffs(hier_val);
5027ccfe9b1SMichel JAOUEN 		latch_offset = (hier_offset << 3) + latch_bit;
5037ccfe9b1SMichel JAOUEN 
5043e1a498fSLee Jones 		update_latch_offset(&latch_offset, hier_offset);
5057ccfe9b1SMichel JAOUEN 
5067ccfe9b1SMichel JAOUEN 		status = get_register_interruptible(ab8500,
5077ccfe9b1SMichel JAOUEN 				AB8500_INTERRUPT,
5087ccfe9b1SMichel JAOUEN 				AB8500_IT_LATCH1_REG + latch_offset,
5097ccfe9b1SMichel JAOUEN 				&latch_val);
5107ccfe9b1SMichel JAOUEN 		if (status < 0 || latch_val == 0)
5117ccfe9b1SMichel JAOUEN 			goto discard;
5127ccfe9b1SMichel JAOUEN 
5137ccfe9b1SMichel JAOUEN 		status = ab8500_handle_hierarchical_line(ab8500,
5147ccfe9b1SMichel JAOUEN 				latch_offset, latch_val);
5157ccfe9b1SMichel JAOUEN 		if (status < 0)
5167ccfe9b1SMichel JAOUEN 			return status;
5177ccfe9b1SMichel JAOUEN discard:
5187ccfe9b1SMichel JAOUEN 		hier_val &= ~(1 << latch_bit);
5197ccfe9b1SMichel JAOUEN 	} while (hier_val);
5207ccfe9b1SMichel JAOUEN 
5217ccfe9b1SMichel JAOUEN 	return 0;
5227ccfe9b1SMichel JAOUEN }
5237ccfe9b1SMichel JAOUEN 
5247ccfe9b1SMichel JAOUEN static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev)
5257ccfe9b1SMichel JAOUEN {
5267ccfe9b1SMichel JAOUEN 	struct ab8500 *ab8500 = dev;
5277ccfe9b1SMichel JAOUEN 	u8 i;
5287ccfe9b1SMichel JAOUEN 
5297ccfe9b1SMichel JAOUEN 	dev_vdbg(ab8500->dev, "interrupt\n");
5307ccfe9b1SMichel JAOUEN 
5317ccfe9b1SMichel JAOUEN 	/*  Hierarchical interrupt version */
5323e1a498fSLee Jones 	for (i = 0; i < (ab8500->it_latchhier_num); i++) {
5337ccfe9b1SMichel JAOUEN 		int status;
5347ccfe9b1SMichel JAOUEN 		u8 hier_val;
5357ccfe9b1SMichel JAOUEN 
5367ccfe9b1SMichel JAOUEN 		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
5377ccfe9b1SMichel JAOUEN 			AB8500_IT_LATCHHIER1_REG + i, &hier_val);
5387ccfe9b1SMichel JAOUEN 		if (status < 0 || hier_val == 0)
5397ccfe9b1SMichel JAOUEN 			continue;
5407ccfe9b1SMichel JAOUEN 
5417ccfe9b1SMichel JAOUEN 		status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val);
5427ccfe9b1SMichel JAOUEN 		if (status < 0)
5437ccfe9b1SMichel JAOUEN 			break;
5447ccfe9b1SMichel JAOUEN 	}
5457ccfe9b1SMichel JAOUEN 	return IRQ_HANDLED;
5467ccfe9b1SMichel JAOUEN }
5477ccfe9b1SMichel JAOUEN 
54806e589efSLee Jones static int ab8500_irq_map(struct irq_domain *d, unsigned int virq,
54906e589efSLee Jones 				irq_hw_number_t hwirq)
55006e589efSLee Jones {
55106e589efSLee Jones 	struct ab8500 *ab8500 = d->host_data;
55206e589efSLee Jones 
55306e589efSLee Jones 	if (!ab8500)
55406e589efSLee Jones 		return -EINVAL;
55506e589efSLee Jones 
55606e589efSLee Jones 	irq_set_chip_data(virq, ab8500);
55706e589efSLee Jones 	irq_set_chip_and_handler(virq, &ab8500_irq_chip,
55806e589efSLee Jones 				handle_simple_irq);
55906e589efSLee Jones 	irq_set_nested_thread(virq, 1);
56006e589efSLee Jones 	irq_set_noprobe(virq);
56162579266SRabin Vincent 
56262579266SRabin Vincent 	return 0;
56362579266SRabin Vincent }
56462579266SRabin Vincent 
5657ce7b26fSKrzysztof Kozlowski static const struct irq_domain_ops ab8500_irq_ops = {
56606e589efSLee Jones 	.map    = ab8500_irq_map,
56706e589efSLee Jones 	.xlate  = irq_domain_xlate_twocell,
56806e589efSLee Jones };
56906e589efSLee Jones 
57006e589efSLee Jones static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np)
57162579266SRabin Vincent {
5722ced445eSLinus Walleij 	int num_irqs;
57362579266SRabin Vincent 
5743e1a498fSLee Jones 	if (is_ab8540(ab8500))
5753e1a498fSLee Jones 		num_irqs = AB8540_NR_IRQS;
5763e1a498fSLee Jones 	else if (is_ab9540(ab8500))
577d6255529SLinus Walleij 		num_irqs = AB9540_NR_IRQS;
578a982362cSBengt Jonsson 	else if (is_ab8505(ab8500))
579a982362cSBengt Jonsson 		num_irqs = AB8505_NR_IRQS;
580d6255529SLinus Walleij 	else
5812ced445eSLinus Walleij 		num_irqs = AB8500_NR_IRQS;
5822ced445eSLinus Walleij 
583f1d11f39SLinus Walleij 	/* If ->irq_base is zero this will give a linear mapping */
5847602e05dSGrygorii Strashko 	ab8500->domain = irq_domain_add_simple(ab8500->dev->of_node,
585f864c46aSLinus Walleij 					       num_irqs, 0,
586f1d11f39SLinus Walleij 					       &ab8500_irq_ops, ab8500);
58706e589efSLee Jones 
58806e589efSLee Jones 	if (!ab8500->domain) {
58906e589efSLee Jones 		dev_err(ab8500->dev, "Failed to create irqdomain\n");
590500e69a1SLee Jones 		return -ENODEV;
59106e589efSLee Jones 	}
59206e589efSLee Jones 
59306e589efSLee Jones 	return 0;
59462579266SRabin Vincent }
59562579266SRabin Vincent 
596112a80d2SJonas Aaberg int ab8500_suspend(struct ab8500 *ab8500)
597112a80d2SJonas Aaberg {
598112a80d2SJonas Aaberg 	if (atomic_read(&ab8500->transfer_ongoing))
599112a80d2SJonas Aaberg 		return -EINVAL;
600f3556302SLee Jones 
601112a80d2SJonas Aaberg 	return 0;
602112a80d2SJonas Aaberg }
603112a80d2SJonas Aaberg 
6045ac98553SGeert Uytterhoeven static const struct mfd_cell ab8500_bm_devs[] = {
605417c0fc2SLinus Walleij 	MFD_CELL_OF("ab8500-charger", NULL, NULL, 0, 0,
606417c0fc2SLinus Walleij 		    "stericsson,ab8500-charger"),
607417c0fc2SLinus Walleij 	MFD_CELL_OF("ab8500-btemp", NULL, NULL, 0, 0,
608417c0fc2SLinus Walleij 		    "stericsson,ab8500-btemp"),
609417c0fc2SLinus Walleij 	MFD_CELL_OF("ab8500-fg", NULL, NULL, 0, 0,
610417c0fc2SLinus Walleij 		    "stericsson,ab8500-fg"),
611417c0fc2SLinus Walleij 	MFD_CELL_OF("ab8500-chargalg", NULL, NULL, 0, 0,
612417c0fc2SLinus Walleij 		    "stericsson,ab8500-chargalg"),
6136ef9418cSRickard Andersson };
6146ef9418cSRickard Andersson 
6155ac98553SGeert Uytterhoeven static const struct mfd_cell ab8500_devs[] = {
6164b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS
617db783e76SLee Jones 	MFD_CELL_OF("ab8500-debug",
618f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-debug"),
6194b106fb9SLee Jones #endif
620db783e76SLee Jones 	MFD_CELL_OF("ab8500-sysctrl",
621f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-sysctrl"),
622db783e76SLee Jones 	MFD_CELL_OF("ab8500-ext-regulator",
623f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-ext-regulator"),
624db783e76SLee Jones 	MFD_CELL_OF("ab8500-regulator",
625f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-regulator"),
626db783e76SLee Jones 	MFD_CELL_OF("ab8500-clk",
627702204c2SLinus Walleij 		    NULL, NULL, 0, 0, "stericsson,ab8500-clk"),
628db783e76SLee Jones 	MFD_CELL_OF("ab8500-gpadc",
629f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-gpadc"),
630db783e76SLee Jones 	MFD_CELL_OF("ab8500-rtc",
631f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-rtc"),
632db783e76SLee Jones 	MFD_CELL_OF("ab8500-acc-det",
633f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-acc-det"),
634db783e76SLee Jones 	MFD_CELL_OF("ab8500-poweron-key",
635f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-poweron-key"),
636db783e76SLee Jones 	MFD_CELL_OF("ab8500-pwm",
637f4d41ad8SLee Jones 		    NULL, NULL, 0, 1, "stericsson,ab8500-pwm"),
638db783e76SLee Jones 	MFD_CELL_OF("ab8500-pwm",
639f4d41ad8SLee Jones 		    NULL, NULL, 0, 2, "stericsson,ab8500-pwm"),
640db783e76SLee Jones 	MFD_CELL_OF("ab8500-pwm",
641f4d41ad8SLee Jones 		    NULL, NULL, 0, 3, "stericsson,ab8500-pwm"),
642db783e76SLee Jones 	MFD_CELL_OF("ab8500-denc",
643f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-denc"),
644db783e76SLee Jones 	MFD_CELL_OF("pinctrl-ab8500",
645f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-gpio"),
646db783e76SLee Jones 	MFD_CELL_OF("abx500-temp",
647f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,abx500-temp"),
648db783e76SLee Jones 	MFD_CELL_OF("ab8500-usb",
649f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-usb"),
650db783e76SLee Jones 	MFD_CELL_OF("ab8500-codec",
651f4d41ad8SLee Jones 		    NULL, NULL, 0, 0, "stericsson,ab8500-codec"),
6524b106fb9SLee Jones };
6534b106fb9SLee Jones 
6545ac98553SGeert Uytterhoeven static const struct mfd_cell ab9540_devs[] = {
6554b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS
6564b106fb9SLee Jones 	{
6574b106fb9SLee Jones 		.name = "ab8500-debug",
6584b106fb9SLee Jones 	},
6594b106fb9SLee Jones #endif
6604b106fb9SLee Jones 	{
6614b106fb9SLee Jones 		.name = "ab8500-sysctrl",
6624b106fb9SLee Jones 	},
6634b106fb9SLee Jones 	{
66453f325beSLee Jones 		.name = "ab8500-ext-regulator",
66553f325beSLee Jones 	},
66653f325beSLee Jones 	{
6674b106fb9SLee Jones 		.name = "ab8500-regulator",
66844f72e53SVirupax Sadashivpetimath 	},
669c0eda9aeSLee Jones 	{
6709ee17676SUlf Hansson 		.name = "abx500-clk",
6719ee17676SUlf Hansson 		.of_compatible = "stericsson,abx500-clk",
6729ee17676SUlf Hansson 	},
6739ee17676SUlf Hansson 	{
674c0eda9aeSLee Jones 		.name = "ab8500-gpadc",
675c0eda9aeSLee Jones 		.of_compatible = "stericsson,ab8500-gpadc",
676c0eda9aeSLee Jones 	},
6774b106fb9SLee Jones 	{
6784b106fb9SLee Jones 		.name = "ab8500-rtc",
6794b106fb9SLee Jones 	},
6804b106fb9SLee Jones 	{
6814b106fb9SLee Jones 		.name = "ab8500-acc-det",
6824b106fb9SLee Jones 	},
6834b106fb9SLee Jones 	{
6844b106fb9SLee Jones 		.name = "ab8500-poweron-key",
6854b106fb9SLee Jones 	},
6864b106fb9SLee Jones 	{
6874b106fb9SLee Jones 		.name = "ab8500-pwm",
6884b106fb9SLee Jones 		.id = 1,
6894b106fb9SLee Jones 	},
6904b106fb9SLee Jones 	{
6914b106fb9SLee Jones 		.name = "abx500-temp",
6924b106fb9SLee Jones 	},
693d6255529SLinus Walleij 	{
694e64d905eSLee Jones 		.name = "pinctrl-ab9540",
695e64d905eSLee Jones 		.of_compatible = "stericsson,ab9540-gpio",
696d6255529SLinus Walleij 	},
697d6255529SLinus Walleij 	{
698d6255529SLinus Walleij 		.name = "ab9540-usb",
699d6255529SLinus Walleij 	},
70044f72e53SVirupax Sadashivpetimath 	{
70144f72e53SVirupax Sadashivpetimath 		.name = "ab9540-codec",
70244f72e53SVirupax Sadashivpetimath 	},
703c0eda9aeSLee Jones 	{
704c0eda9aeSLee Jones 		.name = "ab-iddet",
705c0eda9aeSLee Jones 	},
70644f72e53SVirupax Sadashivpetimath };
70744f72e53SVirupax Sadashivpetimath 
708c0eda9aeSLee Jones /* Device list for ab8505  */
7095ac98553SGeert Uytterhoeven static const struct mfd_cell ab8505_devs[] = {
7104b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS
7114b106fb9SLee Jones 	{
7124b106fb9SLee Jones 		.name = "ab8500-debug",
7131c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-debug",
7144b106fb9SLee Jones 	},
7154b106fb9SLee Jones #endif
7164b106fb9SLee Jones 	{
7174b106fb9SLee Jones 		.name = "ab8500-sysctrl",
7181c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-sysctrl",
7194b106fb9SLee Jones 	},
7204b106fb9SLee Jones 	{
7214b106fb9SLee Jones 		.name = "ab8500-regulator",
7221c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8505-regulator",
7234b106fb9SLee Jones 	},
7244b106fb9SLee Jones 	{
7259ee17676SUlf Hansson 		.name = "abx500-clk",
7261c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-clk",
7279ee17676SUlf Hansson 	},
7289ee17676SUlf Hansson 	{
7294b106fb9SLee Jones 		.name = "ab8500-gpadc",
730955de2eaSLee Jones 		.of_compatible = "stericsson,ab8500-gpadc",
7314b106fb9SLee Jones 	},
7324b106fb9SLee Jones 	{
7334b106fb9SLee Jones 		.name = "ab8500-rtc",
7341c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-rtc",
7354b106fb9SLee Jones 	},
7364b106fb9SLee Jones 	{
7374b106fb9SLee Jones 		.name = "ab8500-acc-det",
7381c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-acc-det",
7394b106fb9SLee Jones 	},
7404b106fb9SLee Jones 	{
7414b106fb9SLee Jones 		.name = "ab8500-poweron-key",
7421c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-poweron-key",
7434b106fb9SLee Jones 	},
7444b106fb9SLee Jones 	{
7454b106fb9SLee Jones 		.name = "ab8500-pwm",
7461c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-pwm",
7474b106fb9SLee Jones 		.id = 1,
7484b106fb9SLee Jones 	},
7494b106fb9SLee Jones 	{
750eb696c31SLee Jones 		.name = "pinctrl-ab8505",
7511c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8505-gpio",
7524b106fb9SLee Jones 	},
7534b106fb9SLee Jones 	{
7544b106fb9SLee Jones 		.name = "ab8500-usb",
7551c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-usb",
7564b106fb9SLee Jones 	},
7574b106fb9SLee Jones 	{
7584b106fb9SLee Jones 		.name = "ab8500-codec",
7591c0769d2SStephan Gerhold 		.of_compatible = "stericsson,ab8500-codec",
7604b106fb9SLee Jones 	},
761c0eda9aeSLee Jones 	{
762c0eda9aeSLee Jones 		.name = "ab-iddet",
763c0eda9aeSLee Jones 	},
764c0eda9aeSLee Jones };
765c0eda9aeSLee Jones 
7665ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_devs[] = {
7674b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS
7684b106fb9SLee Jones 	{
7694b106fb9SLee Jones 		.name = "ab8500-debug",
7704b106fb9SLee Jones 	},
7714b106fb9SLee Jones #endif
7724b106fb9SLee Jones 	{
7734b106fb9SLee Jones 		.name = "ab8500-sysctrl",
7744b106fb9SLee Jones 	},
7754b106fb9SLee Jones 	{
77653f325beSLee Jones 		.name = "ab8500-ext-regulator",
77753f325beSLee Jones 	},
77853f325beSLee Jones 	{
7794b106fb9SLee Jones 		.name = "ab8500-regulator",
7804b106fb9SLee Jones 	},
7814b106fb9SLee Jones 	{
7829ee17676SUlf Hansson 		.name = "abx500-clk",
7839ee17676SUlf Hansson 		.of_compatible = "stericsson,abx500-clk",
7849ee17676SUlf Hansson 	},
7859ee17676SUlf Hansson 	{
7864b106fb9SLee Jones 		.name = "ab8500-gpadc",
787955de2eaSLee Jones 		.of_compatible = "stericsson,ab8500-gpadc",
7884b106fb9SLee Jones 	},
7894b106fb9SLee Jones 	{
7904b106fb9SLee Jones 		.name = "ab8500-acc-det",
7914b106fb9SLee Jones 	},
7924b106fb9SLee Jones 	{
7934b106fb9SLee Jones 		.name = "ab8500-poweron-key",
7944b106fb9SLee Jones 	},
7954b106fb9SLee Jones 	{
7964b106fb9SLee Jones 		.name = "ab8500-pwm",
7974b106fb9SLee Jones 		.id = 1,
7984b106fb9SLee Jones 	},
7994b106fb9SLee Jones 	{
8004b106fb9SLee Jones 		.name = "abx500-temp",
8014b106fb9SLee Jones 	},
802c0eda9aeSLee Jones 	{
803eb696c31SLee Jones 		.name = "pinctrl-ab8540",
804c0eda9aeSLee Jones 	},
805c0eda9aeSLee Jones 	{
806c0eda9aeSLee Jones 		.name = "ab8540-usb",
807c0eda9aeSLee Jones 	},
808c0eda9aeSLee Jones 	{
809c0eda9aeSLee Jones 		.name = "ab8540-codec",
810c0eda9aeSLee Jones 	},
811c0eda9aeSLee Jones 	{
81244f72e53SVirupax Sadashivpetimath 		.name = "ab-iddet",
81344f72e53SVirupax Sadashivpetimath 	},
814d6255529SLinus Walleij };
815d6255529SLinus Walleij 
8165ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_cut1_devs[] = {
8179c717cf3SAlexandre Torgue 	{
8189c717cf3SAlexandre Torgue 		.name = "ab8500-rtc",
8199c717cf3SAlexandre Torgue 		.of_compatible = "stericsson,ab8500-rtc",
8209c717cf3SAlexandre Torgue 	},
8219c717cf3SAlexandre Torgue };
8229c717cf3SAlexandre Torgue 
8235ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_cut2_devs[] = {
8249c717cf3SAlexandre Torgue 	{
8259c717cf3SAlexandre Torgue 		.name = "ab8540-rtc",
8269c717cf3SAlexandre Torgue 		.of_compatible = "stericsson,ab8540-rtc",
8279c717cf3SAlexandre Torgue 	},
8289c717cf3SAlexandre Torgue };
8299c717cf3SAlexandre Torgue 
830*afb349c0SZhen Lei static ssize_t chip_id_show(struct device *dev,
831cca69b67SMattias Wallin 			    struct device_attribute *attr, char *buf)
832cca69b67SMattias Wallin {
833cca69b67SMattias Wallin 	struct ab8500 *ab8500;
834cca69b67SMattias Wallin 
835cca69b67SMattias Wallin 	ab8500 = dev_get_drvdata(dev);
836e436ddffSLee Jones 
837cca69b67SMattias Wallin 	return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
838cca69b67SMattias Wallin }
839cca69b67SMattias Wallin 
840e5c238c3SMattias Wallin /*
841e5c238c3SMattias Wallin  * ab8500 has switched off due to (SWITCH_OFF_STATUS):
842e5c238c3SMattias Wallin  * 0x01 Swoff bit programming
843e5c238c3SMattias Wallin  * 0x02 Thermal protection activation
844e5c238c3SMattias Wallin  * 0x04 Vbat lower then BattOk falling threshold
845e5c238c3SMattias Wallin  * 0x08 Watchdog expired
846e5c238c3SMattias Wallin  * 0x10 Non presence of 32kHz clock
847e5c238c3SMattias Wallin  * 0x20 Battery level lower than power on reset threshold
848e5c238c3SMattias Wallin  * 0x40 Power on key 1 pressed longer than 10 seconds
849e5c238c3SMattias Wallin  * 0x80 DB8500 thermal shutdown
850e5c238c3SMattias Wallin  */
851*afb349c0SZhen Lei static ssize_t switch_off_status_show(struct device *dev,
852e5c238c3SMattias Wallin 				      struct device_attribute *attr, char *buf)
853e5c238c3SMattias Wallin {
854e5c238c3SMattias Wallin 	int ret;
855e5c238c3SMattias Wallin 	u8 value;
856e5c238c3SMattias Wallin 	struct ab8500 *ab8500;
857e5c238c3SMattias Wallin 
858e5c238c3SMattias Wallin 	ab8500 = dev_get_drvdata(dev);
859e5c238c3SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_RTC,
860e5c238c3SMattias Wallin 		AB8500_SWITCH_OFF_STATUS, &value);
861e5c238c3SMattias Wallin 	if (ret < 0)
862e5c238c3SMattias Wallin 		return ret;
863e5c238c3SMattias Wallin 	return sprintf(buf, "%#x\n", value);
864e5c238c3SMattias Wallin }
865e5c238c3SMattias Wallin 
866f04a9d8aSRajkumar Kasirajan /* use mask and set to override the register turn_on_stat value */
867f04a9d8aSRajkumar Kasirajan void ab8500_override_turn_on_stat(u8 mask, u8 set)
868f04a9d8aSRajkumar Kasirajan {
869f04a9d8aSRajkumar Kasirajan 	spin_lock(&on_stat_lock);
870f04a9d8aSRajkumar Kasirajan 	turn_on_stat_mask = mask;
871f04a9d8aSRajkumar Kasirajan 	turn_on_stat_set = set;
872f04a9d8aSRajkumar Kasirajan 	spin_unlock(&on_stat_lock);
873f04a9d8aSRajkumar Kasirajan }
874f04a9d8aSRajkumar Kasirajan 
875b4a31037SAndrew Lynn /*
876b4a31037SAndrew Lynn  * ab8500 has turned on due to (TURN_ON_STATUS):
877b4a31037SAndrew Lynn  * 0x01 PORnVbat
878b4a31037SAndrew Lynn  * 0x02 PonKey1dbF
879b4a31037SAndrew Lynn  * 0x04 PonKey2dbF
880b4a31037SAndrew Lynn  * 0x08 RTCAlarm
881b4a31037SAndrew Lynn  * 0x10 MainChDet
882b4a31037SAndrew Lynn  * 0x20 VbusDet
883b4a31037SAndrew Lynn  * 0x40 UsbIDDetect
884b4a31037SAndrew Lynn  * 0x80 Reserved
885b4a31037SAndrew Lynn  */
886*afb349c0SZhen Lei static ssize_t turn_on_status_show(struct device *dev,
887b4a31037SAndrew Lynn 				   struct device_attribute *attr, char *buf)
888b4a31037SAndrew Lynn {
889b4a31037SAndrew Lynn 	int ret;
890b4a31037SAndrew Lynn 	u8 value;
891b4a31037SAndrew Lynn 	struct ab8500 *ab8500;
892b4a31037SAndrew Lynn 
893b4a31037SAndrew Lynn 	ab8500 = dev_get_drvdata(dev);
894b4a31037SAndrew Lynn 	ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
895b4a31037SAndrew Lynn 		AB8500_TURN_ON_STATUS, &value);
896b4a31037SAndrew Lynn 	if (ret < 0)
897b4a31037SAndrew Lynn 		return ret;
898f04a9d8aSRajkumar Kasirajan 
899f04a9d8aSRajkumar Kasirajan 	/*
900f04a9d8aSRajkumar Kasirajan 	 * In L9540, turn_on_status register is not updated correctly if
901f04a9d8aSRajkumar Kasirajan 	 * the device is rebooted with AC/USB charger connected. Due to
902f04a9d8aSRajkumar Kasirajan 	 * this, the device boots android instead of entering into charge
903f04a9d8aSRajkumar Kasirajan 	 * only mode. Read the AC/USB status register to detect the charger
904f04a9d8aSRajkumar Kasirajan 	 * presence and update the turn on status manually.
905f04a9d8aSRajkumar Kasirajan 	 */
906f04a9d8aSRajkumar Kasirajan 	if (is_ab9540(ab8500)) {
907f04a9d8aSRajkumar Kasirajan 		spin_lock(&on_stat_lock);
908f04a9d8aSRajkumar Kasirajan 		value = (value & turn_on_stat_mask) | turn_on_stat_set;
909f04a9d8aSRajkumar Kasirajan 		spin_unlock(&on_stat_lock);
910f04a9d8aSRajkumar Kasirajan 	}
911f04a9d8aSRajkumar Kasirajan 
912b4a31037SAndrew Lynn 	return sprintf(buf, "%#x\n", value);
913b4a31037SAndrew Lynn }
914b4a31037SAndrew Lynn 
915*afb349c0SZhen Lei static ssize_t turn_on_status_2_show(struct device *dev,
91693ff722eSLee Jones 				     struct device_attribute *attr, char *buf)
91793ff722eSLee Jones {
91893ff722eSLee Jones 	int ret;
91993ff722eSLee Jones 	u8 value;
92093ff722eSLee Jones 	struct ab8500 *ab8500;
92193ff722eSLee Jones 
92293ff722eSLee Jones 	ab8500 = dev_get_drvdata(dev);
92393ff722eSLee Jones 	ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
92493ff722eSLee Jones 		AB8505_TURN_ON_STATUS_2, &value);
92593ff722eSLee Jones 	if (ret < 0)
92693ff722eSLee Jones 		return ret;
92793ff722eSLee Jones 	return sprintf(buf, "%#x\n", (value & 0x1));
92893ff722eSLee Jones }
92993ff722eSLee Jones 
930*afb349c0SZhen Lei static ssize_t dbbrstn_show(struct device *dev,
931d6255529SLinus Walleij 			    struct device_attribute *attr, char *buf)
932d6255529SLinus Walleij {
933d6255529SLinus Walleij 	struct ab8500 *ab8500;
934d6255529SLinus Walleij 	int ret;
935d6255529SLinus Walleij 	u8 value;
936d6255529SLinus Walleij 
937d6255529SLinus Walleij 	ab8500 = dev_get_drvdata(dev);
938d6255529SLinus Walleij 
939d6255529SLinus Walleij 	ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2,
940d6255529SLinus Walleij 		AB9540_MODEM_CTRL2_REG, &value);
941d6255529SLinus Walleij 	if (ret < 0)
942d6255529SLinus Walleij 		return ret;
943d6255529SLinus Walleij 
944d6255529SLinus Walleij 	return sprintf(buf, "%d\n",
945d6255529SLinus Walleij 			(value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0);
946d6255529SLinus Walleij }
947d6255529SLinus Walleij 
948*afb349c0SZhen Lei static ssize_t dbbrstn_store(struct device *dev,
949d6255529SLinus Walleij 	struct device_attribute *attr, const char *buf, size_t count)
950d6255529SLinus Walleij {
951d6255529SLinus Walleij 	struct ab8500 *ab8500;
952d6255529SLinus Walleij 	int ret = count;
953d6255529SLinus Walleij 	int err;
954d6255529SLinus Walleij 	u8 bitvalues;
955d6255529SLinus Walleij 
956d6255529SLinus Walleij 	ab8500 = dev_get_drvdata(dev);
957d6255529SLinus Walleij 
958d6255529SLinus Walleij 	if (count > 0) {
959d6255529SLinus Walleij 		switch (buf[0]) {
960d6255529SLinus Walleij 		case '0':
961d6255529SLinus Walleij 			bitvalues = 0;
962d6255529SLinus Walleij 			break;
963d6255529SLinus Walleij 		case '1':
964d6255529SLinus Walleij 			bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT;
965d6255529SLinus Walleij 			break;
966d6255529SLinus Walleij 		default:
967d6255529SLinus Walleij 			goto exit;
968d6255529SLinus Walleij 		}
969d6255529SLinus Walleij 
970d6255529SLinus Walleij 		err = mask_and_set_register_interruptible(ab8500,
971d6255529SLinus Walleij 			AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG,
972d6255529SLinus Walleij 			AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues);
973d6255529SLinus Walleij 		if (err)
974d6255529SLinus Walleij 			dev_info(ab8500->dev,
975d6255529SLinus Walleij 				"Failed to set DBBRSTN %c, err %#x\n",
976d6255529SLinus Walleij 				buf[0], err);
977d6255529SLinus Walleij 	}
978d6255529SLinus Walleij 
979d6255529SLinus Walleij exit:
980d6255529SLinus Walleij 	return ret;
981d6255529SLinus Walleij }
982d6255529SLinus Walleij 
983*afb349c0SZhen Lei static DEVICE_ATTR_RO(chip_id);
984*afb349c0SZhen Lei static DEVICE_ATTR_RO(switch_off_status);
985*afb349c0SZhen Lei static DEVICE_ATTR_RO(turn_on_status);
986*afb349c0SZhen Lei static DEVICE_ATTR_RO(turn_on_status_2);
987*afb349c0SZhen Lei static DEVICE_ATTR_RW(dbbrstn);
988cca69b67SMattias Wallin 
989cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = {
990cca69b67SMattias Wallin 	&dev_attr_chip_id.attr,
991e5c238c3SMattias Wallin 	&dev_attr_switch_off_status.attr,
992b4a31037SAndrew Lynn 	&dev_attr_turn_on_status.attr,
993cca69b67SMattias Wallin 	NULL,
994cca69b67SMattias Wallin };
995cca69b67SMattias Wallin 
99693ff722eSLee Jones static struct attribute *ab8505_sysfs_entries[] = {
99793ff722eSLee Jones 	&dev_attr_turn_on_status_2.attr,
99893ff722eSLee Jones 	NULL,
99993ff722eSLee Jones };
100093ff722eSLee Jones 
1001d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = {
1002d6255529SLinus Walleij 	&dev_attr_chip_id.attr,
1003d6255529SLinus Walleij 	&dev_attr_switch_off_status.attr,
1004d6255529SLinus Walleij 	&dev_attr_turn_on_status.attr,
1005d6255529SLinus Walleij 	&dev_attr_dbbrstn.attr,
1006d6255529SLinus Walleij 	NULL,
1007d6255529SLinus Walleij };
1008d6255529SLinus Walleij 
100952557dc6SArvind Yadav static const struct attribute_group ab8500_attr_group = {
1010cca69b67SMattias Wallin 	.attrs	= ab8500_sysfs_entries,
1011cca69b67SMattias Wallin };
1012cca69b67SMattias Wallin 
101352557dc6SArvind Yadav static const struct attribute_group ab8505_attr_group = {
101493ff722eSLee Jones 	.attrs	= ab8505_sysfs_entries,
101593ff722eSLee Jones };
101693ff722eSLee Jones 
101752557dc6SArvind Yadav static const struct attribute_group ab9540_attr_group = {
1018d6255529SLinus Walleij 	.attrs	= ab9540_sysfs_entries,
1019d6255529SLinus Walleij };
1020d6255529SLinus Walleij 
1021f791be49SBill Pemberton static int ab8500_probe(struct platform_device *pdev)
102262579266SRabin Vincent {
1023500e69a1SLee Jones 	static const char * const switch_off_status[] = {
1024b04c530cSJonas Aaberg 		"Swoff bit programming",
1025b04c530cSJonas Aaberg 		"Thermal protection activation",
1026b04c530cSJonas Aaberg 		"Vbat lower then BattOk falling threshold",
1027b04c530cSJonas Aaberg 		"Watchdog expired",
1028b04c530cSJonas Aaberg 		"Non presence of 32kHz clock",
1029b04c530cSJonas Aaberg 		"Battery level lower than power on reset threshold",
1030b04c530cSJonas Aaberg 		"Power on key 1 pressed longer than 10 seconds",
1031b04c530cSJonas Aaberg 		"DB8500 thermal shutdown"};
1032500e69a1SLee Jones 	static const char * const turn_on_status[] = {
1033abee26cdSMattias Wallin 		"Battery rising (Vbat)",
1034abee26cdSMattias Wallin 		"Power On Key 1 dbF",
1035abee26cdSMattias Wallin 		"Power On Key 2 dbF",
1036abee26cdSMattias Wallin 		"RTC Alarm",
1037abee26cdSMattias Wallin 		"Main Charger Detect",
1038abee26cdSMattias Wallin 		"Vbus Detect (USB)",
1039abee26cdSMattias Wallin 		"USB ID Detect",
1040abee26cdSMattias Wallin 		"UART Factory Mode Detect"};
1041d28f1db8SLee Jones 	const struct platform_device_id *platid = platform_get_device_id(pdev);
10426bc4a568SLee Jones 	enum ab8500_version version = AB8500_VERSION_UNDEFINED;
10436bc4a568SLee Jones 	struct device_node *np = pdev->dev.of_node;
1044d28f1db8SLee Jones 	struct ab8500 *ab8500;
1045d28f1db8SLee Jones 	struct resource *resource;
104662579266SRabin Vincent 	int ret;
104762579266SRabin Vincent 	int i;
104847c16975SMattias Wallin 	u8 value;
104962579266SRabin Vincent 
10507ccf40b1SLee Jones 	ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL);
1051d28f1db8SLee Jones 	if (!ab8500)
1052d28f1db8SLee Jones 		return -ENOMEM;
1053d28f1db8SLee Jones 
1054d28f1db8SLee Jones 	ab8500->dev = &pdev->dev;
1055d28f1db8SLee Jones 
1056d28f1db8SLee Jones 	resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1057f864c46aSLinus Walleij 	if (!resource) {
1058f864c46aSLinus Walleij 		dev_err(&pdev->dev, "no IRQ resource\n");
10598c4203cbSLee Jones 		return -ENODEV;
1060f864c46aSLinus Walleij 	}
1061d28f1db8SLee Jones 
1062d28f1db8SLee Jones 	ab8500->irq = resource->start;
1063d28f1db8SLee Jones 
1064822672a7SLee Jones 	ab8500->read = ab8500_prcmu_read;
1065822672a7SLee Jones 	ab8500->write = ab8500_prcmu_write;
1066822672a7SLee Jones 	ab8500->write_masked = ab8500_prcmu_write_masked;
1067d28f1db8SLee Jones 
106862579266SRabin Vincent 	mutex_init(&ab8500->lock);
106962579266SRabin Vincent 	mutex_init(&ab8500->irq_lock);
1070112a80d2SJonas Aaberg 	atomic_set(&ab8500->transfer_ongoing, 0);
107162579266SRabin Vincent 
1072d28f1db8SLee Jones 	platform_set_drvdata(pdev, ab8500);
1073d28f1db8SLee Jones 
10746bc4a568SLee Jones 	if (platid)
10756bc4a568SLee Jones 		version = platid->driver_data;
10766bc4a568SLee Jones 
10770f620837SLinus Walleij 	if (version != AB8500_VERSION_UNDEFINED)
10780f620837SLinus Walleij 		ab8500->version = version;
10790f620837SLinus Walleij 	else {
10800f620837SLinus Walleij 		ret = get_register_interruptible(ab8500, AB8500_MISC,
10810f620837SLinus Walleij 			AB8500_IC_NAME_REG, &value);
1082f864c46aSLinus Walleij 		if (ret < 0) {
1083f864c46aSLinus Walleij 			dev_err(&pdev->dev, "could not probe HW\n");
10848c4203cbSLee Jones 			return ret;
1085f864c46aSLinus Walleij 		}
10860f620837SLinus Walleij 
10870f620837SLinus Walleij 		ab8500->version = value;
10880f620837SLinus Walleij 	}
10890f620837SLinus Walleij 
109047c16975SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_MISC,
109147c16975SMattias Wallin 		AB8500_REV_REG, &value);
109262579266SRabin Vincent 	if (ret < 0)
10938c4203cbSLee Jones 		return ret;
109462579266SRabin Vincent 
109547c16975SMattias Wallin 	ab8500->chip_id = value;
109662579266SRabin Vincent 
10970f620837SLinus Walleij 	dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n",
10980f620837SLinus Walleij 			ab8500_version_str[ab8500->version],
10990f620837SLinus Walleij 			ab8500->chip_id >> 4,
11000f620837SLinus Walleij 			ab8500->chip_id & 0x0F);
11010f620837SLinus Walleij 
11023e1a498fSLee Jones 	/* Configure AB8540 */
11033e1a498fSLee Jones 	if (is_ab8540(ab8500)) {
11043e1a498fSLee Jones 		ab8500->mask_size = AB8540_NUM_IRQ_REGS;
11053e1a498fSLee Jones 		ab8500->irq_reg_offset = ab8540_irq_regoffset;
11063e1a498fSLee Jones 		ab8500->it_latchhier_num = AB8540_IT_LATCHHIER_NUM;
11073e1a498fSLee Jones 	} /* Configure AB8500 or AB9540 IRQ */
11083e1a498fSLee Jones 	else if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
1109d6255529SLinus Walleij 		ab8500->mask_size = AB9540_NUM_IRQ_REGS;
1110d6255529SLinus Walleij 		ab8500->irq_reg_offset = ab9540_irq_regoffset;
11113e1a498fSLee Jones 		ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM;
1112d6255529SLinus Walleij 	} else {
11132ced445eSLinus Walleij 		ab8500->mask_size = AB8500_NUM_IRQ_REGS;
11142ced445eSLinus Walleij 		ab8500->irq_reg_offset = ab8500_irq_regoffset;
11153e1a498fSLee Jones 		ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM;
1116d6255529SLinus Walleij 	}
11177ccf40b1SLee Jones 	ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size,
11187ccf40b1SLee Jones 				    GFP_KERNEL);
11192ced445eSLinus Walleij 	if (!ab8500->mask)
11202ced445eSLinus Walleij 		return -ENOMEM;
11217ccf40b1SLee Jones 	ab8500->oldmask = devm_kzalloc(&pdev->dev, ab8500->mask_size,
11227ccf40b1SLee Jones 				       GFP_KERNEL);
11238c4203cbSLee Jones 	if (!ab8500->oldmask)
11248c4203cbSLee Jones 		return -ENOMEM;
11258c4203cbSLee Jones 
1126e5c238c3SMattias Wallin 	/*
1127e5c238c3SMattias Wallin 	 * ab8500 has switched off due to (SWITCH_OFF_STATUS):
1128e5c238c3SMattias Wallin 	 * 0x01 Swoff bit programming
1129e5c238c3SMattias Wallin 	 * 0x02 Thermal protection activation
1130e5c238c3SMattias Wallin 	 * 0x04 Vbat lower then BattOk falling threshold
1131e5c238c3SMattias Wallin 	 * 0x08 Watchdog expired
1132e5c238c3SMattias Wallin 	 * 0x10 Non presence of 32kHz clock
1133e5c238c3SMattias Wallin 	 * 0x20 Battery level lower than power on reset threshold
1134e5c238c3SMattias Wallin 	 * 0x40 Power on key 1 pressed longer than 10 seconds
1135e5c238c3SMattias Wallin 	 * 0x80 DB8500 thermal shutdown
1136e5c238c3SMattias Wallin 	 */
1137e5c238c3SMattias Wallin 
1138e5c238c3SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_RTC,
1139e5c238c3SMattias Wallin 		AB8500_SWITCH_OFF_STATUS, &value);
1140e5c238c3SMattias Wallin 	if (ret < 0)
1141e5c238c3SMattias Wallin 		return ret;
1142b04c530cSJonas Aaberg 	dev_info(ab8500->dev, "switch off cause(s) (%#x): ", value);
1143b04c530cSJonas Aaberg 
1144b04c530cSJonas Aaberg 	if (value) {
1145b04c530cSJonas Aaberg 		for (i = 0; i < ARRAY_SIZE(switch_off_status); i++) {
1146b04c530cSJonas Aaberg 			if (value & 1)
11477ccf40b1SLee Jones 				pr_cont(" \"%s\"", switch_off_status[i]);
1148b04c530cSJonas Aaberg 			value = value >> 1;
1149b04c530cSJonas Aaberg 
1150b04c530cSJonas Aaberg 		}
11517ccf40b1SLee Jones 		pr_cont("\n");
1152b04c530cSJonas Aaberg 	} else {
11537ccf40b1SLee Jones 		pr_cont(" None\n");
1154b04c530cSJonas Aaberg 	}
1155abee26cdSMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
1156abee26cdSMattias Wallin 		AB8500_TURN_ON_STATUS, &value);
1157abee26cdSMattias Wallin 	if (ret < 0)
1158abee26cdSMattias Wallin 		return ret;
1159abee26cdSMattias Wallin 	dev_info(ab8500->dev, "turn on reason(s) (%#x): ", value);
1160abee26cdSMattias Wallin 
1161abee26cdSMattias Wallin 	if (value) {
1162abee26cdSMattias Wallin 		for (i = 0; i < ARRAY_SIZE(turn_on_status); i++) {
1163abee26cdSMattias Wallin 			if (value & 1)
11647ccf40b1SLee Jones 				pr_cont("\"%s\" ", turn_on_status[i]);
1165abee26cdSMattias Wallin 			value = value >> 1;
1166abee26cdSMattias Wallin 		}
11677ccf40b1SLee Jones 		pr_cont("\n");
1168abee26cdSMattias Wallin 	} else {
11697ccf40b1SLee Jones 		pr_cont("None\n");
1170abee26cdSMattias Wallin 	}
1171e5c238c3SMattias Wallin 
1172f04a9d8aSRajkumar Kasirajan 	if (is_ab9540(ab8500)) {
1173f04a9d8aSRajkumar Kasirajan 		ret = get_register_interruptible(ab8500, AB8500_CHARGER,
1174f04a9d8aSRajkumar Kasirajan 			AB8500_CH_USBCH_STAT1_REG, &value);
1175f04a9d8aSRajkumar Kasirajan 		if (ret < 0)
1176f04a9d8aSRajkumar Kasirajan 			return ret;
1177f04a9d8aSRajkumar Kasirajan 		if ((value & VBUS_DET_DBNC1) && (value & VBUS_DET_DBNC100))
1178f04a9d8aSRajkumar Kasirajan 			ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON,
1179f04a9d8aSRajkumar Kasirajan 						     AB8500_VBUS_DET);
1180f04a9d8aSRajkumar Kasirajan 	}
118162579266SRabin Vincent 
118262579266SRabin Vincent 	/* Clear and mask all interrupts */
11832ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++) {
11840f620837SLinus Walleij 		/*
11850f620837SLinus Walleij 		 * Interrupt register 12 doesn't exist prior to AB8500 version
11860f620837SLinus Walleij 		 * 2.0
11870f620837SLinus Walleij 		 */
11880f620837SLinus Walleij 		if (ab8500->irq_reg_offset[i] == 11 &&
11890f620837SLinus Walleij 				is_ab8500_1p1_or_earlier(ab8500))
119092d50a41SMattias Wallin 			continue;
119162579266SRabin Vincent 
11923e1a498fSLee Jones 		if (ab8500->irq_reg_offset[i] < 0)
11933e1a498fSLee Jones 			continue;
11943e1a498fSLee Jones 
119547c16975SMattias Wallin 		get_register_interruptible(ab8500, AB8500_INTERRUPT,
11962ced445eSLinus Walleij 			AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
119792d50a41SMattias Wallin 			&value);
119847c16975SMattias Wallin 		set_register_interruptible(ab8500, AB8500_INTERRUPT,
11992ced445eSLinus Walleij 			AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff);
120062579266SRabin Vincent 	}
120162579266SRabin Vincent 
120247c16975SMattias Wallin 	ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
120347c16975SMattias Wallin 	if (ret)
12048c4203cbSLee Jones 		return ret;
120547c16975SMattias Wallin 
12062ced445eSLinus Walleij 	for (i = 0; i < ab8500->mask_size; i++)
120762579266SRabin Vincent 		ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
120862579266SRabin Vincent 
120906e589efSLee Jones 	ret = ab8500_irq_init(ab8500, np);
121062579266SRabin Vincent 	if (ret)
12118c4203cbSLee Jones 		return ret;
121262579266SRabin Vincent 
12138c4203cbSLee Jones 	ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL,
12147ccfe9b1SMichel JAOUEN 			ab8500_hierarchical_irq,
12157ccfe9b1SMichel JAOUEN 			IRQF_ONESHOT | IRQF_NO_SUSPEND,
12167ccfe9b1SMichel JAOUEN 			"ab8500", ab8500);
121762579266SRabin Vincent 	if (ret)
12188c4203cbSLee Jones 		return ret;
121962579266SRabin Vincent 
1220d6255529SLinus Walleij 	if (is_ab9540(ab8500))
1221d6255529SLinus Walleij 		ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
1222d6255529SLinus Walleij 				ARRAY_SIZE(ab9540_devs), NULL,
1223f864c46aSLinus Walleij 				0, ab8500->domain);
12249c717cf3SAlexandre Torgue 	else if (is_ab8540(ab8500)) {
1225c0eda9aeSLee Jones 		ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs,
1226c0eda9aeSLee Jones 			      ARRAY_SIZE(ab8540_devs), NULL,
1227f864c46aSLinus Walleij 			      0, ab8500->domain);
12289c717cf3SAlexandre Torgue 		if (ret)
12299c717cf3SAlexandre Torgue 			return ret;
12309c717cf3SAlexandre Torgue 
12319c717cf3SAlexandre Torgue 		if (is_ab8540_1p2_or_earlier(ab8500))
12329c717cf3SAlexandre Torgue 			ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut1_devs,
12339c717cf3SAlexandre Torgue 			      ARRAY_SIZE(ab8540_cut1_devs), NULL,
1234f864c46aSLinus Walleij 			      0, ab8500->domain);
12359c717cf3SAlexandre Torgue 		else /* ab8540 >= cut2 */
12369c717cf3SAlexandre Torgue 			ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut2_devs,
12379c717cf3SAlexandre Torgue 			      ARRAY_SIZE(ab8540_cut2_devs), NULL,
1238f864c46aSLinus Walleij 			      0, ab8500->domain);
12399c717cf3SAlexandre Torgue 	} else if (is_ab8505(ab8500))
1240c0eda9aeSLee Jones 		ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs,
1241c0eda9aeSLee Jones 			      ARRAY_SIZE(ab8505_devs), NULL,
1242f864c46aSLinus Walleij 			      0, ab8500->domain);
1243d6255529SLinus Walleij 	else
1244549931f9SSundar R Iyer 		ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
124544f72e53SVirupax Sadashivpetimath 				ARRAY_SIZE(ab8500_devs), NULL,
1246f864c46aSLinus Walleij 				0, ab8500->domain);
12476bc4a568SLee Jones 	if (ret)
12488c4203cbSLee Jones 		return ret;
124944f72e53SVirupax Sadashivpetimath 
12506ef9418cSRickard Andersson 	/* Add battery management devices */
12516ef9418cSRickard Andersson 	ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
12526ef9418cSRickard Andersson 			      ARRAY_SIZE(ab8500_bm_devs), NULL,
1253f864c46aSLinus Walleij 			      0, ab8500->domain);
12546ef9418cSRickard Andersson 	if (ret)
12556ef9418cSRickard Andersson 		dev_err(ab8500->dev, "error adding bm devices\n");
12566ef9418cSRickard Andersson 
1257e436ddffSLee Jones 	if (((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
1258e436ddffSLee Jones 			ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500))
1259d6255529SLinus Walleij 		ret = sysfs_create_group(&ab8500->dev->kobj,
1260d6255529SLinus Walleij 					&ab9540_attr_group);
1261d6255529SLinus Walleij 	else
1262d6255529SLinus Walleij 		ret = sysfs_create_group(&ab8500->dev->kobj,
1263d6255529SLinus Walleij 					&ab8500_attr_group);
126493ff722eSLee Jones 
126593ff722eSLee Jones 	if ((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
126693ff722eSLee Jones 			ab8500->chip_id >= AB8500_CUT2P0)
126793ff722eSLee Jones 		ret = sysfs_create_group(&ab8500->dev->kobj,
126893ff722eSLee Jones 					 &ab8505_attr_group);
126993ff722eSLee Jones 
1270cca69b67SMattias Wallin 	if (ret)
1271cca69b67SMattias Wallin 		dev_err(ab8500->dev, "error creating sysfs entries\n");
127206e589efSLee Jones 
127362579266SRabin Vincent 	return ret;
127462579266SRabin Vincent }
127562579266SRabin Vincent 
1276d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = {
1277d28f1db8SLee Jones 	{ "ab8500-core", AB8500_VERSION_AB8500 },
12781c0769d2SStephan Gerhold 	{ "ab8505-core", AB8500_VERSION_AB8505 },
1279d28f1db8SLee Jones 	{ "ab9540-i2c", AB8500_VERSION_AB9540 },
1280d28f1db8SLee Jones 	{ "ab8540-i2c", AB8500_VERSION_AB8540 },
1281d28f1db8SLee Jones 	{ }
1282d28f1db8SLee Jones };
1283d28f1db8SLee Jones 
1284d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = {
1285d28f1db8SLee Jones 	.driver = {
1286d28f1db8SLee Jones 		.name = "ab8500-core",
128731cbae22SPaul Gortmaker 		.suppress_bind_attrs = true,
1288d28f1db8SLee Jones 	},
1289d28f1db8SLee Jones 	.probe	= ab8500_probe,
1290d28f1db8SLee Jones 	.id_table = ab8500_id,
1291d28f1db8SLee Jones };
1292d28f1db8SLee Jones 
1293d28f1db8SLee Jones static int __init ab8500_core_init(void)
1294d28f1db8SLee Jones {
1295d28f1db8SLee Jones 	return platform_driver_register(&ab8500_core_driver);
1296d28f1db8SLee Jones }
1297ba7cbc3eSLee Jones core_initcall(ab8500_core_init);
1298