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 1067ccfe9b1SMichel JAOUEN 1077ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER_NUM 3 1087ccfe9b1SMichel JAOUEN 10947c16975SMattias Wallin #define AB8500_REV_REG 0x80 1100f620837SLinus Walleij #define AB8500_IC_NAME_REG 0x82 111e5c238c3SMattias Wallin #define AB8500_SWITCH_OFF_STATUS 0x00 11262579266SRabin Vincent 113b4a31037SAndrew Lynn #define AB8500_TURN_ON_STATUS 0x00 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 static bool no_bm; /* No battery management */ 1236ef9418cSRickard Andersson module_param(no_bm, bool, S_IRUGO); 1246ef9418cSRickard Andersson 125d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_REG 0x23 126d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2) 127d6255529SLinus Walleij 12862579266SRabin Vincent /* 12962579266SRabin Vincent * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt 1302ced445eSLinus Walleij * numbers are indexed into this array with (num / 8). The interupts are 1312ced445eSLinus Walleij * defined in linux/mfd/ab8500.h 13262579266SRabin Vincent * 13362579266SRabin Vincent * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at 13462579266SRabin Vincent * offset 0. 13562579266SRabin Vincent */ 1362ced445eSLinus Walleij /* AB8500 support */ 13762579266SRabin Vincent static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { 13892d50a41SMattias Wallin 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 13962579266SRabin Vincent }; 14062579266SRabin Vincent 141a29264b6SLee Jones /* AB9540 / AB8505 support */ 142d6255529SLinus Walleij static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = { 143a29264b6SLee Jones 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23 144d6255529SLinus Walleij }; 145d6255529SLinus Walleij 1460f620837SLinus Walleij static const char ab8500_version_str[][7] = { 1470f620837SLinus Walleij [AB8500_VERSION_AB8500] = "AB8500", 1480f620837SLinus Walleij [AB8500_VERSION_AB8505] = "AB8505", 1490f620837SLinus Walleij [AB8500_VERSION_AB9540] = "AB9540", 1500f620837SLinus Walleij [AB8500_VERSION_AB8540] = "AB8540", 1510f620837SLinus Walleij }; 1520f620837SLinus Walleij 153822672a7SLee Jones static int ab8500_prcmu_write(struct ab8500 *ab8500, u16 addr, u8 data) 154d28f1db8SLee Jones { 155d28f1db8SLee Jones int ret; 156d28f1db8SLee Jones 157d28f1db8SLee Jones ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 158d28f1db8SLee Jones if (ret < 0) 159d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 160d28f1db8SLee Jones return ret; 161d28f1db8SLee Jones } 162d28f1db8SLee Jones 163822672a7SLee Jones static int ab8500_prcmu_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask, 164d28f1db8SLee Jones u8 data) 165d28f1db8SLee Jones { 166d28f1db8SLee Jones int ret; 167d28f1db8SLee Jones 168d28f1db8SLee Jones ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 169d28f1db8SLee Jones &mask, 1); 170d28f1db8SLee Jones if (ret < 0) 171d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 172d28f1db8SLee Jones return ret; 173d28f1db8SLee Jones } 174d28f1db8SLee Jones 175822672a7SLee Jones static int ab8500_prcmu_read(struct ab8500 *ab8500, u16 addr) 176d28f1db8SLee Jones { 177d28f1db8SLee Jones int ret; 178d28f1db8SLee Jones u8 data; 179d28f1db8SLee Jones 180d28f1db8SLee Jones ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 181d28f1db8SLee Jones if (ret < 0) { 182d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 183d28f1db8SLee Jones return ret; 184d28f1db8SLee Jones } 185d28f1db8SLee Jones return (int)data; 186d28f1db8SLee Jones } 187d28f1db8SLee Jones 18847c16975SMattias Wallin static int ab8500_get_chip_id(struct device *dev) 18947c16975SMattias Wallin { 1906bce7bf1SMattias Wallin struct ab8500 *ab8500; 1916bce7bf1SMattias Wallin 1926bce7bf1SMattias Wallin if (!dev) 1936bce7bf1SMattias Wallin return -EINVAL; 1946bce7bf1SMattias Wallin ab8500 = dev_get_drvdata(dev->parent); 1956bce7bf1SMattias Wallin return ab8500 ? (int)ab8500->chip_id : -EINVAL; 19647c16975SMattias Wallin } 19747c16975SMattias Wallin 19847c16975SMattias Wallin static int set_register_interruptible(struct ab8500 *ab8500, u8 bank, 19947c16975SMattias Wallin u8 reg, u8 data) 20062579266SRabin Vincent { 20162579266SRabin Vincent int ret; 20247c16975SMattias Wallin /* 20347c16975SMattias Wallin * Put the u8 bank and u8 register together into a an u16. 20447c16975SMattias Wallin * The bank on higher 8 bits and register in lower 8 bits. 20547c16975SMattias Wallin * */ 20647c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 20762579266SRabin Vincent 20862579266SRabin Vincent dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data); 20962579266SRabin Vincent 210392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 21147c16975SMattias Wallin 21247c16975SMattias Wallin ret = ab8500->write(ab8500, addr, data); 21347c16975SMattias Wallin if (ret < 0) 21447c16975SMattias Wallin dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 21547c16975SMattias Wallin addr, ret); 21647c16975SMattias Wallin mutex_unlock(&ab8500->lock); 21747c16975SMattias Wallin 21847c16975SMattias Wallin return ret; 21947c16975SMattias Wallin } 22047c16975SMattias Wallin 22147c16975SMattias Wallin static int ab8500_set_register(struct device *dev, u8 bank, 22247c16975SMattias Wallin u8 reg, u8 value) 22347c16975SMattias Wallin { 224112a80d2SJonas Aaberg int ret; 22547c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 22647c16975SMattias Wallin 227112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 228112a80d2SJonas Aaberg ret = set_register_interruptible(ab8500, bank, reg, value); 229112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 230112a80d2SJonas Aaberg return ret; 23147c16975SMattias Wallin } 23247c16975SMattias Wallin 23347c16975SMattias Wallin static int get_register_interruptible(struct ab8500 *ab8500, u8 bank, 23447c16975SMattias Wallin u8 reg, u8 *value) 23547c16975SMattias Wallin { 23647c16975SMattias Wallin int ret; 23747c16975SMattias Wallin /* put the u8 bank and u8 reg together into a an u16. 23847c16975SMattias Wallin * bank on higher 8 bits and reg in lower */ 23947c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 24047c16975SMattias Wallin 241392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 24247c16975SMattias Wallin 24347c16975SMattias Wallin ret = ab8500->read(ab8500, addr); 24447c16975SMattias Wallin if (ret < 0) 24547c16975SMattias Wallin dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 24647c16975SMattias Wallin addr, ret); 24747c16975SMattias Wallin else 24847c16975SMattias Wallin *value = ret; 24947c16975SMattias Wallin 25047c16975SMattias Wallin mutex_unlock(&ab8500->lock); 25147c16975SMattias Wallin dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret); 25247c16975SMattias Wallin 25347c16975SMattias Wallin return ret; 25447c16975SMattias Wallin } 25547c16975SMattias Wallin 25647c16975SMattias Wallin static int ab8500_get_register(struct device *dev, u8 bank, 25747c16975SMattias Wallin u8 reg, u8 *value) 25847c16975SMattias Wallin { 259112a80d2SJonas Aaberg int ret; 26047c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 26147c16975SMattias Wallin 262112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 263112a80d2SJonas Aaberg ret = get_register_interruptible(ab8500, bank, reg, value); 264112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 265112a80d2SJonas Aaberg return ret; 26647c16975SMattias Wallin } 26747c16975SMattias Wallin 26847c16975SMattias Wallin static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank, 26947c16975SMattias Wallin u8 reg, u8 bitmask, u8 bitvalues) 27047c16975SMattias Wallin { 27147c16975SMattias Wallin int ret; 27247c16975SMattias Wallin /* put the u8 bank and u8 reg together into a an u16. 27347c16975SMattias Wallin * bank on higher 8 bits and reg in lower */ 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 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 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 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 36362579266SRabin Vincent ab8500->oldmask[i] = new; 36462579266SRabin Vincent 3652ced445eSLinus Walleij reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i]; 36647c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new); 36762579266SRabin Vincent } 368112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 36962579266SRabin Vincent mutex_unlock(&ab8500->irq_lock); 37062579266SRabin Vincent } 37162579266SRabin Vincent 3729505a0a0SMark Brown static void ab8500_irq_mask(struct irq_data *data) 37362579266SRabin Vincent { 3749505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 37506e589efSLee Jones int offset = data->hwirq; 37662579266SRabin Vincent int index = offset / 8; 37762579266SRabin Vincent int mask = 1 << (offset % 8); 37862579266SRabin Vincent 37962579266SRabin Vincent ab8500->mask[index] |= mask; 3809c677b9bSLee Jones 3819c677b9bSLee Jones /* The AB8500 GPIOs have two interrupts each (rising & falling). */ 3829c677b9bSLee Jones if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R) 3839c677b9bSLee Jones ab8500->mask[index + 2] |= mask; 3849c677b9bSLee Jones if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R) 3859c677b9bSLee Jones ab8500->mask[index + 1] |= mask; 3869c677b9bSLee Jones if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R) 387e2ddf46aSLinus Walleij /* Here the falling IRQ is one bit lower */ 388e2ddf46aSLinus Walleij ab8500->mask[index] |= (mask << 1); 38962579266SRabin Vincent } 39062579266SRabin Vincent 3919505a0a0SMark Brown static void ab8500_irq_unmask(struct irq_data *data) 39262579266SRabin Vincent { 3939505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 3949c677b9bSLee Jones unsigned int type = irqd_get_trigger_type(data); 39506e589efSLee Jones int offset = data->hwirq; 39662579266SRabin Vincent int index = offset / 8; 39762579266SRabin Vincent int mask = 1 << (offset % 8); 39862579266SRabin Vincent 3999c677b9bSLee Jones if (type & IRQ_TYPE_EDGE_RISING) 40062579266SRabin Vincent ab8500->mask[index] &= ~mask; 4019c677b9bSLee Jones 4029c677b9bSLee Jones /* The AB8500 GPIOs have two interrupts each (rising & falling). */ 4039c677b9bSLee Jones if (type & IRQ_TYPE_EDGE_FALLING) { 4049c677b9bSLee Jones if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R) 4059c677b9bSLee Jones ab8500->mask[index + 2] &= ~mask; 4069c677b9bSLee Jones else if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R) 4079c677b9bSLee Jones ab8500->mask[index + 1] &= ~mask; 4089c677b9bSLee Jones else if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R) 409e2ddf46aSLinus Walleij /* Here the falling IRQ is one bit lower */ 410e2ddf46aSLinus Walleij ab8500->mask[index] &= ~(mask << 1); 4119c677b9bSLee Jones else 4129c677b9bSLee Jones ab8500->mask[index] &= ~mask; 413e2ddf46aSLinus Walleij } else { 4149c677b9bSLee Jones /* Satisfies the case where type is not set. */ 41562579266SRabin Vincent ab8500->mask[index] &= ~mask; 41662579266SRabin Vincent } 417e2ddf46aSLinus Walleij } 41862579266SRabin Vincent 41940f6e5a2SLee Jones static int ab8500_irq_set_type(struct irq_data *data, unsigned int type) 42040f6e5a2SLee Jones { 42140f6e5a2SLee Jones return 0; 42262579266SRabin Vincent } 42362579266SRabin Vincent 42462579266SRabin Vincent static struct irq_chip ab8500_irq_chip = { 42562579266SRabin Vincent .name = "ab8500", 4269505a0a0SMark Brown .irq_bus_lock = ab8500_irq_lock, 4279505a0a0SMark Brown .irq_bus_sync_unlock = ab8500_irq_sync_unlock, 4289505a0a0SMark Brown .irq_mask = ab8500_irq_mask, 429e6f9306eSVirupax Sadashivpetimath .irq_disable = ab8500_irq_mask, 4309505a0a0SMark Brown .irq_unmask = ab8500_irq_unmask, 43140f6e5a2SLee Jones .irq_set_type = ab8500_irq_set_type, 43262579266SRabin Vincent }; 43362579266SRabin Vincent 4347ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, 4357ccfe9b1SMichel JAOUEN int latch_offset, u8 latch_val) 4367ccfe9b1SMichel JAOUEN { 4377ccfe9b1SMichel JAOUEN int int_bit = __ffs(latch_val); 4387ccfe9b1SMichel JAOUEN int line, i; 4397ccfe9b1SMichel JAOUEN 4407ccfe9b1SMichel JAOUEN do { 4417ccfe9b1SMichel JAOUEN int_bit = __ffs(latch_val); 4427ccfe9b1SMichel JAOUEN 4437ccfe9b1SMichel JAOUEN for (i = 0; i < ab8500->mask_size; i++) 4447ccfe9b1SMichel JAOUEN if (ab8500->irq_reg_offset[i] == latch_offset) 4457ccfe9b1SMichel JAOUEN break; 4467ccfe9b1SMichel JAOUEN 4477ccfe9b1SMichel JAOUEN if (i >= ab8500->mask_size) { 4487ccfe9b1SMichel JAOUEN dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", 4497ccfe9b1SMichel JAOUEN latch_offset); 4507ccfe9b1SMichel JAOUEN return -ENXIO; 4517ccfe9b1SMichel JAOUEN } 4527ccfe9b1SMichel JAOUEN 4537ccfe9b1SMichel JAOUEN line = (i << 3) + int_bit; 4547ccfe9b1SMichel JAOUEN latch_val &= ~(1 << int_bit); 4557ccfe9b1SMichel JAOUEN 456e2ddf46aSLinus Walleij /* 457e2ddf46aSLinus Walleij * This handles the falling edge hwirqs from the GPIO 458e2ddf46aSLinus Walleij * lines. Route them back to the line registered for the 459e2ddf46aSLinus Walleij * rising IRQ, as this is merely a flag for the same IRQ 460e2ddf46aSLinus Walleij * in linux terms. 461e2ddf46aSLinus Walleij */ 462e2ddf46aSLinus Walleij if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F) 463e2ddf46aSLinus Walleij line -= 16; 464e2ddf46aSLinus Walleij if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F) 465e2ddf46aSLinus Walleij line -= 8; 466e2ddf46aSLinus Walleij if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F) 467e2ddf46aSLinus Walleij line += 1; 468e2ddf46aSLinus Walleij 4697ccfe9b1SMichel JAOUEN handle_nested_irq(ab8500->irq_base + line); 4707ccfe9b1SMichel JAOUEN } while (latch_val); 4717ccfe9b1SMichel JAOUEN 4727ccfe9b1SMichel JAOUEN return 0; 4737ccfe9b1SMichel JAOUEN } 4747ccfe9b1SMichel JAOUEN 4757ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500, 4767ccfe9b1SMichel JAOUEN int hier_offset, u8 hier_val) 4777ccfe9b1SMichel JAOUEN { 4787ccfe9b1SMichel JAOUEN int latch_bit, status; 4797ccfe9b1SMichel JAOUEN u8 latch_offset, latch_val; 4807ccfe9b1SMichel JAOUEN 4817ccfe9b1SMichel JAOUEN do { 4827ccfe9b1SMichel JAOUEN latch_bit = __ffs(hier_val); 4837ccfe9b1SMichel JAOUEN latch_offset = (hier_offset << 3) + latch_bit; 4847ccfe9b1SMichel JAOUEN 4857ccfe9b1SMichel JAOUEN /* Fix inconsistent ITFromLatch25 bit mapping... */ 4867ccfe9b1SMichel JAOUEN if (unlikely(latch_offset == 17)) 4877ccfe9b1SMichel JAOUEN latch_offset = 24; 4887ccfe9b1SMichel JAOUEN 4897ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, 4907ccfe9b1SMichel JAOUEN AB8500_INTERRUPT, 4917ccfe9b1SMichel JAOUEN AB8500_IT_LATCH1_REG + latch_offset, 4927ccfe9b1SMichel JAOUEN &latch_val); 4937ccfe9b1SMichel JAOUEN if (status < 0 || latch_val == 0) 4947ccfe9b1SMichel JAOUEN goto discard; 4957ccfe9b1SMichel JAOUEN 4967ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_line(ab8500, 4977ccfe9b1SMichel JAOUEN latch_offset, latch_val); 4987ccfe9b1SMichel JAOUEN if (status < 0) 4997ccfe9b1SMichel JAOUEN return status; 5007ccfe9b1SMichel JAOUEN discard: 5017ccfe9b1SMichel JAOUEN hier_val &= ~(1 << latch_bit); 5027ccfe9b1SMichel JAOUEN } while (hier_val); 5037ccfe9b1SMichel JAOUEN 5047ccfe9b1SMichel JAOUEN return 0; 5057ccfe9b1SMichel JAOUEN } 5067ccfe9b1SMichel JAOUEN 5077ccfe9b1SMichel JAOUEN static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev) 5087ccfe9b1SMichel JAOUEN { 5097ccfe9b1SMichel JAOUEN struct ab8500 *ab8500 = dev; 5107ccfe9b1SMichel JAOUEN u8 i; 5117ccfe9b1SMichel JAOUEN 5127ccfe9b1SMichel JAOUEN dev_vdbg(ab8500->dev, "interrupt\n"); 5137ccfe9b1SMichel JAOUEN 5147ccfe9b1SMichel JAOUEN /* Hierarchical interrupt version */ 5157ccfe9b1SMichel JAOUEN for (i = 0; i < AB8500_IT_LATCHHIER_NUM; i++) { 5167ccfe9b1SMichel JAOUEN int status; 5177ccfe9b1SMichel JAOUEN u8 hier_val; 5187ccfe9b1SMichel JAOUEN 5197ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, AB8500_INTERRUPT, 5207ccfe9b1SMichel JAOUEN AB8500_IT_LATCHHIER1_REG + i, &hier_val); 5217ccfe9b1SMichel JAOUEN if (status < 0 || hier_val == 0) 5227ccfe9b1SMichel JAOUEN continue; 5237ccfe9b1SMichel JAOUEN 5247ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val); 5257ccfe9b1SMichel JAOUEN if (status < 0) 5267ccfe9b1SMichel JAOUEN break; 5277ccfe9b1SMichel JAOUEN } 5287ccfe9b1SMichel JAOUEN return IRQ_HANDLED; 5297ccfe9b1SMichel JAOUEN } 5307ccfe9b1SMichel JAOUEN 53180633f05SLee Jones /** 53280633f05SLee Jones * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ 53380633f05SLee Jones * 53480633f05SLee Jones * @ab8500: ab8500_irq controller to operate on. 53580633f05SLee Jones * @irq: index of the interrupt requested in the chip IRQs 53680633f05SLee Jones * 53780633f05SLee Jones * Useful for drivers to request their own IRQs. 53880633f05SLee Jones */ 53980633f05SLee Jones static int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq) 54080633f05SLee Jones { 54180633f05SLee Jones if (!ab8500) 54280633f05SLee Jones return -EINVAL; 54380633f05SLee Jones 54480633f05SLee Jones return irq_create_mapping(ab8500->domain, irq); 54580633f05SLee Jones } 54680633f05SLee Jones 54762579266SRabin Vincent static irqreturn_t ab8500_irq(int irq, void *dev) 54862579266SRabin Vincent { 54962579266SRabin Vincent struct ab8500 *ab8500 = dev; 55062579266SRabin Vincent int i; 55162579266SRabin Vincent 55262579266SRabin Vincent dev_vdbg(ab8500->dev, "interrupt\n"); 55362579266SRabin Vincent 554112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 555112a80d2SJonas Aaberg 5562ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 5572ced445eSLinus Walleij int regoffset = ab8500->irq_reg_offset[i]; 55862579266SRabin Vincent int status; 55947c16975SMattias Wallin u8 value; 56062579266SRabin Vincent 5610f620837SLinus Walleij /* 5620f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 5630f620837SLinus Walleij * 2.0 5640f620837SLinus Walleij */ 5650f620837SLinus Walleij if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500)) 56692d50a41SMattias Wallin continue; 56792d50a41SMattias Wallin 56847c16975SMattias Wallin status = get_register_interruptible(ab8500, AB8500_INTERRUPT, 56947c16975SMattias Wallin AB8500_IT_LATCH1_REG + regoffset, &value); 57047c16975SMattias Wallin if (status < 0 || value == 0) 57162579266SRabin Vincent continue; 57262579266SRabin Vincent 57362579266SRabin Vincent do { 57488aec4f7SMattias Wallin int bit = __ffs(value); 57562579266SRabin Vincent int line = i * 8 + bit; 5760a37fc56SLee Jones int virq = ab8500_irq_get_virq(ab8500, line); 57762579266SRabin Vincent 5780a37fc56SLee Jones handle_nested_irq(virq); 5798f0eb43bSBengt Jonsson ab8500_debug_register_interrupt(line); 58047c16975SMattias Wallin value &= ~(1 << bit); 581112a80d2SJonas Aaberg 58247c16975SMattias Wallin } while (value); 58362579266SRabin Vincent } 584112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 58562579266SRabin Vincent return IRQ_HANDLED; 58662579266SRabin Vincent } 58762579266SRabin Vincent 58806e589efSLee Jones static int ab8500_irq_map(struct irq_domain *d, unsigned int virq, 58906e589efSLee Jones irq_hw_number_t hwirq) 59006e589efSLee Jones { 59106e589efSLee Jones struct ab8500 *ab8500 = d->host_data; 59206e589efSLee Jones 59306e589efSLee Jones if (!ab8500) 59406e589efSLee Jones return -EINVAL; 59506e589efSLee Jones 59606e589efSLee Jones irq_set_chip_data(virq, ab8500); 59706e589efSLee Jones irq_set_chip_and_handler(virq, &ab8500_irq_chip, 59806e589efSLee Jones handle_simple_irq); 59906e589efSLee Jones irq_set_nested_thread(virq, 1); 60006e589efSLee Jones #ifdef CONFIG_ARM 60106e589efSLee Jones set_irq_flags(virq, IRQF_VALID); 60206e589efSLee Jones #else 60306e589efSLee Jones irq_set_noprobe(virq); 60406e589efSLee Jones #endif 60562579266SRabin Vincent 60662579266SRabin Vincent return 0; 60762579266SRabin Vincent } 60862579266SRabin Vincent 60906e589efSLee Jones static struct irq_domain_ops ab8500_irq_ops = { 61006e589efSLee Jones .map = ab8500_irq_map, 61106e589efSLee Jones .xlate = irq_domain_xlate_twocell, 61206e589efSLee Jones }; 61306e589efSLee Jones 61406e589efSLee Jones static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np) 61562579266SRabin Vincent { 6162ced445eSLinus Walleij int num_irqs; 61762579266SRabin Vincent 618d6255529SLinus Walleij if (is_ab9540(ab8500)) 619d6255529SLinus Walleij num_irqs = AB9540_NR_IRQS; 620a982362cSBengt Jonsson else if (is_ab8505(ab8500)) 621a982362cSBengt Jonsson num_irqs = AB8505_NR_IRQS; 622d6255529SLinus Walleij else 6232ced445eSLinus Walleij num_irqs = AB8500_NR_IRQS; 6242ced445eSLinus Walleij 625f1d11f39SLinus Walleij /* If ->irq_base is zero this will give a linear mapping */ 626f1d11f39SLinus Walleij ab8500->domain = irq_domain_add_simple(NULL, 627f1d11f39SLinus Walleij num_irqs, ab8500->irq_base, 628f1d11f39SLinus Walleij &ab8500_irq_ops, ab8500); 62906e589efSLee Jones 63006e589efSLee Jones if (!ab8500->domain) { 63106e589efSLee Jones dev_err(ab8500->dev, "Failed to create irqdomain\n"); 63206e589efSLee Jones return -ENOSYS; 63306e589efSLee Jones } 63406e589efSLee Jones 63506e589efSLee Jones return 0; 63662579266SRabin Vincent } 63762579266SRabin Vincent 638112a80d2SJonas Aaberg int ab8500_suspend(struct ab8500 *ab8500) 639112a80d2SJonas Aaberg { 640112a80d2SJonas Aaberg if (atomic_read(&ab8500->transfer_ongoing)) 641112a80d2SJonas Aaberg return -EINVAL; 642112a80d2SJonas Aaberg else 643112a80d2SJonas Aaberg return 0; 644112a80d2SJonas Aaberg } 645112a80d2SJonas Aaberg 646a9e9ce4cSBill Pemberton static struct resource ab8500_gpadc_resources[] = { 64762579266SRabin Vincent { 64862579266SRabin Vincent .name = "HW_CONV_END", 64962579266SRabin Vincent .start = AB8500_INT_GP_HW_ADC_CONV_END, 65062579266SRabin Vincent .end = AB8500_INT_GP_HW_ADC_CONV_END, 65162579266SRabin Vincent .flags = IORESOURCE_IRQ, 65262579266SRabin Vincent }, 65362579266SRabin Vincent { 65462579266SRabin Vincent .name = "SW_CONV_END", 65562579266SRabin Vincent .start = AB8500_INT_GP_SW_ADC_CONV_END, 65662579266SRabin Vincent .end = AB8500_INT_GP_SW_ADC_CONV_END, 65762579266SRabin Vincent .flags = IORESOURCE_IRQ, 65862579266SRabin Vincent }, 65962579266SRabin Vincent }; 66062579266SRabin Vincent 661*4b106fb9SLee Jones static struct resource ab8505_gpadc_resources[] = { 662c0eda9aeSLee Jones { 663c0eda9aeSLee Jones .name = "SW_CONV_END", 664c0eda9aeSLee Jones .start = AB8500_INT_GP_SW_ADC_CONV_END, 665c0eda9aeSLee Jones .end = AB8500_INT_GP_SW_ADC_CONV_END, 666c0eda9aeSLee Jones .flags = IORESOURCE_IRQ, 667c0eda9aeSLee Jones }, 668c0eda9aeSLee Jones }; 669c0eda9aeSLee Jones 670a9e9ce4cSBill Pemberton static struct resource ab8500_rtc_resources[] = { 67162579266SRabin Vincent { 67262579266SRabin Vincent .name = "60S", 67362579266SRabin Vincent .start = AB8500_INT_RTC_60S, 67462579266SRabin Vincent .end = AB8500_INT_RTC_60S, 67562579266SRabin Vincent .flags = IORESOURCE_IRQ, 67662579266SRabin Vincent }, 67762579266SRabin Vincent { 67862579266SRabin Vincent .name = "ALARM", 67962579266SRabin Vincent .start = AB8500_INT_RTC_ALARM, 68062579266SRabin Vincent .end = AB8500_INT_RTC_ALARM, 68162579266SRabin Vincent .flags = IORESOURCE_IRQ, 68262579266SRabin Vincent }, 68362579266SRabin Vincent }; 68462579266SRabin Vincent 685a9e9ce4cSBill Pemberton static struct resource ab8500_poweronkey_db_resources[] = { 68677686517SSundar R Iyer { 68777686517SSundar R Iyer .name = "ONKEY_DBF", 68877686517SSundar R Iyer .start = AB8500_INT_PON_KEY1DB_F, 68977686517SSundar R Iyer .end = AB8500_INT_PON_KEY1DB_F, 69077686517SSundar R Iyer .flags = IORESOURCE_IRQ, 69177686517SSundar R Iyer }, 69277686517SSundar R Iyer { 69377686517SSundar R Iyer .name = "ONKEY_DBR", 69477686517SSundar R Iyer .start = AB8500_INT_PON_KEY1DB_R, 69577686517SSundar R Iyer .end = AB8500_INT_PON_KEY1DB_R, 69677686517SSundar R Iyer .flags = IORESOURCE_IRQ, 69777686517SSundar R Iyer }, 69877686517SSundar R Iyer }; 69977686517SSundar R Iyer 700a9e9ce4cSBill Pemberton static struct resource ab8500_av_acc_detect_resources[] = { 701e098adedSMattias Wallin { 7026af75ecdSLinus Walleij .name = "ACC_DETECT_1DB_F", 7036af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_1DB_F, 7046af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_1DB_F, 705e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 706e098adedSMattias Wallin }, 707e098adedSMattias Wallin { 7086af75ecdSLinus Walleij .name = "ACC_DETECT_1DB_R", 7096af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_1DB_R, 7106af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_1DB_R, 711e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 712e098adedSMattias Wallin }, 713e098adedSMattias Wallin { 7146af75ecdSLinus Walleij .name = "ACC_DETECT_21DB_F", 7156af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_21DB_F, 7166af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_21DB_F, 7176af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7186af75ecdSLinus Walleij }, 7196af75ecdSLinus Walleij { 7206af75ecdSLinus Walleij .name = "ACC_DETECT_21DB_R", 7216af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_21DB_R, 7226af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_21DB_R, 7236af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7246af75ecdSLinus Walleij }, 7256af75ecdSLinus Walleij { 7266af75ecdSLinus Walleij .name = "ACC_DETECT_22DB_F", 7276af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_22DB_F, 7286af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_22DB_F, 7296af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7306af75ecdSLinus Walleij }, 7316af75ecdSLinus Walleij { 7326af75ecdSLinus Walleij .name = "ACC_DETECT_22DB_R", 7336af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_22DB_R, 7346af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_22DB_R, 7356af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7366af75ecdSLinus Walleij }, 7376af75ecdSLinus Walleij }; 7386af75ecdSLinus Walleij 739a9e9ce4cSBill Pemberton static struct resource ab8500_charger_resources[] = { 7406af75ecdSLinus Walleij { 741e098adedSMattias Wallin .name = "MAIN_CH_UNPLUG_DET", 742e098adedSMattias Wallin .start = AB8500_INT_MAIN_CH_UNPLUG_DET, 743e098adedSMattias Wallin .end = AB8500_INT_MAIN_CH_UNPLUG_DET, 744e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 745e098adedSMattias Wallin }, 746e098adedSMattias Wallin { 747e098adedSMattias Wallin .name = "MAIN_CHARGE_PLUG_DET", 748e098adedSMattias Wallin .start = AB8500_INT_MAIN_CH_PLUG_DET, 749e098adedSMattias Wallin .end = AB8500_INT_MAIN_CH_PLUG_DET, 750e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 751e098adedSMattias Wallin }, 752e098adedSMattias Wallin { 753e098adedSMattias Wallin .name = "VBUS_DET_R", 754e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_R, 755e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_R, 756e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 757e098adedSMattias Wallin }, 758e098adedSMattias Wallin { 7596af75ecdSLinus Walleij .name = "VBUS_DET_F", 7606af75ecdSLinus Walleij .start = AB8500_INT_VBUS_DET_F, 7616af75ecdSLinus Walleij .end = AB8500_INT_VBUS_DET_F, 762e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 763e098adedSMattias Wallin }, 764e098adedSMattias Wallin { 7656af75ecdSLinus Walleij .name = "USB_LINK_STATUS", 7666af75ecdSLinus Walleij .start = AB8500_INT_USB_LINK_STATUS, 7676af75ecdSLinus Walleij .end = AB8500_INT_USB_LINK_STATUS, 7686af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7696af75ecdSLinus Walleij }, 7706af75ecdSLinus Walleij { 771e098adedSMattias Wallin .name = "VBUS_OVV", 772e098adedSMattias Wallin .start = AB8500_INT_VBUS_OVV, 773e098adedSMattias Wallin .end = AB8500_INT_VBUS_OVV, 774e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 775e098adedSMattias Wallin }, 776e098adedSMattias Wallin { 7776af75ecdSLinus Walleij .name = "USB_CH_TH_PROT_R", 7786af75ecdSLinus Walleij .start = AB8500_INT_USB_CH_TH_PROT_R, 7796af75ecdSLinus Walleij .end = AB8500_INT_USB_CH_TH_PROT_R, 780e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 781e098adedSMattias Wallin }, 782e098adedSMattias Wallin { 7836af75ecdSLinus Walleij .name = "USB_CH_TH_PROT_F", 7846af75ecdSLinus Walleij .start = AB8500_INT_USB_CH_TH_PROT_F, 7856af75ecdSLinus Walleij .end = AB8500_INT_USB_CH_TH_PROT_F, 786e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 787e098adedSMattias Wallin }, 788e098adedSMattias Wallin { 7896af75ecdSLinus Walleij .name = "MAIN_EXT_CH_NOT_OK", 7906af75ecdSLinus Walleij .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, 7916af75ecdSLinus Walleij .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, 7926af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7936af75ecdSLinus Walleij }, 7946af75ecdSLinus Walleij { 7956af75ecdSLinus Walleij .name = "MAIN_CH_TH_PROT_R", 7966af75ecdSLinus Walleij .start = AB8500_INT_MAIN_CH_TH_PROT_R, 7976af75ecdSLinus Walleij .end = AB8500_INT_MAIN_CH_TH_PROT_R, 7986af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7996af75ecdSLinus Walleij }, 8006af75ecdSLinus Walleij { 8016af75ecdSLinus Walleij .name = "MAIN_CH_TH_PROT_F", 8026af75ecdSLinus Walleij .start = AB8500_INT_MAIN_CH_TH_PROT_F, 8036af75ecdSLinus Walleij .end = AB8500_INT_MAIN_CH_TH_PROT_F, 8046af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8056af75ecdSLinus Walleij }, 8066af75ecdSLinus Walleij { 8076af75ecdSLinus Walleij .name = "USB_CHARGER_NOT_OKR", 808a982362cSBengt Jonsson .start = AB8500_INT_USB_CHARGER_NOT_OKR, 809a982362cSBengt Jonsson .end = AB8500_INT_USB_CHARGER_NOT_OKR, 8106af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8116af75ecdSLinus Walleij }, 8126af75ecdSLinus Walleij { 8136af75ecdSLinus Walleij .name = "CH_WD_EXP", 8146af75ecdSLinus Walleij .start = AB8500_INT_CH_WD_EXP, 8156af75ecdSLinus Walleij .end = AB8500_INT_CH_WD_EXP, 8166af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8176af75ecdSLinus Walleij }, 81834c11a70SPaer-Olof Haakansson { 81934c11a70SPaer-Olof Haakansson .name = "VBUS_CH_DROP_END", 82034c11a70SPaer-Olof Haakansson .start = AB8500_INT_VBUS_CH_DROP_END, 82134c11a70SPaer-Olof Haakansson .end = AB8500_INT_VBUS_CH_DROP_END, 82234c11a70SPaer-Olof Haakansson .flags = IORESOURCE_IRQ, 82334c11a70SPaer-Olof Haakansson }, 8246af75ecdSLinus Walleij }; 8256af75ecdSLinus Walleij 826a9e9ce4cSBill Pemberton static struct resource ab8500_btemp_resources[] = { 8276af75ecdSLinus Walleij { 8286af75ecdSLinus Walleij .name = "BAT_CTRL_INDB", 8296af75ecdSLinus Walleij .start = AB8500_INT_BAT_CTRL_INDB, 8306af75ecdSLinus Walleij .end = AB8500_INT_BAT_CTRL_INDB, 831e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 832e098adedSMattias Wallin }, 833e098adedSMattias Wallin { 834e098adedSMattias Wallin .name = "BTEMP_LOW", 835e098adedSMattias Wallin .start = AB8500_INT_BTEMP_LOW, 836e098adedSMattias Wallin .end = AB8500_INT_BTEMP_LOW, 837e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 838e098adedSMattias Wallin }, 839e098adedSMattias Wallin { 840e098adedSMattias Wallin .name = "BTEMP_HIGH", 841e098adedSMattias Wallin .start = AB8500_INT_BTEMP_HIGH, 842e098adedSMattias Wallin .end = AB8500_INT_BTEMP_HIGH, 843e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 844e098adedSMattias Wallin }, 845e098adedSMattias Wallin { 8466af75ecdSLinus Walleij .name = "BTEMP_LOW_MEDIUM", 8476af75ecdSLinus Walleij .start = AB8500_INT_BTEMP_LOW_MEDIUM, 8486af75ecdSLinus Walleij .end = AB8500_INT_BTEMP_LOW_MEDIUM, 849e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 850e098adedSMattias Wallin }, 851e098adedSMattias Wallin { 8526af75ecdSLinus Walleij .name = "BTEMP_MEDIUM_HIGH", 8536af75ecdSLinus Walleij .start = AB8500_INT_BTEMP_MEDIUM_HIGH, 8546af75ecdSLinus Walleij .end = AB8500_INT_BTEMP_MEDIUM_HIGH, 855e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 856e098adedSMattias Wallin }, 857e098adedSMattias Wallin }; 858e098adedSMattias Wallin 859a9e9ce4cSBill Pemberton static struct resource ab8500_fg_resources[] = { 8606af75ecdSLinus Walleij { 8616af75ecdSLinus Walleij .name = "NCONV_ACCU", 8626af75ecdSLinus Walleij .start = AB8500_INT_CCN_CONV_ACC, 8636af75ecdSLinus Walleij .end = AB8500_INT_CCN_CONV_ACC, 8646af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8656af75ecdSLinus Walleij }, 8666af75ecdSLinus Walleij { 8676af75ecdSLinus Walleij .name = "BATT_OVV", 8686af75ecdSLinus Walleij .start = AB8500_INT_BATT_OVV, 8696af75ecdSLinus Walleij .end = AB8500_INT_BATT_OVV, 8706af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8716af75ecdSLinus Walleij }, 8726af75ecdSLinus Walleij { 8736af75ecdSLinus Walleij .name = "LOW_BAT_F", 8746af75ecdSLinus Walleij .start = AB8500_INT_LOW_BAT_F, 8756af75ecdSLinus Walleij .end = AB8500_INT_LOW_BAT_F, 8766af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8776af75ecdSLinus Walleij }, 8786af75ecdSLinus Walleij { 8796af75ecdSLinus Walleij .name = "LOW_BAT_R", 8806af75ecdSLinus Walleij .start = AB8500_INT_LOW_BAT_R, 8816af75ecdSLinus Walleij .end = AB8500_INT_LOW_BAT_R, 8826af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8836af75ecdSLinus Walleij }, 8846af75ecdSLinus Walleij { 8856af75ecdSLinus Walleij .name = "CC_INT_CALIB", 8866af75ecdSLinus Walleij .start = AB8500_INT_CC_INT_CALIB, 8876af75ecdSLinus Walleij .end = AB8500_INT_CC_INT_CALIB, 8886af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8896af75ecdSLinus Walleij }, 890a982362cSBengt Jonsson { 891a982362cSBengt Jonsson .name = "CCEOC", 892a982362cSBengt Jonsson .start = AB8500_INT_CCEOC, 893a982362cSBengt Jonsson .end = AB8500_INT_CCEOC, 894a982362cSBengt Jonsson .flags = IORESOURCE_IRQ, 895a982362cSBengt Jonsson }, 8966af75ecdSLinus Walleij }; 8976af75ecdSLinus Walleij 898a9e9ce4cSBill Pemberton static struct resource ab8500_chargalg_resources[] = {}; 8996af75ecdSLinus Walleij 900df720647SAxel Lin #ifdef CONFIG_DEBUG_FS 901a9e9ce4cSBill Pemberton static struct resource ab8500_debug_resources[] = { 902e098adedSMattias Wallin { 903e098adedSMattias Wallin .name = "IRQ_FIRST", 904e098adedSMattias Wallin .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, 905e098adedSMattias Wallin .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, 906e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 907e098adedSMattias Wallin }, 908e098adedSMattias Wallin { 909e098adedSMattias Wallin .name = "IRQ_LAST", 910a982362cSBengt Jonsson .start = AB8500_INT_XTAL32K_KO, 911a982362cSBengt Jonsson .end = AB8500_INT_XTAL32K_KO, 912e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 913e098adedSMattias Wallin }, 914e098adedSMattias Wallin }; 915df720647SAxel Lin #endif 916e098adedSMattias Wallin 917a9e9ce4cSBill Pemberton static struct resource ab8500_usb_resources[] = { 918e098adedSMattias Wallin { 919e098adedSMattias Wallin .name = "ID_WAKEUP_R", 920e098adedSMattias Wallin .start = AB8500_INT_ID_WAKEUP_R, 921e098adedSMattias Wallin .end = AB8500_INT_ID_WAKEUP_R, 922e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 923e098adedSMattias Wallin }, 924e098adedSMattias Wallin { 925e098adedSMattias Wallin .name = "ID_WAKEUP_F", 926e098adedSMattias Wallin .start = AB8500_INT_ID_WAKEUP_F, 927e098adedSMattias Wallin .end = AB8500_INT_ID_WAKEUP_F, 928e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 929e098adedSMattias Wallin }, 930e098adedSMattias Wallin { 931e098adedSMattias Wallin .name = "VBUS_DET_F", 932e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_F, 933e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_F, 934e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 935e098adedSMattias Wallin }, 936e098adedSMattias Wallin { 937e098adedSMattias Wallin .name = "VBUS_DET_R", 938e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_R, 939e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_R, 940e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 941e098adedSMattias Wallin }, 94292d50a41SMattias Wallin { 94392d50a41SMattias Wallin .name = "USB_LINK_STATUS", 94492d50a41SMattias Wallin .start = AB8500_INT_USB_LINK_STATUS, 94592d50a41SMattias Wallin .end = AB8500_INT_USB_LINK_STATUS, 94692d50a41SMattias Wallin .flags = IORESOURCE_IRQ, 94792d50a41SMattias Wallin }, 9486af75ecdSLinus Walleij { 9496af75ecdSLinus Walleij .name = "USB_ADP_PROBE_PLUG", 9506af75ecdSLinus Walleij .start = AB8500_INT_ADP_PROBE_PLUG, 9516af75ecdSLinus Walleij .end = AB8500_INT_ADP_PROBE_PLUG, 9526af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 9536af75ecdSLinus Walleij }, 9546af75ecdSLinus Walleij { 9556af75ecdSLinus Walleij .name = "USB_ADP_PROBE_UNPLUG", 9566af75ecdSLinus Walleij .start = AB8500_INT_ADP_PROBE_UNPLUG, 9576af75ecdSLinus Walleij .end = AB8500_INT_ADP_PROBE_UNPLUG, 9586af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 9596af75ecdSLinus Walleij }, 960e098adedSMattias Wallin }; 961e098adedSMattias Wallin 962a9e9ce4cSBill Pemberton static struct resource ab8505_iddet_resources[] = { 96344f72e53SVirupax Sadashivpetimath { 96444f72e53SVirupax Sadashivpetimath .name = "KeyDeglitch", 96544f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KEYDEGLITCH, 96644f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KEYDEGLITCH, 96744f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 96844f72e53SVirupax Sadashivpetimath }, 96944f72e53SVirupax Sadashivpetimath { 97044f72e53SVirupax Sadashivpetimath .name = "KP", 97144f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KP, 97244f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KP, 97344f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 97444f72e53SVirupax Sadashivpetimath }, 97544f72e53SVirupax Sadashivpetimath { 97644f72e53SVirupax Sadashivpetimath .name = "IKP", 97744f72e53SVirupax Sadashivpetimath .start = AB8505_INT_IKP, 97844f72e53SVirupax Sadashivpetimath .end = AB8505_INT_IKP, 97944f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 98044f72e53SVirupax Sadashivpetimath }, 98144f72e53SVirupax Sadashivpetimath { 98244f72e53SVirupax Sadashivpetimath .name = "IKR", 98344f72e53SVirupax Sadashivpetimath .start = AB8505_INT_IKR, 98444f72e53SVirupax Sadashivpetimath .end = AB8505_INT_IKR, 98544f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 98644f72e53SVirupax Sadashivpetimath }, 98744f72e53SVirupax Sadashivpetimath { 98844f72e53SVirupax Sadashivpetimath .name = "KeyStuck", 98944f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KEYSTUCK, 99044f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KEYSTUCK, 99144f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 99244f72e53SVirupax Sadashivpetimath }, 99344f72e53SVirupax Sadashivpetimath }; 99444f72e53SVirupax Sadashivpetimath 995a9e9ce4cSBill Pemberton static struct resource ab8500_temp_resources[] = { 996e098adedSMattias Wallin { 997151621a7SHongbo Zhang .name = "ABX500_TEMP_WARM", 998e098adedSMattias Wallin .start = AB8500_INT_TEMP_WARM, 999e098adedSMattias Wallin .end = AB8500_INT_TEMP_WARM, 1000e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 1001e098adedSMattias Wallin }, 1002e098adedSMattias Wallin }; 1003e098adedSMattias Wallin 1004a9e9ce4cSBill Pemberton static struct mfd_cell ab8500_bm_devs[] = { 10056ef9418cSRickard Andersson { 10066ef9418cSRickard Andersson .name = "ab8500-charger", 10074aef72dbSRajanikanth H.V .of_compatible = "stericsson,ab8500-charger", 10086ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_charger_resources), 10096ef9418cSRickard Andersson .resources = ab8500_charger_resources, 10104aef72dbSRajanikanth H.V .platform_data = &ab8500_bm_data, 10114aef72dbSRajanikanth H.V .pdata_size = sizeof(ab8500_bm_data), 10126ef9418cSRickard Andersson }, 10136ef9418cSRickard Andersson { 10146ef9418cSRickard Andersson .name = "ab8500-btemp", 1015bd9e8ab2SRajanikanth H.V .of_compatible = "stericsson,ab8500-btemp", 10166ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_btemp_resources), 10176ef9418cSRickard Andersson .resources = ab8500_btemp_resources, 1018bd9e8ab2SRajanikanth H.V .platform_data = &ab8500_bm_data, 1019bd9e8ab2SRajanikanth H.V .pdata_size = sizeof(ab8500_bm_data), 10206ef9418cSRickard Andersson }, 10216ef9418cSRickard Andersson { 10226ef9418cSRickard Andersson .name = "ab8500-fg", 1023e0f1abebSRajanikanth H.V .of_compatible = "stericsson,ab8500-fg", 10246ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_fg_resources), 10256ef9418cSRickard Andersson .resources = ab8500_fg_resources, 1026e0f1abebSRajanikanth H.V .platform_data = &ab8500_bm_data, 1027e0f1abebSRajanikanth H.V .pdata_size = sizeof(ab8500_bm_data), 10286ef9418cSRickard Andersson }, 10296ef9418cSRickard Andersson { 10306ef9418cSRickard Andersson .name = "ab8500-chargalg", 1031a12810abSRajanikanth H.V .of_compatible = "stericsson,ab8500-chargalg", 10326ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_chargalg_resources), 10336ef9418cSRickard Andersson .resources = ab8500_chargalg_resources, 1034a12810abSRajanikanth H.V .platform_data = &ab8500_bm_data, 1035a12810abSRajanikanth H.V .pdata_size = sizeof(ab8500_bm_data), 10366ef9418cSRickard Andersson }, 10376ef9418cSRickard Andersson }; 10386ef9418cSRickard Andersson 1039a9e9ce4cSBill Pemberton static struct mfd_cell ab8500_devs[] = { 1040*4b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 1041d6255529SLinus Walleij { 1042*4b106fb9SLee Jones .name = "ab8500-debug", 1043*4b106fb9SLee Jones .of_compatible = "stericsson,ab8500-debug", 1044*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_debug_resources), 1045*4b106fb9SLee Jones .resources = ab8500_debug_resources, 1046*4b106fb9SLee Jones }, 1047*4b106fb9SLee Jones #endif 1048*4b106fb9SLee Jones { 1049*4b106fb9SLee Jones .name = "ab8500-sysctrl", 1050*4b106fb9SLee Jones .of_compatible = "stericsson,ab8500-sysctrl", 1051*4b106fb9SLee Jones }, 1052*4b106fb9SLee Jones { 1053*4b106fb9SLee Jones .name = "ab8500-regulator", 1054*4b106fb9SLee Jones .of_compatible = "stericsson,ab8500-regulator", 1055*4b106fb9SLee Jones }, 1056*4b106fb9SLee Jones { 1057*4b106fb9SLee Jones .name = "abx500-clk", 1058*4b106fb9SLee Jones .of_compatible = "stericsson,abx500-clk", 1059*4b106fb9SLee Jones }, 1060*4b106fb9SLee Jones { 1061*4b106fb9SLee Jones .name = "ab8500-gpadc", 1062*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), 1063*4b106fb9SLee Jones .resources = ab8500_gpadc_resources, 1064*4b106fb9SLee Jones }, 1065*4b106fb9SLee Jones { 1066*4b106fb9SLee Jones .name = "ab8500-rtc", 1067*4b106fb9SLee Jones .of_compatible = "stericsson,ab8500-rtc", 1068*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_rtc_resources), 1069*4b106fb9SLee Jones .resources = ab8500_rtc_resources, 1070*4b106fb9SLee Jones }, 1071*4b106fb9SLee Jones { 1072*4b106fb9SLee Jones .name = "ab8500-acc-det", 1073*4b106fb9SLee Jones .of_compatible = "stericsson,ab8500-acc-det", 1074*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources), 1075*4b106fb9SLee Jones .resources = ab8500_av_acc_detect_resources, 1076*4b106fb9SLee Jones }, 1077*4b106fb9SLee Jones { 1078*4b106fb9SLee Jones 1079*4b106fb9SLee Jones .name = "ab8500-poweron-key", 1080*4b106fb9SLee Jones .of_compatible = "stericsson,ab8500-poweron-key", 1081*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), 1082*4b106fb9SLee Jones .resources = ab8500_poweronkey_db_resources, 1083*4b106fb9SLee Jones }, 1084*4b106fb9SLee Jones { 1085*4b106fb9SLee Jones .name = "ab8500-pwm", 1086*4b106fb9SLee Jones .of_compatible = "stericsson,ab8500-pwm", 1087*4b106fb9SLee Jones .id = 1, 1088*4b106fb9SLee Jones }, 1089*4b106fb9SLee Jones { 1090*4b106fb9SLee Jones .name = "ab8500-pwm", 1091*4b106fb9SLee Jones .of_compatible = "stericsson,ab8500-pwm", 1092*4b106fb9SLee Jones .id = 2, 1093*4b106fb9SLee Jones }, 1094*4b106fb9SLee Jones { 1095*4b106fb9SLee Jones .name = "ab8500-pwm", 1096*4b106fb9SLee Jones .of_compatible = "stericsson,ab8500-pwm", 1097*4b106fb9SLee Jones .id = 3, 1098*4b106fb9SLee Jones }, 1099*4b106fb9SLee Jones { 1100*4b106fb9SLee Jones .name = "ab8500-leds", 1101*4b106fb9SLee Jones .of_compatible = "stericsson,ab8500-leds", 1102*4b106fb9SLee Jones }, 1103*4b106fb9SLee Jones { 1104*4b106fb9SLee Jones .name = "ab8500-denc", 1105*4b106fb9SLee Jones .of_compatible = "stericsson,ab8500-denc", 1106*4b106fb9SLee Jones }, 1107*4b106fb9SLee Jones { 1108*4b106fb9SLee Jones .name = "ab8500-gpio", 1109bad76991SLee Jones .of_compatible = "stericsson,ab8500-gpio", 1110d6255529SLinus Walleij }, 1111d6255529SLinus Walleij { 1112*4b106fb9SLee Jones .name = "abx500-temp", 1113*4b106fb9SLee Jones .of_compatible = "stericsson,abx500-temp", 1114*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_temp_resources), 1115*4b106fb9SLee Jones .resources = ab8500_temp_resources, 1116*4b106fb9SLee Jones }, 1117*4b106fb9SLee Jones { 1118d6255529SLinus Walleij .name = "ab8500-usb", 1119d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab8500_usb_resources), 1120d6255529SLinus Walleij .resources = ab8500_usb_resources, 1121d6255529SLinus Walleij }, 112244f72e53SVirupax Sadashivpetimath { 112344f72e53SVirupax Sadashivpetimath .name = "ab8500-codec", 1124*4b106fb9SLee Jones }, 1125*4b106fb9SLee Jones }; 1126*4b106fb9SLee Jones 1127*4b106fb9SLee Jones static struct mfd_cell ab9540_devs[] = { 1128*4b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 1129*4b106fb9SLee Jones { 1130*4b106fb9SLee Jones .name = "ab8500-debug", 1131*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_debug_resources), 1132*4b106fb9SLee Jones .resources = ab8500_debug_resources, 1133*4b106fb9SLee Jones }, 1134*4b106fb9SLee Jones #endif 1135*4b106fb9SLee Jones { 1136*4b106fb9SLee Jones .name = "ab8500-sysctrl", 1137*4b106fb9SLee Jones }, 1138*4b106fb9SLee Jones { 1139*4b106fb9SLee Jones .name = "ab8500-regulator", 114044f72e53SVirupax Sadashivpetimath }, 1141c0eda9aeSLee Jones { 1142c0eda9aeSLee Jones .name = "ab8500-gpadc", 1143c0eda9aeSLee Jones .of_compatible = "stericsson,ab8500-gpadc", 1144c0eda9aeSLee Jones .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), 1145c0eda9aeSLee Jones .resources = ab8500_gpadc_resources, 1146c0eda9aeSLee Jones }, 1147*4b106fb9SLee Jones { 1148*4b106fb9SLee Jones .name = "ab8500-rtc", 1149*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_rtc_resources), 1150*4b106fb9SLee Jones .resources = ab8500_rtc_resources, 1151*4b106fb9SLee Jones }, 1152*4b106fb9SLee Jones { 1153*4b106fb9SLee Jones .name = "ab8500-acc-det", 1154*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources), 1155*4b106fb9SLee Jones .resources = ab8500_av_acc_detect_resources, 1156*4b106fb9SLee Jones }, 1157*4b106fb9SLee Jones { 1158*4b106fb9SLee Jones .name = "ab8500-poweron-key", 1159*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), 1160*4b106fb9SLee Jones .resources = ab8500_poweronkey_db_resources, 1161*4b106fb9SLee Jones }, 1162*4b106fb9SLee Jones { 1163*4b106fb9SLee Jones .name = "ab8500-pwm", 1164*4b106fb9SLee Jones .id = 1, 1165*4b106fb9SLee Jones }, 1166*4b106fb9SLee Jones { 1167*4b106fb9SLee Jones .name = "ab8500-leds", 1168*4b106fb9SLee Jones }, 1169*4b106fb9SLee Jones { 1170*4b106fb9SLee Jones .name = "abx500-temp", 1171*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_temp_resources), 1172*4b106fb9SLee Jones .resources = ab8500_temp_resources, 1173*4b106fb9SLee Jones }, 1174d6255529SLinus Walleij { 1175e64d905eSLee Jones .name = "pinctrl-ab9540", 1176e64d905eSLee Jones .of_compatible = "stericsson,ab9540-gpio", 1177d6255529SLinus Walleij }, 1178d6255529SLinus Walleij { 1179d6255529SLinus Walleij .name = "ab9540-usb", 1180d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab8500_usb_resources), 1181d6255529SLinus Walleij .resources = ab8500_usb_resources, 1182d6255529SLinus Walleij }, 118344f72e53SVirupax Sadashivpetimath { 118444f72e53SVirupax Sadashivpetimath .name = "ab9540-codec", 118544f72e53SVirupax Sadashivpetimath }, 1186c0eda9aeSLee Jones { 1187c0eda9aeSLee Jones .name = "ab-iddet", 1188c0eda9aeSLee Jones .num_resources = ARRAY_SIZE(ab8505_iddet_resources), 1189c0eda9aeSLee Jones .resources = ab8505_iddet_resources, 1190c0eda9aeSLee Jones }, 119144f72e53SVirupax Sadashivpetimath }; 119244f72e53SVirupax Sadashivpetimath 1193c0eda9aeSLee Jones /* Device list for ab8505 */ 1194c0eda9aeSLee Jones static struct mfd_cell ab8505_devs[] = { 1195*4b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 1196*4b106fb9SLee Jones { 1197*4b106fb9SLee Jones .name = "ab8500-debug", 1198*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_debug_resources), 1199*4b106fb9SLee Jones .resources = ab8500_debug_resources, 1200*4b106fb9SLee Jones }, 1201*4b106fb9SLee Jones #endif 1202*4b106fb9SLee Jones { 1203*4b106fb9SLee Jones .name = "ab8500-sysctrl", 1204*4b106fb9SLee Jones }, 1205*4b106fb9SLee Jones { 1206*4b106fb9SLee Jones .name = "ab8500-regulator", 1207*4b106fb9SLee Jones }, 1208*4b106fb9SLee Jones { 1209*4b106fb9SLee Jones .name = "ab8500-gpadc", 1210*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8505_gpadc_resources), 1211*4b106fb9SLee Jones .resources = ab8505_gpadc_resources, 1212*4b106fb9SLee Jones }, 1213*4b106fb9SLee Jones { 1214*4b106fb9SLee Jones .name = "ab8500-rtc", 1215*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_rtc_resources), 1216*4b106fb9SLee Jones .resources = ab8500_rtc_resources, 1217*4b106fb9SLee Jones }, 1218*4b106fb9SLee Jones { 1219*4b106fb9SLee Jones .name = "ab8500-acc-det", 1220*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources), 1221*4b106fb9SLee Jones .resources = ab8500_av_acc_detect_resources, 1222*4b106fb9SLee Jones }, 1223*4b106fb9SLee Jones { 1224*4b106fb9SLee Jones .name = "ab8500-poweron-key", 1225*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), 1226*4b106fb9SLee Jones .resources = ab8500_poweronkey_db_resources, 1227*4b106fb9SLee Jones }, 1228*4b106fb9SLee Jones { 1229*4b106fb9SLee Jones .name = "ab8500-pwm", 1230*4b106fb9SLee Jones .id = 1, 1231*4b106fb9SLee Jones }, 1232*4b106fb9SLee Jones { 1233*4b106fb9SLee Jones .name = "ab8500-leds", 1234*4b106fb9SLee Jones }, 1235*4b106fb9SLee Jones { 1236*4b106fb9SLee Jones .name = "ab8500-gpio", 1237*4b106fb9SLee Jones }, 1238*4b106fb9SLee Jones { 1239*4b106fb9SLee Jones .name = "ab8500-usb", 1240*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_usb_resources), 1241*4b106fb9SLee Jones .resources = ab8500_usb_resources, 1242*4b106fb9SLee Jones }, 1243*4b106fb9SLee Jones { 1244*4b106fb9SLee Jones .name = "ab8500-codec", 1245*4b106fb9SLee Jones }, 1246c0eda9aeSLee Jones { 1247c0eda9aeSLee Jones .name = "ab-iddet", 1248c0eda9aeSLee Jones .num_resources = ARRAY_SIZE(ab8505_iddet_resources), 1249c0eda9aeSLee Jones .resources = ab8505_iddet_resources, 1250c0eda9aeSLee Jones }, 1251c0eda9aeSLee Jones }; 1252c0eda9aeSLee Jones 1253c0eda9aeSLee Jones static struct mfd_cell ab8540_devs[] = { 1254*4b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 1255*4b106fb9SLee Jones { 1256*4b106fb9SLee Jones .name = "ab8500-debug", 1257*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_debug_resources), 1258*4b106fb9SLee Jones .resources = ab8500_debug_resources, 1259*4b106fb9SLee Jones }, 1260*4b106fb9SLee Jones #endif 1261*4b106fb9SLee Jones { 1262*4b106fb9SLee Jones .name = "ab8500-sysctrl", 1263*4b106fb9SLee Jones }, 1264*4b106fb9SLee Jones { 1265*4b106fb9SLee Jones .name = "ab8500-regulator", 1266*4b106fb9SLee Jones }, 1267*4b106fb9SLee Jones { 1268*4b106fb9SLee Jones .name = "ab8500-gpadc", 1269*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8505_gpadc_resources), 1270*4b106fb9SLee Jones .resources = ab8505_gpadc_resources, 1271*4b106fb9SLee Jones }, 1272*4b106fb9SLee Jones { 1273*4b106fb9SLee Jones .name = "ab8500-rtc", 1274*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_rtc_resources), 1275*4b106fb9SLee Jones .resources = ab8500_rtc_resources, 1276*4b106fb9SLee Jones }, 1277*4b106fb9SLee Jones { 1278*4b106fb9SLee Jones .name = "ab8500-acc-det", 1279*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources), 1280*4b106fb9SLee Jones .resources = ab8500_av_acc_detect_resources, 1281*4b106fb9SLee Jones }, 1282*4b106fb9SLee Jones { 1283*4b106fb9SLee Jones .name = "ab8500-poweron-key", 1284*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), 1285*4b106fb9SLee Jones .resources = ab8500_poweronkey_db_resources, 1286*4b106fb9SLee Jones }, 1287*4b106fb9SLee Jones { 1288*4b106fb9SLee Jones .name = "ab8500-pwm", 1289*4b106fb9SLee Jones .id = 1, 1290*4b106fb9SLee Jones }, 1291*4b106fb9SLee Jones { 1292*4b106fb9SLee Jones .name = "ab8500-leds", 1293*4b106fb9SLee Jones }, 1294*4b106fb9SLee Jones { 1295*4b106fb9SLee Jones .name = "abx500-temp", 1296*4b106fb9SLee Jones .num_resources = ARRAY_SIZE(ab8500_temp_resources), 1297*4b106fb9SLee Jones .resources = ab8500_temp_resources, 1298*4b106fb9SLee Jones }, 1299c0eda9aeSLee Jones { 1300c0eda9aeSLee Jones .name = "ab8500-gpio", 1301c0eda9aeSLee Jones }, 1302c0eda9aeSLee Jones { 1303c0eda9aeSLee Jones .name = "ab8540-usb", 1304c0eda9aeSLee Jones .num_resources = ARRAY_SIZE(ab8500_usb_resources), 1305c0eda9aeSLee Jones .resources = ab8500_usb_resources, 1306c0eda9aeSLee Jones }, 1307c0eda9aeSLee Jones { 1308c0eda9aeSLee Jones .name = "ab8540-codec", 1309c0eda9aeSLee Jones }, 1310c0eda9aeSLee Jones { 131144f72e53SVirupax Sadashivpetimath .name = "ab-iddet", 131244f72e53SVirupax Sadashivpetimath .num_resources = ARRAY_SIZE(ab8505_iddet_resources), 131344f72e53SVirupax Sadashivpetimath .resources = ab8505_iddet_resources, 131444f72e53SVirupax Sadashivpetimath }, 1315d6255529SLinus Walleij }; 1316d6255529SLinus Walleij 1317cca69b67SMattias Wallin static ssize_t show_chip_id(struct device *dev, 1318cca69b67SMattias Wallin struct device_attribute *attr, char *buf) 1319cca69b67SMattias Wallin { 1320cca69b67SMattias Wallin struct ab8500 *ab8500; 1321cca69b67SMattias Wallin 1322cca69b67SMattias Wallin ab8500 = dev_get_drvdata(dev); 1323cca69b67SMattias Wallin return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); 1324cca69b67SMattias Wallin } 1325cca69b67SMattias Wallin 1326e5c238c3SMattias Wallin /* 1327e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 1328e5c238c3SMattias Wallin * 0x01 Swoff bit programming 1329e5c238c3SMattias Wallin * 0x02 Thermal protection activation 1330e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 1331e5c238c3SMattias Wallin * 0x08 Watchdog expired 1332e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 1333e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 1334e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 1335e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 1336e5c238c3SMattias Wallin */ 1337e5c238c3SMattias Wallin static ssize_t show_switch_off_status(struct device *dev, 1338e5c238c3SMattias Wallin struct device_attribute *attr, char *buf) 1339e5c238c3SMattias Wallin { 1340e5c238c3SMattias Wallin int ret; 1341e5c238c3SMattias Wallin u8 value; 1342e5c238c3SMattias Wallin struct ab8500 *ab8500; 1343e5c238c3SMattias Wallin 1344e5c238c3SMattias Wallin ab8500 = dev_get_drvdata(dev); 1345e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 1346e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 1347e5c238c3SMattias Wallin if (ret < 0) 1348e5c238c3SMattias Wallin return ret; 1349e5c238c3SMattias Wallin return sprintf(buf, "%#x\n", value); 1350e5c238c3SMattias Wallin } 1351e5c238c3SMattias Wallin 1352f04a9d8aSRajkumar Kasirajan /* use mask and set to override the register turn_on_stat value */ 1353f04a9d8aSRajkumar Kasirajan void ab8500_override_turn_on_stat(u8 mask, u8 set) 1354f04a9d8aSRajkumar Kasirajan { 1355f04a9d8aSRajkumar Kasirajan spin_lock(&on_stat_lock); 1356f04a9d8aSRajkumar Kasirajan turn_on_stat_mask = mask; 1357f04a9d8aSRajkumar Kasirajan turn_on_stat_set = set; 1358f04a9d8aSRajkumar Kasirajan spin_unlock(&on_stat_lock); 1359f04a9d8aSRajkumar Kasirajan } 1360f04a9d8aSRajkumar Kasirajan 1361b4a31037SAndrew Lynn /* 1362b4a31037SAndrew Lynn * ab8500 has turned on due to (TURN_ON_STATUS): 1363b4a31037SAndrew Lynn * 0x01 PORnVbat 1364b4a31037SAndrew Lynn * 0x02 PonKey1dbF 1365b4a31037SAndrew Lynn * 0x04 PonKey2dbF 1366b4a31037SAndrew Lynn * 0x08 RTCAlarm 1367b4a31037SAndrew Lynn * 0x10 MainChDet 1368b4a31037SAndrew Lynn * 0x20 VbusDet 1369b4a31037SAndrew Lynn * 0x40 UsbIDDetect 1370b4a31037SAndrew Lynn * 0x80 Reserved 1371b4a31037SAndrew Lynn */ 1372b4a31037SAndrew Lynn static ssize_t show_turn_on_status(struct device *dev, 1373b4a31037SAndrew Lynn struct device_attribute *attr, char *buf) 1374b4a31037SAndrew Lynn { 1375b4a31037SAndrew Lynn int ret; 1376b4a31037SAndrew Lynn u8 value; 1377b4a31037SAndrew Lynn struct ab8500 *ab8500; 1378b4a31037SAndrew Lynn 1379b4a31037SAndrew Lynn ab8500 = dev_get_drvdata(dev); 1380b4a31037SAndrew Lynn ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 1381b4a31037SAndrew Lynn AB8500_TURN_ON_STATUS, &value); 1382b4a31037SAndrew Lynn if (ret < 0) 1383b4a31037SAndrew Lynn return ret; 1384f04a9d8aSRajkumar Kasirajan 1385f04a9d8aSRajkumar Kasirajan /* 1386f04a9d8aSRajkumar Kasirajan * In L9540, turn_on_status register is not updated correctly if 1387f04a9d8aSRajkumar Kasirajan * the device is rebooted with AC/USB charger connected. Due to 1388f04a9d8aSRajkumar Kasirajan * this, the device boots android instead of entering into charge 1389f04a9d8aSRajkumar Kasirajan * only mode. Read the AC/USB status register to detect the charger 1390f04a9d8aSRajkumar Kasirajan * presence and update the turn on status manually. 1391f04a9d8aSRajkumar Kasirajan */ 1392f04a9d8aSRajkumar Kasirajan if (is_ab9540(ab8500)) { 1393f04a9d8aSRajkumar Kasirajan spin_lock(&on_stat_lock); 1394f04a9d8aSRajkumar Kasirajan value = (value & turn_on_stat_mask) | turn_on_stat_set; 1395f04a9d8aSRajkumar Kasirajan spin_unlock(&on_stat_lock); 1396f04a9d8aSRajkumar Kasirajan } 1397f04a9d8aSRajkumar Kasirajan 1398b4a31037SAndrew Lynn return sprintf(buf, "%#x\n", value); 1399b4a31037SAndrew Lynn } 1400b4a31037SAndrew Lynn 1401d6255529SLinus Walleij static ssize_t show_ab9540_dbbrstn(struct device *dev, 1402d6255529SLinus Walleij struct device_attribute *attr, char *buf) 1403d6255529SLinus Walleij { 1404d6255529SLinus Walleij struct ab8500 *ab8500; 1405d6255529SLinus Walleij int ret; 1406d6255529SLinus Walleij u8 value; 1407d6255529SLinus Walleij 1408d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 1409d6255529SLinus Walleij 1410d6255529SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2, 1411d6255529SLinus Walleij AB9540_MODEM_CTRL2_REG, &value); 1412d6255529SLinus Walleij if (ret < 0) 1413d6255529SLinus Walleij return ret; 1414d6255529SLinus Walleij 1415d6255529SLinus Walleij return sprintf(buf, "%d\n", 1416d6255529SLinus Walleij (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0); 1417d6255529SLinus Walleij } 1418d6255529SLinus Walleij 1419d6255529SLinus Walleij static ssize_t store_ab9540_dbbrstn(struct device *dev, 1420d6255529SLinus Walleij struct device_attribute *attr, const char *buf, size_t count) 1421d6255529SLinus Walleij { 1422d6255529SLinus Walleij struct ab8500 *ab8500; 1423d6255529SLinus Walleij int ret = count; 1424d6255529SLinus Walleij int err; 1425d6255529SLinus Walleij u8 bitvalues; 1426d6255529SLinus Walleij 1427d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 1428d6255529SLinus Walleij 1429d6255529SLinus Walleij if (count > 0) { 1430d6255529SLinus Walleij switch (buf[0]) { 1431d6255529SLinus Walleij case '0': 1432d6255529SLinus Walleij bitvalues = 0; 1433d6255529SLinus Walleij break; 1434d6255529SLinus Walleij case '1': 1435d6255529SLinus Walleij bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT; 1436d6255529SLinus Walleij break; 1437d6255529SLinus Walleij default: 1438d6255529SLinus Walleij goto exit; 1439d6255529SLinus Walleij } 1440d6255529SLinus Walleij 1441d6255529SLinus Walleij err = mask_and_set_register_interruptible(ab8500, 1442d6255529SLinus Walleij AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG, 1443d6255529SLinus Walleij AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues); 1444d6255529SLinus Walleij if (err) 1445d6255529SLinus Walleij dev_info(ab8500->dev, 1446d6255529SLinus Walleij "Failed to set DBBRSTN %c, err %#x\n", 1447d6255529SLinus Walleij buf[0], err); 1448d6255529SLinus Walleij } 1449d6255529SLinus Walleij 1450d6255529SLinus Walleij exit: 1451d6255529SLinus Walleij return ret; 1452d6255529SLinus Walleij } 1453d6255529SLinus Walleij 1454cca69b67SMattias Wallin static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); 1455e5c238c3SMattias Wallin static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL); 1456b4a31037SAndrew Lynn static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL); 1457d6255529SLinus Walleij static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR, 1458d6255529SLinus Walleij show_ab9540_dbbrstn, store_ab9540_dbbrstn); 1459cca69b67SMattias Wallin 1460cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = { 1461cca69b67SMattias Wallin &dev_attr_chip_id.attr, 1462e5c238c3SMattias Wallin &dev_attr_switch_off_status.attr, 1463b4a31037SAndrew Lynn &dev_attr_turn_on_status.attr, 1464cca69b67SMattias Wallin NULL, 1465cca69b67SMattias Wallin }; 1466cca69b67SMattias Wallin 1467d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = { 1468d6255529SLinus Walleij &dev_attr_chip_id.attr, 1469d6255529SLinus Walleij &dev_attr_switch_off_status.attr, 1470d6255529SLinus Walleij &dev_attr_turn_on_status.attr, 1471d6255529SLinus Walleij &dev_attr_dbbrstn.attr, 1472d6255529SLinus Walleij NULL, 1473d6255529SLinus Walleij }; 1474d6255529SLinus Walleij 1475cca69b67SMattias Wallin static struct attribute_group ab8500_attr_group = { 1476cca69b67SMattias Wallin .attrs = ab8500_sysfs_entries, 1477cca69b67SMattias Wallin }; 1478cca69b67SMattias Wallin 1479d6255529SLinus Walleij static struct attribute_group ab9540_attr_group = { 1480d6255529SLinus Walleij .attrs = ab9540_sysfs_entries, 1481d6255529SLinus Walleij }; 1482d6255529SLinus Walleij 1483f791be49SBill Pemberton static int ab8500_probe(struct platform_device *pdev) 148462579266SRabin Vincent { 1485b04c530cSJonas Aaberg static char *switch_off_status[] = { 1486b04c530cSJonas Aaberg "Swoff bit programming", 1487b04c530cSJonas Aaberg "Thermal protection activation", 1488b04c530cSJonas Aaberg "Vbat lower then BattOk falling threshold", 1489b04c530cSJonas Aaberg "Watchdog expired", 1490b04c530cSJonas Aaberg "Non presence of 32kHz clock", 1491b04c530cSJonas Aaberg "Battery level lower than power on reset threshold", 1492b04c530cSJonas Aaberg "Power on key 1 pressed longer than 10 seconds", 1493b04c530cSJonas Aaberg "DB8500 thermal shutdown"}; 1494d28f1db8SLee Jones struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev); 1495d28f1db8SLee Jones const struct platform_device_id *platid = platform_get_device_id(pdev); 14966bc4a568SLee Jones enum ab8500_version version = AB8500_VERSION_UNDEFINED; 14976bc4a568SLee Jones struct device_node *np = pdev->dev.of_node; 1498d28f1db8SLee Jones struct ab8500 *ab8500; 1499d28f1db8SLee Jones struct resource *resource; 150062579266SRabin Vincent int ret; 150162579266SRabin Vincent int i; 150247c16975SMattias Wallin u8 value; 150362579266SRabin Vincent 15048c4203cbSLee Jones ab8500 = devm_kzalloc(&pdev->dev, sizeof *ab8500, GFP_KERNEL); 1505d28f1db8SLee Jones if (!ab8500) 1506d28f1db8SLee Jones return -ENOMEM; 1507d28f1db8SLee Jones 150862579266SRabin Vincent if (plat) 150962579266SRabin Vincent ab8500->irq_base = plat->irq_base; 151062579266SRabin Vincent 1511d28f1db8SLee Jones ab8500->dev = &pdev->dev; 1512d28f1db8SLee Jones 1513d28f1db8SLee Jones resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 15148c4203cbSLee Jones if (!resource) 15158c4203cbSLee Jones return -ENODEV; 1516d28f1db8SLee Jones 1517d28f1db8SLee Jones ab8500->irq = resource->start; 1518d28f1db8SLee Jones 1519822672a7SLee Jones ab8500->read = ab8500_prcmu_read; 1520822672a7SLee Jones ab8500->write = ab8500_prcmu_write; 1521822672a7SLee Jones ab8500->write_masked = ab8500_prcmu_write_masked; 1522d28f1db8SLee Jones 152362579266SRabin Vincent mutex_init(&ab8500->lock); 152462579266SRabin Vincent mutex_init(&ab8500->irq_lock); 1525112a80d2SJonas Aaberg atomic_set(&ab8500->transfer_ongoing, 0); 152662579266SRabin Vincent 1527d28f1db8SLee Jones platform_set_drvdata(pdev, ab8500); 1528d28f1db8SLee Jones 15296bc4a568SLee Jones if (platid) 15306bc4a568SLee Jones version = platid->driver_data; 15316bc4a568SLee Jones 15320f620837SLinus Walleij if (version != AB8500_VERSION_UNDEFINED) 15330f620837SLinus Walleij ab8500->version = version; 15340f620837SLinus Walleij else { 15350f620837SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_MISC, 15360f620837SLinus Walleij AB8500_IC_NAME_REG, &value); 15370f620837SLinus Walleij if (ret < 0) 15388c4203cbSLee Jones return ret; 15390f620837SLinus Walleij 15400f620837SLinus Walleij ab8500->version = value; 15410f620837SLinus Walleij } 15420f620837SLinus Walleij 154347c16975SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_MISC, 154447c16975SMattias Wallin AB8500_REV_REG, &value); 154562579266SRabin Vincent if (ret < 0) 15468c4203cbSLee Jones return ret; 154762579266SRabin Vincent 154847c16975SMattias Wallin ab8500->chip_id = value; 154962579266SRabin Vincent 15500f620837SLinus Walleij dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n", 15510f620837SLinus Walleij ab8500_version_str[ab8500->version], 15520f620837SLinus Walleij ab8500->chip_id >> 4, 15530f620837SLinus Walleij ab8500->chip_id & 0x0F); 15540f620837SLinus Walleij 1555d6255529SLinus Walleij /* Configure AB8500 or AB9540 IRQ */ 1556a982362cSBengt Jonsson if (is_ab9540(ab8500) || is_ab8505(ab8500)) { 1557d6255529SLinus Walleij ab8500->mask_size = AB9540_NUM_IRQ_REGS; 1558d6255529SLinus Walleij ab8500->irq_reg_offset = ab9540_irq_regoffset; 1559d6255529SLinus Walleij } else { 15602ced445eSLinus Walleij ab8500->mask_size = AB8500_NUM_IRQ_REGS; 15612ced445eSLinus Walleij ab8500->irq_reg_offset = ab8500_irq_regoffset; 1562d6255529SLinus Walleij } 15638c4203cbSLee Jones ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size, GFP_KERNEL); 15642ced445eSLinus Walleij if (!ab8500->mask) 15652ced445eSLinus Walleij return -ENOMEM; 15668c4203cbSLee Jones ab8500->oldmask = devm_kzalloc(&pdev->dev, ab8500->mask_size, GFP_KERNEL); 15678c4203cbSLee Jones if (!ab8500->oldmask) 15688c4203cbSLee Jones return -ENOMEM; 15698c4203cbSLee Jones 1570e5c238c3SMattias Wallin /* 1571e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 1572e5c238c3SMattias Wallin * 0x01 Swoff bit programming 1573e5c238c3SMattias Wallin * 0x02 Thermal protection activation 1574e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 1575e5c238c3SMattias Wallin * 0x08 Watchdog expired 1576e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 1577e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 1578e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 1579e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 1580e5c238c3SMattias Wallin */ 1581e5c238c3SMattias Wallin 1582e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 1583e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 1584e5c238c3SMattias Wallin if (ret < 0) 1585e5c238c3SMattias Wallin return ret; 1586b04c530cSJonas Aaberg dev_info(ab8500->dev, "switch off cause(s) (%#x): ", value); 1587b04c530cSJonas Aaberg 1588b04c530cSJonas Aaberg if (value) { 1589b04c530cSJonas Aaberg for (i = 0; i < ARRAY_SIZE(switch_off_status); i++) { 1590b04c530cSJonas Aaberg if (value & 1) 1591b04c530cSJonas Aaberg printk(KERN_CONT " \"%s\"", 1592b04c530cSJonas Aaberg switch_off_status[i]); 1593b04c530cSJonas Aaberg value = value >> 1; 1594b04c530cSJonas Aaberg 1595b04c530cSJonas Aaberg } 1596b04c530cSJonas Aaberg printk(KERN_CONT "\n"); 1597b04c530cSJonas Aaberg } else { 1598b04c530cSJonas Aaberg printk(KERN_CONT " None\n"); 1599b04c530cSJonas Aaberg } 1600e5c238c3SMattias Wallin 160162579266SRabin Vincent if (plat && plat->init) 160262579266SRabin Vincent plat->init(ab8500); 1603f04a9d8aSRajkumar Kasirajan if (is_ab9540(ab8500)) { 1604f04a9d8aSRajkumar Kasirajan ret = get_register_interruptible(ab8500, AB8500_CHARGER, 1605f04a9d8aSRajkumar Kasirajan AB8500_CH_USBCH_STAT1_REG, &value); 1606f04a9d8aSRajkumar Kasirajan if (ret < 0) 1607f04a9d8aSRajkumar Kasirajan return ret; 1608f04a9d8aSRajkumar Kasirajan if ((value & VBUS_DET_DBNC1) && (value & VBUS_DET_DBNC100)) 1609f04a9d8aSRajkumar Kasirajan ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON, 1610f04a9d8aSRajkumar Kasirajan AB8500_VBUS_DET); 1611f04a9d8aSRajkumar Kasirajan } 161262579266SRabin Vincent 161362579266SRabin Vincent /* Clear and mask all interrupts */ 16142ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 16150f620837SLinus Walleij /* 16160f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 16170f620837SLinus Walleij * 2.0 16180f620837SLinus Walleij */ 16190f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 16200f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 162192d50a41SMattias Wallin continue; 162262579266SRabin Vincent 162347c16975SMattias Wallin get_register_interruptible(ab8500, AB8500_INTERRUPT, 16242ced445eSLinus Walleij AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i], 162592d50a41SMattias Wallin &value); 162647c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, 16272ced445eSLinus Walleij AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff); 162862579266SRabin Vincent } 162962579266SRabin Vincent 163047c16975SMattias Wallin ret = abx500_register_ops(ab8500->dev, &ab8500_ops); 163147c16975SMattias Wallin if (ret) 16328c4203cbSLee Jones return ret; 163347c16975SMattias Wallin 16342ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) 163562579266SRabin Vincent ab8500->mask[i] = ab8500->oldmask[i] = 0xff; 163662579266SRabin Vincent 163706e589efSLee Jones ret = ab8500_irq_init(ab8500, np); 163862579266SRabin Vincent if (ret) 16398c4203cbSLee Jones return ret; 164062579266SRabin Vincent 16417ccfe9b1SMichel JAOUEN /* Activate this feature only in ab9540 */ 16427ccfe9b1SMichel JAOUEN /* till tests are done on ab8500 1p2 or later*/ 164306e589efSLee Jones if (is_ab9540(ab8500)) { 16448c4203cbSLee Jones ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL, 16457ccfe9b1SMichel JAOUEN ab8500_hierarchical_irq, 16467ccfe9b1SMichel JAOUEN IRQF_ONESHOT | IRQF_NO_SUSPEND, 16477ccfe9b1SMichel JAOUEN "ab8500", ab8500); 164806e589efSLee Jones } 164906e589efSLee Jones else { 16508c4203cbSLee Jones ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL, 16517ccfe9b1SMichel JAOUEN ab8500_irq, 16524f079985SMattias Wallin IRQF_ONESHOT | IRQF_NO_SUSPEND, 16534f079985SMattias Wallin "ab8500", ab8500); 165462579266SRabin Vincent if (ret) 16558c4203cbSLee Jones return ret; 165662579266SRabin Vincent } 165762579266SRabin Vincent 1658d6255529SLinus Walleij if (is_ab9540(ab8500)) 1659d6255529SLinus Walleij ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, 1660d6255529SLinus Walleij ARRAY_SIZE(ab9540_devs), NULL, 166155692af5SMark Brown ab8500->irq_base, ab8500->domain); 1662c0eda9aeSLee Jones else if (is_ab8540(ab8500)) 1663c0eda9aeSLee Jones ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs, 1664c0eda9aeSLee Jones ARRAY_SIZE(ab8540_devs), NULL, 1665c0eda9aeSLee Jones ab8500->irq_base, ab8500->domain); 1666c0eda9aeSLee Jones else if (is_ab8505(ab8500)) 1667c0eda9aeSLee Jones ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs, 1668c0eda9aeSLee Jones ARRAY_SIZE(ab8505_devs), NULL, 1669c0eda9aeSLee Jones ab8500->irq_base, ab8500->domain); 1670d6255529SLinus Walleij else 1671549931f9SSundar R Iyer ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, 167244f72e53SVirupax Sadashivpetimath ARRAY_SIZE(ab8500_devs), NULL, 167355692af5SMark Brown ab8500->irq_base, ab8500->domain); 16746bc4a568SLee Jones if (ret) 16758c4203cbSLee Jones return ret; 167644f72e53SVirupax Sadashivpetimath 16776ef9418cSRickard Andersson if (!no_bm) { 16786ef9418cSRickard Andersson /* Add battery management devices */ 16796ef9418cSRickard Andersson ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, 16806ef9418cSRickard Andersson ARRAY_SIZE(ab8500_bm_devs), NULL, 168155692af5SMark Brown ab8500->irq_base, ab8500->domain); 16826ef9418cSRickard Andersson if (ret) 16836ef9418cSRickard Andersson dev_err(ab8500->dev, "error adding bm devices\n"); 16846ef9418cSRickard Andersson } 16856ef9418cSRickard Andersson 1686d6255529SLinus Walleij if (is_ab9540(ab8500)) 1687d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1688d6255529SLinus Walleij &ab9540_attr_group); 1689d6255529SLinus Walleij else 1690d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1691d6255529SLinus Walleij &ab8500_attr_group); 1692cca69b67SMattias Wallin if (ret) 1693cca69b67SMattias Wallin dev_err(ab8500->dev, "error creating sysfs entries\n"); 169406e589efSLee Jones 169562579266SRabin Vincent return ret; 169662579266SRabin Vincent } 169762579266SRabin Vincent 16984740f73fSBill Pemberton static int ab8500_remove(struct platform_device *pdev) 169962579266SRabin Vincent { 1700d28f1db8SLee Jones struct ab8500 *ab8500 = platform_get_drvdata(pdev); 1701d28f1db8SLee Jones 1702d6255529SLinus Walleij if (is_ab9540(ab8500)) 1703d6255529SLinus Walleij sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group); 1704d6255529SLinus Walleij else 1705cca69b67SMattias Wallin sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group); 170606e589efSLee Jones 170762579266SRabin Vincent mfd_remove_devices(ab8500->dev); 170862579266SRabin Vincent 170962579266SRabin Vincent return 0; 171062579266SRabin Vincent } 171162579266SRabin Vincent 1712d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = { 1713d28f1db8SLee Jones { "ab8500-core", AB8500_VERSION_AB8500 }, 1714d28f1db8SLee Jones { "ab8505-i2c", AB8500_VERSION_AB8505 }, 1715d28f1db8SLee Jones { "ab9540-i2c", AB8500_VERSION_AB9540 }, 1716d28f1db8SLee Jones { "ab8540-i2c", AB8500_VERSION_AB8540 }, 1717d28f1db8SLee Jones { } 1718d28f1db8SLee Jones }; 1719d28f1db8SLee Jones 1720d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = { 1721d28f1db8SLee Jones .driver = { 1722d28f1db8SLee Jones .name = "ab8500-core", 1723d28f1db8SLee Jones .owner = THIS_MODULE, 1724d28f1db8SLee Jones }, 1725d28f1db8SLee Jones .probe = ab8500_probe, 172684449216SBill Pemberton .remove = ab8500_remove, 1727d28f1db8SLee Jones .id_table = ab8500_id, 1728d28f1db8SLee Jones }; 1729d28f1db8SLee Jones 1730d28f1db8SLee Jones static int __init ab8500_core_init(void) 1731d28f1db8SLee Jones { 1732d28f1db8SLee Jones return platform_driver_register(&ab8500_core_driver); 1733d28f1db8SLee Jones } 1734d28f1db8SLee Jones 1735d28f1db8SLee Jones static void __exit ab8500_core_exit(void) 1736d28f1db8SLee Jones { 1737d28f1db8SLee Jones platform_driver_unregister(&ab8500_core_driver); 1738d28f1db8SLee Jones } 1739ba7cbc3eSLee Jones core_initcall(ab8500_core_init); 1740d28f1db8SLee Jones module_exit(ab8500_core_exit); 1741d28f1db8SLee Jones 1742adceed62SMattias Wallin MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent"); 174362579266SRabin Vincent MODULE_DESCRIPTION("AB8500 MFD core"); 174462579266SRabin Vincent MODULE_LICENSE("GPL v2"); 1745