162579266SRabin Vincent /* 262579266SRabin Vincent * Copyright (C) ST-Ericsson SA 2010 362579266SRabin Vincent * 462579266SRabin Vincent * License Terms: GNU General Public License v2 562579266SRabin Vincent * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> 662579266SRabin Vincent * Author: Rabin Vincent <rabin.vincent@stericsson.com> 7adceed62SMattias Wallin * Author: Mattias Wallin <mattias.wallin@stericsson.com> 862579266SRabin Vincent */ 962579266SRabin Vincent 1062579266SRabin Vincent #include <linux/kernel.h> 1162579266SRabin Vincent #include <linux/slab.h> 1262579266SRabin Vincent #include <linux/init.h> 1362579266SRabin Vincent #include <linux/irq.h> 1406e589efSLee Jones #include <linux/irqdomain.h> 1562579266SRabin Vincent #include <linux/delay.h> 1662579266SRabin Vincent #include <linux/interrupt.h> 1762579266SRabin Vincent #include <linux/module.h> 1862579266SRabin Vincent #include <linux/platform_device.h> 1962579266SRabin Vincent #include <linux/mfd/core.h> 2047c16975SMattias Wallin #include <linux/mfd/abx500.h> 21ee66e653SLinus Walleij #include <linux/mfd/abx500/ab8500.h> 2200441b5eSLee Jones #include <linux/mfd/abx500/ab8500-bm.h> 23d28f1db8SLee Jones #include <linux/mfd/dbx500-prcmu.h> 24549931f9SSundar R Iyer #include <linux/regulator/ab8500.h> 256bc4a568SLee Jones #include <linux/of.h> 266bc4a568SLee Jones #include <linux/of_device.h> 2762579266SRabin Vincent 2862579266SRabin Vincent /* 2962579266SRabin Vincent * Interrupt register offsets 3062579266SRabin Vincent * Bank : 0x0E 3162579266SRabin Vincent */ 3247c16975SMattias Wallin #define AB8500_IT_SOURCE1_REG 0x00 3347c16975SMattias Wallin #define AB8500_IT_SOURCE2_REG 0x01 3447c16975SMattias Wallin #define AB8500_IT_SOURCE3_REG 0x02 3547c16975SMattias Wallin #define AB8500_IT_SOURCE4_REG 0x03 3647c16975SMattias Wallin #define AB8500_IT_SOURCE5_REG 0x04 3747c16975SMattias Wallin #define AB8500_IT_SOURCE6_REG 0x05 3847c16975SMattias Wallin #define AB8500_IT_SOURCE7_REG 0x06 3947c16975SMattias Wallin #define AB8500_IT_SOURCE8_REG 0x07 40d6255529SLinus Walleij #define AB9540_IT_SOURCE13_REG 0x0C 4147c16975SMattias Wallin #define AB8500_IT_SOURCE19_REG 0x12 4247c16975SMattias Wallin #define AB8500_IT_SOURCE20_REG 0x13 4347c16975SMattias Wallin #define AB8500_IT_SOURCE21_REG 0x14 4447c16975SMattias Wallin #define AB8500_IT_SOURCE22_REG 0x15 4547c16975SMattias Wallin #define AB8500_IT_SOURCE23_REG 0x16 4647c16975SMattias Wallin #define AB8500_IT_SOURCE24_REG 0x17 4762579266SRabin Vincent 4862579266SRabin Vincent /* 4962579266SRabin Vincent * latch registers 5062579266SRabin Vincent */ 5147c16975SMattias Wallin #define AB8500_IT_LATCH1_REG 0x20 5247c16975SMattias Wallin #define AB8500_IT_LATCH2_REG 0x21 5347c16975SMattias Wallin #define AB8500_IT_LATCH3_REG 0x22 5447c16975SMattias Wallin #define AB8500_IT_LATCH4_REG 0x23 5547c16975SMattias Wallin #define AB8500_IT_LATCH5_REG 0x24 5647c16975SMattias Wallin #define AB8500_IT_LATCH6_REG 0x25 5747c16975SMattias Wallin #define AB8500_IT_LATCH7_REG 0x26 5847c16975SMattias Wallin #define AB8500_IT_LATCH8_REG 0x27 5947c16975SMattias Wallin #define AB8500_IT_LATCH9_REG 0x28 6047c16975SMattias Wallin #define AB8500_IT_LATCH10_REG 0x29 6192d50a41SMattias Wallin #define AB8500_IT_LATCH12_REG 0x2B 62d6255529SLinus Walleij #define AB9540_IT_LATCH13_REG 0x2C 6347c16975SMattias Wallin #define AB8500_IT_LATCH19_REG 0x32 6447c16975SMattias Wallin #define AB8500_IT_LATCH20_REG 0x33 6547c16975SMattias Wallin #define AB8500_IT_LATCH21_REG 0x34 6647c16975SMattias Wallin #define AB8500_IT_LATCH22_REG 0x35 6747c16975SMattias Wallin #define AB8500_IT_LATCH23_REG 0x36 6847c16975SMattias Wallin #define AB8500_IT_LATCH24_REG 0x37 6962579266SRabin Vincent 7062579266SRabin Vincent /* 7162579266SRabin Vincent * mask registers 7262579266SRabin Vincent */ 7362579266SRabin Vincent 7447c16975SMattias Wallin #define AB8500_IT_MASK1_REG 0x40 7547c16975SMattias Wallin #define AB8500_IT_MASK2_REG 0x41 7647c16975SMattias Wallin #define AB8500_IT_MASK3_REG 0x42 7747c16975SMattias Wallin #define AB8500_IT_MASK4_REG 0x43 7847c16975SMattias Wallin #define AB8500_IT_MASK5_REG 0x44 7947c16975SMattias Wallin #define AB8500_IT_MASK6_REG 0x45 8047c16975SMattias Wallin #define AB8500_IT_MASK7_REG 0x46 8147c16975SMattias Wallin #define AB8500_IT_MASK8_REG 0x47 8247c16975SMattias Wallin #define AB8500_IT_MASK9_REG 0x48 8347c16975SMattias Wallin #define AB8500_IT_MASK10_REG 0x49 8447c16975SMattias Wallin #define AB8500_IT_MASK11_REG 0x4A 8547c16975SMattias Wallin #define AB8500_IT_MASK12_REG 0x4B 8647c16975SMattias Wallin #define AB8500_IT_MASK13_REG 0x4C 8747c16975SMattias Wallin #define AB8500_IT_MASK14_REG 0x4D 8847c16975SMattias Wallin #define AB8500_IT_MASK15_REG 0x4E 8947c16975SMattias Wallin #define AB8500_IT_MASK16_REG 0x4F 9047c16975SMattias Wallin #define AB8500_IT_MASK17_REG 0x50 9147c16975SMattias Wallin #define AB8500_IT_MASK18_REG 0x51 9247c16975SMattias Wallin #define AB8500_IT_MASK19_REG 0x52 9347c16975SMattias Wallin #define AB8500_IT_MASK20_REG 0x53 9447c16975SMattias Wallin #define AB8500_IT_MASK21_REG 0x54 9547c16975SMattias Wallin #define AB8500_IT_MASK22_REG 0x55 9647c16975SMattias Wallin #define AB8500_IT_MASK23_REG 0x56 9747c16975SMattias Wallin #define AB8500_IT_MASK24_REG 0x57 98a29264b6SLee Jones #define AB8500_IT_MASK25_REG 0x58 9962579266SRabin Vincent 1007ccfe9b1SMichel JAOUEN /* 1017ccfe9b1SMichel JAOUEN * latch hierarchy registers 1027ccfe9b1SMichel JAOUEN */ 1037ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER1_REG 0x60 1047ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER2_REG 0x61 1057ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER3_REG 0x62 1063e1a498fSLee Jones #define AB8540_IT_LATCHHIER4_REG 0x63 1077ccfe9b1SMichel JAOUEN 1087ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER_NUM 3 1093e1a498fSLee Jones #define AB8540_IT_LATCHHIER_NUM 4 1107ccfe9b1SMichel JAOUEN 11147c16975SMattias Wallin #define AB8500_REV_REG 0x80 1120f620837SLinus Walleij #define AB8500_IC_NAME_REG 0x82 113e5c238c3SMattias Wallin #define AB8500_SWITCH_OFF_STATUS 0x00 11462579266SRabin Vincent 115b4a31037SAndrew Lynn #define AB8500_TURN_ON_STATUS 0x00 11693ff722eSLee Jones #define AB8505_TURN_ON_STATUS_2 0x04 117b4a31037SAndrew Lynn 118f04a9d8aSRajkumar Kasirajan #define AB8500_CH_USBCH_STAT1_REG 0x02 119f04a9d8aSRajkumar Kasirajan #define VBUS_DET_DBNC100 0x02 120f04a9d8aSRajkumar Kasirajan #define VBUS_DET_DBNC1 0x01 121f04a9d8aSRajkumar Kasirajan 122f04a9d8aSRajkumar Kasirajan static DEFINE_SPINLOCK(on_stat_lock); 123f04a9d8aSRajkumar Kasirajan static u8 turn_on_stat_mask = 0xFF; 124f04a9d8aSRajkumar Kasirajan static u8 turn_on_stat_set; 1256ef9418cSRickard Andersson static bool no_bm; /* No battery management */ 1266ef9418cSRickard Andersson module_param(no_bm, bool, S_IRUGO); 1276ef9418cSRickard Andersson 128d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_REG 0x23 129d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2) 130d6255529SLinus Walleij 13162579266SRabin Vincent /* 13262579266SRabin Vincent * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt 1332ced445eSLinus Walleij * numbers are indexed into this array with (num / 8). The interupts are 1342ced445eSLinus Walleij * defined in linux/mfd/ab8500.h 13562579266SRabin Vincent * 13662579266SRabin Vincent * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at 13762579266SRabin Vincent * offset 0. 13862579266SRabin Vincent */ 1392ced445eSLinus Walleij /* AB8500 support */ 14062579266SRabin Vincent static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { 14192d50a41SMattias Wallin 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 14262579266SRabin Vincent }; 14362579266SRabin Vincent 144a29264b6SLee Jones /* AB9540 / AB8505 support */ 145d6255529SLinus Walleij static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = { 146a29264b6SLee Jones 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23 147d6255529SLinus Walleij }; 148d6255529SLinus Walleij 1493e1a498fSLee Jones /* AB8540 support */ 1503e1a498fSLee Jones static const int ab8540_irq_regoffset[AB8540_NUM_IRQ_REGS] = { 1517ccf40b1SLee Jones 0, 1, 2, 3, 4, -1, -1, -1, -1, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 1527ccf40b1SLee Jones 23, 25, 26, 27, 28, 29, 30, 31, 1533e1a498fSLee Jones }; 1543e1a498fSLee Jones 1550f620837SLinus Walleij static const char ab8500_version_str[][7] = { 1560f620837SLinus Walleij [AB8500_VERSION_AB8500] = "AB8500", 1570f620837SLinus Walleij [AB8500_VERSION_AB8505] = "AB8505", 1580f620837SLinus Walleij [AB8500_VERSION_AB9540] = "AB9540", 1590f620837SLinus Walleij [AB8500_VERSION_AB8540] = "AB8540", 1600f620837SLinus Walleij }; 1610f620837SLinus Walleij 162822672a7SLee Jones static int ab8500_prcmu_write(struct ab8500 *ab8500, u16 addr, u8 data) 163d28f1db8SLee Jones { 164d28f1db8SLee Jones int ret; 165d28f1db8SLee Jones 166d28f1db8SLee Jones ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 167d28f1db8SLee Jones if (ret < 0) 168d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 169d28f1db8SLee Jones return ret; 170d28f1db8SLee Jones } 171d28f1db8SLee Jones 172822672a7SLee Jones static int ab8500_prcmu_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask, 173d28f1db8SLee Jones u8 data) 174d28f1db8SLee Jones { 175d28f1db8SLee Jones int ret; 176d28f1db8SLee Jones 177d28f1db8SLee Jones ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 178d28f1db8SLee Jones &mask, 1); 179d28f1db8SLee Jones if (ret < 0) 180d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 181d28f1db8SLee Jones return ret; 182d28f1db8SLee Jones } 183d28f1db8SLee Jones 184822672a7SLee Jones static int ab8500_prcmu_read(struct ab8500 *ab8500, u16 addr) 185d28f1db8SLee Jones { 186d28f1db8SLee Jones int ret; 187d28f1db8SLee Jones u8 data; 188d28f1db8SLee Jones 189d28f1db8SLee Jones ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 190d28f1db8SLee Jones if (ret < 0) { 191d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 192d28f1db8SLee Jones return ret; 193d28f1db8SLee Jones } 194d28f1db8SLee Jones return (int)data; 195d28f1db8SLee Jones } 196d28f1db8SLee Jones 19747c16975SMattias Wallin static int ab8500_get_chip_id(struct device *dev) 19847c16975SMattias Wallin { 1996bce7bf1SMattias Wallin struct ab8500 *ab8500; 2006bce7bf1SMattias Wallin 2016bce7bf1SMattias Wallin if (!dev) 2026bce7bf1SMattias Wallin return -EINVAL; 2036bce7bf1SMattias Wallin ab8500 = dev_get_drvdata(dev->parent); 2046bce7bf1SMattias Wallin return ab8500 ? (int)ab8500->chip_id : -EINVAL; 20547c16975SMattias Wallin } 20647c16975SMattias Wallin 20747c16975SMattias Wallin static int set_register_interruptible(struct ab8500 *ab8500, u8 bank, 20847c16975SMattias Wallin u8 reg, u8 data) 20962579266SRabin Vincent { 21062579266SRabin Vincent int ret; 21147c16975SMattias Wallin /* 21247c16975SMattias Wallin * Put the u8 bank and u8 register together into a an u16. 21347c16975SMattias Wallin * The bank on higher 8 bits and register in lower 8 bits. 214*500e69a1SLee Jones */ 21547c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 21662579266SRabin Vincent 21762579266SRabin Vincent dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data); 21862579266SRabin Vincent 219392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 22047c16975SMattias Wallin 22147c16975SMattias Wallin ret = ab8500->write(ab8500, addr, data); 22247c16975SMattias Wallin if (ret < 0) 22347c16975SMattias Wallin dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 22447c16975SMattias Wallin addr, ret); 22547c16975SMattias Wallin mutex_unlock(&ab8500->lock); 22647c16975SMattias Wallin 22747c16975SMattias Wallin return ret; 22847c16975SMattias Wallin } 22947c16975SMattias Wallin 23047c16975SMattias Wallin static int ab8500_set_register(struct device *dev, u8 bank, 23147c16975SMattias Wallin u8 reg, u8 value) 23247c16975SMattias Wallin { 233112a80d2SJonas Aaberg int ret; 23447c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 23547c16975SMattias Wallin 236112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 237112a80d2SJonas Aaberg ret = set_register_interruptible(ab8500, bank, reg, value); 238112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 239112a80d2SJonas Aaberg return ret; 24047c16975SMattias Wallin } 24147c16975SMattias Wallin 24247c16975SMattias Wallin static int get_register_interruptible(struct ab8500 *ab8500, u8 bank, 24347c16975SMattias Wallin u8 reg, u8 *value) 24447c16975SMattias Wallin { 24547c16975SMattias Wallin int ret; 24647c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 24747c16975SMattias Wallin 248392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 24947c16975SMattias Wallin 25047c16975SMattias Wallin ret = ab8500->read(ab8500, addr); 25147c16975SMattias Wallin if (ret < 0) 25247c16975SMattias Wallin dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 25347c16975SMattias Wallin addr, ret); 25447c16975SMattias Wallin else 25547c16975SMattias Wallin *value = ret; 25647c16975SMattias Wallin 25747c16975SMattias Wallin mutex_unlock(&ab8500->lock); 25847c16975SMattias Wallin dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret); 25947c16975SMattias Wallin 26047c16975SMattias Wallin return ret; 26147c16975SMattias Wallin } 26247c16975SMattias Wallin 26347c16975SMattias Wallin static int ab8500_get_register(struct device *dev, u8 bank, 26447c16975SMattias Wallin u8 reg, u8 *value) 26547c16975SMattias Wallin { 266112a80d2SJonas Aaberg int ret; 26747c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 26847c16975SMattias Wallin 269112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 270112a80d2SJonas Aaberg ret = get_register_interruptible(ab8500, bank, reg, value); 271112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 272112a80d2SJonas Aaberg return ret; 27347c16975SMattias Wallin } 27447c16975SMattias Wallin 27547c16975SMattias Wallin static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank, 27647c16975SMattias Wallin u8 reg, u8 bitmask, u8 bitvalues) 27747c16975SMattias Wallin { 27847c16975SMattias Wallin int ret; 27947c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 28047c16975SMattias Wallin 281392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 28247c16975SMattias Wallin 283bc628fd1SMattias Nilsson if (ab8500->write_masked == NULL) { 284bc628fd1SMattias Nilsson u8 data; 285bc628fd1SMattias Nilsson 28647c16975SMattias Wallin ret = ab8500->read(ab8500, addr); 28747c16975SMattias Wallin if (ret < 0) { 28847c16975SMattias Wallin dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 28947c16975SMattias Wallin addr, ret); 29047c16975SMattias Wallin goto out; 29147c16975SMattias Wallin } 29247c16975SMattias Wallin 29347c16975SMattias Wallin data = (u8)ret; 29447c16975SMattias Wallin data = (~bitmask & data) | (bitmask & bitvalues); 29547c16975SMattias Wallin 29662579266SRabin Vincent ret = ab8500->write(ab8500, addr, data); 29762579266SRabin Vincent if (ret < 0) 29862579266SRabin Vincent dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 29962579266SRabin Vincent addr, ret); 30062579266SRabin Vincent 301bc628fd1SMattias Nilsson dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, 302bc628fd1SMattias Nilsson data); 303bc628fd1SMattias Nilsson goto out; 304bc628fd1SMattias Nilsson } 305bc628fd1SMattias Nilsson ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues); 306bc628fd1SMattias Nilsson if (ret < 0) 307bc628fd1SMattias Nilsson dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr, 308bc628fd1SMattias Nilsson ret); 30962579266SRabin Vincent out: 31062579266SRabin Vincent mutex_unlock(&ab8500->lock); 31162579266SRabin Vincent return ret; 31262579266SRabin Vincent } 31347c16975SMattias Wallin 31447c16975SMattias Wallin static int ab8500_mask_and_set_register(struct device *dev, 31547c16975SMattias Wallin u8 bank, u8 reg, u8 bitmask, u8 bitvalues) 31647c16975SMattias Wallin { 317112a80d2SJonas Aaberg int ret; 31847c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 31947c16975SMattias Wallin 320112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 321112a80d2SJonas Aaberg ret = mask_and_set_register_interruptible(ab8500, bank, reg, 32247c16975SMattias Wallin bitmask, bitvalues); 323112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 324112a80d2SJonas Aaberg return ret; 32547c16975SMattias Wallin } 32647c16975SMattias Wallin 32747c16975SMattias Wallin static struct abx500_ops ab8500_ops = { 32847c16975SMattias Wallin .get_chip_id = ab8500_get_chip_id, 32947c16975SMattias Wallin .get_register = ab8500_get_register, 33047c16975SMattias Wallin .set_register = ab8500_set_register, 33147c16975SMattias Wallin .get_register_page = NULL, 33247c16975SMattias Wallin .set_register_page = NULL, 33347c16975SMattias Wallin .mask_and_set_register = ab8500_mask_and_set_register, 33447c16975SMattias Wallin .event_registers_startup_state_get = NULL, 33547c16975SMattias Wallin .startup_irq_enabled = NULL, 3361d843a6cSMian Yousaf Kaukab .dump_all_banks = ab8500_dump_all_banks, 33747c16975SMattias Wallin }; 33862579266SRabin Vincent 3399505a0a0SMark Brown static void ab8500_irq_lock(struct irq_data *data) 34062579266SRabin Vincent { 3419505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 34262579266SRabin Vincent 34362579266SRabin Vincent mutex_lock(&ab8500->irq_lock); 344112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 34562579266SRabin Vincent } 34662579266SRabin Vincent 3479505a0a0SMark Brown static void ab8500_irq_sync_unlock(struct irq_data *data) 34862579266SRabin Vincent { 3499505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 35062579266SRabin Vincent int i; 35162579266SRabin Vincent 3522ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 35362579266SRabin Vincent u8 old = ab8500->oldmask[i]; 35462579266SRabin Vincent u8 new = ab8500->mask[i]; 35562579266SRabin Vincent int reg; 35662579266SRabin Vincent 35762579266SRabin Vincent if (new == old) 35862579266SRabin Vincent continue; 35962579266SRabin Vincent 3600f620837SLinus Walleij /* 3610f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 3620f620837SLinus Walleij * 2.0 3630f620837SLinus Walleij */ 3640f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 3650f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 36692d50a41SMattias Wallin continue; 36792d50a41SMattias Wallin 3683e1a498fSLee Jones if (ab8500->irq_reg_offset[i] < 0) 3693e1a498fSLee Jones continue; 3703e1a498fSLee Jones 37162579266SRabin Vincent ab8500->oldmask[i] = new; 37262579266SRabin Vincent 3732ced445eSLinus Walleij reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i]; 37447c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new); 37562579266SRabin Vincent } 376112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 37762579266SRabin Vincent mutex_unlock(&ab8500->irq_lock); 37862579266SRabin Vincent } 37962579266SRabin Vincent 3809505a0a0SMark Brown static void ab8500_irq_mask(struct irq_data *data) 38162579266SRabin Vincent { 3829505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 38306e589efSLee Jones int offset = data->hwirq; 38462579266SRabin Vincent int index = offset / 8; 38562579266SRabin Vincent int mask = 1 << (offset % 8); 38662579266SRabin Vincent 38762579266SRabin Vincent ab8500->mask[index] |= mask; 3889c677b9bSLee Jones 3899c677b9bSLee Jones /* The AB8500 GPIOs have two interrupts each (rising & falling). */ 3909c677b9bSLee Jones if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R) 3919c677b9bSLee Jones ab8500->mask[index + 2] |= mask; 3929c677b9bSLee Jones if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R) 3939c677b9bSLee Jones ab8500->mask[index + 1] |= mask; 3949c677b9bSLee Jones if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R) 395e2ddf46aSLinus Walleij /* Here the falling IRQ is one bit lower */ 396e2ddf46aSLinus Walleij ab8500->mask[index] |= (mask << 1); 39762579266SRabin Vincent } 39862579266SRabin Vincent 3999505a0a0SMark Brown static void ab8500_irq_unmask(struct irq_data *data) 40062579266SRabin Vincent { 4019505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 4029c677b9bSLee Jones unsigned int type = irqd_get_trigger_type(data); 40306e589efSLee Jones int offset = data->hwirq; 40462579266SRabin Vincent int index = offset / 8; 40562579266SRabin Vincent int mask = 1 << (offset % 8); 40662579266SRabin Vincent 4079c677b9bSLee Jones if (type & IRQ_TYPE_EDGE_RISING) 40862579266SRabin Vincent ab8500->mask[index] &= ~mask; 4099c677b9bSLee Jones 4109c677b9bSLee Jones /* The AB8500 GPIOs have two interrupts each (rising & falling). */ 4119c677b9bSLee Jones if (type & IRQ_TYPE_EDGE_FALLING) { 4129c677b9bSLee Jones if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R) 4139c677b9bSLee Jones ab8500->mask[index + 2] &= ~mask; 4147ccf40b1SLee Jones else if (offset >= AB9540_INT_GPIO50R && 4157ccf40b1SLee Jones offset <= AB9540_INT_GPIO54R) 4169c677b9bSLee Jones ab8500->mask[index + 1] &= ~mask; 4177ccf40b1SLee Jones else if (offset == AB8540_INT_GPIO43R || 4187ccf40b1SLee Jones offset == AB8540_INT_GPIO44R) 419e2ddf46aSLinus Walleij /* Here the falling IRQ is one bit lower */ 420e2ddf46aSLinus Walleij ab8500->mask[index] &= ~(mask << 1); 4219c677b9bSLee Jones else 4229c677b9bSLee Jones ab8500->mask[index] &= ~mask; 423e2ddf46aSLinus Walleij } else { 4249c677b9bSLee Jones /* Satisfies the case where type is not set. */ 42562579266SRabin Vincent ab8500->mask[index] &= ~mask; 42662579266SRabin Vincent } 427e2ddf46aSLinus Walleij } 42862579266SRabin Vincent 42940f6e5a2SLee Jones static int ab8500_irq_set_type(struct irq_data *data, unsigned int type) 43040f6e5a2SLee Jones { 43140f6e5a2SLee Jones return 0; 43262579266SRabin Vincent } 43362579266SRabin Vincent 43462579266SRabin Vincent static struct irq_chip ab8500_irq_chip = { 43562579266SRabin Vincent .name = "ab8500", 4369505a0a0SMark Brown .irq_bus_lock = ab8500_irq_lock, 4379505a0a0SMark Brown .irq_bus_sync_unlock = ab8500_irq_sync_unlock, 4389505a0a0SMark Brown .irq_mask = ab8500_irq_mask, 439e6f9306eSVirupax Sadashivpetimath .irq_disable = ab8500_irq_mask, 4409505a0a0SMark Brown .irq_unmask = ab8500_irq_unmask, 44140f6e5a2SLee Jones .irq_set_type = ab8500_irq_set_type, 44262579266SRabin Vincent }; 44362579266SRabin Vincent 4443e1a498fSLee Jones static void update_latch_offset(u8 *offset, int i) 4453e1a498fSLee Jones { 4463e1a498fSLee Jones /* Fix inconsistent ITFromLatch25 bit mapping... */ 4473e1a498fSLee Jones if (unlikely(*offset == 17)) 4483e1a498fSLee Jones *offset = 24; 4493e1a498fSLee Jones /* Fix inconsistent ab8540 bit mapping... */ 4503e1a498fSLee Jones if (unlikely(*offset == 16)) 4513e1a498fSLee Jones *offset = 25; 4523e1a498fSLee Jones if ((i == 3) && (*offset >= 24)) 4533e1a498fSLee Jones *offset += 2; 4543e1a498fSLee Jones } 4553e1a498fSLee Jones 4567ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, 4577ccfe9b1SMichel JAOUEN int latch_offset, u8 latch_val) 4587ccfe9b1SMichel JAOUEN { 4597a93fb37SFabio Baltieri int int_bit, line, i; 4607ccfe9b1SMichel JAOUEN 4617ccfe9b1SMichel JAOUEN for (i = 0; i < ab8500->mask_size; i++) 4627ccfe9b1SMichel JAOUEN if (ab8500->irq_reg_offset[i] == latch_offset) 4637ccfe9b1SMichel JAOUEN break; 4647ccfe9b1SMichel JAOUEN 4657ccfe9b1SMichel JAOUEN if (i >= ab8500->mask_size) { 4667ccfe9b1SMichel JAOUEN dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", 4677ccfe9b1SMichel JAOUEN latch_offset); 4687ccfe9b1SMichel JAOUEN return -ENXIO; 4697ccfe9b1SMichel JAOUEN } 4707ccfe9b1SMichel JAOUEN 4717a93fb37SFabio Baltieri /* ignore masked out interrupts */ 4727a93fb37SFabio Baltieri latch_val &= ~ab8500->mask[i]; 4737a93fb37SFabio Baltieri 4747a93fb37SFabio Baltieri while (latch_val) { 4757a93fb37SFabio Baltieri int_bit = __ffs(latch_val); 4767ccfe9b1SMichel JAOUEN line = (i << 3) + int_bit; 4777ccfe9b1SMichel JAOUEN latch_val &= ~(1 << int_bit); 4787ccfe9b1SMichel JAOUEN 479e2ddf46aSLinus Walleij /* 480e2ddf46aSLinus Walleij * This handles the falling edge hwirqs from the GPIO 481e2ddf46aSLinus Walleij * lines. Route them back to the line registered for the 482e2ddf46aSLinus Walleij * rising IRQ, as this is merely a flag for the same IRQ 483e2ddf46aSLinus Walleij * in linux terms. 484e2ddf46aSLinus Walleij */ 485e2ddf46aSLinus Walleij if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F) 486e2ddf46aSLinus Walleij line -= 16; 487e2ddf46aSLinus Walleij if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F) 488e2ddf46aSLinus Walleij line -= 8; 489e2ddf46aSLinus Walleij if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F) 490e2ddf46aSLinus Walleij line += 1; 491e2ddf46aSLinus Walleij 492ed83d301SLinus Walleij handle_nested_irq(irq_create_mapping(ab8500->domain, line)); 4937a93fb37SFabio Baltieri } 4947ccfe9b1SMichel JAOUEN 4957ccfe9b1SMichel JAOUEN return 0; 4967ccfe9b1SMichel JAOUEN } 4977ccfe9b1SMichel JAOUEN 4987ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500, 4997ccfe9b1SMichel JAOUEN int hier_offset, u8 hier_val) 5007ccfe9b1SMichel JAOUEN { 5017ccfe9b1SMichel JAOUEN int latch_bit, status; 5027ccfe9b1SMichel JAOUEN u8 latch_offset, latch_val; 5037ccfe9b1SMichel JAOUEN 5047ccfe9b1SMichel JAOUEN do { 5057ccfe9b1SMichel JAOUEN latch_bit = __ffs(hier_val); 5067ccfe9b1SMichel JAOUEN latch_offset = (hier_offset << 3) + latch_bit; 5077ccfe9b1SMichel JAOUEN 5083e1a498fSLee Jones update_latch_offset(&latch_offset, hier_offset); 5097ccfe9b1SMichel JAOUEN 5107ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, 5117ccfe9b1SMichel JAOUEN AB8500_INTERRUPT, 5127ccfe9b1SMichel JAOUEN AB8500_IT_LATCH1_REG + latch_offset, 5137ccfe9b1SMichel JAOUEN &latch_val); 5147ccfe9b1SMichel JAOUEN if (status < 0 || latch_val == 0) 5157ccfe9b1SMichel JAOUEN goto discard; 5167ccfe9b1SMichel JAOUEN 5177ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_line(ab8500, 5187ccfe9b1SMichel JAOUEN latch_offset, latch_val); 5197ccfe9b1SMichel JAOUEN if (status < 0) 5207ccfe9b1SMichel JAOUEN return status; 5217ccfe9b1SMichel JAOUEN discard: 5227ccfe9b1SMichel JAOUEN hier_val &= ~(1 << latch_bit); 5237ccfe9b1SMichel JAOUEN } while (hier_val); 5247ccfe9b1SMichel JAOUEN 5257ccfe9b1SMichel JAOUEN return 0; 5267ccfe9b1SMichel JAOUEN } 5277ccfe9b1SMichel JAOUEN 5287ccfe9b1SMichel JAOUEN static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev) 5297ccfe9b1SMichel JAOUEN { 5307ccfe9b1SMichel JAOUEN struct ab8500 *ab8500 = dev; 5317ccfe9b1SMichel JAOUEN u8 i; 5327ccfe9b1SMichel JAOUEN 5337ccfe9b1SMichel JAOUEN dev_vdbg(ab8500->dev, "interrupt\n"); 5347ccfe9b1SMichel JAOUEN 5357ccfe9b1SMichel JAOUEN /* Hierarchical interrupt version */ 5363e1a498fSLee Jones for (i = 0; i < (ab8500->it_latchhier_num); i++) { 5377ccfe9b1SMichel JAOUEN int status; 5387ccfe9b1SMichel JAOUEN u8 hier_val; 5397ccfe9b1SMichel JAOUEN 5407ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, AB8500_INTERRUPT, 5417ccfe9b1SMichel JAOUEN AB8500_IT_LATCHHIER1_REG + i, &hier_val); 5427ccfe9b1SMichel JAOUEN if (status < 0 || hier_val == 0) 5437ccfe9b1SMichel JAOUEN continue; 5447ccfe9b1SMichel JAOUEN 5457ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val); 5467ccfe9b1SMichel JAOUEN if (status < 0) 5477ccfe9b1SMichel JAOUEN break; 5487ccfe9b1SMichel JAOUEN } 5497ccfe9b1SMichel JAOUEN return IRQ_HANDLED; 5507ccfe9b1SMichel JAOUEN } 5517ccfe9b1SMichel JAOUEN 55206e589efSLee Jones static int ab8500_irq_map(struct irq_domain *d, unsigned int virq, 55306e589efSLee Jones irq_hw_number_t hwirq) 55406e589efSLee Jones { 55506e589efSLee Jones struct ab8500 *ab8500 = d->host_data; 55606e589efSLee Jones 55706e589efSLee Jones if (!ab8500) 55806e589efSLee Jones return -EINVAL; 55906e589efSLee Jones 56006e589efSLee Jones irq_set_chip_data(virq, ab8500); 56106e589efSLee Jones irq_set_chip_and_handler(virq, &ab8500_irq_chip, 56206e589efSLee Jones handle_simple_irq); 56306e589efSLee Jones irq_set_nested_thread(virq, 1); 56406e589efSLee Jones irq_set_noprobe(virq); 56562579266SRabin Vincent 56662579266SRabin Vincent return 0; 56762579266SRabin Vincent } 56862579266SRabin Vincent 5697ce7b26fSKrzysztof Kozlowski static const struct irq_domain_ops ab8500_irq_ops = { 57006e589efSLee Jones .map = ab8500_irq_map, 57106e589efSLee Jones .xlate = irq_domain_xlate_twocell, 57206e589efSLee Jones }; 57306e589efSLee Jones 57406e589efSLee Jones static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np) 57562579266SRabin Vincent { 5762ced445eSLinus Walleij int num_irqs; 57762579266SRabin Vincent 5783e1a498fSLee Jones if (is_ab8540(ab8500)) 5793e1a498fSLee Jones num_irqs = AB8540_NR_IRQS; 5803e1a498fSLee Jones else if (is_ab9540(ab8500)) 581d6255529SLinus Walleij num_irqs = AB9540_NR_IRQS; 582a982362cSBengt Jonsson else if (is_ab8505(ab8500)) 583a982362cSBengt Jonsson num_irqs = AB8505_NR_IRQS; 584d6255529SLinus Walleij else 5852ced445eSLinus Walleij num_irqs = AB8500_NR_IRQS; 5862ced445eSLinus Walleij 587f1d11f39SLinus Walleij /* If ->irq_base is zero this will give a linear mapping */ 5887602e05dSGrygorii Strashko ab8500->domain = irq_domain_add_simple(ab8500->dev->of_node, 589f864c46aSLinus Walleij num_irqs, 0, 590f1d11f39SLinus Walleij &ab8500_irq_ops, ab8500); 59106e589efSLee Jones 59206e589efSLee Jones if (!ab8500->domain) { 59306e589efSLee Jones dev_err(ab8500->dev, "Failed to create irqdomain\n"); 594*500e69a1SLee Jones return -ENODEV; 59506e589efSLee Jones } 59606e589efSLee Jones 59706e589efSLee Jones return 0; 59862579266SRabin Vincent } 59962579266SRabin Vincent 600112a80d2SJonas Aaberg int ab8500_suspend(struct ab8500 *ab8500) 601112a80d2SJonas Aaberg { 602112a80d2SJonas Aaberg if (atomic_read(&ab8500->transfer_ongoing)) 603112a80d2SJonas Aaberg return -EINVAL; 604f3556302SLee Jones 605112a80d2SJonas Aaberg return 0; 606112a80d2SJonas Aaberg } 607112a80d2SJonas Aaberg 6085ac98553SGeert Uytterhoeven static const struct mfd_cell ab8500_bm_devs[] = { 6096ef9418cSRickard Andersson { 6106ef9418cSRickard Andersson .name = "ab8500-charger", 6114aef72dbSRajanikanth H.V .of_compatible = "stericsson,ab8500-charger", 6124aef72dbSRajanikanth H.V .platform_data = &ab8500_bm_data, 6134aef72dbSRajanikanth H.V .pdata_size = sizeof(ab8500_bm_data), 6146ef9418cSRickard Andersson }, 6156ef9418cSRickard Andersson { 6166ef9418cSRickard Andersson .name = "ab8500-btemp", 617bd9e8ab2SRajanikanth H.V .of_compatible = "stericsson,ab8500-btemp", 618bd9e8ab2SRajanikanth H.V .platform_data = &ab8500_bm_data, 619bd9e8ab2SRajanikanth H.V .pdata_size = sizeof(ab8500_bm_data), 6206ef9418cSRickard Andersson }, 6216ef9418cSRickard Andersson { 6226ef9418cSRickard Andersson .name = "ab8500-fg", 623e0f1abebSRajanikanth H.V .of_compatible = "stericsson,ab8500-fg", 624e0f1abebSRajanikanth H.V .platform_data = &ab8500_bm_data, 625e0f1abebSRajanikanth H.V .pdata_size = sizeof(ab8500_bm_data), 6266ef9418cSRickard Andersson }, 6276ef9418cSRickard Andersson { 6286ef9418cSRickard Andersson .name = "ab8500-chargalg", 629a12810abSRajanikanth H.V .of_compatible = "stericsson,ab8500-chargalg", 630a12810abSRajanikanth H.V .platform_data = &ab8500_bm_data, 631a12810abSRajanikanth H.V .pdata_size = sizeof(ab8500_bm_data), 6326ef9418cSRickard Andersson }, 6336ef9418cSRickard Andersson }; 6346ef9418cSRickard Andersson 6355ac98553SGeert Uytterhoeven static const struct mfd_cell ab8500_devs[] = { 6364b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 637d6255529SLinus Walleij { 6384b106fb9SLee Jones .name = "ab8500-debug", 6394b106fb9SLee Jones .of_compatible = "stericsson,ab8500-debug", 6404b106fb9SLee Jones }, 6414b106fb9SLee Jones #endif 6424b106fb9SLee Jones { 6434b106fb9SLee Jones .name = "ab8500-sysctrl", 6444b106fb9SLee Jones .of_compatible = "stericsson,ab8500-sysctrl", 6454b106fb9SLee Jones }, 6464b106fb9SLee Jones { 64753f325beSLee Jones .name = "ab8500-ext-regulator", 64853f325beSLee Jones .of_compatible = "stericsson,ab8500-ext-regulator", 64953f325beSLee Jones }, 65053f325beSLee Jones { 6514b106fb9SLee Jones .name = "ab8500-regulator", 6524b106fb9SLee Jones .of_compatible = "stericsson,ab8500-regulator", 6534b106fb9SLee Jones }, 6544b106fb9SLee Jones { 6554b106fb9SLee Jones .name = "abx500-clk", 6564b106fb9SLee Jones .of_compatible = "stericsson,abx500-clk", 6574b106fb9SLee Jones }, 6584b106fb9SLee Jones { 6594b106fb9SLee Jones .name = "ab8500-gpadc", 660955de2eaSLee Jones .of_compatible = "stericsson,ab8500-gpadc", 6614b106fb9SLee Jones }, 6624b106fb9SLee Jones { 6634b106fb9SLee Jones .name = "ab8500-rtc", 6644b106fb9SLee Jones .of_compatible = "stericsson,ab8500-rtc", 6654b106fb9SLee Jones }, 6664b106fb9SLee Jones { 6674b106fb9SLee Jones .name = "ab8500-acc-det", 6684b106fb9SLee Jones .of_compatible = "stericsson,ab8500-acc-det", 6694b106fb9SLee Jones }, 6704b106fb9SLee Jones { 6714b106fb9SLee Jones 6724b106fb9SLee Jones .name = "ab8500-poweron-key", 6734b106fb9SLee Jones .of_compatible = "stericsson,ab8500-poweron-key", 6744b106fb9SLee Jones }, 6754b106fb9SLee Jones { 6764b106fb9SLee Jones .name = "ab8500-pwm", 6774b106fb9SLee Jones .of_compatible = "stericsson,ab8500-pwm", 6784b106fb9SLee Jones .id = 1, 6794b106fb9SLee Jones }, 6804b106fb9SLee Jones { 6814b106fb9SLee Jones .name = "ab8500-pwm", 6824b106fb9SLee Jones .of_compatible = "stericsson,ab8500-pwm", 6834b106fb9SLee Jones .id = 2, 6844b106fb9SLee Jones }, 6854b106fb9SLee Jones { 6864b106fb9SLee Jones .name = "ab8500-pwm", 6874b106fb9SLee Jones .of_compatible = "stericsson,ab8500-pwm", 6884b106fb9SLee Jones .id = 3, 6894b106fb9SLee Jones }, 6904b106fb9SLee Jones { 6914b106fb9SLee Jones .name = "ab8500-denc", 6924b106fb9SLee Jones .of_compatible = "stericsson,ab8500-denc", 6934b106fb9SLee Jones }, 6944b106fb9SLee Jones { 695eb696c31SLee Jones .name = "pinctrl-ab8500", 696bad76991SLee Jones .of_compatible = "stericsson,ab8500-gpio", 697d6255529SLinus Walleij }, 698d6255529SLinus Walleij { 6994b106fb9SLee Jones .name = "abx500-temp", 7004b106fb9SLee Jones .of_compatible = "stericsson,abx500-temp", 7014b106fb9SLee Jones }, 7024b106fb9SLee Jones { 703d6255529SLinus Walleij .name = "ab8500-usb", 704f201f730SFabio Baltieri .of_compatible = "stericsson,ab8500-usb", 705d6255529SLinus Walleij }, 70644f72e53SVirupax Sadashivpetimath { 70744f72e53SVirupax Sadashivpetimath .name = "ab8500-codec", 708fccf14adSFabio Baltieri .of_compatible = "stericsson,ab8500-codec", 7094b106fb9SLee Jones }, 7104b106fb9SLee Jones }; 7114b106fb9SLee Jones 7125ac98553SGeert Uytterhoeven static const struct mfd_cell ab9540_devs[] = { 7134b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 7144b106fb9SLee Jones { 7154b106fb9SLee Jones .name = "ab8500-debug", 7164b106fb9SLee Jones }, 7174b106fb9SLee Jones #endif 7184b106fb9SLee Jones { 7194b106fb9SLee Jones .name = "ab8500-sysctrl", 7204b106fb9SLee Jones }, 7214b106fb9SLee Jones { 72253f325beSLee Jones .name = "ab8500-ext-regulator", 72353f325beSLee Jones }, 72453f325beSLee Jones { 7254b106fb9SLee Jones .name = "ab8500-regulator", 72644f72e53SVirupax Sadashivpetimath }, 727c0eda9aeSLee Jones { 7289ee17676SUlf Hansson .name = "abx500-clk", 7299ee17676SUlf Hansson .of_compatible = "stericsson,abx500-clk", 7309ee17676SUlf Hansson }, 7319ee17676SUlf Hansson { 732c0eda9aeSLee Jones .name = "ab8500-gpadc", 733c0eda9aeSLee Jones .of_compatible = "stericsson,ab8500-gpadc", 734c0eda9aeSLee Jones }, 7354b106fb9SLee Jones { 7364b106fb9SLee Jones .name = "ab8500-rtc", 7374b106fb9SLee Jones }, 7384b106fb9SLee Jones { 7394b106fb9SLee Jones .name = "ab8500-acc-det", 7404b106fb9SLee Jones }, 7414b106fb9SLee Jones { 7424b106fb9SLee Jones .name = "ab8500-poweron-key", 7434b106fb9SLee Jones }, 7444b106fb9SLee Jones { 7454b106fb9SLee Jones .name = "ab8500-pwm", 7464b106fb9SLee Jones .id = 1, 7474b106fb9SLee Jones }, 7484b106fb9SLee Jones { 7494b106fb9SLee Jones .name = "abx500-temp", 7504b106fb9SLee Jones }, 751d6255529SLinus Walleij { 752e64d905eSLee Jones .name = "pinctrl-ab9540", 753e64d905eSLee Jones .of_compatible = "stericsson,ab9540-gpio", 754d6255529SLinus Walleij }, 755d6255529SLinus Walleij { 756d6255529SLinus Walleij .name = "ab9540-usb", 757d6255529SLinus Walleij }, 75844f72e53SVirupax Sadashivpetimath { 75944f72e53SVirupax Sadashivpetimath .name = "ab9540-codec", 76044f72e53SVirupax Sadashivpetimath }, 761c0eda9aeSLee Jones { 762c0eda9aeSLee Jones .name = "ab-iddet", 763c0eda9aeSLee Jones }, 76444f72e53SVirupax Sadashivpetimath }; 76544f72e53SVirupax Sadashivpetimath 766c0eda9aeSLee Jones /* Device list for ab8505 */ 7675ac98553SGeert Uytterhoeven static const struct mfd_cell ab8505_devs[] = { 7684b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 7694b106fb9SLee Jones { 7704b106fb9SLee Jones .name = "ab8500-debug", 7714b106fb9SLee Jones }, 7724b106fb9SLee Jones #endif 7734b106fb9SLee Jones { 7744b106fb9SLee Jones .name = "ab8500-sysctrl", 7754b106fb9SLee Jones }, 7764b106fb9SLee Jones { 7774b106fb9SLee Jones .name = "ab8500-regulator", 7784b106fb9SLee Jones }, 7794b106fb9SLee Jones { 7809ee17676SUlf Hansson .name = "abx500-clk", 7819ee17676SUlf Hansson .of_compatible = "stericsson,abx500-clk", 7829ee17676SUlf Hansson }, 7839ee17676SUlf Hansson { 7844b106fb9SLee Jones .name = "ab8500-gpadc", 785955de2eaSLee Jones .of_compatible = "stericsson,ab8500-gpadc", 7864b106fb9SLee Jones }, 7874b106fb9SLee Jones { 7884b106fb9SLee Jones .name = "ab8500-rtc", 7894b106fb9SLee Jones }, 7904b106fb9SLee Jones { 7914b106fb9SLee Jones .name = "ab8500-acc-det", 7924b106fb9SLee Jones }, 7934b106fb9SLee Jones { 7944b106fb9SLee Jones .name = "ab8500-poweron-key", 7954b106fb9SLee Jones }, 7964b106fb9SLee Jones { 7974b106fb9SLee Jones .name = "ab8500-pwm", 7984b106fb9SLee Jones .id = 1, 7994b106fb9SLee Jones }, 8004b106fb9SLee Jones { 801eb696c31SLee Jones .name = "pinctrl-ab8505", 8024b106fb9SLee Jones }, 8034b106fb9SLee Jones { 8044b106fb9SLee Jones .name = "ab8500-usb", 8054b106fb9SLee Jones }, 8064b106fb9SLee Jones { 8074b106fb9SLee Jones .name = "ab8500-codec", 8084b106fb9SLee Jones }, 809c0eda9aeSLee Jones { 810c0eda9aeSLee Jones .name = "ab-iddet", 811c0eda9aeSLee Jones }, 812c0eda9aeSLee Jones }; 813c0eda9aeSLee Jones 8145ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_devs[] = { 8154b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 8164b106fb9SLee Jones { 8174b106fb9SLee Jones .name = "ab8500-debug", 8184b106fb9SLee Jones }, 8194b106fb9SLee Jones #endif 8204b106fb9SLee Jones { 8214b106fb9SLee Jones .name = "ab8500-sysctrl", 8224b106fb9SLee Jones }, 8234b106fb9SLee Jones { 82453f325beSLee Jones .name = "ab8500-ext-regulator", 82553f325beSLee Jones }, 82653f325beSLee Jones { 8274b106fb9SLee Jones .name = "ab8500-regulator", 8284b106fb9SLee Jones }, 8294b106fb9SLee Jones { 8309ee17676SUlf Hansson .name = "abx500-clk", 8319ee17676SUlf Hansson .of_compatible = "stericsson,abx500-clk", 8329ee17676SUlf Hansson }, 8339ee17676SUlf Hansson { 8344b106fb9SLee Jones .name = "ab8500-gpadc", 835955de2eaSLee Jones .of_compatible = "stericsson,ab8500-gpadc", 8364b106fb9SLee Jones }, 8374b106fb9SLee Jones { 8384b106fb9SLee Jones .name = "ab8500-acc-det", 8394b106fb9SLee Jones }, 8404b106fb9SLee Jones { 8414b106fb9SLee Jones .name = "ab8500-poweron-key", 8424b106fb9SLee Jones }, 8434b106fb9SLee Jones { 8444b106fb9SLee Jones .name = "ab8500-pwm", 8454b106fb9SLee Jones .id = 1, 8464b106fb9SLee Jones }, 8474b106fb9SLee Jones { 8484b106fb9SLee Jones .name = "abx500-temp", 8494b106fb9SLee Jones }, 850c0eda9aeSLee Jones { 851eb696c31SLee Jones .name = "pinctrl-ab8540", 852c0eda9aeSLee Jones }, 853c0eda9aeSLee Jones { 854c0eda9aeSLee Jones .name = "ab8540-usb", 855c0eda9aeSLee Jones }, 856c0eda9aeSLee Jones { 857c0eda9aeSLee Jones .name = "ab8540-codec", 858c0eda9aeSLee Jones }, 859c0eda9aeSLee Jones { 86044f72e53SVirupax Sadashivpetimath .name = "ab-iddet", 86144f72e53SVirupax Sadashivpetimath }, 862d6255529SLinus Walleij }; 863d6255529SLinus Walleij 8645ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_cut1_devs[] = { 8659c717cf3SAlexandre Torgue { 8669c717cf3SAlexandre Torgue .name = "ab8500-rtc", 8679c717cf3SAlexandre Torgue .of_compatible = "stericsson,ab8500-rtc", 8689c717cf3SAlexandre Torgue }, 8699c717cf3SAlexandre Torgue }; 8709c717cf3SAlexandre Torgue 8715ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_cut2_devs[] = { 8729c717cf3SAlexandre Torgue { 8739c717cf3SAlexandre Torgue .name = "ab8540-rtc", 8749c717cf3SAlexandre Torgue .of_compatible = "stericsson,ab8540-rtc", 8759c717cf3SAlexandre Torgue }, 8769c717cf3SAlexandre Torgue }; 8779c717cf3SAlexandre Torgue 878cca69b67SMattias Wallin static ssize_t show_chip_id(struct device *dev, 879cca69b67SMattias Wallin struct device_attribute *attr, char *buf) 880cca69b67SMattias Wallin { 881cca69b67SMattias Wallin struct ab8500 *ab8500; 882cca69b67SMattias Wallin 883cca69b67SMattias Wallin ab8500 = dev_get_drvdata(dev); 884e436ddffSLee Jones 885cca69b67SMattias Wallin return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); 886cca69b67SMattias Wallin } 887cca69b67SMattias Wallin 888e5c238c3SMattias Wallin /* 889e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 890e5c238c3SMattias Wallin * 0x01 Swoff bit programming 891e5c238c3SMattias Wallin * 0x02 Thermal protection activation 892e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 893e5c238c3SMattias Wallin * 0x08 Watchdog expired 894e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 895e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 896e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 897e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 898e5c238c3SMattias Wallin */ 899e5c238c3SMattias Wallin static ssize_t show_switch_off_status(struct device *dev, 900e5c238c3SMattias Wallin struct device_attribute *attr, char *buf) 901e5c238c3SMattias Wallin { 902e5c238c3SMattias Wallin int ret; 903e5c238c3SMattias Wallin u8 value; 904e5c238c3SMattias Wallin struct ab8500 *ab8500; 905e5c238c3SMattias Wallin 906e5c238c3SMattias Wallin ab8500 = dev_get_drvdata(dev); 907e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 908e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 909e5c238c3SMattias Wallin if (ret < 0) 910e5c238c3SMattias Wallin return ret; 911e5c238c3SMattias Wallin return sprintf(buf, "%#x\n", value); 912e5c238c3SMattias Wallin } 913e5c238c3SMattias Wallin 914f04a9d8aSRajkumar Kasirajan /* use mask and set to override the register turn_on_stat value */ 915f04a9d8aSRajkumar Kasirajan void ab8500_override_turn_on_stat(u8 mask, u8 set) 916f04a9d8aSRajkumar Kasirajan { 917f04a9d8aSRajkumar Kasirajan spin_lock(&on_stat_lock); 918f04a9d8aSRajkumar Kasirajan turn_on_stat_mask = mask; 919f04a9d8aSRajkumar Kasirajan turn_on_stat_set = set; 920f04a9d8aSRajkumar Kasirajan spin_unlock(&on_stat_lock); 921f04a9d8aSRajkumar Kasirajan } 922f04a9d8aSRajkumar Kasirajan 923b4a31037SAndrew Lynn /* 924b4a31037SAndrew Lynn * ab8500 has turned on due to (TURN_ON_STATUS): 925b4a31037SAndrew Lynn * 0x01 PORnVbat 926b4a31037SAndrew Lynn * 0x02 PonKey1dbF 927b4a31037SAndrew Lynn * 0x04 PonKey2dbF 928b4a31037SAndrew Lynn * 0x08 RTCAlarm 929b4a31037SAndrew Lynn * 0x10 MainChDet 930b4a31037SAndrew Lynn * 0x20 VbusDet 931b4a31037SAndrew Lynn * 0x40 UsbIDDetect 932b4a31037SAndrew Lynn * 0x80 Reserved 933b4a31037SAndrew Lynn */ 934b4a31037SAndrew Lynn static ssize_t show_turn_on_status(struct device *dev, 935b4a31037SAndrew Lynn struct device_attribute *attr, char *buf) 936b4a31037SAndrew Lynn { 937b4a31037SAndrew Lynn int ret; 938b4a31037SAndrew Lynn u8 value; 939b4a31037SAndrew Lynn struct ab8500 *ab8500; 940b4a31037SAndrew Lynn 941b4a31037SAndrew Lynn ab8500 = dev_get_drvdata(dev); 942b4a31037SAndrew Lynn ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 943b4a31037SAndrew Lynn AB8500_TURN_ON_STATUS, &value); 944b4a31037SAndrew Lynn if (ret < 0) 945b4a31037SAndrew Lynn return ret; 946f04a9d8aSRajkumar Kasirajan 947f04a9d8aSRajkumar Kasirajan /* 948f04a9d8aSRajkumar Kasirajan * In L9540, turn_on_status register is not updated correctly if 949f04a9d8aSRajkumar Kasirajan * the device is rebooted with AC/USB charger connected. Due to 950f04a9d8aSRajkumar Kasirajan * this, the device boots android instead of entering into charge 951f04a9d8aSRajkumar Kasirajan * only mode. Read the AC/USB status register to detect the charger 952f04a9d8aSRajkumar Kasirajan * presence and update the turn on status manually. 953f04a9d8aSRajkumar Kasirajan */ 954f04a9d8aSRajkumar Kasirajan if (is_ab9540(ab8500)) { 955f04a9d8aSRajkumar Kasirajan spin_lock(&on_stat_lock); 956f04a9d8aSRajkumar Kasirajan value = (value & turn_on_stat_mask) | turn_on_stat_set; 957f04a9d8aSRajkumar Kasirajan spin_unlock(&on_stat_lock); 958f04a9d8aSRajkumar Kasirajan } 959f04a9d8aSRajkumar Kasirajan 960b4a31037SAndrew Lynn return sprintf(buf, "%#x\n", value); 961b4a31037SAndrew Lynn } 962b4a31037SAndrew Lynn 96393ff722eSLee Jones static ssize_t show_turn_on_status_2(struct device *dev, 96493ff722eSLee Jones struct device_attribute *attr, char *buf) 96593ff722eSLee Jones { 96693ff722eSLee Jones int ret; 96793ff722eSLee Jones u8 value; 96893ff722eSLee Jones struct ab8500 *ab8500; 96993ff722eSLee Jones 97093ff722eSLee Jones ab8500 = dev_get_drvdata(dev); 97193ff722eSLee Jones ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 97293ff722eSLee Jones AB8505_TURN_ON_STATUS_2, &value); 97393ff722eSLee Jones if (ret < 0) 97493ff722eSLee Jones return ret; 97593ff722eSLee Jones return sprintf(buf, "%#x\n", (value & 0x1)); 97693ff722eSLee Jones } 97793ff722eSLee Jones 978d6255529SLinus Walleij static ssize_t show_ab9540_dbbrstn(struct device *dev, 979d6255529SLinus Walleij struct device_attribute *attr, char *buf) 980d6255529SLinus Walleij { 981d6255529SLinus Walleij struct ab8500 *ab8500; 982d6255529SLinus Walleij int ret; 983d6255529SLinus Walleij u8 value; 984d6255529SLinus Walleij 985d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 986d6255529SLinus Walleij 987d6255529SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2, 988d6255529SLinus Walleij AB9540_MODEM_CTRL2_REG, &value); 989d6255529SLinus Walleij if (ret < 0) 990d6255529SLinus Walleij return ret; 991d6255529SLinus Walleij 992d6255529SLinus Walleij return sprintf(buf, "%d\n", 993d6255529SLinus Walleij (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0); 994d6255529SLinus Walleij } 995d6255529SLinus Walleij 996d6255529SLinus Walleij static ssize_t store_ab9540_dbbrstn(struct device *dev, 997d6255529SLinus Walleij struct device_attribute *attr, const char *buf, size_t count) 998d6255529SLinus Walleij { 999d6255529SLinus Walleij struct ab8500 *ab8500; 1000d6255529SLinus Walleij int ret = count; 1001d6255529SLinus Walleij int err; 1002d6255529SLinus Walleij u8 bitvalues; 1003d6255529SLinus Walleij 1004d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 1005d6255529SLinus Walleij 1006d6255529SLinus Walleij if (count > 0) { 1007d6255529SLinus Walleij switch (buf[0]) { 1008d6255529SLinus Walleij case '0': 1009d6255529SLinus Walleij bitvalues = 0; 1010d6255529SLinus Walleij break; 1011d6255529SLinus Walleij case '1': 1012d6255529SLinus Walleij bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT; 1013d6255529SLinus Walleij break; 1014d6255529SLinus Walleij default: 1015d6255529SLinus Walleij goto exit; 1016d6255529SLinus Walleij } 1017d6255529SLinus Walleij 1018d6255529SLinus Walleij err = mask_and_set_register_interruptible(ab8500, 1019d6255529SLinus Walleij AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG, 1020d6255529SLinus Walleij AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues); 1021d6255529SLinus Walleij if (err) 1022d6255529SLinus Walleij dev_info(ab8500->dev, 1023d6255529SLinus Walleij "Failed to set DBBRSTN %c, err %#x\n", 1024d6255529SLinus Walleij buf[0], err); 1025d6255529SLinus Walleij } 1026d6255529SLinus Walleij 1027d6255529SLinus Walleij exit: 1028d6255529SLinus Walleij return ret; 1029d6255529SLinus Walleij } 1030d6255529SLinus Walleij 1031cca69b67SMattias Wallin static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); 1032e5c238c3SMattias Wallin static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL); 1033b4a31037SAndrew Lynn static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL); 103493ff722eSLee Jones static DEVICE_ATTR(turn_on_status_2, S_IRUGO, show_turn_on_status_2, NULL); 1035d6255529SLinus Walleij static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR, 1036d6255529SLinus Walleij show_ab9540_dbbrstn, store_ab9540_dbbrstn); 1037cca69b67SMattias Wallin 1038cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = { 1039cca69b67SMattias Wallin &dev_attr_chip_id.attr, 1040e5c238c3SMattias Wallin &dev_attr_switch_off_status.attr, 1041b4a31037SAndrew Lynn &dev_attr_turn_on_status.attr, 1042cca69b67SMattias Wallin NULL, 1043cca69b67SMattias Wallin }; 1044cca69b67SMattias Wallin 104593ff722eSLee Jones static struct attribute *ab8505_sysfs_entries[] = { 104693ff722eSLee Jones &dev_attr_turn_on_status_2.attr, 104793ff722eSLee Jones NULL, 104893ff722eSLee Jones }; 104993ff722eSLee Jones 1050d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = { 1051d6255529SLinus Walleij &dev_attr_chip_id.attr, 1052d6255529SLinus Walleij &dev_attr_switch_off_status.attr, 1053d6255529SLinus Walleij &dev_attr_turn_on_status.attr, 1054d6255529SLinus Walleij &dev_attr_dbbrstn.attr, 1055d6255529SLinus Walleij NULL, 1056d6255529SLinus Walleij }; 1057d6255529SLinus Walleij 1058cca69b67SMattias Wallin static struct attribute_group ab8500_attr_group = { 1059cca69b67SMattias Wallin .attrs = ab8500_sysfs_entries, 1060cca69b67SMattias Wallin }; 1061cca69b67SMattias Wallin 106293ff722eSLee Jones static struct attribute_group ab8505_attr_group = { 106393ff722eSLee Jones .attrs = ab8505_sysfs_entries, 106493ff722eSLee Jones }; 106593ff722eSLee Jones 1066d6255529SLinus Walleij static struct attribute_group ab9540_attr_group = { 1067d6255529SLinus Walleij .attrs = ab9540_sysfs_entries, 1068d6255529SLinus Walleij }; 1069d6255529SLinus Walleij 1070f791be49SBill Pemberton static int ab8500_probe(struct platform_device *pdev) 107162579266SRabin Vincent { 1072*500e69a1SLee Jones static const char * const switch_off_status[] = { 1073b04c530cSJonas Aaberg "Swoff bit programming", 1074b04c530cSJonas Aaberg "Thermal protection activation", 1075b04c530cSJonas Aaberg "Vbat lower then BattOk falling threshold", 1076b04c530cSJonas Aaberg "Watchdog expired", 1077b04c530cSJonas Aaberg "Non presence of 32kHz clock", 1078b04c530cSJonas Aaberg "Battery level lower than power on reset threshold", 1079b04c530cSJonas Aaberg "Power on key 1 pressed longer than 10 seconds", 1080b04c530cSJonas Aaberg "DB8500 thermal shutdown"}; 1081*500e69a1SLee Jones static const char * const turn_on_status[] = { 1082abee26cdSMattias Wallin "Battery rising (Vbat)", 1083abee26cdSMattias Wallin "Power On Key 1 dbF", 1084abee26cdSMattias Wallin "Power On Key 2 dbF", 1085abee26cdSMattias Wallin "RTC Alarm", 1086abee26cdSMattias Wallin "Main Charger Detect", 1087abee26cdSMattias Wallin "Vbus Detect (USB)", 1088abee26cdSMattias Wallin "USB ID Detect", 1089abee26cdSMattias Wallin "UART Factory Mode Detect"}; 1090d28f1db8SLee Jones struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev); 1091d28f1db8SLee Jones const struct platform_device_id *platid = platform_get_device_id(pdev); 10926bc4a568SLee Jones enum ab8500_version version = AB8500_VERSION_UNDEFINED; 10936bc4a568SLee Jones struct device_node *np = pdev->dev.of_node; 1094d28f1db8SLee Jones struct ab8500 *ab8500; 1095d28f1db8SLee Jones struct resource *resource; 109662579266SRabin Vincent int ret; 109762579266SRabin Vincent int i; 109847c16975SMattias Wallin u8 value; 109962579266SRabin Vincent 11007ccf40b1SLee Jones ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL); 1101d28f1db8SLee Jones if (!ab8500) 1102d28f1db8SLee Jones return -ENOMEM; 1103d28f1db8SLee Jones 1104d28f1db8SLee Jones ab8500->dev = &pdev->dev; 1105d28f1db8SLee Jones 1106d28f1db8SLee Jones resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 1107f864c46aSLinus Walleij if (!resource) { 1108f864c46aSLinus Walleij dev_err(&pdev->dev, "no IRQ resource\n"); 11098c4203cbSLee Jones return -ENODEV; 1110f864c46aSLinus Walleij } 1111d28f1db8SLee Jones 1112d28f1db8SLee Jones ab8500->irq = resource->start; 1113d28f1db8SLee Jones 1114822672a7SLee Jones ab8500->read = ab8500_prcmu_read; 1115822672a7SLee Jones ab8500->write = ab8500_prcmu_write; 1116822672a7SLee Jones ab8500->write_masked = ab8500_prcmu_write_masked; 1117d28f1db8SLee Jones 111862579266SRabin Vincent mutex_init(&ab8500->lock); 111962579266SRabin Vincent mutex_init(&ab8500->irq_lock); 1120112a80d2SJonas Aaberg atomic_set(&ab8500->transfer_ongoing, 0); 112162579266SRabin Vincent 1122d28f1db8SLee Jones platform_set_drvdata(pdev, ab8500); 1123d28f1db8SLee Jones 11246bc4a568SLee Jones if (platid) 11256bc4a568SLee Jones version = platid->driver_data; 11266bc4a568SLee Jones 11270f620837SLinus Walleij if (version != AB8500_VERSION_UNDEFINED) 11280f620837SLinus Walleij ab8500->version = version; 11290f620837SLinus Walleij else { 11300f620837SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_MISC, 11310f620837SLinus Walleij AB8500_IC_NAME_REG, &value); 1132f864c46aSLinus Walleij if (ret < 0) { 1133f864c46aSLinus Walleij dev_err(&pdev->dev, "could not probe HW\n"); 11348c4203cbSLee Jones return ret; 1135f864c46aSLinus Walleij } 11360f620837SLinus Walleij 11370f620837SLinus Walleij ab8500->version = value; 11380f620837SLinus Walleij } 11390f620837SLinus Walleij 114047c16975SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_MISC, 114147c16975SMattias Wallin AB8500_REV_REG, &value); 114262579266SRabin Vincent if (ret < 0) 11438c4203cbSLee Jones return ret; 114462579266SRabin Vincent 114547c16975SMattias Wallin ab8500->chip_id = value; 114662579266SRabin Vincent 11470f620837SLinus Walleij dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n", 11480f620837SLinus Walleij ab8500_version_str[ab8500->version], 11490f620837SLinus Walleij ab8500->chip_id >> 4, 11500f620837SLinus Walleij ab8500->chip_id & 0x0F); 11510f620837SLinus Walleij 11523e1a498fSLee Jones /* Configure AB8540 */ 11533e1a498fSLee Jones if (is_ab8540(ab8500)) { 11543e1a498fSLee Jones ab8500->mask_size = AB8540_NUM_IRQ_REGS; 11553e1a498fSLee Jones ab8500->irq_reg_offset = ab8540_irq_regoffset; 11563e1a498fSLee Jones ab8500->it_latchhier_num = AB8540_IT_LATCHHIER_NUM; 11573e1a498fSLee Jones } /* Configure AB8500 or AB9540 IRQ */ 11583e1a498fSLee Jones else if (is_ab9540(ab8500) || is_ab8505(ab8500)) { 1159d6255529SLinus Walleij ab8500->mask_size = AB9540_NUM_IRQ_REGS; 1160d6255529SLinus Walleij ab8500->irq_reg_offset = ab9540_irq_regoffset; 11613e1a498fSLee Jones ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM; 1162d6255529SLinus Walleij } else { 11632ced445eSLinus Walleij ab8500->mask_size = AB8500_NUM_IRQ_REGS; 11642ced445eSLinus Walleij ab8500->irq_reg_offset = ab8500_irq_regoffset; 11653e1a498fSLee Jones ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM; 1166d6255529SLinus Walleij } 11677ccf40b1SLee Jones ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size, 11687ccf40b1SLee Jones GFP_KERNEL); 11692ced445eSLinus Walleij if (!ab8500->mask) 11702ced445eSLinus Walleij return -ENOMEM; 11717ccf40b1SLee Jones ab8500->oldmask = devm_kzalloc(&pdev->dev, ab8500->mask_size, 11727ccf40b1SLee Jones GFP_KERNEL); 11738c4203cbSLee Jones if (!ab8500->oldmask) 11748c4203cbSLee Jones return -ENOMEM; 11758c4203cbSLee Jones 1176e5c238c3SMattias Wallin /* 1177e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 1178e5c238c3SMattias Wallin * 0x01 Swoff bit programming 1179e5c238c3SMattias Wallin * 0x02 Thermal protection activation 1180e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 1181e5c238c3SMattias Wallin * 0x08 Watchdog expired 1182e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 1183e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 1184e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 1185e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 1186e5c238c3SMattias Wallin */ 1187e5c238c3SMattias Wallin 1188e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 1189e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 1190e5c238c3SMattias Wallin if (ret < 0) 1191e5c238c3SMattias Wallin return ret; 1192b04c530cSJonas Aaberg dev_info(ab8500->dev, "switch off cause(s) (%#x): ", value); 1193b04c530cSJonas Aaberg 1194b04c530cSJonas Aaberg if (value) { 1195b04c530cSJonas Aaberg for (i = 0; i < ARRAY_SIZE(switch_off_status); i++) { 1196b04c530cSJonas Aaberg if (value & 1) 11977ccf40b1SLee Jones pr_cont(" \"%s\"", switch_off_status[i]); 1198b04c530cSJonas Aaberg value = value >> 1; 1199b04c530cSJonas Aaberg 1200b04c530cSJonas Aaberg } 12017ccf40b1SLee Jones pr_cont("\n"); 1202b04c530cSJonas Aaberg } else { 12037ccf40b1SLee Jones pr_cont(" None\n"); 1204b04c530cSJonas Aaberg } 1205abee26cdSMattias Wallin ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 1206abee26cdSMattias Wallin AB8500_TURN_ON_STATUS, &value); 1207abee26cdSMattias Wallin if (ret < 0) 1208abee26cdSMattias Wallin return ret; 1209abee26cdSMattias Wallin dev_info(ab8500->dev, "turn on reason(s) (%#x): ", value); 1210abee26cdSMattias Wallin 1211abee26cdSMattias Wallin if (value) { 1212abee26cdSMattias Wallin for (i = 0; i < ARRAY_SIZE(turn_on_status); i++) { 1213abee26cdSMattias Wallin if (value & 1) 12147ccf40b1SLee Jones pr_cont("\"%s\" ", turn_on_status[i]); 1215abee26cdSMattias Wallin value = value >> 1; 1216abee26cdSMattias Wallin } 12177ccf40b1SLee Jones pr_cont("\n"); 1218abee26cdSMattias Wallin } else { 12197ccf40b1SLee Jones pr_cont("None\n"); 1220abee26cdSMattias Wallin } 1221e5c238c3SMattias Wallin 122262579266SRabin Vincent if (plat && plat->init) 122362579266SRabin Vincent plat->init(ab8500); 1224abee26cdSMattias Wallin 1225f04a9d8aSRajkumar Kasirajan if (is_ab9540(ab8500)) { 1226f04a9d8aSRajkumar Kasirajan ret = get_register_interruptible(ab8500, AB8500_CHARGER, 1227f04a9d8aSRajkumar Kasirajan AB8500_CH_USBCH_STAT1_REG, &value); 1228f04a9d8aSRajkumar Kasirajan if (ret < 0) 1229f04a9d8aSRajkumar Kasirajan return ret; 1230f04a9d8aSRajkumar Kasirajan if ((value & VBUS_DET_DBNC1) && (value & VBUS_DET_DBNC100)) 1231f04a9d8aSRajkumar Kasirajan ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON, 1232f04a9d8aSRajkumar Kasirajan AB8500_VBUS_DET); 1233f04a9d8aSRajkumar Kasirajan } 123462579266SRabin Vincent 123562579266SRabin Vincent /* Clear and mask all interrupts */ 12362ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 12370f620837SLinus Walleij /* 12380f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 12390f620837SLinus Walleij * 2.0 12400f620837SLinus Walleij */ 12410f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 12420f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 124392d50a41SMattias Wallin continue; 124462579266SRabin Vincent 12453e1a498fSLee Jones if (ab8500->irq_reg_offset[i] < 0) 12463e1a498fSLee Jones continue; 12473e1a498fSLee Jones 124847c16975SMattias Wallin get_register_interruptible(ab8500, AB8500_INTERRUPT, 12492ced445eSLinus Walleij AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i], 125092d50a41SMattias Wallin &value); 125147c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, 12522ced445eSLinus Walleij AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff); 125362579266SRabin Vincent } 125462579266SRabin Vincent 125547c16975SMattias Wallin ret = abx500_register_ops(ab8500->dev, &ab8500_ops); 125647c16975SMattias Wallin if (ret) 12578c4203cbSLee Jones return ret; 125847c16975SMattias Wallin 12592ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) 126062579266SRabin Vincent ab8500->mask[i] = ab8500->oldmask[i] = 0xff; 126162579266SRabin Vincent 126206e589efSLee Jones ret = ab8500_irq_init(ab8500, np); 126362579266SRabin Vincent if (ret) 12648c4203cbSLee Jones return ret; 126562579266SRabin Vincent 12668c4203cbSLee Jones ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL, 12677ccfe9b1SMichel JAOUEN ab8500_hierarchical_irq, 12687ccfe9b1SMichel JAOUEN IRQF_ONESHOT | IRQF_NO_SUSPEND, 12697ccfe9b1SMichel JAOUEN "ab8500", ab8500); 127062579266SRabin Vincent if (ret) 12718c4203cbSLee Jones return ret; 127262579266SRabin Vincent 1273d6255529SLinus Walleij if (is_ab9540(ab8500)) 1274d6255529SLinus Walleij ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, 1275d6255529SLinus Walleij ARRAY_SIZE(ab9540_devs), NULL, 1276f864c46aSLinus Walleij 0, ab8500->domain); 12779c717cf3SAlexandre Torgue else if (is_ab8540(ab8500)) { 1278c0eda9aeSLee Jones ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs, 1279c0eda9aeSLee Jones ARRAY_SIZE(ab8540_devs), NULL, 1280f864c46aSLinus Walleij 0, ab8500->domain); 12819c717cf3SAlexandre Torgue if (ret) 12829c717cf3SAlexandre Torgue return ret; 12839c717cf3SAlexandre Torgue 12849c717cf3SAlexandre Torgue if (is_ab8540_1p2_or_earlier(ab8500)) 12859c717cf3SAlexandre Torgue ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut1_devs, 12869c717cf3SAlexandre Torgue ARRAY_SIZE(ab8540_cut1_devs), NULL, 1287f864c46aSLinus Walleij 0, ab8500->domain); 12889c717cf3SAlexandre Torgue else /* ab8540 >= cut2 */ 12899c717cf3SAlexandre Torgue ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut2_devs, 12909c717cf3SAlexandre Torgue ARRAY_SIZE(ab8540_cut2_devs), NULL, 1291f864c46aSLinus Walleij 0, ab8500->domain); 12929c717cf3SAlexandre Torgue } else if (is_ab8505(ab8500)) 1293c0eda9aeSLee Jones ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs, 1294c0eda9aeSLee Jones ARRAY_SIZE(ab8505_devs), NULL, 1295f864c46aSLinus Walleij 0, ab8500->domain); 1296d6255529SLinus Walleij else 1297549931f9SSundar R Iyer ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, 129844f72e53SVirupax Sadashivpetimath ARRAY_SIZE(ab8500_devs), NULL, 1299f864c46aSLinus Walleij 0, ab8500->domain); 13006bc4a568SLee Jones if (ret) 13018c4203cbSLee Jones return ret; 130244f72e53SVirupax Sadashivpetimath 13036ef9418cSRickard Andersson if (!no_bm) { 13046ef9418cSRickard Andersson /* Add battery management devices */ 13056ef9418cSRickard Andersson ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, 13066ef9418cSRickard Andersson ARRAY_SIZE(ab8500_bm_devs), NULL, 1307f864c46aSLinus Walleij 0, ab8500->domain); 13086ef9418cSRickard Andersson if (ret) 13096ef9418cSRickard Andersson dev_err(ab8500->dev, "error adding bm devices\n"); 13106ef9418cSRickard Andersson } 13116ef9418cSRickard Andersson 1312e436ddffSLee Jones if (((is_ab8505(ab8500) || is_ab9540(ab8500)) && 1313e436ddffSLee Jones ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500)) 1314d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1315d6255529SLinus Walleij &ab9540_attr_group); 1316d6255529SLinus Walleij else 1317d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1318d6255529SLinus Walleij &ab8500_attr_group); 131993ff722eSLee Jones 132093ff722eSLee Jones if ((is_ab8505(ab8500) || is_ab9540(ab8500)) && 132193ff722eSLee Jones ab8500->chip_id >= AB8500_CUT2P0) 132293ff722eSLee Jones ret = sysfs_create_group(&ab8500->dev->kobj, 132393ff722eSLee Jones &ab8505_attr_group); 132493ff722eSLee Jones 1325cca69b67SMattias Wallin if (ret) 1326cca69b67SMattias Wallin dev_err(ab8500->dev, "error creating sysfs entries\n"); 132706e589efSLee Jones 132862579266SRabin Vincent return ret; 132962579266SRabin Vincent } 133062579266SRabin Vincent 13314740f73fSBill Pemberton static int ab8500_remove(struct platform_device *pdev) 133262579266SRabin Vincent { 1333d28f1db8SLee Jones struct ab8500 *ab8500 = platform_get_drvdata(pdev); 1334d28f1db8SLee Jones 1335e436ddffSLee Jones if (((is_ab8505(ab8500) || is_ab9540(ab8500)) && 1336e436ddffSLee Jones ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500)) 1337d6255529SLinus Walleij sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group); 1338d6255529SLinus Walleij else 1339cca69b67SMattias Wallin sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group); 134006e589efSLee Jones 134193ff722eSLee Jones if ((is_ab8505(ab8500) || is_ab9540(ab8500)) && 134293ff722eSLee Jones ab8500->chip_id >= AB8500_CUT2P0) 134393ff722eSLee Jones sysfs_remove_group(&ab8500->dev->kobj, &ab8505_attr_group); 134493ff722eSLee Jones 134562579266SRabin Vincent mfd_remove_devices(ab8500->dev); 134662579266SRabin Vincent 134762579266SRabin Vincent return 0; 134862579266SRabin Vincent } 134962579266SRabin Vincent 1350d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = { 1351d28f1db8SLee Jones { "ab8500-core", AB8500_VERSION_AB8500 }, 1352d28f1db8SLee Jones { "ab8505-i2c", AB8500_VERSION_AB8505 }, 1353d28f1db8SLee Jones { "ab9540-i2c", AB8500_VERSION_AB9540 }, 1354d28f1db8SLee Jones { "ab8540-i2c", AB8500_VERSION_AB8540 }, 1355d28f1db8SLee Jones { } 1356d28f1db8SLee Jones }; 1357d28f1db8SLee Jones 1358d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = { 1359d28f1db8SLee Jones .driver = { 1360d28f1db8SLee Jones .name = "ab8500-core", 1361d28f1db8SLee Jones }, 1362d28f1db8SLee Jones .probe = ab8500_probe, 136384449216SBill Pemberton .remove = ab8500_remove, 1364d28f1db8SLee Jones .id_table = ab8500_id, 1365d28f1db8SLee Jones }; 1366d28f1db8SLee Jones 1367d28f1db8SLee Jones static int __init ab8500_core_init(void) 1368d28f1db8SLee Jones { 1369d28f1db8SLee Jones return platform_driver_register(&ab8500_core_driver); 1370d28f1db8SLee Jones } 1371d28f1db8SLee Jones 1372d28f1db8SLee Jones static void __exit ab8500_core_exit(void) 1373d28f1db8SLee Jones { 1374d28f1db8SLee Jones platform_driver_unregister(&ab8500_core_driver); 1375d28f1db8SLee Jones } 1376ba7cbc3eSLee Jones core_initcall(ab8500_core_init); 1377d28f1db8SLee Jones module_exit(ab8500_core_exit); 1378d28f1db8SLee Jones 1379adceed62SMattias Wallin MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent"); 138062579266SRabin Vincent MODULE_DESCRIPTION("AB8500 MFD core"); 138162579266SRabin Vincent MODULE_LICENSE("GPL v2"); 1382