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>
2462579266SRabin Vincent
2562579266SRabin Vincent /*
2662579266SRabin Vincent * Interrupt register offsets
2762579266SRabin Vincent * Bank : 0x0E
2862579266SRabin Vincent */
2947c16975SMattias Wallin #define AB8500_IT_SOURCE1_REG 0x00
3047c16975SMattias Wallin #define AB8500_IT_SOURCE2_REG 0x01
3147c16975SMattias Wallin #define AB8500_IT_SOURCE3_REG 0x02
3247c16975SMattias Wallin #define AB8500_IT_SOURCE4_REG 0x03
3347c16975SMattias Wallin #define AB8500_IT_SOURCE5_REG 0x04
3447c16975SMattias Wallin #define AB8500_IT_SOURCE6_REG 0x05
3547c16975SMattias Wallin #define AB8500_IT_SOURCE7_REG 0x06
3647c16975SMattias Wallin #define AB8500_IT_SOURCE8_REG 0x07
37d6255529SLinus Walleij #define AB9540_IT_SOURCE13_REG 0x0C
3847c16975SMattias Wallin #define AB8500_IT_SOURCE19_REG 0x12
3947c16975SMattias Wallin #define AB8500_IT_SOURCE20_REG 0x13
4047c16975SMattias Wallin #define AB8500_IT_SOURCE21_REG 0x14
4147c16975SMattias Wallin #define AB8500_IT_SOURCE22_REG 0x15
4247c16975SMattias Wallin #define AB8500_IT_SOURCE23_REG 0x16
4347c16975SMattias Wallin #define AB8500_IT_SOURCE24_REG 0x17
4462579266SRabin Vincent
4562579266SRabin Vincent /*
4662579266SRabin Vincent * latch registers
4762579266SRabin Vincent */
4847c16975SMattias Wallin #define AB8500_IT_LATCH1_REG 0x20
4947c16975SMattias Wallin #define AB8500_IT_LATCH2_REG 0x21
5047c16975SMattias Wallin #define AB8500_IT_LATCH3_REG 0x22
5147c16975SMattias Wallin #define AB8500_IT_LATCH4_REG 0x23
5247c16975SMattias Wallin #define AB8500_IT_LATCH5_REG 0x24
5347c16975SMattias Wallin #define AB8500_IT_LATCH6_REG 0x25
5447c16975SMattias Wallin #define AB8500_IT_LATCH7_REG 0x26
5547c16975SMattias Wallin #define AB8500_IT_LATCH8_REG 0x27
5647c16975SMattias Wallin #define AB8500_IT_LATCH9_REG 0x28
5747c16975SMattias Wallin #define AB8500_IT_LATCH10_REG 0x29
5892d50a41SMattias Wallin #define AB8500_IT_LATCH12_REG 0x2B
59d6255529SLinus Walleij #define AB9540_IT_LATCH13_REG 0x2C
6047c16975SMattias Wallin #define AB8500_IT_LATCH19_REG 0x32
6147c16975SMattias Wallin #define AB8500_IT_LATCH20_REG 0x33
6247c16975SMattias Wallin #define AB8500_IT_LATCH21_REG 0x34
6347c16975SMattias Wallin #define AB8500_IT_LATCH22_REG 0x35
6447c16975SMattias Wallin #define AB8500_IT_LATCH23_REG 0x36
6547c16975SMattias Wallin #define AB8500_IT_LATCH24_REG 0x37
6662579266SRabin Vincent
6762579266SRabin Vincent /*
6862579266SRabin Vincent * mask registers
6962579266SRabin Vincent */
7062579266SRabin Vincent
7147c16975SMattias Wallin #define AB8500_IT_MASK1_REG 0x40
7247c16975SMattias Wallin #define AB8500_IT_MASK2_REG 0x41
7347c16975SMattias Wallin #define AB8500_IT_MASK3_REG 0x42
7447c16975SMattias Wallin #define AB8500_IT_MASK4_REG 0x43
7547c16975SMattias Wallin #define AB8500_IT_MASK5_REG 0x44
7647c16975SMattias Wallin #define AB8500_IT_MASK6_REG 0x45
7747c16975SMattias Wallin #define AB8500_IT_MASK7_REG 0x46
7847c16975SMattias Wallin #define AB8500_IT_MASK8_REG 0x47
7947c16975SMattias Wallin #define AB8500_IT_MASK9_REG 0x48
8047c16975SMattias Wallin #define AB8500_IT_MASK10_REG 0x49
8147c16975SMattias Wallin #define AB8500_IT_MASK11_REG 0x4A
8247c16975SMattias Wallin #define AB8500_IT_MASK12_REG 0x4B
8347c16975SMattias Wallin #define AB8500_IT_MASK13_REG 0x4C
8447c16975SMattias Wallin #define AB8500_IT_MASK14_REG 0x4D
8547c16975SMattias Wallin #define AB8500_IT_MASK15_REG 0x4E
8647c16975SMattias Wallin #define AB8500_IT_MASK16_REG 0x4F
8747c16975SMattias Wallin #define AB8500_IT_MASK17_REG 0x50
8847c16975SMattias Wallin #define AB8500_IT_MASK18_REG 0x51
8947c16975SMattias Wallin #define AB8500_IT_MASK19_REG 0x52
9047c16975SMattias Wallin #define AB8500_IT_MASK20_REG 0x53
9147c16975SMattias Wallin #define AB8500_IT_MASK21_REG 0x54
9247c16975SMattias Wallin #define AB8500_IT_MASK22_REG 0x55
9347c16975SMattias Wallin #define AB8500_IT_MASK23_REG 0x56
9447c16975SMattias Wallin #define AB8500_IT_MASK24_REG 0x57
95a29264b6SLee Jones #define AB8500_IT_MASK25_REG 0x58
9662579266SRabin Vincent
977ccfe9b1SMichel JAOUEN /*
987ccfe9b1SMichel JAOUEN * latch hierarchy registers
997ccfe9b1SMichel JAOUEN */
1007ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER1_REG 0x60
1017ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER2_REG 0x61
1027ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER3_REG 0x62
1033e1a498fSLee Jones #define AB8540_IT_LATCHHIER4_REG 0x63
1047ccfe9b1SMichel JAOUEN
1057ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER_NUM 3
1063e1a498fSLee Jones #define AB8540_IT_LATCHHIER_NUM 4
1077ccfe9b1SMichel JAOUEN
10847c16975SMattias Wallin #define AB8500_REV_REG 0x80
1090f620837SLinus Walleij #define AB8500_IC_NAME_REG 0x82
110e5c238c3SMattias Wallin #define AB8500_SWITCH_OFF_STATUS 0x00
11162579266SRabin Vincent
112b4a31037SAndrew Lynn #define AB8500_TURN_ON_STATUS 0x00
11393ff722eSLee Jones #define AB8505_TURN_ON_STATUS_2 0x04
114b4a31037SAndrew Lynn
115f04a9d8aSRajkumar Kasirajan #define AB8500_CH_USBCH_STAT1_REG 0x02
116f04a9d8aSRajkumar Kasirajan #define VBUS_DET_DBNC100 0x02
117f04a9d8aSRajkumar Kasirajan #define VBUS_DET_DBNC1 0x01
118f04a9d8aSRajkumar Kasirajan
119f04a9d8aSRajkumar Kasirajan static DEFINE_SPINLOCK(on_stat_lock);
120f04a9d8aSRajkumar Kasirajan static u8 turn_on_stat_mask = 0xFF;
121f04a9d8aSRajkumar Kasirajan static u8 turn_on_stat_set;
1226ef9418cSRickard Andersson
123d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_REG 0x23
124d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2)
125d6255529SLinus Walleij
12662579266SRabin Vincent /*
12762579266SRabin Vincent * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
1282ced445eSLinus Walleij * numbers are indexed into this array with (num / 8). The interupts are
1292ced445eSLinus Walleij * defined in linux/mfd/ab8500.h
13062579266SRabin Vincent *
13162579266SRabin Vincent * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
13262579266SRabin Vincent * offset 0.
13362579266SRabin Vincent */
1342ced445eSLinus Walleij /* AB8500 support */
13562579266SRabin Vincent static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
13692d50a41SMattias Wallin 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
13762579266SRabin Vincent };
13862579266SRabin Vincent
139a29264b6SLee Jones /* AB9540 / AB8505 support */
140d6255529SLinus Walleij static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
141a29264b6SLee Jones 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23
142d6255529SLinus Walleij };
143d6255529SLinus Walleij
1443e1a498fSLee Jones /* AB8540 support */
1453e1a498fSLee Jones static const int ab8540_irq_regoffset[AB8540_NUM_IRQ_REGS] = {
1467ccf40b1SLee Jones 0, 1, 2, 3, 4, -1, -1, -1, -1, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22,
1477ccf40b1SLee Jones 23, 25, 26, 27, 28, 29, 30, 31,
1483e1a498fSLee Jones };
1493e1a498fSLee Jones
1500f620837SLinus Walleij static const char ab8500_version_str[][7] = {
1510f620837SLinus Walleij [AB8500_VERSION_AB8500] = "AB8500",
1520f620837SLinus Walleij [AB8500_VERSION_AB8505] = "AB8505",
1530f620837SLinus Walleij [AB8500_VERSION_AB9540] = "AB9540",
1540f620837SLinus Walleij [AB8500_VERSION_AB8540] = "AB8540",
1550f620837SLinus Walleij };
1560f620837SLinus Walleij
ab8500_prcmu_write(struct ab8500 * ab8500,u16 addr,u8 data)157822672a7SLee Jones static int ab8500_prcmu_write(struct ab8500 *ab8500, u16 addr, u8 data)
158d28f1db8SLee Jones {
159d28f1db8SLee Jones int ret;
160d28f1db8SLee Jones
161d28f1db8SLee Jones ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
162d28f1db8SLee Jones if (ret < 0)
163d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
164d28f1db8SLee Jones return ret;
165d28f1db8SLee Jones }
166d28f1db8SLee Jones
ab8500_prcmu_write_masked(struct ab8500 * ab8500,u16 addr,u8 mask,u8 data)167822672a7SLee Jones static int ab8500_prcmu_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
168d28f1db8SLee Jones u8 data)
169d28f1db8SLee Jones {
170d28f1db8SLee Jones int ret;
171d28f1db8SLee Jones
172d28f1db8SLee Jones ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data,
173d28f1db8SLee Jones &mask, 1);
174d28f1db8SLee Jones if (ret < 0)
175d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
176d28f1db8SLee Jones return ret;
177d28f1db8SLee Jones }
178d28f1db8SLee Jones
ab8500_prcmu_read(struct ab8500 * ab8500,u16 addr)179822672a7SLee Jones static int ab8500_prcmu_read(struct ab8500 *ab8500, u16 addr)
180d28f1db8SLee Jones {
181d28f1db8SLee Jones int ret;
182d28f1db8SLee Jones u8 data;
183d28f1db8SLee Jones
184d28f1db8SLee Jones ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
185d28f1db8SLee Jones if (ret < 0) {
186d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
187d28f1db8SLee Jones return ret;
188d28f1db8SLee Jones }
189d28f1db8SLee Jones return (int)data;
190d28f1db8SLee Jones }
191d28f1db8SLee Jones
ab8500_get_chip_id(struct device * dev)19247c16975SMattias Wallin static int ab8500_get_chip_id(struct device *dev)
19347c16975SMattias Wallin {
1946bce7bf1SMattias Wallin struct ab8500 *ab8500;
1956bce7bf1SMattias Wallin
1966bce7bf1SMattias Wallin if (!dev)
1976bce7bf1SMattias Wallin return -EINVAL;
1986bce7bf1SMattias Wallin ab8500 = dev_get_drvdata(dev->parent);
1996bce7bf1SMattias Wallin return ab8500 ? (int)ab8500->chip_id : -EINVAL;
20047c16975SMattias Wallin }
20147c16975SMattias Wallin
set_register_interruptible(struct ab8500 * ab8500,u8 bank,u8 reg,u8 data)20247c16975SMattias Wallin static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
20347c16975SMattias Wallin u8 reg, u8 data)
20462579266SRabin Vincent {
20562579266SRabin Vincent int ret;
20647c16975SMattias Wallin /*
20747c16975SMattias Wallin * Put the u8 bank and u8 register together into a an u16.
20847c16975SMattias Wallin * The bank on higher 8 bits and register in lower 8 bits.
209500e69a1SLee Jones */
21047c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg;
21162579266SRabin Vincent
21262579266SRabin Vincent dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
21362579266SRabin Vincent
214392cbd1eSRabin Vincent mutex_lock(&ab8500->lock);
21547c16975SMattias Wallin
21647c16975SMattias Wallin ret = ab8500->write(ab8500, addr, data);
21747c16975SMattias Wallin if (ret < 0)
21847c16975SMattias Wallin dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
21947c16975SMattias Wallin addr, ret);
22047c16975SMattias Wallin mutex_unlock(&ab8500->lock);
22147c16975SMattias Wallin
22247c16975SMattias Wallin return ret;
22347c16975SMattias Wallin }
22447c16975SMattias Wallin
ab8500_set_register(struct device * dev,u8 bank,u8 reg,u8 value)22547c16975SMattias Wallin static int ab8500_set_register(struct device *dev, u8 bank,
22647c16975SMattias Wallin u8 reg, u8 value)
22747c16975SMattias Wallin {
228112a80d2SJonas Aaberg int ret;
22947c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
23047c16975SMattias Wallin
231112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing);
232112a80d2SJonas Aaberg ret = set_register_interruptible(ab8500, bank, reg, value);
233112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing);
234112a80d2SJonas Aaberg return ret;
23547c16975SMattias Wallin }
23647c16975SMattias Wallin
get_register_interruptible(struct ab8500 * ab8500,u8 bank,u8 reg,u8 * value)23747c16975SMattias Wallin static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
23847c16975SMattias Wallin u8 reg, u8 *value)
23947c16975SMattias Wallin {
24047c16975SMattias Wallin int ret;
24147c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg;
24247c16975SMattias Wallin
243392cbd1eSRabin Vincent mutex_lock(&ab8500->lock);
24447c16975SMattias Wallin
24547c16975SMattias Wallin ret = ab8500->read(ab8500, addr);
24647c16975SMattias Wallin if (ret < 0)
24747c16975SMattias Wallin dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
24847c16975SMattias Wallin addr, ret);
24947c16975SMattias Wallin else
25047c16975SMattias Wallin *value = ret;
25147c16975SMattias Wallin
25247c16975SMattias Wallin mutex_unlock(&ab8500->lock);
25347c16975SMattias Wallin dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret);
25447c16975SMattias Wallin
25510628e3eSDan Carpenter return (ret < 0) ? ret : 0;
25647c16975SMattias Wallin }
25747c16975SMattias Wallin
ab8500_get_register(struct device * dev,u8 bank,u8 reg,u8 * value)25847c16975SMattias Wallin static int ab8500_get_register(struct device *dev, u8 bank,
25947c16975SMattias Wallin u8 reg, u8 *value)
26047c16975SMattias Wallin {
261112a80d2SJonas Aaberg int ret;
26247c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
26347c16975SMattias Wallin
264112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing);
265112a80d2SJonas Aaberg ret = get_register_interruptible(ab8500, bank, reg, value);
266112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing);
267112a80d2SJonas Aaberg return ret;
26847c16975SMattias Wallin }
26947c16975SMattias Wallin
mask_and_set_register_interruptible(struct ab8500 * ab8500,u8 bank,u8 reg,u8 bitmask,u8 bitvalues)27047c16975SMattias Wallin static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
27147c16975SMattias Wallin u8 reg, u8 bitmask, u8 bitvalues)
27247c16975SMattias Wallin {
27347c16975SMattias Wallin int ret;
27447c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg;
27547c16975SMattias Wallin
276392cbd1eSRabin Vincent mutex_lock(&ab8500->lock);
27747c16975SMattias Wallin
278bc628fd1SMattias Nilsson if (ab8500->write_masked == NULL) {
279bc628fd1SMattias Nilsson u8 data;
280bc628fd1SMattias Nilsson
28147c16975SMattias Wallin ret = ab8500->read(ab8500, addr);
28247c16975SMattias Wallin if (ret < 0) {
28347c16975SMattias Wallin dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
28447c16975SMattias Wallin addr, ret);
28547c16975SMattias Wallin goto out;
28647c16975SMattias Wallin }
28747c16975SMattias Wallin
28847c16975SMattias Wallin data = (u8)ret;
28947c16975SMattias Wallin data = (~bitmask & data) | (bitmask & bitvalues);
29047c16975SMattias Wallin
29162579266SRabin Vincent ret = ab8500->write(ab8500, addr, data);
29262579266SRabin Vincent if (ret < 0)
29362579266SRabin Vincent dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
29462579266SRabin Vincent addr, ret);
29562579266SRabin Vincent
296bc628fd1SMattias Nilsson dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr,
297bc628fd1SMattias Nilsson data);
298bc628fd1SMattias Nilsson goto out;
299bc628fd1SMattias Nilsson }
300bc628fd1SMattias Nilsson ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues);
301bc628fd1SMattias Nilsson if (ret < 0)
302bc628fd1SMattias Nilsson dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr,
303bc628fd1SMattias Nilsson ret);
30462579266SRabin Vincent out:
30562579266SRabin Vincent mutex_unlock(&ab8500->lock);
30662579266SRabin Vincent return ret;
30762579266SRabin Vincent }
30847c16975SMattias Wallin
ab8500_mask_and_set_register(struct device * dev,u8 bank,u8 reg,u8 bitmask,u8 bitvalues)30947c16975SMattias Wallin static int ab8500_mask_and_set_register(struct device *dev,
31047c16975SMattias Wallin u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
31147c16975SMattias Wallin {
312112a80d2SJonas Aaberg int ret;
31347c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
31447c16975SMattias Wallin
315112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing);
316112a80d2SJonas Aaberg ret = mask_and_set_register_interruptible(ab8500, bank, reg,
31747c16975SMattias Wallin bitmask, bitvalues);
318112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing);
319112a80d2SJonas Aaberg return ret;
32047c16975SMattias Wallin }
32147c16975SMattias Wallin
32247c16975SMattias Wallin static struct abx500_ops ab8500_ops = {
32347c16975SMattias Wallin .get_chip_id = ab8500_get_chip_id,
32447c16975SMattias Wallin .get_register = ab8500_get_register,
32547c16975SMattias Wallin .set_register = ab8500_set_register,
32647c16975SMattias Wallin .get_register_page = NULL,
32747c16975SMattias Wallin .set_register_page = NULL,
32847c16975SMattias Wallin .mask_and_set_register = ab8500_mask_and_set_register,
32947c16975SMattias Wallin .event_registers_startup_state_get = NULL,
33047c16975SMattias Wallin .startup_irq_enabled = NULL,
3311d843a6cSMian Yousaf Kaukab .dump_all_banks = ab8500_dump_all_banks,
33247c16975SMattias Wallin };
33362579266SRabin Vincent
ab8500_irq_lock(struct irq_data * data)3349505a0a0SMark Brown static void ab8500_irq_lock(struct irq_data *data)
33562579266SRabin Vincent {
3369505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
33762579266SRabin Vincent
33862579266SRabin Vincent mutex_lock(&ab8500->irq_lock);
339112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing);
34062579266SRabin Vincent }
34162579266SRabin Vincent
ab8500_irq_sync_unlock(struct irq_data * data)3429505a0a0SMark Brown static void ab8500_irq_sync_unlock(struct irq_data *data)
34362579266SRabin Vincent {
3449505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
34562579266SRabin Vincent int i;
34662579266SRabin Vincent
3472ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) {
34862579266SRabin Vincent u8 old = ab8500->oldmask[i];
34962579266SRabin Vincent u8 new = ab8500->mask[i];
35062579266SRabin Vincent int reg;
35162579266SRabin Vincent
35262579266SRabin Vincent if (new == old)
35362579266SRabin Vincent continue;
35462579266SRabin Vincent
3550f620837SLinus Walleij /*
3560f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version
3570f620837SLinus Walleij * 2.0
3580f620837SLinus Walleij */
3590f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 &&
3600f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500))
36192d50a41SMattias Wallin continue;
36292d50a41SMattias Wallin
3633e1a498fSLee Jones if (ab8500->irq_reg_offset[i] < 0)
3643e1a498fSLee Jones continue;
3653e1a498fSLee Jones
36662579266SRabin Vincent ab8500->oldmask[i] = new;
36762579266SRabin Vincent
3682ced445eSLinus Walleij reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
36947c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
37062579266SRabin Vincent }
371112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing);
37262579266SRabin Vincent mutex_unlock(&ab8500->irq_lock);
37362579266SRabin Vincent }
37462579266SRabin Vincent
ab8500_irq_mask(struct irq_data * data)3759505a0a0SMark Brown static void ab8500_irq_mask(struct irq_data *data)
37662579266SRabin Vincent {
3779505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
37806e589efSLee Jones int offset = data->hwirq;
37962579266SRabin Vincent int index = offset / 8;
38062579266SRabin Vincent int mask = 1 << (offset % 8);
38162579266SRabin Vincent
38262579266SRabin Vincent ab8500->mask[index] |= mask;
3839c677b9bSLee Jones
3849c677b9bSLee Jones /* The AB8500 GPIOs have two interrupts each (rising & falling). */
3859c677b9bSLee Jones if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
3869c677b9bSLee Jones ab8500->mask[index + 2] |= mask;
3879c677b9bSLee Jones if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R)
3889c677b9bSLee Jones ab8500->mask[index + 1] |= mask;
3899c677b9bSLee Jones if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R)
390e2ddf46aSLinus Walleij /* Here the falling IRQ is one bit lower */
391e2ddf46aSLinus Walleij ab8500->mask[index] |= (mask << 1);
39262579266SRabin Vincent }
39362579266SRabin Vincent
ab8500_irq_unmask(struct irq_data * data)3949505a0a0SMark Brown static void ab8500_irq_unmask(struct irq_data *data)
39562579266SRabin Vincent {
3969505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
3979c677b9bSLee Jones unsigned int type = irqd_get_trigger_type(data);
39806e589efSLee Jones int offset = data->hwirq;
39962579266SRabin Vincent int index = offset / 8;
40062579266SRabin Vincent int mask = 1 << (offset % 8);
40162579266SRabin Vincent
4029c677b9bSLee Jones if (type & IRQ_TYPE_EDGE_RISING)
40362579266SRabin Vincent ab8500->mask[index] &= ~mask;
4049c677b9bSLee Jones
4059c677b9bSLee Jones /* The AB8500 GPIOs have two interrupts each (rising & falling). */
4069c677b9bSLee Jones if (type & IRQ_TYPE_EDGE_FALLING) {
4079c677b9bSLee Jones if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
4089c677b9bSLee Jones ab8500->mask[index + 2] &= ~mask;
4097ccf40b1SLee Jones else if (offset >= AB9540_INT_GPIO50R &&
4107ccf40b1SLee Jones offset <= AB9540_INT_GPIO54R)
4119c677b9bSLee Jones ab8500->mask[index + 1] &= ~mask;
4127ccf40b1SLee Jones else if (offset == AB8540_INT_GPIO43R ||
4137ccf40b1SLee Jones offset == AB8540_INT_GPIO44R)
414e2ddf46aSLinus Walleij /* Here the falling IRQ is one bit lower */
415e2ddf46aSLinus Walleij ab8500->mask[index] &= ~(mask << 1);
4169c677b9bSLee Jones else
4179c677b9bSLee Jones ab8500->mask[index] &= ~mask;
418e2ddf46aSLinus Walleij } else {
4199c677b9bSLee Jones /* Satisfies the case where type is not set. */
42062579266SRabin Vincent ab8500->mask[index] &= ~mask;
42162579266SRabin Vincent }
422e2ddf46aSLinus Walleij }
42362579266SRabin Vincent
ab8500_irq_set_type(struct irq_data * data,unsigned int type)42440f6e5a2SLee Jones static int ab8500_irq_set_type(struct irq_data *data, unsigned int type)
42540f6e5a2SLee Jones {
42640f6e5a2SLee Jones return 0;
42762579266SRabin Vincent }
42862579266SRabin Vincent
42962579266SRabin Vincent static struct irq_chip ab8500_irq_chip = {
43062579266SRabin Vincent .name = "ab8500",
4319505a0a0SMark Brown .irq_bus_lock = ab8500_irq_lock,
4329505a0a0SMark Brown .irq_bus_sync_unlock = ab8500_irq_sync_unlock,
4339505a0a0SMark Brown .irq_mask = ab8500_irq_mask,
434e6f9306eSVirupax Sadashivpetimath .irq_disable = ab8500_irq_mask,
4359505a0a0SMark Brown .irq_unmask = ab8500_irq_unmask,
43640f6e5a2SLee Jones .irq_set_type = ab8500_irq_set_type,
43762579266SRabin Vincent };
43862579266SRabin Vincent
update_latch_offset(u8 * offset,int i)4393e1a498fSLee Jones static void update_latch_offset(u8 *offset, int i)
4403e1a498fSLee Jones {
4413e1a498fSLee Jones /* Fix inconsistent ITFromLatch25 bit mapping... */
4423e1a498fSLee Jones if (unlikely(*offset == 17))
4433e1a498fSLee Jones *offset = 24;
4443e1a498fSLee Jones /* Fix inconsistent ab8540 bit mapping... */
4453e1a498fSLee Jones if (unlikely(*offset == 16))
4463e1a498fSLee Jones *offset = 25;
4473e1a498fSLee Jones if ((i == 3) && (*offset >= 24))
4483e1a498fSLee Jones *offset += 2;
4493e1a498fSLee Jones }
4503e1a498fSLee Jones
ab8500_handle_hierarchical_line(struct ab8500 * ab8500,int latch_offset,u8 latch_val)4517ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
4527ccfe9b1SMichel JAOUEN int latch_offset, u8 latch_val)
4537ccfe9b1SMichel JAOUEN {
4547a93fb37SFabio Baltieri int int_bit, line, i;
4557ccfe9b1SMichel JAOUEN
4567ccfe9b1SMichel JAOUEN for (i = 0; i < ab8500->mask_size; i++)
4577ccfe9b1SMichel JAOUEN if (ab8500->irq_reg_offset[i] == latch_offset)
4587ccfe9b1SMichel JAOUEN break;
4597ccfe9b1SMichel JAOUEN
4607ccfe9b1SMichel JAOUEN if (i >= ab8500->mask_size) {
4617ccfe9b1SMichel JAOUEN dev_err(ab8500->dev, "Register offset 0x%2x not declared\n",
4627ccfe9b1SMichel JAOUEN latch_offset);
4637ccfe9b1SMichel JAOUEN return -ENXIO;
4647ccfe9b1SMichel JAOUEN }
4657ccfe9b1SMichel JAOUEN
4667a93fb37SFabio Baltieri /* ignore masked out interrupts */
4677a93fb37SFabio Baltieri latch_val &= ~ab8500->mask[i];
4687a93fb37SFabio Baltieri
4697a93fb37SFabio Baltieri while (latch_val) {
4707a93fb37SFabio Baltieri int_bit = __ffs(latch_val);
4717ccfe9b1SMichel JAOUEN line = (i << 3) + int_bit;
4727ccfe9b1SMichel JAOUEN latch_val &= ~(1 << int_bit);
4737ccfe9b1SMichel JAOUEN
474e2ddf46aSLinus Walleij /*
475e2ddf46aSLinus Walleij * This handles the falling edge hwirqs from the GPIO
476e2ddf46aSLinus Walleij * lines. Route them back to the line registered for the
477e2ddf46aSLinus Walleij * rising IRQ, as this is merely a flag for the same IRQ
478e2ddf46aSLinus Walleij * in linux terms.
479e2ddf46aSLinus Walleij */
480e2ddf46aSLinus Walleij if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F)
481e2ddf46aSLinus Walleij line -= 16;
482e2ddf46aSLinus Walleij if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F)
483e2ddf46aSLinus Walleij line -= 8;
484e2ddf46aSLinus Walleij if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F)
485e2ddf46aSLinus Walleij line += 1;
486e2ddf46aSLinus Walleij
4879ff80e2dSMarc Zyngier handle_nested_irq(irq_find_mapping(ab8500->domain, line));
4887a93fb37SFabio Baltieri }
4897ccfe9b1SMichel JAOUEN
4907ccfe9b1SMichel JAOUEN return 0;
4917ccfe9b1SMichel JAOUEN }
4927ccfe9b1SMichel JAOUEN
ab8500_handle_hierarchical_latch(struct ab8500 * ab8500,int hier_offset,u8 hier_val)4937ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500,
4947ccfe9b1SMichel JAOUEN int hier_offset, u8 hier_val)
4957ccfe9b1SMichel JAOUEN {
4967ccfe9b1SMichel JAOUEN int latch_bit, status;
4977ccfe9b1SMichel JAOUEN u8 latch_offset, latch_val;
4987ccfe9b1SMichel JAOUEN
4997ccfe9b1SMichel JAOUEN do {
5007ccfe9b1SMichel JAOUEN latch_bit = __ffs(hier_val);
5017ccfe9b1SMichel JAOUEN latch_offset = (hier_offset << 3) + latch_bit;
5027ccfe9b1SMichel JAOUEN
5033e1a498fSLee Jones update_latch_offset(&latch_offset, hier_offset);
5047ccfe9b1SMichel JAOUEN
5057ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500,
5067ccfe9b1SMichel JAOUEN AB8500_INTERRUPT,
5077ccfe9b1SMichel JAOUEN AB8500_IT_LATCH1_REG + latch_offset,
5087ccfe9b1SMichel JAOUEN &latch_val);
5097ccfe9b1SMichel JAOUEN if (status < 0 || latch_val == 0)
5107ccfe9b1SMichel JAOUEN goto discard;
5117ccfe9b1SMichel JAOUEN
5127ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_line(ab8500,
5137ccfe9b1SMichel JAOUEN latch_offset, latch_val);
5147ccfe9b1SMichel JAOUEN if (status < 0)
5157ccfe9b1SMichel JAOUEN return status;
5167ccfe9b1SMichel JAOUEN discard:
5177ccfe9b1SMichel JAOUEN hier_val &= ~(1 << latch_bit);
5187ccfe9b1SMichel JAOUEN } while (hier_val);
5197ccfe9b1SMichel JAOUEN
5207ccfe9b1SMichel JAOUEN return 0;
5217ccfe9b1SMichel JAOUEN }
5227ccfe9b1SMichel JAOUEN
ab8500_hierarchical_irq(int irq,void * dev)5237ccfe9b1SMichel JAOUEN static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev)
5247ccfe9b1SMichel JAOUEN {
5257ccfe9b1SMichel JAOUEN struct ab8500 *ab8500 = dev;
5267ccfe9b1SMichel JAOUEN u8 i;
5277ccfe9b1SMichel JAOUEN
5287ccfe9b1SMichel JAOUEN dev_vdbg(ab8500->dev, "interrupt\n");
5297ccfe9b1SMichel JAOUEN
5307ccfe9b1SMichel JAOUEN /* Hierarchical interrupt version */
5313e1a498fSLee Jones for (i = 0; i < (ab8500->it_latchhier_num); i++) {
5327ccfe9b1SMichel JAOUEN int status;
5337ccfe9b1SMichel JAOUEN u8 hier_val;
5347ccfe9b1SMichel JAOUEN
5357ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
5367ccfe9b1SMichel JAOUEN AB8500_IT_LATCHHIER1_REG + i, &hier_val);
5377ccfe9b1SMichel JAOUEN if (status < 0 || hier_val == 0)
5387ccfe9b1SMichel JAOUEN continue;
5397ccfe9b1SMichel JAOUEN
5407ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val);
5417ccfe9b1SMichel JAOUEN if (status < 0)
5427ccfe9b1SMichel JAOUEN break;
5437ccfe9b1SMichel JAOUEN }
5447ccfe9b1SMichel JAOUEN return IRQ_HANDLED;
5457ccfe9b1SMichel JAOUEN }
5467ccfe9b1SMichel JAOUEN
ab8500_irq_map(struct irq_domain * d,unsigned int virq,irq_hw_number_t hwirq)54706e589efSLee Jones static int ab8500_irq_map(struct irq_domain *d, unsigned int virq,
54806e589efSLee Jones irq_hw_number_t hwirq)
54906e589efSLee Jones {
55006e589efSLee Jones struct ab8500 *ab8500 = d->host_data;
55106e589efSLee Jones
55206e589efSLee Jones if (!ab8500)
55306e589efSLee Jones return -EINVAL;
55406e589efSLee Jones
55506e589efSLee Jones irq_set_chip_data(virq, ab8500);
55606e589efSLee Jones irq_set_chip_and_handler(virq, &ab8500_irq_chip,
55706e589efSLee Jones handle_simple_irq);
55806e589efSLee Jones irq_set_nested_thread(virq, 1);
55906e589efSLee Jones irq_set_noprobe(virq);
56062579266SRabin Vincent
56162579266SRabin Vincent return 0;
56262579266SRabin Vincent }
56362579266SRabin Vincent
5647ce7b26fSKrzysztof Kozlowski static const struct irq_domain_ops ab8500_irq_ops = {
56506e589efSLee Jones .map = ab8500_irq_map,
56606e589efSLee Jones .xlate = irq_domain_xlate_twocell,
56706e589efSLee Jones };
56806e589efSLee Jones
ab8500_irq_init(struct ab8500 * ab8500,struct device_node * np)56906e589efSLee Jones static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np)
57062579266SRabin Vincent {
5712ced445eSLinus Walleij int num_irqs;
57262579266SRabin Vincent
5733e1a498fSLee Jones if (is_ab8540(ab8500))
5743e1a498fSLee Jones num_irqs = AB8540_NR_IRQS;
5753e1a498fSLee Jones else if (is_ab9540(ab8500))
576d6255529SLinus Walleij num_irqs = AB9540_NR_IRQS;
577a982362cSBengt Jonsson else if (is_ab8505(ab8500))
578a982362cSBengt Jonsson num_irqs = AB8505_NR_IRQS;
579d6255529SLinus Walleij else
5802ced445eSLinus Walleij num_irqs = AB8500_NR_IRQS;
5812ced445eSLinus Walleij
582f1d11f39SLinus Walleij /* If ->irq_base is zero this will give a linear mapping */
5837602e05dSGrygorii Strashko ab8500->domain = irq_domain_add_simple(ab8500->dev->of_node,
584f864c46aSLinus Walleij num_irqs, 0,
585f1d11f39SLinus Walleij &ab8500_irq_ops, ab8500);
58606e589efSLee Jones
58706e589efSLee Jones if (!ab8500->domain) {
58806e589efSLee Jones dev_err(ab8500->dev, "Failed to create irqdomain\n");
589500e69a1SLee Jones return -ENODEV;
59006e589efSLee Jones }
59106e589efSLee Jones
59206e589efSLee Jones return 0;
59362579266SRabin Vincent }
59462579266SRabin Vincent
ab8500_suspend(struct ab8500 * ab8500)595112a80d2SJonas Aaberg int ab8500_suspend(struct ab8500 *ab8500)
596112a80d2SJonas Aaberg {
597112a80d2SJonas Aaberg if (atomic_read(&ab8500->transfer_ongoing))
598112a80d2SJonas Aaberg return -EINVAL;
599f3556302SLee Jones
600112a80d2SJonas Aaberg return 0;
601112a80d2SJonas Aaberg }
602112a80d2SJonas Aaberg
6035ac98553SGeert Uytterhoeven static const struct mfd_cell ab8500_bm_devs[] = {
604417c0fc2SLinus Walleij MFD_CELL_OF("ab8500-charger", NULL, NULL, 0, 0,
605417c0fc2SLinus Walleij "stericsson,ab8500-charger"),
606417c0fc2SLinus Walleij MFD_CELL_OF("ab8500-btemp", NULL, NULL, 0, 0,
607417c0fc2SLinus Walleij "stericsson,ab8500-btemp"),
608417c0fc2SLinus Walleij MFD_CELL_OF("ab8500-fg", NULL, NULL, 0, 0,
609417c0fc2SLinus Walleij "stericsson,ab8500-fg"),
610417c0fc2SLinus Walleij MFD_CELL_OF("ab8500-chargalg", NULL, NULL, 0, 0,
611417c0fc2SLinus Walleij "stericsson,ab8500-chargalg"),
6126ef9418cSRickard Andersson };
6136ef9418cSRickard Andersson
6145ac98553SGeert Uytterhoeven static const struct mfd_cell ab8500_devs[] = {
615db783e76SLee Jones MFD_CELL_OF("ab8500-sysctrl",
616f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-sysctrl"),
617db783e76SLee Jones MFD_CELL_OF("ab8500-ext-regulator",
618f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-ext-regulator"),
619db783e76SLee Jones MFD_CELL_OF("ab8500-regulator",
620f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-regulator"),
621db783e76SLee Jones MFD_CELL_OF("ab8500-clk",
622702204c2SLinus Walleij NULL, NULL, 0, 0, "stericsson,ab8500-clk"),
623db783e76SLee Jones MFD_CELL_OF("ab8500-gpadc",
624f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-gpadc"),
625db783e76SLee Jones MFD_CELL_OF("ab8500-rtc",
626f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-rtc"),
627db783e76SLee Jones MFD_CELL_OF("ab8500-acc-det",
628f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-acc-det"),
629db783e76SLee Jones MFD_CELL_OF("ab8500-poweron-key",
630f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-poweron-key"),
631db783e76SLee Jones MFD_CELL_OF("ab8500-pwm",
632f4d41ad8SLee Jones NULL, NULL, 0, 1, "stericsson,ab8500-pwm"),
633db783e76SLee Jones MFD_CELL_OF("ab8500-pwm",
634f4d41ad8SLee Jones NULL, NULL, 0, 2, "stericsson,ab8500-pwm"),
635db783e76SLee Jones MFD_CELL_OF("ab8500-pwm",
636f4d41ad8SLee Jones NULL, NULL, 0, 3, "stericsson,ab8500-pwm"),
637db783e76SLee Jones MFD_CELL_OF("ab8500-denc",
638f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-denc"),
639db783e76SLee Jones MFD_CELL_OF("pinctrl-ab8500",
640f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-gpio"),
641db783e76SLee Jones MFD_CELL_OF("abx500-temp",
642f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,abx500-temp"),
643db783e76SLee Jones MFD_CELL_OF("ab8500-usb",
644f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-usb"),
645db783e76SLee Jones MFD_CELL_OF("ab8500-codec",
646f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-codec"),
6474b106fb9SLee Jones };
6484b106fb9SLee Jones
6495ac98553SGeert Uytterhoeven static const struct mfd_cell ab9540_devs[] = {
6504b106fb9SLee Jones {
6514b106fb9SLee Jones .name = "ab8500-sysctrl",
6524b106fb9SLee Jones },
6534b106fb9SLee Jones {
65453f325beSLee Jones .name = "ab8500-ext-regulator",
65553f325beSLee Jones },
65653f325beSLee Jones {
6574b106fb9SLee Jones .name = "ab8500-regulator",
65844f72e53SVirupax Sadashivpetimath },
659c0eda9aeSLee Jones {
6609ee17676SUlf Hansson .name = "abx500-clk",
6619ee17676SUlf Hansson .of_compatible = "stericsson,abx500-clk",
6629ee17676SUlf Hansson },
6639ee17676SUlf Hansson {
664c0eda9aeSLee Jones .name = "ab8500-gpadc",
665c0eda9aeSLee Jones .of_compatible = "stericsson,ab8500-gpadc",
666c0eda9aeSLee Jones },
6674b106fb9SLee Jones {
6684b106fb9SLee Jones .name = "ab8500-rtc",
6694b106fb9SLee Jones },
6704b106fb9SLee Jones {
6714b106fb9SLee Jones .name = "ab8500-acc-det",
6724b106fb9SLee Jones },
6734b106fb9SLee Jones {
6744b106fb9SLee Jones .name = "ab8500-poweron-key",
6754b106fb9SLee Jones },
6764b106fb9SLee Jones {
6774b106fb9SLee Jones .name = "ab8500-pwm",
6784b106fb9SLee Jones .id = 1,
6794b106fb9SLee Jones },
6804b106fb9SLee Jones {
6814b106fb9SLee Jones .name = "abx500-temp",
6824b106fb9SLee Jones },
683d6255529SLinus Walleij {
684e64d905eSLee Jones .name = "pinctrl-ab9540",
685e64d905eSLee Jones .of_compatible = "stericsson,ab9540-gpio",
686d6255529SLinus Walleij },
687d6255529SLinus Walleij {
688d6255529SLinus Walleij .name = "ab9540-usb",
689d6255529SLinus Walleij },
69044f72e53SVirupax Sadashivpetimath {
69144f72e53SVirupax Sadashivpetimath .name = "ab9540-codec",
69244f72e53SVirupax Sadashivpetimath },
693c0eda9aeSLee Jones {
694c0eda9aeSLee Jones .name = "ab-iddet",
695c0eda9aeSLee Jones },
69644f72e53SVirupax Sadashivpetimath };
69744f72e53SVirupax Sadashivpetimath
698c0eda9aeSLee Jones /* Device list for ab8505 */
6995ac98553SGeert Uytterhoeven static const struct mfd_cell ab8505_devs[] = {
7004b106fb9SLee Jones {
7014b106fb9SLee Jones .name = "ab8500-sysctrl",
7021c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-sysctrl",
7034b106fb9SLee Jones },
7044b106fb9SLee Jones {
7054b106fb9SLee Jones .name = "ab8500-regulator",
7061c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8505-regulator",
7074b106fb9SLee Jones },
7084b106fb9SLee Jones {
7099ee17676SUlf Hansson .name = "abx500-clk",
7101c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-clk",
7119ee17676SUlf Hansson },
7129ee17676SUlf Hansson {
7134b106fb9SLee Jones .name = "ab8500-gpadc",
714955de2eaSLee Jones .of_compatible = "stericsson,ab8500-gpadc",
7154b106fb9SLee Jones },
7164b106fb9SLee Jones {
7174b106fb9SLee Jones .name = "ab8500-rtc",
7181c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-rtc",
7194b106fb9SLee Jones },
7204b106fb9SLee Jones {
7214b106fb9SLee Jones .name = "ab8500-acc-det",
7221c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-acc-det",
7234b106fb9SLee Jones },
7244b106fb9SLee Jones {
7254b106fb9SLee Jones .name = "ab8500-poweron-key",
7261c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-poweron-key",
7274b106fb9SLee Jones },
7284b106fb9SLee Jones {
7294b106fb9SLee Jones .name = "ab8500-pwm",
7301c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-pwm",
7314b106fb9SLee Jones .id = 1,
7324b106fb9SLee Jones },
7334b106fb9SLee Jones {
734eb696c31SLee Jones .name = "pinctrl-ab8505",
7351c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8505-gpio",
7364b106fb9SLee Jones },
7374b106fb9SLee Jones {
7384b106fb9SLee Jones .name = "ab8500-usb",
7391c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-usb",
7404b106fb9SLee Jones },
7414b106fb9SLee Jones {
7424b106fb9SLee Jones .name = "ab8500-codec",
7431c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-codec",
7444b106fb9SLee Jones },
745c0eda9aeSLee Jones {
746c0eda9aeSLee Jones .name = "ab-iddet",
747c0eda9aeSLee Jones },
748c0eda9aeSLee Jones };
749c0eda9aeSLee Jones
7505ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_devs[] = {
7514b106fb9SLee Jones {
7524b106fb9SLee Jones .name = "ab8500-sysctrl",
7534b106fb9SLee Jones },
7544b106fb9SLee Jones {
75553f325beSLee Jones .name = "ab8500-ext-regulator",
75653f325beSLee Jones },
75753f325beSLee Jones {
7584b106fb9SLee Jones .name = "ab8500-regulator",
7594b106fb9SLee Jones },
7604b106fb9SLee Jones {
7619ee17676SUlf Hansson .name = "abx500-clk",
7629ee17676SUlf Hansson .of_compatible = "stericsson,abx500-clk",
7639ee17676SUlf Hansson },
7649ee17676SUlf Hansson {
7654b106fb9SLee Jones .name = "ab8500-gpadc",
766955de2eaSLee Jones .of_compatible = "stericsson,ab8500-gpadc",
7674b106fb9SLee Jones },
7684b106fb9SLee Jones {
7694b106fb9SLee Jones .name = "ab8500-acc-det",
7704b106fb9SLee Jones },
7714b106fb9SLee Jones {
7724b106fb9SLee Jones .name = "ab8500-poweron-key",
7734b106fb9SLee Jones },
7744b106fb9SLee Jones {
7754b106fb9SLee Jones .name = "ab8500-pwm",
7764b106fb9SLee Jones .id = 1,
7774b106fb9SLee Jones },
7784b106fb9SLee Jones {
7794b106fb9SLee Jones .name = "abx500-temp",
7804b106fb9SLee Jones },
781c0eda9aeSLee Jones {
782eb696c31SLee Jones .name = "pinctrl-ab8540",
783c0eda9aeSLee Jones },
784c0eda9aeSLee Jones {
785c0eda9aeSLee Jones .name = "ab8540-usb",
786c0eda9aeSLee Jones },
787c0eda9aeSLee Jones {
788c0eda9aeSLee Jones .name = "ab8540-codec",
789c0eda9aeSLee Jones },
790c0eda9aeSLee Jones {
79144f72e53SVirupax Sadashivpetimath .name = "ab-iddet",
79244f72e53SVirupax Sadashivpetimath },
793d6255529SLinus Walleij };
794d6255529SLinus Walleij
7955ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_cut1_devs[] = {
7969c717cf3SAlexandre Torgue {
7979c717cf3SAlexandre Torgue .name = "ab8500-rtc",
7989c717cf3SAlexandre Torgue .of_compatible = "stericsson,ab8500-rtc",
7999c717cf3SAlexandre Torgue },
8009c717cf3SAlexandre Torgue };
8019c717cf3SAlexandre Torgue
8025ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_cut2_devs[] = {
8039c717cf3SAlexandre Torgue {
8049c717cf3SAlexandre Torgue .name = "ab8540-rtc",
8059c717cf3SAlexandre Torgue .of_compatible = "stericsson,ab8540-rtc",
8069c717cf3SAlexandre Torgue },
8079c717cf3SAlexandre Torgue };
8089c717cf3SAlexandre Torgue
chip_id_show(struct device * dev,struct device_attribute * attr,char * buf)809afb349c0SZhen Lei static ssize_t chip_id_show(struct device *dev,
810cca69b67SMattias Wallin struct device_attribute *attr, char *buf)
811cca69b67SMattias Wallin {
812cca69b67SMattias Wallin struct ab8500 *ab8500;
813cca69b67SMattias Wallin
814cca69b67SMattias Wallin ab8500 = dev_get_drvdata(dev);
815e436ddffSLee Jones
816cca69b67SMattias Wallin return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
817cca69b67SMattias Wallin }
818cca69b67SMattias Wallin
819e5c238c3SMattias Wallin /*
820e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS):
821e5c238c3SMattias Wallin * 0x01 Swoff bit programming
822e5c238c3SMattias Wallin * 0x02 Thermal protection activation
823e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold
824e5c238c3SMattias Wallin * 0x08 Watchdog expired
825e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock
826e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold
827e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds
828e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown
829e5c238c3SMattias Wallin */
switch_off_status_show(struct device * dev,struct device_attribute * attr,char * buf)830afb349c0SZhen Lei static ssize_t switch_off_status_show(struct device *dev,
831e5c238c3SMattias Wallin struct device_attribute *attr, char *buf)
832e5c238c3SMattias Wallin {
833e5c238c3SMattias Wallin int ret;
834e5c238c3SMattias Wallin u8 value;
835e5c238c3SMattias Wallin struct ab8500 *ab8500;
836e5c238c3SMattias Wallin
837e5c238c3SMattias Wallin ab8500 = dev_get_drvdata(dev);
838e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC,
839e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value);
840e5c238c3SMattias Wallin if (ret < 0)
841e5c238c3SMattias Wallin return ret;
842e5c238c3SMattias Wallin return sprintf(buf, "%#x\n", value);
843e5c238c3SMattias Wallin }
844e5c238c3SMattias Wallin
845f04a9d8aSRajkumar Kasirajan /* use mask and set to override the register turn_on_stat value */
ab8500_override_turn_on_stat(u8 mask,u8 set)846f04a9d8aSRajkumar Kasirajan void ab8500_override_turn_on_stat(u8 mask, u8 set)
847f04a9d8aSRajkumar Kasirajan {
848f04a9d8aSRajkumar Kasirajan spin_lock(&on_stat_lock);
849f04a9d8aSRajkumar Kasirajan turn_on_stat_mask = mask;
850f04a9d8aSRajkumar Kasirajan turn_on_stat_set = set;
851f04a9d8aSRajkumar Kasirajan spin_unlock(&on_stat_lock);
852f04a9d8aSRajkumar Kasirajan }
853f04a9d8aSRajkumar Kasirajan
854b4a31037SAndrew Lynn /*
855b4a31037SAndrew Lynn * ab8500 has turned on due to (TURN_ON_STATUS):
856b4a31037SAndrew Lynn * 0x01 PORnVbat
857b4a31037SAndrew Lynn * 0x02 PonKey1dbF
858b4a31037SAndrew Lynn * 0x04 PonKey2dbF
859b4a31037SAndrew Lynn * 0x08 RTCAlarm
860b4a31037SAndrew Lynn * 0x10 MainChDet
861b4a31037SAndrew Lynn * 0x20 VbusDet
862b4a31037SAndrew Lynn * 0x40 UsbIDDetect
863b4a31037SAndrew Lynn * 0x80 Reserved
864b4a31037SAndrew Lynn */
turn_on_status_show(struct device * dev,struct device_attribute * attr,char * buf)865afb349c0SZhen Lei static ssize_t turn_on_status_show(struct device *dev,
866b4a31037SAndrew Lynn struct device_attribute *attr, char *buf)
867b4a31037SAndrew Lynn {
868b4a31037SAndrew Lynn int ret;
869b4a31037SAndrew Lynn u8 value;
870b4a31037SAndrew Lynn struct ab8500 *ab8500;
871b4a31037SAndrew Lynn
872b4a31037SAndrew Lynn ab8500 = dev_get_drvdata(dev);
873b4a31037SAndrew Lynn ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
874b4a31037SAndrew Lynn AB8500_TURN_ON_STATUS, &value);
875b4a31037SAndrew Lynn if (ret < 0)
876b4a31037SAndrew Lynn return ret;
877f04a9d8aSRajkumar Kasirajan
878f04a9d8aSRajkumar Kasirajan /*
879f04a9d8aSRajkumar Kasirajan * In L9540, turn_on_status register is not updated correctly if
880f04a9d8aSRajkumar Kasirajan * the device is rebooted with AC/USB charger connected. Due to
881f04a9d8aSRajkumar Kasirajan * this, the device boots android instead of entering into charge
882f04a9d8aSRajkumar Kasirajan * only mode. Read the AC/USB status register to detect the charger
883f04a9d8aSRajkumar Kasirajan * presence and update the turn on status manually.
884f04a9d8aSRajkumar Kasirajan */
885f04a9d8aSRajkumar Kasirajan if (is_ab9540(ab8500)) {
886f04a9d8aSRajkumar Kasirajan spin_lock(&on_stat_lock);
887f04a9d8aSRajkumar Kasirajan value = (value & turn_on_stat_mask) | turn_on_stat_set;
888f04a9d8aSRajkumar Kasirajan spin_unlock(&on_stat_lock);
889f04a9d8aSRajkumar Kasirajan }
890f04a9d8aSRajkumar Kasirajan
891b4a31037SAndrew Lynn return sprintf(buf, "%#x\n", value);
892b4a31037SAndrew Lynn }
893b4a31037SAndrew Lynn
turn_on_status_2_show(struct device * dev,struct device_attribute * attr,char * buf)894afb349c0SZhen Lei static ssize_t turn_on_status_2_show(struct device *dev,
89593ff722eSLee Jones struct device_attribute *attr, char *buf)
89693ff722eSLee Jones {
89793ff722eSLee Jones int ret;
89893ff722eSLee Jones u8 value;
89993ff722eSLee Jones struct ab8500 *ab8500;
90093ff722eSLee Jones
90193ff722eSLee Jones ab8500 = dev_get_drvdata(dev);
90293ff722eSLee Jones ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
90393ff722eSLee Jones AB8505_TURN_ON_STATUS_2, &value);
90493ff722eSLee Jones if (ret < 0)
90593ff722eSLee Jones return ret;
90693ff722eSLee Jones return sprintf(buf, "%#x\n", (value & 0x1));
90793ff722eSLee Jones }
90893ff722eSLee Jones
dbbrstn_show(struct device * dev,struct device_attribute * attr,char * buf)909afb349c0SZhen Lei static ssize_t dbbrstn_show(struct device *dev,
910d6255529SLinus Walleij struct device_attribute *attr, char *buf)
911d6255529SLinus Walleij {
912d6255529SLinus Walleij struct ab8500 *ab8500;
913d6255529SLinus Walleij int ret;
914d6255529SLinus Walleij u8 value;
915d6255529SLinus Walleij
916d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev);
917d6255529SLinus Walleij
918d6255529SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2,
919d6255529SLinus Walleij AB9540_MODEM_CTRL2_REG, &value);
920d6255529SLinus Walleij if (ret < 0)
921d6255529SLinus Walleij return ret;
922d6255529SLinus Walleij
923d6255529SLinus Walleij return sprintf(buf, "%d\n",
924d6255529SLinus Walleij (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0);
925d6255529SLinus Walleij }
926d6255529SLinus Walleij
dbbrstn_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)927afb349c0SZhen Lei static ssize_t dbbrstn_store(struct device *dev,
928d6255529SLinus Walleij struct device_attribute *attr, const char *buf, size_t count)
929d6255529SLinus Walleij {
930d6255529SLinus Walleij struct ab8500 *ab8500;
931d6255529SLinus Walleij int ret = count;
932d6255529SLinus Walleij int err;
933d6255529SLinus Walleij u8 bitvalues;
934d6255529SLinus Walleij
935d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev);
936d6255529SLinus Walleij
937d6255529SLinus Walleij if (count > 0) {
938d6255529SLinus Walleij switch (buf[0]) {
939d6255529SLinus Walleij case '0':
940d6255529SLinus Walleij bitvalues = 0;
941d6255529SLinus Walleij break;
942d6255529SLinus Walleij case '1':
943d6255529SLinus Walleij bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT;
944d6255529SLinus Walleij break;
945d6255529SLinus Walleij default:
946d6255529SLinus Walleij goto exit;
947d6255529SLinus Walleij }
948d6255529SLinus Walleij
949d6255529SLinus Walleij err = mask_and_set_register_interruptible(ab8500,
950d6255529SLinus Walleij AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG,
951d6255529SLinus Walleij AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues);
952d6255529SLinus Walleij if (err)
953d6255529SLinus Walleij dev_info(ab8500->dev,
954d6255529SLinus Walleij "Failed to set DBBRSTN %c, err %#x\n",
955d6255529SLinus Walleij buf[0], err);
956d6255529SLinus Walleij }
957d6255529SLinus Walleij
958d6255529SLinus Walleij exit:
959d6255529SLinus Walleij return ret;
960d6255529SLinus Walleij }
961d6255529SLinus Walleij
962afb349c0SZhen Lei static DEVICE_ATTR_RO(chip_id);
963afb349c0SZhen Lei static DEVICE_ATTR_RO(switch_off_status);
964afb349c0SZhen Lei static DEVICE_ATTR_RO(turn_on_status);
965afb349c0SZhen Lei static DEVICE_ATTR_RO(turn_on_status_2);
966afb349c0SZhen Lei static DEVICE_ATTR_RW(dbbrstn);
967cca69b67SMattias Wallin
968cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = {
969cca69b67SMattias Wallin &dev_attr_chip_id.attr,
970e5c238c3SMattias Wallin &dev_attr_switch_off_status.attr,
971b4a31037SAndrew Lynn &dev_attr_turn_on_status.attr,
972cca69b67SMattias Wallin NULL,
973cca69b67SMattias Wallin };
974cca69b67SMattias Wallin
97593ff722eSLee Jones static struct attribute *ab8505_sysfs_entries[] = {
97693ff722eSLee Jones &dev_attr_turn_on_status_2.attr,
97793ff722eSLee Jones NULL,
97893ff722eSLee Jones };
97993ff722eSLee Jones
980d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = {
981d6255529SLinus Walleij &dev_attr_chip_id.attr,
982d6255529SLinus Walleij &dev_attr_switch_off_status.attr,
983d6255529SLinus Walleij &dev_attr_turn_on_status.attr,
984d6255529SLinus Walleij &dev_attr_dbbrstn.attr,
985d6255529SLinus Walleij NULL,
986d6255529SLinus Walleij };
987d6255529SLinus Walleij
98852557dc6SArvind Yadav static const struct attribute_group ab8500_attr_group = {
989cca69b67SMattias Wallin .attrs = ab8500_sysfs_entries,
990cca69b67SMattias Wallin };
991cca69b67SMattias Wallin
99252557dc6SArvind Yadav static const struct attribute_group ab8505_attr_group = {
99393ff722eSLee Jones .attrs = ab8505_sysfs_entries,
99493ff722eSLee Jones };
99593ff722eSLee Jones
99652557dc6SArvind Yadav static const struct attribute_group ab9540_attr_group = {
997d6255529SLinus Walleij .attrs = ab9540_sysfs_entries,
998d6255529SLinus Walleij };
999d6255529SLinus Walleij
ab8500_probe(struct platform_device * pdev)1000f791be49SBill Pemberton static int ab8500_probe(struct platform_device *pdev)
100162579266SRabin Vincent {
1002500e69a1SLee Jones static const char * const switch_off_status[] = {
1003b04c530cSJonas Aaberg "Swoff bit programming",
1004b04c530cSJonas Aaberg "Thermal protection activation",
1005b04c530cSJonas Aaberg "Vbat lower then BattOk falling threshold",
1006b04c530cSJonas Aaberg "Watchdog expired",
1007b04c530cSJonas Aaberg "Non presence of 32kHz clock",
1008b04c530cSJonas Aaberg "Battery level lower than power on reset threshold",
1009b04c530cSJonas Aaberg "Power on key 1 pressed longer than 10 seconds",
1010b04c530cSJonas Aaberg "DB8500 thermal shutdown"};
1011500e69a1SLee Jones static const char * const turn_on_status[] = {
1012abee26cdSMattias Wallin "Battery rising (Vbat)",
1013abee26cdSMattias Wallin "Power On Key 1 dbF",
1014abee26cdSMattias Wallin "Power On Key 2 dbF",
1015abee26cdSMattias Wallin "RTC Alarm",
1016abee26cdSMattias Wallin "Main Charger Detect",
1017abee26cdSMattias Wallin "Vbus Detect (USB)",
1018abee26cdSMattias Wallin "USB ID Detect",
1019abee26cdSMattias Wallin "UART Factory Mode Detect"};
1020d28f1db8SLee Jones const struct platform_device_id *platid = platform_get_device_id(pdev);
10216bc4a568SLee Jones enum ab8500_version version = AB8500_VERSION_UNDEFINED;
10226bc4a568SLee Jones struct device_node *np = pdev->dev.of_node;
1023d28f1db8SLee Jones struct ab8500 *ab8500;
102462579266SRabin Vincent int ret;
102562579266SRabin Vincent int i;
1026*fc832ac9SMinghao Chi (CGEL ZTE) int irq;
102747c16975SMattias Wallin u8 value;
102862579266SRabin Vincent
10297ccf40b1SLee Jones ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL);
1030d28f1db8SLee Jones if (!ab8500)
1031d28f1db8SLee Jones return -ENOMEM;
1032d28f1db8SLee Jones
1033d28f1db8SLee Jones ab8500->dev = &pdev->dev;
1034d28f1db8SLee Jones
1035*fc832ac9SMinghao Chi (CGEL ZTE) irq = platform_get_irq(pdev, 0);
1036*fc832ac9SMinghao Chi (CGEL ZTE) if (irq < 0)
1037*fc832ac9SMinghao Chi (CGEL ZTE) return irq;
1038d28f1db8SLee Jones
1039*fc832ac9SMinghao Chi (CGEL ZTE) ab8500->irq = irq;
1040d28f1db8SLee Jones
1041822672a7SLee Jones ab8500->read = ab8500_prcmu_read;
1042822672a7SLee Jones ab8500->write = ab8500_prcmu_write;
1043822672a7SLee Jones ab8500->write_masked = ab8500_prcmu_write_masked;
1044d28f1db8SLee Jones
104562579266SRabin Vincent mutex_init(&ab8500->lock);
104662579266SRabin Vincent mutex_init(&ab8500->irq_lock);
1047112a80d2SJonas Aaberg atomic_set(&ab8500->transfer_ongoing, 0);
104862579266SRabin Vincent
1049d28f1db8SLee Jones platform_set_drvdata(pdev, ab8500);
1050d28f1db8SLee Jones
10516bc4a568SLee Jones if (platid)
10526bc4a568SLee Jones version = platid->driver_data;
10536bc4a568SLee Jones
10540f620837SLinus Walleij if (version != AB8500_VERSION_UNDEFINED)
10550f620837SLinus Walleij ab8500->version = version;
10560f620837SLinus Walleij else {
10570f620837SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_MISC,
10580f620837SLinus Walleij AB8500_IC_NAME_REG, &value);
1059f864c46aSLinus Walleij if (ret < 0) {
1060f864c46aSLinus Walleij dev_err(&pdev->dev, "could not probe HW\n");
10618c4203cbSLee Jones return ret;
1062f864c46aSLinus Walleij }
10630f620837SLinus Walleij
10640f620837SLinus Walleij ab8500->version = value;
10650f620837SLinus Walleij }
10660f620837SLinus Walleij
106747c16975SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_MISC,
106847c16975SMattias Wallin AB8500_REV_REG, &value);
106962579266SRabin Vincent if (ret < 0)
10708c4203cbSLee Jones return ret;
107162579266SRabin Vincent
107247c16975SMattias Wallin ab8500->chip_id = value;
107362579266SRabin Vincent
10740f620837SLinus Walleij dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n",
10750f620837SLinus Walleij ab8500_version_str[ab8500->version],
10760f620837SLinus Walleij ab8500->chip_id >> 4,
10770f620837SLinus Walleij ab8500->chip_id & 0x0F);
10780f620837SLinus Walleij
10793e1a498fSLee Jones /* Configure AB8540 */
10803e1a498fSLee Jones if (is_ab8540(ab8500)) {
10813e1a498fSLee Jones ab8500->mask_size = AB8540_NUM_IRQ_REGS;
10823e1a498fSLee Jones ab8500->irq_reg_offset = ab8540_irq_regoffset;
10833e1a498fSLee Jones ab8500->it_latchhier_num = AB8540_IT_LATCHHIER_NUM;
10843e1a498fSLee Jones } /* Configure AB8500 or AB9540 IRQ */
10853e1a498fSLee Jones else if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
1086d6255529SLinus Walleij ab8500->mask_size = AB9540_NUM_IRQ_REGS;
1087d6255529SLinus Walleij ab8500->irq_reg_offset = ab9540_irq_regoffset;
10883e1a498fSLee Jones ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM;
1089d6255529SLinus Walleij } else {
10902ced445eSLinus Walleij ab8500->mask_size = AB8500_NUM_IRQ_REGS;
10912ced445eSLinus Walleij ab8500->irq_reg_offset = ab8500_irq_regoffset;
10923e1a498fSLee Jones ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM;
1093d6255529SLinus Walleij }
10947ccf40b1SLee Jones ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size,
10957ccf40b1SLee Jones GFP_KERNEL);
10962ced445eSLinus Walleij if (!ab8500->mask)
10972ced445eSLinus Walleij return -ENOMEM;
10987ccf40b1SLee Jones ab8500->oldmask = devm_kzalloc(&pdev->dev, ab8500->mask_size,
10997ccf40b1SLee Jones GFP_KERNEL);
11008c4203cbSLee Jones if (!ab8500->oldmask)
11018c4203cbSLee Jones return -ENOMEM;
11028c4203cbSLee Jones
1103e5c238c3SMattias Wallin /*
1104e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS):
1105e5c238c3SMattias Wallin * 0x01 Swoff bit programming
1106e5c238c3SMattias Wallin * 0x02 Thermal protection activation
1107e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold
1108e5c238c3SMattias Wallin * 0x08 Watchdog expired
1109e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock
1110e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold
1111e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds
1112e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown
1113e5c238c3SMattias Wallin */
1114e5c238c3SMattias Wallin
1115e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC,
1116e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value);
1117e5c238c3SMattias Wallin if (ret < 0)
1118e5c238c3SMattias Wallin return ret;
1119b04c530cSJonas Aaberg dev_info(ab8500->dev, "switch off cause(s) (%#x): ", value);
1120b04c530cSJonas Aaberg
1121b04c530cSJonas Aaberg if (value) {
1122b04c530cSJonas Aaberg for (i = 0; i < ARRAY_SIZE(switch_off_status); i++) {
1123b04c530cSJonas Aaberg if (value & 1)
11247ccf40b1SLee Jones pr_cont(" \"%s\"", switch_off_status[i]);
1125b04c530cSJonas Aaberg value = value >> 1;
1126b04c530cSJonas Aaberg
1127b04c530cSJonas Aaberg }
11287ccf40b1SLee Jones pr_cont("\n");
1129b04c530cSJonas Aaberg } else {
11307ccf40b1SLee Jones pr_cont(" None\n");
1131b04c530cSJonas Aaberg }
1132abee26cdSMattias Wallin ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
1133abee26cdSMattias Wallin AB8500_TURN_ON_STATUS, &value);
1134abee26cdSMattias Wallin if (ret < 0)
1135abee26cdSMattias Wallin return ret;
1136abee26cdSMattias Wallin dev_info(ab8500->dev, "turn on reason(s) (%#x): ", value);
1137abee26cdSMattias Wallin
1138abee26cdSMattias Wallin if (value) {
1139abee26cdSMattias Wallin for (i = 0; i < ARRAY_SIZE(turn_on_status); i++) {
1140abee26cdSMattias Wallin if (value & 1)
11417ccf40b1SLee Jones pr_cont("\"%s\" ", turn_on_status[i]);
1142abee26cdSMattias Wallin value = value >> 1;
1143abee26cdSMattias Wallin }
11447ccf40b1SLee Jones pr_cont("\n");
1145abee26cdSMattias Wallin } else {
11467ccf40b1SLee Jones pr_cont("None\n");
1147abee26cdSMattias Wallin }
1148e5c238c3SMattias Wallin
1149f04a9d8aSRajkumar Kasirajan if (is_ab9540(ab8500)) {
1150f04a9d8aSRajkumar Kasirajan ret = get_register_interruptible(ab8500, AB8500_CHARGER,
1151f04a9d8aSRajkumar Kasirajan AB8500_CH_USBCH_STAT1_REG, &value);
1152f04a9d8aSRajkumar Kasirajan if (ret < 0)
1153f04a9d8aSRajkumar Kasirajan return ret;
1154f04a9d8aSRajkumar Kasirajan if ((value & VBUS_DET_DBNC1) && (value & VBUS_DET_DBNC100))
1155f04a9d8aSRajkumar Kasirajan ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON,
1156f04a9d8aSRajkumar Kasirajan AB8500_VBUS_DET);
1157f04a9d8aSRajkumar Kasirajan }
115862579266SRabin Vincent
115962579266SRabin Vincent /* Clear and mask all interrupts */
11602ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) {
11610f620837SLinus Walleij /*
11620f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version
11630f620837SLinus Walleij * 2.0
11640f620837SLinus Walleij */
11650f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 &&
11660f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500))
116792d50a41SMattias Wallin continue;
116862579266SRabin Vincent
11693e1a498fSLee Jones if (ab8500->irq_reg_offset[i] < 0)
11703e1a498fSLee Jones continue;
11713e1a498fSLee Jones
117247c16975SMattias Wallin get_register_interruptible(ab8500, AB8500_INTERRUPT,
11732ced445eSLinus Walleij AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
117492d50a41SMattias Wallin &value);
117547c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT,
11762ced445eSLinus Walleij AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff);
117762579266SRabin Vincent }
117862579266SRabin Vincent
117947c16975SMattias Wallin ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
118047c16975SMattias Wallin if (ret)
11818c4203cbSLee Jones return ret;
118247c16975SMattias Wallin
11832ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++)
118462579266SRabin Vincent ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
118562579266SRabin Vincent
118606e589efSLee Jones ret = ab8500_irq_init(ab8500, np);
118762579266SRabin Vincent if (ret)
11888c4203cbSLee Jones return ret;
118962579266SRabin Vincent
11908c4203cbSLee Jones ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL,
11917ccfe9b1SMichel JAOUEN ab8500_hierarchical_irq,
11927ccfe9b1SMichel JAOUEN IRQF_ONESHOT | IRQF_NO_SUSPEND,
11937ccfe9b1SMichel JAOUEN "ab8500", ab8500);
119462579266SRabin Vincent if (ret)
11958c4203cbSLee Jones return ret;
119662579266SRabin Vincent
1197d6255529SLinus Walleij if (is_ab9540(ab8500))
1198d6255529SLinus Walleij ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
1199d6255529SLinus Walleij ARRAY_SIZE(ab9540_devs), NULL,
1200f864c46aSLinus Walleij 0, ab8500->domain);
12019c717cf3SAlexandre Torgue else if (is_ab8540(ab8500)) {
1202c0eda9aeSLee Jones ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs,
1203c0eda9aeSLee Jones ARRAY_SIZE(ab8540_devs), NULL,
1204f864c46aSLinus Walleij 0, ab8500->domain);
12059c717cf3SAlexandre Torgue if (ret)
12069c717cf3SAlexandre Torgue return ret;
12079c717cf3SAlexandre Torgue
12089c717cf3SAlexandre Torgue if (is_ab8540_1p2_or_earlier(ab8500))
12099c717cf3SAlexandre Torgue ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut1_devs,
12109c717cf3SAlexandre Torgue ARRAY_SIZE(ab8540_cut1_devs), NULL,
1211f864c46aSLinus Walleij 0, ab8500->domain);
12129c717cf3SAlexandre Torgue else /* ab8540 >= cut2 */
12139c717cf3SAlexandre Torgue ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut2_devs,
12149c717cf3SAlexandre Torgue ARRAY_SIZE(ab8540_cut2_devs), NULL,
1215f864c46aSLinus Walleij 0, ab8500->domain);
12169c717cf3SAlexandre Torgue } else if (is_ab8505(ab8500))
1217c0eda9aeSLee Jones ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs,
1218c0eda9aeSLee Jones ARRAY_SIZE(ab8505_devs), NULL,
1219f864c46aSLinus Walleij 0, ab8500->domain);
1220d6255529SLinus Walleij else
1221549931f9SSundar R Iyer ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
122244f72e53SVirupax Sadashivpetimath ARRAY_SIZE(ab8500_devs), NULL,
1223f864c46aSLinus Walleij 0, ab8500->domain);
12246bc4a568SLee Jones if (ret)
12258c4203cbSLee Jones return ret;
122644f72e53SVirupax Sadashivpetimath
12276ef9418cSRickard Andersson /* Add battery management devices */
12286ef9418cSRickard Andersson ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
12296ef9418cSRickard Andersson ARRAY_SIZE(ab8500_bm_devs), NULL,
1230f864c46aSLinus Walleij 0, ab8500->domain);
12316ef9418cSRickard Andersson if (ret)
12326ef9418cSRickard Andersson dev_err(ab8500->dev, "error adding bm devices\n");
12336ef9418cSRickard Andersson
1234e436ddffSLee Jones if (((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
1235e436ddffSLee Jones ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500))
1236d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj,
1237d6255529SLinus Walleij &ab9540_attr_group);
1238d6255529SLinus Walleij else
1239d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj,
1240d6255529SLinus Walleij &ab8500_attr_group);
124193ff722eSLee Jones
124293ff722eSLee Jones if ((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
124393ff722eSLee Jones ab8500->chip_id >= AB8500_CUT2P0)
124493ff722eSLee Jones ret = sysfs_create_group(&ab8500->dev->kobj,
124593ff722eSLee Jones &ab8505_attr_group);
124693ff722eSLee Jones
1247cca69b67SMattias Wallin if (ret)
1248cca69b67SMattias Wallin dev_err(ab8500->dev, "error creating sysfs entries\n");
124906e589efSLee Jones
125062579266SRabin Vincent return ret;
125162579266SRabin Vincent }
125262579266SRabin Vincent
1253d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = {
1254d28f1db8SLee Jones { "ab8500-core", AB8500_VERSION_AB8500 },
12551c0769d2SStephan Gerhold { "ab8505-core", AB8500_VERSION_AB8505 },
1256d28f1db8SLee Jones { "ab9540-i2c", AB8500_VERSION_AB9540 },
1257d28f1db8SLee Jones { "ab8540-i2c", AB8500_VERSION_AB8540 },
1258d28f1db8SLee Jones { }
1259d28f1db8SLee Jones };
1260d28f1db8SLee Jones
1261d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = {
1262d28f1db8SLee Jones .driver = {
1263d28f1db8SLee Jones .name = "ab8500-core",
126431cbae22SPaul Gortmaker .suppress_bind_attrs = true,
1265d28f1db8SLee Jones },
1266d28f1db8SLee Jones .probe = ab8500_probe,
1267d28f1db8SLee Jones .id_table = ab8500_id,
1268d28f1db8SLee Jones };
1269d28f1db8SLee Jones
ab8500_core_init(void)1270d28f1db8SLee Jones static int __init ab8500_core_init(void)
1271d28f1db8SLee Jones {
1272d28f1db8SLee Jones return platform_driver_register(&ab8500_core_driver);
1273d28f1db8SLee Jones }
1274ba7cbc3eSLee Jones core_initcall(ab8500_core_init);
1275