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> 22d28f1db8SLee Jones #include <linux/mfd/dbx500-prcmu.h> 23549931f9SSundar R Iyer #include <linux/regulator/ab8500.h> 246bc4a568SLee Jones #include <linux/of.h> 256bc4a568SLee Jones #include <linux/of_device.h> 2662579266SRabin Vincent 2762579266SRabin Vincent /* 2862579266SRabin Vincent * Interrupt register offsets 2962579266SRabin Vincent * Bank : 0x0E 3062579266SRabin Vincent */ 3147c16975SMattias Wallin #define AB8500_IT_SOURCE1_REG 0x00 3247c16975SMattias Wallin #define AB8500_IT_SOURCE2_REG 0x01 3347c16975SMattias Wallin #define AB8500_IT_SOURCE3_REG 0x02 3447c16975SMattias Wallin #define AB8500_IT_SOURCE4_REG 0x03 3547c16975SMattias Wallin #define AB8500_IT_SOURCE5_REG 0x04 3647c16975SMattias Wallin #define AB8500_IT_SOURCE6_REG 0x05 3747c16975SMattias Wallin #define AB8500_IT_SOURCE7_REG 0x06 3847c16975SMattias Wallin #define AB8500_IT_SOURCE8_REG 0x07 39d6255529SLinus Walleij #define AB9540_IT_SOURCE13_REG 0x0C 4047c16975SMattias Wallin #define AB8500_IT_SOURCE19_REG 0x12 4147c16975SMattias Wallin #define AB8500_IT_SOURCE20_REG 0x13 4247c16975SMattias Wallin #define AB8500_IT_SOURCE21_REG 0x14 4347c16975SMattias Wallin #define AB8500_IT_SOURCE22_REG 0x15 4447c16975SMattias Wallin #define AB8500_IT_SOURCE23_REG 0x16 4547c16975SMattias Wallin #define AB8500_IT_SOURCE24_REG 0x17 4662579266SRabin Vincent 4762579266SRabin Vincent /* 4862579266SRabin Vincent * latch registers 4962579266SRabin Vincent */ 5047c16975SMattias Wallin #define AB8500_IT_LATCH1_REG 0x20 5147c16975SMattias Wallin #define AB8500_IT_LATCH2_REG 0x21 5247c16975SMattias Wallin #define AB8500_IT_LATCH3_REG 0x22 5347c16975SMattias Wallin #define AB8500_IT_LATCH4_REG 0x23 5447c16975SMattias Wallin #define AB8500_IT_LATCH5_REG 0x24 5547c16975SMattias Wallin #define AB8500_IT_LATCH6_REG 0x25 5647c16975SMattias Wallin #define AB8500_IT_LATCH7_REG 0x26 5747c16975SMattias Wallin #define AB8500_IT_LATCH8_REG 0x27 5847c16975SMattias Wallin #define AB8500_IT_LATCH9_REG 0x28 5947c16975SMattias Wallin #define AB8500_IT_LATCH10_REG 0x29 6092d50a41SMattias Wallin #define AB8500_IT_LATCH12_REG 0x2B 61d6255529SLinus Walleij #define AB9540_IT_LATCH13_REG 0x2C 6247c16975SMattias Wallin #define AB8500_IT_LATCH19_REG 0x32 6347c16975SMattias Wallin #define AB8500_IT_LATCH20_REG 0x33 6447c16975SMattias Wallin #define AB8500_IT_LATCH21_REG 0x34 6547c16975SMattias Wallin #define AB8500_IT_LATCH22_REG 0x35 6647c16975SMattias Wallin #define AB8500_IT_LATCH23_REG 0x36 6747c16975SMattias Wallin #define AB8500_IT_LATCH24_REG 0x37 6862579266SRabin Vincent 6962579266SRabin Vincent /* 7062579266SRabin Vincent * mask registers 7162579266SRabin Vincent */ 7262579266SRabin Vincent 7347c16975SMattias Wallin #define AB8500_IT_MASK1_REG 0x40 7447c16975SMattias Wallin #define AB8500_IT_MASK2_REG 0x41 7547c16975SMattias Wallin #define AB8500_IT_MASK3_REG 0x42 7647c16975SMattias Wallin #define AB8500_IT_MASK4_REG 0x43 7747c16975SMattias Wallin #define AB8500_IT_MASK5_REG 0x44 7847c16975SMattias Wallin #define AB8500_IT_MASK6_REG 0x45 7947c16975SMattias Wallin #define AB8500_IT_MASK7_REG 0x46 8047c16975SMattias Wallin #define AB8500_IT_MASK8_REG 0x47 8147c16975SMattias Wallin #define AB8500_IT_MASK9_REG 0x48 8247c16975SMattias Wallin #define AB8500_IT_MASK10_REG 0x49 8347c16975SMattias Wallin #define AB8500_IT_MASK11_REG 0x4A 8447c16975SMattias Wallin #define AB8500_IT_MASK12_REG 0x4B 8547c16975SMattias Wallin #define AB8500_IT_MASK13_REG 0x4C 8647c16975SMattias Wallin #define AB8500_IT_MASK14_REG 0x4D 8747c16975SMattias Wallin #define AB8500_IT_MASK15_REG 0x4E 8847c16975SMattias Wallin #define AB8500_IT_MASK16_REG 0x4F 8947c16975SMattias Wallin #define AB8500_IT_MASK17_REG 0x50 9047c16975SMattias Wallin #define AB8500_IT_MASK18_REG 0x51 9147c16975SMattias Wallin #define AB8500_IT_MASK19_REG 0x52 9247c16975SMattias Wallin #define AB8500_IT_MASK20_REG 0x53 9347c16975SMattias Wallin #define AB8500_IT_MASK21_REG 0x54 9447c16975SMattias Wallin #define AB8500_IT_MASK22_REG 0x55 9547c16975SMattias Wallin #define AB8500_IT_MASK23_REG 0x56 9647c16975SMattias Wallin #define AB8500_IT_MASK24_REG 0x57 9762579266SRabin Vincent 987ccfe9b1SMichel JAOUEN /* 997ccfe9b1SMichel JAOUEN * latch hierarchy registers 1007ccfe9b1SMichel JAOUEN */ 1017ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER1_REG 0x60 1027ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER2_REG 0x61 1037ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER3_REG 0x62 1047ccfe9b1SMichel JAOUEN 1057ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER_NUM 3 1067ccfe9b1SMichel JAOUEN 10747c16975SMattias Wallin #define AB8500_REV_REG 0x80 1080f620837SLinus Walleij #define AB8500_IC_NAME_REG 0x82 109e5c238c3SMattias Wallin #define AB8500_SWITCH_OFF_STATUS 0x00 11062579266SRabin Vincent 111b4a31037SAndrew Lynn #define AB8500_TURN_ON_STATUS 0x00 112b4a31037SAndrew Lynn 1136ef9418cSRickard Andersson static bool no_bm; /* No battery management */ 1146ef9418cSRickard Andersson module_param(no_bm, bool, S_IRUGO); 1156ef9418cSRickard Andersson 116d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_REG 0x23 117d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2) 118d6255529SLinus Walleij 11962579266SRabin Vincent /* 12062579266SRabin Vincent * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt 1212ced445eSLinus Walleij * numbers are indexed into this array with (num / 8). The interupts are 1222ced445eSLinus Walleij * defined in linux/mfd/ab8500.h 12362579266SRabin Vincent * 12462579266SRabin Vincent * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at 12562579266SRabin Vincent * offset 0. 12662579266SRabin Vincent */ 1272ced445eSLinus Walleij /* AB8500 support */ 12862579266SRabin Vincent static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { 12992d50a41SMattias Wallin 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 13062579266SRabin Vincent }; 13162579266SRabin Vincent 132d6255529SLinus Walleij /* AB9540 support */ 133d6255529SLinus Walleij static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = { 134d6255529SLinus Walleij 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 135d6255529SLinus Walleij }; 136d6255529SLinus Walleij 1370f620837SLinus Walleij static const char ab8500_version_str[][7] = { 1380f620837SLinus Walleij [AB8500_VERSION_AB8500] = "AB8500", 1390f620837SLinus Walleij [AB8500_VERSION_AB8505] = "AB8505", 1400f620837SLinus Walleij [AB8500_VERSION_AB9540] = "AB9540", 1410f620837SLinus Walleij [AB8500_VERSION_AB8540] = "AB8540", 1420f620837SLinus Walleij }; 1430f620837SLinus Walleij 144822672a7SLee Jones static int ab8500_prcmu_write(struct ab8500 *ab8500, u16 addr, u8 data) 145d28f1db8SLee Jones { 146d28f1db8SLee Jones int ret; 147d28f1db8SLee Jones 148d28f1db8SLee Jones ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 149d28f1db8SLee Jones if (ret < 0) 150d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 151d28f1db8SLee Jones return ret; 152d28f1db8SLee Jones } 153d28f1db8SLee Jones 154822672a7SLee Jones static int ab8500_prcmu_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask, 155d28f1db8SLee Jones u8 data) 156d28f1db8SLee Jones { 157d28f1db8SLee Jones int ret; 158d28f1db8SLee Jones 159d28f1db8SLee Jones ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 160d28f1db8SLee Jones &mask, 1); 161d28f1db8SLee Jones if (ret < 0) 162d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 163d28f1db8SLee Jones return ret; 164d28f1db8SLee Jones } 165d28f1db8SLee Jones 166822672a7SLee Jones static int ab8500_prcmu_read(struct ab8500 *ab8500, u16 addr) 167d28f1db8SLee Jones { 168d28f1db8SLee Jones int ret; 169d28f1db8SLee Jones u8 data; 170d28f1db8SLee Jones 171d28f1db8SLee Jones ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 172d28f1db8SLee Jones if (ret < 0) { 173d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 174d28f1db8SLee Jones return ret; 175d28f1db8SLee Jones } 176d28f1db8SLee Jones return (int)data; 177d28f1db8SLee Jones } 178d28f1db8SLee Jones 17947c16975SMattias Wallin static int ab8500_get_chip_id(struct device *dev) 18047c16975SMattias Wallin { 1816bce7bf1SMattias Wallin struct ab8500 *ab8500; 1826bce7bf1SMattias Wallin 1836bce7bf1SMattias Wallin if (!dev) 1846bce7bf1SMattias Wallin return -EINVAL; 1856bce7bf1SMattias Wallin ab8500 = dev_get_drvdata(dev->parent); 1866bce7bf1SMattias Wallin return ab8500 ? (int)ab8500->chip_id : -EINVAL; 18747c16975SMattias Wallin } 18847c16975SMattias Wallin 18947c16975SMattias Wallin static int set_register_interruptible(struct ab8500 *ab8500, u8 bank, 19047c16975SMattias Wallin u8 reg, u8 data) 19162579266SRabin Vincent { 19262579266SRabin Vincent int ret; 19347c16975SMattias Wallin /* 19447c16975SMattias Wallin * Put the u8 bank and u8 register together into a an u16. 19547c16975SMattias Wallin * The bank on higher 8 bits and register in lower 8 bits. 19647c16975SMattias Wallin * */ 19747c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 19862579266SRabin Vincent 19962579266SRabin Vincent dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data); 20062579266SRabin Vincent 201392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 20247c16975SMattias Wallin 20347c16975SMattias Wallin ret = ab8500->write(ab8500, addr, data); 20447c16975SMattias Wallin if (ret < 0) 20547c16975SMattias Wallin dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 20647c16975SMattias Wallin addr, ret); 20747c16975SMattias Wallin mutex_unlock(&ab8500->lock); 20847c16975SMattias Wallin 20947c16975SMattias Wallin return ret; 21047c16975SMattias Wallin } 21147c16975SMattias Wallin 21247c16975SMattias Wallin static int ab8500_set_register(struct device *dev, u8 bank, 21347c16975SMattias Wallin u8 reg, u8 value) 21447c16975SMattias Wallin { 215112a80d2SJonas Aaberg int ret; 21647c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 21747c16975SMattias Wallin 218112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 219112a80d2SJonas Aaberg ret = set_register_interruptible(ab8500, bank, reg, value); 220112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 221112a80d2SJonas Aaberg return ret; 22247c16975SMattias Wallin } 22347c16975SMattias Wallin 22447c16975SMattias Wallin static int get_register_interruptible(struct ab8500 *ab8500, u8 bank, 22547c16975SMattias Wallin u8 reg, u8 *value) 22647c16975SMattias Wallin { 22747c16975SMattias Wallin int ret; 22847c16975SMattias Wallin /* put the u8 bank and u8 reg together into a an u16. 22947c16975SMattias Wallin * bank on higher 8 bits and reg in lower */ 23047c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 23147c16975SMattias Wallin 232392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 23347c16975SMattias Wallin 23447c16975SMattias Wallin ret = ab8500->read(ab8500, addr); 23547c16975SMattias Wallin if (ret < 0) 23647c16975SMattias Wallin dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 23747c16975SMattias Wallin addr, ret); 23847c16975SMattias Wallin else 23947c16975SMattias Wallin *value = ret; 24047c16975SMattias Wallin 24147c16975SMattias Wallin mutex_unlock(&ab8500->lock); 24247c16975SMattias Wallin dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret); 24347c16975SMattias Wallin 24447c16975SMattias Wallin return ret; 24547c16975SMattias Wallin } 24647c16975SMattias Wallin 24747c16975SMattias Wallin static int ab8500_get_register(struct device *dev, u8 bank, 24847c16975SMattias Wallin u8 reg, u8 *value) 24947c16975SMattias Wallin { 250112a80d2SJonas Aaberg int ret; 25147c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 25247c16975SMattias Wallin 253112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 254112a80d2SJonas Aaberg ret = get_register_interruptible(ab8500, bank, reg, value); 255112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 256112a80d2SJonas Aaberg return ret; 25747c16975SMattias Wallin } 25847c16975SMattias Wallin 25947c16975SMattias Wallin static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank, 26047c16975SMattias Wallin u8 reg, u8 bitmask, u8 bitvalues) 26147c16975SMattias Wallin { 26247c16975SMattias Wallin int ret; 26347c16975SMattias Wallin /* put the u8 bank and u8 reg together into a an u16. 26447c16975SMattias Wallin * bank on higher 8 bits and reg in lower */ 26547c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 26647c16975SMattias Wallin 267392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 26847c16975SMattias Wallin 269bc628fd1SMattias Nilsson if (ab8500->write_masked == NULL) { 270bc628fd1SMattias Nilsson u8 data; 271bc628fd1SMattias Nilsson 27247c16975SMattias Wallin ret = ab8500->read(ab8500, addr); 27347c16975SMattias Wallin if (ret < 0) { 27447c16975SMattias Wallin dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 27547c16975SMattias Wallin addr, ret); 27647c16975SMattias Wallin goto out; 27747c16975SMattias Wallin } 27847c16975SMattias Wallin 27947c16975SMattias Wallin data = (u8)ret; 28047c16975SMattias Wallin data = (~bitmask & data) | (bitmask & bitvalues); 28147c16975SMattias Wallin 28262579266SRabin Vincent ret = ab8500->write(ab8500, addr, data); 28362579266SRabin Vincent if (ret < 0) 28462579266SRabin Vincent dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 28562579266SRabin Vincent addr, ret); 28662579266SRabin Vincent 287bc628fd1SMattias Nilsson dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, 288bc628fd1SMattias Nilsson data); 289bc628fd1SMattias Nilsson goto out; 290bc628fd1SMattias Nilsson } 291bc628fd1SMattias Nilsson ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues); 292bc628fd1SMattias Nilsson if (ret < 0) 293bc628fd1SMattias Nilsson dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr, 294bc628fd1SMattias Nilsson ret); 29562579266SRabin Vincent out: 29662579266SRabin Vincent mutex_unlock(&ab8500->lock); 29762579266SRabin Vincent return ret; 29862579266SRabin Vincent } 29947c16975SMattias Wallin 30047c16975SMattias Wallin static int ab8500_mask_and_set_register(struct device *dev, 30147c16975SMattias Wallin u8 bank, u8 reg, u8 bitmask, u8 bitvalues) 30247c16975SMattias Wallin { 303112a80d2SJonas Aaberg int ret; 30447c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 30547c16975SMattias Wallin 306112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 307112a80d2SJonas Aaberg ret= mask_and_set_register_interruptible(ab8500, bank, reg, 30847c16975SMattias Wallin bitmask, bitvalues); 309112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 310112a80d2SJonas Aaberg return ret; 31147c16975SMattias Wallin } 31247c16975SMattias Wallin 31347c16975SMattias Wallin static struct abx500_ops ab8500_ops = { 31447c16975SMattias Wallin .get_chip_id = ab8500_get_chip_id, 31547c16975SMattias Wallin .get_register = ab8500_get_register, 31647c16975SMattias Wallin .set_register = ab8500_set_register, 31747c16975SMattias Wallin .get_register_page = NULL, 31847c16975SMattias Wallin .set_register_page = NULL, 31947c16975SMattias Wallin .mask_and_set_register = ab8500_mask_and_set_register, 32047c16975SMattias Wallin .event_registers_startup_state_get = NULL, 32147c16975SMattias Wallin .startup_irq_enabled = NULL, 3221d843a6cSMian Yousaf Kaukab .dump_all_banks = ab8500_dump_all_banks, 32347c16975SMattias Wallin }; 32462579266SRabin Vincent 3259505a0a0SMark Brown static void ab8500_irq_lock(struct irq_data *data) 32662579266SRabin Vincent { 3279505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 32862579266SRabin Vincent 32962579266SRabin Vincent mutex_lock(&ab8500->irq_lock); 330112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 33162579266SRabin Vincent } 33262579266SRabin Vincent 3339505a0a0SMark Brown static void ab8500_irq_sync_unlock(struct irq_data *data) 33462579266SRabin Vincent { 3359505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 33662579266SRabin Vincent int i; 33762579266SRabin Vincent 3382ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 33962579266SRabin Vincent u8 old = ab8500->oldmask[i]; 34062579266SRabin Vincent u8 new = ab8500->mask[i]; 34162579266SRabin Vincent int reg; 34262579266SRabin Vincent 34362579266SRabin Vincent if (new == old) 34462579266SRabin Vincent continue; 34562579266SRabin Vincent 3460f620837SLinus Walleij /* 3470f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 3480f620837SLinus Walleij * 2.0 3490f620837SLinus Walleij */ 3500f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 3510f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 35292d50a41SMattias Wallin continue; 35392d50a41SMattias Wallin 35462579266SRabin Vincent ab8500->oldmask[i] = new; 35562579266SRabin Vincent 3562ced445eSLinus Walleij reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i]; 35747c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new); 35862579266SRabin Vincent } 359112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 36062579266SRabin Vincent mutex_unlock(&ab8500->irq_lock); 36162579266SRabin Vincent } 36262579266SRabin Vincent 3639505a0a0SMark Brown static void ab8500_irq_mask(struct irq_data *data) 36462579266SRabin Vincent { 3659505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 36606e589efSLee Jones int offset = data->hwirq; 36762579266SRabin Vincent int index = offset / 8; 36862579266SRabin Vincent int mask = 1 << (offset % 8); 36962579266SRabin Vincent 37062579266SRabin Vincent ab8500->mask[index] |= mask; 37162579266SRabin Vincent } 37262579266SRabin Vincent 3739505a0a0SMark Brown static void ab8500_irq_unmask(struct irq_data *data) 37462579266SRabin Vincent { 3759505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 37606e589efSLee Jones int offset = data->hwirq; 37762579266SRabin Vincent int index = offset / 8; 37862579266SRabin Vincent int mask = 1 << (offset % 8); 37962579266SRabin Vincent 38062579266SRabin Vincent ab8500->mask[index] &= ~mask; 38162579266SRabin Vincent } 38262579266SRabin Vincent 38362579266SRabin Vincent static struct irq_chip ab8500_irq_chip = { 38462579266SRabin Vincent .name = "ab8500", 3859505a0a0SMark Brown .irq_bus_lock = ab8500_irq_lock, 3869505a0a0SMark Brown .irq_bus_sync_unlock = ab8500_irq_sync_unlock, 3879505a0a0SMark Brown .irq_mask = ab8500_irq_mask, 388e6f9306eSVirupax Sadashivpetimath .irq_disable = ab8500_irq_mask, 3899505a0a0SMark Brown .irq_unmask = ab8500_irq_unmask, 39062579266SRabin Vincent }; 39162579266SRabin Vincent 3927ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, 3937ccfe9b1SMichel JAOUEN int latch_offset, u8 latch_val) 3947ccfe9b1SMichel JAOUEN { 3957ccfe9b1SMichel JAOUEN int int_bit = __ffs(latch_val); 3967ccfe9b1SMichel JAOUEN int line, i; 3977ccfe9b1SMichel JAOUEN 3987ccfe9b1SMichel JAOUEN do { 3997ccfe9b1SMichel JAOUEN int_bit = __ffs(latch_val); 4007ccfe9b1SMichel JAOUEN 4017ccfe9b1SMichel JAOUEN for (i = 0; i < ab8500->mask_size; i++) 4027ccfe9b1SMichel JAOUEN if (ab8500->irq_reg_offset[i] == latch_offset) 4037ccfe9b1SMichel JAOUEN break; 4047ccfe9b1SMichel JAOUEN 4057ccfe9b1SMichel JAOUEN if (i >= ab8500->mask_size) { 4067ccfe9b1SMichel JAOUEN dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", 4077ccfe9b1SMichel JAOUEN latch_offset); 4087ccfe9b1SMichel JAOUEN return -ENXIO; 4097ccfe9b1SMichel JAOUEN } 4107ccfe9b1SMichel JAOUEN 4117ccfe9b1SMichel JAOUEN line = (i << 3) + int_bit; 4127ccfe9b1SMichel JAOUEN latch_val &= ~(1 << int_bit); 4137ccfe9b1SMichel JAOUEN 4147ccfe9b1SMichel JAOUEN handle_nested_irq(ab8500->irq_base + line); 4157ccfe9b1SMichel JAOUEN } while (latch_val); 4167ccfe9b1SMichel JAOUEN 4177ccfe9b1SMichel JAOUEN return 0; 4187ccfe9b1SMichel JAOUEN } 4197ccfe9b1SMichel JAOUEN 4207ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500, 4217ccfe9b1SMichel JAOUEN int hier_offset, u8 hier_val) 4227ccfe9b1SMichel JAOUEN { 4237ccfe9b1SMichel JAOUEN int latch_bit, status; 4247ccfe9b1SMichel JAOUEN u8 latch_offset, latch_val; 4257ccfe9b1SMichel JAOUEN 4267ccfe9b1SMichel JAOUEN do { 4277ccfe9b1SMichel JAOUEN latch_bit = __ffs(hier_val); 4287ccfe9b1SMichel JAOUEN latch_offset = (hier_offset << 3) + latch_bit; 4297ccfe9b1SMichel JAOUEN 4307ccfe9b1SMichel JAOUEN /* Fix inconsistent ITFromLatch25 bit mapping... */ 4317ccfe9b1SMichel JAOUEN if (unlikely(latch_offset == 17)) 4327ccfe9b1SMichel JAOUEN latch_offset = 24; 4337ccfe9b1SMichel JAOUEN 4347ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, 4357ccfe9b1SMichel JAOUEN AB8500_INTERRUPT, 4367ccfe9b1SMichel JAOUEN AB8500_IT_LATCH1_REG + latch_offset, 4377ccfe9b1SMichel JAOUEN &latch_val); 4387ccfe9b1SMichel JAOUEN if (status < 0 || latch_val == 0) 4397ccfe9b1SMichel JAOUEN goto discard; 4407ccfe9b1SMichel JAOUEN 4417ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_line(ab8500, 4427ccfe9b1SMichel JAOUEN latch_offset, latch_val); 4437ccfe9b1SMichel JAOUEN if (status < 0) 4447ccfe9b1SMichel JAOUEN return status; 4457ccfe9b1SMichel JAOUEN discard: 4467ccfe9b1SMichel JAOUEN hier_val &= ~(1 << latch_bit); 4477ccfe9b1SMichel JAOUEN } while (hier_val); 4487ccfe9b1SMichel JAOUEN 4497ccfe9b1SMichel JAOUEN return 0; 4507ccfe9b1SMichel JAOUEN } 4517ccfe9b1SMichel JAOUEN 4527ccfe9b1SMichel JAOUEN static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev) 4537ccfe9b1SMichel JAOUEN { 4547ccfe9b1SMichel JAOUEN struct ab8500 *ab8500 = dev; 4557ccfe9b1SMichel JAOUEN u8 i; 4567ccfe9b1SMichel JAOUEN 4577ccfe9b1SMichel JAOUEN dev_vdbg(ab8500->dev, "interrupt\n"); 4587ccfe9b1SMichel JAOUEN 4597ccfe9b1SMichel JAOUEN /* Hierarchical interrupt version */ 4607ccfe9b1SMichel JAOUEN for (i = 0; i < AB8500_IT_LATCHHIER_NUM; i++) { 4617ccfe9b1SMichel JAOUEN int status; 4627ccfe9b1SMichel JAOUEN u8 hier_val; 4637ccfe9b1SMichel JAOUEN 4647ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, AB8500_INTERRUPT, 4657ccfe9b1SMichel JAOUEN AB8500_IT_LATCHHIER1_REG + i, &hier_val); 4667ccfe9b1SMichel JAOUEN if (status < 0 || hier_val == 0) 4677ccfe9b1SMichel JAOUEN continue; 4687ccfe9b1SMichel JAOUEN 4697ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val); 4707ccfe9b1SMichel JAOUEN if (status < 0) 4717ccfe9b1SMichel JAOUEN break; 4727ccfe9b1SMichel JAOUEN } 4737ccfe9b1SMichel JAOUEN return IRQ_HANDLED; 4747ccfe9b1SMichel JAOUEN } 4757ccfe9b1SMichel JAOUEN 47680633f05SLee Jones /** 47780633f05SLee Jones * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ 47880633f05SLee Jones * 47980633f05SLee Jones * @ab8500: ab8500_irq controller to operate on. 48080633f05SLee Jones * @irq: index of the interrupt requested in the chip IRQs 48180633f05SLee Jones * 48280633f05SLee Jones * Useful for drivers to request their own IRQs. 48380633f05SLee Jones */ 48480633f05SLee Jones static int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq) 48580633f05SLee Jones { 48680633f05SLee Jones if (!ab8500) 48780633f05SLee Jones return -EINVAL; 48880633f05SLee Jones 48980633f05SLee Jones return irq_create_mapping(ab8500->domain, irq); 49080633f05SLee Jones } 49180633f05SLee Jones 49262579266SRabin Vincent static irqreturn_t ab8500_irq(int irq, void *dev) 49362579266SRabin Vincent { 49462579266SRabin Vincent struct ab8500 *ab8500 = dev; 49562579266SRabin Vincent int i; 49662579266SRabin Vincent 49762579266SRabin Vincent dev_vdbg(ab8500->dev, "interrupt\n"); 49862579266SRabin Vincent 499112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 500112a80d2SJonas Aaberg 5012ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 5022ced445eSLinus Walleij int regoffset = ab8500->irq_reg_offset[i]; 50362579266SRabin Vincent int status; 50447c16975SMattias Wallin u8 value; 50562579266SRabin Vincent 5060f620837SLinus Walleij /* 5070f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 5080f620837SLinus Walleij * 2.0 5090f620837SLinus Walleij */ 5100f620837SLinus Walleij if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500)) 51192d50a41SMattias Wallin continue; 51292d50a41SMattias Wallin 51347c16975SMattias Wallin status = get_register_interruptible(ab8500, AB8500_INTERRUPT, 51447c16975SMattias Wallin AB8500_IT_LATCH1_REG + regoffset, &value); 51547c16975SMattias Wallin if (status < 0 || value == 0) 51662579266SRabin Vincent continue; 51762579266SRabin Vincent 51862579266SRabin Vincent do { 51988aec4f7SMattias Wallin int bit = __ffs(value); 52062579266SRabin Vincent int line = i * 8 + bit; 5210a37fc56SLee Jones int virq = ab8500_irq_get_virq(ab8500, line); 52262579266SRabin Vincent 5230a37fc56SLee Jones handle_nested_irq(virq); 524*8f0eb43bSBengt Jonsson ab8500_debug_register_interrupt(line); 52547c16975SMattias Wallin value &= ~(1 << bit); 526112a80d2SJonas Aaberg 52747c16975SMattias Wallin } while (value); 52862579266SRabin Vincent } 529112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 53062579266SRabin Vincent return IRQ_HANDLED; 53162579266SRabin Vincent } 53262579266SRabin Vincent 53306e589efSLee Jones static int ab8500_irq_map(struct irq_domain *d, unsigned int virq, 53406e589efSLee Jones irq_hw_number_t hwirq) 53506e589efSLee Jones { 53606e589efSLee Jones struct ab8500 *ab8500 = d->host_data; 53706e589efSLee Jones 53806e589efSLee Jones if (!ab8500) 53906e589efSLee Jones return -EINVAL; 54006e589efSLee Jones 54106e589efSLee Jones irq_set_chip_data(virq, ab8500); 54206e589efSLee Jones irq_set_chip_and_handler(virq, &ab8500_irq_chip, 54306e589efSLee Jones handle_simple_irq); 54406e589efSLee Jones irq_set_nested_thread(virq, 1); 54506e589efSLee Jones #ifdef CONFIG_ARM 54606e589efSLee Jones set_irq_flags(virq, IRQF_VALID); 54706e589efSLee Jones #else 54806e589efSLee Jones irq_set_noprobe(virq); 54906e589efSLee Jones #endif 55062579266SRabin Vincent 55162579266SRabin Vincent return 0; 55262579266SRabin Vincent } 55362579266SRabin Vincent 55406e589efSLee Jones static struct irq_domain_ops ab8500_irq_ops = { 55506e589efSLee Jones .map = ab8500_irq_map, 55606e589efSLee Jones .xlate = irq_domain_xlate_twocell, 55706e589efSLee Jones }; 55806e589efSLee Jones 55906e589efSLee Jones static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np) 56062579266SRabin Vincent { 5612ced445eSLinus Walleij int num_irqs; 56262579266SRabin Vincent 563d6255529SLinus Walleij if (is_ab9540(ab8500)) 564d6255529SLinus Walleij num_irqs = AB9540_NR_IRQS; 565a982362cSBengt Jonsson else if (is_ab8505(ab8500)) 566a982362cSBengt Jonsson num_irqs = AB8505_NR_IRQS; 567d6255529SLinus Walleij else 5682ced445eSLinus Walleij num_irqs = AB8500_NR_IRQS; 5692ced445eSLinus Walleij 570f1d11f39SLinus Walleij /* If ->irq_base is zero this will give a linear mapping */ 571f1d11f39SLinus Walleij ab8500->domain = irq_domain_add_simple(NULL, 572f1d11f39SLinus Walleij num_irqs, ab8500->irq_base, 573f1d11f39SLinus Walleij &ab8500_irq_ops, ab8500); 57406e589efSLee Jones 57506e589efSLee Jones if (!ab8500->domain) { 57606e589efSLee Jones dev_err(ab8500->dev, "Failed to create irqdomain\n"); 57706e589efSLee Jones return -ENOSYS; 57806e589efSLee Jones } 57906e589efSLee Jones 58006e589efSLee Jones return 0; 58162579266SRabin Vincent } 58262579266SRabin Vincent 583112a80d2SJonas Aaberg int ab8500_suspend(struct ab8500 *ab8500) 584112a80d2SJonas Aaberg { 585112a80d2SJonas Aaberg if (atomic_read(&ab8500->transfer_ongoing)) 586112a80d2SJonas Aaberg return -EINVAL; 587112a80d2SJonas Aaberg else 588112a80d2SJonas Aaberg return 0; 589112a80d2SJonas Aaberg } 590112a80d2SJonas Aaberg 591a9e9ce4cSBill Pemberton static struct resource ab8500_gpadc_resources[] = { 59262579266SRabin Vincent { 59362579266SRabin Vincent .name = "HW_CONV_END", 59462579266SRabin Vincent .start = AB8500_INT_GP_HW_ADC_CONV_END, 59562579266SRabin Vincent .end = AB8500_INT_GP_HW_ADC_CONV_END, 59662579266SRabin Vincent .flags = IORESOURCE_IRQ, 59762579266SRabin Vincent }, 59862579266SRabin Vincent { 59962579266SRabin Vincent .name = "SW_CONV_END", 60062579266SRabin Vincent .start = AB8500_INT_GP_SW_ADC_CONV_END, 60162579266SRabin Vincent .end = AB8500_INT_GP_SW_ADC_CONV_END, 60262579266SRabin Vincent .flags = IORESOURCE_IRQ, 60362579266SRabin Vincent }, 60462579266SRabin Vincent }; 60562579266SRabin Vincent 606a9e9ce4cSBill Pemberton static struct resource ab8500_rtc_resources[] = { 60762579266SRabin Vincent { 60862579266SRabin Vincent .name = "60S", 60962579266SRabin Vincent .start = AB8500_INT_RTC_60S, 61062579266SRabin Vincent .end = AB8500_INT_RTC_60S, 61162579266SRabin Vincent .flags = IORESOURCE_IRQ, 61262579266SRabin Vincent }, 61362579266SRabin Vincent { 61462579266SRabin Vincent .name = "ALARM", 61562579266SRabin Vincent .start = AB8500_INT_RTC_ALARM, 61662579266SRabin Vincent .end = AB8500_INT_RTC_ALARM, 61762579266SRabin Vincent .flags = IORESOURCE_IRQ, 61862579266SRabin Vincent }, 61962579266SRabin Vincent }; 62062579266SRabin Vincent 621a9e9ce4cSBill Pemberton static struct resource ab8500_poweronkey_db_resources[] = { 62277686517SSundar R Iyer { 62377686517SSundar R Iyer .name = "ONKEY_DBF", 62477686517SSundar R Iyer .start = AB8500_INT_PON_KEY1DB_F, 62577686517SSundar R Iyer .end = AB8500_INT_PON_KEY1DB_F, 62677686517SSundar R Iyer .flags = IORESOURCE_IRQ, 62777686517SSundar R Iyer }, 62877686517SSundar R Iyer { 62977686517SSundar R Iyer .name = "ONKEY_DBR", 63077686517SSundar R Iyer .start = AB8500_INT_PON_KEY1DB_R, 63177686517SSundar R Iyer .end = AB8500_INT_PON_KEY1DB_R, 63277686517SSundar R Iyer .flags = IORESOURCE_IRQ, 63377686517SSundar R Iyer }, 63477686517SSundar R Iyer }; 63577686517SSundar R Iyer 636a9e9ce4cSBill Pemberton static struct resource ab8500_av_acc_detect_resources[] = { 637e098adedSMattias Wallin { 6386af75ecdSLinus Walleij .name = "ACC_DETECT_1DB_F", 6396af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_1DB_F, 6406af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_1DB_F, 641e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 642e098adedSMattias Wallin }, 643e098adedSMattias Wallin { 6446af75ecdSLinus Walleij .name = "ACC_DETECT_1DB_R", 6456af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_1DB_R, 6466af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_1DB_R, 647e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 648e098adedSMattias Wallin }, 649e098adedSMattias Wallin { 6506af75ecdSLinus Walleij .name = "ACC_DETECT_21DB_F", 6516af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_21DB_F, 6526af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_21DB_F, 6536af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 6546af75ecdSLinus Walleij }, 6556af75ecdSLinus Walleij { 6566af75ecdSLinus Walleij .name = "ACC_DETECT_21DB_R", 6576af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_21DB_R, 6586af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_21DB_R, 6596af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 6606af75ecdSLinus Walleij }, 6616af75ecdSLinus Walleij { 6626af75ecdSLinus Walleij .name = "ACC_DETECT_22DB_F", 6636af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_22DB_F, 6646af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_22DB_F, 6656af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 6666af75ecdSLinus Walleij }, 6676af75ecdSLinus Walleij { 6686af75ecdSLinus Walleij .name = "ACC_DETECT_22DB_R", 6696af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_22DB_R, 6706af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_22DB_R, 6716af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 6726af75ecdSLinus Walleij }, 6736af75ecdSLinus Walleij }; 6746af75ecdSLinus Walleij 675a9e9ce4cSBill Pemberton static struct resource ab8500_charger_resources[] = { 6766af75ecdSLinus Walleij { 677e098adedSMattias Wallin .name = "MAIN_CH_UNPLUG_DET", 678e098adedSMattias Wallin .start = AB8500_INT_MAIN_CH_UNPLUG_DET, 679e098adedSMattias Wallin .end = AB8500_INT_MAIN_CH_UNPLUG_DET, 680e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 681e098adedSMattias Wallin }, 682e098adedSMattias Wallin { 683e098adedSMattias Wallin .name = "MAIN_CHARGE_PLUG_DET", 684e098adedSMattias Wallin .start = AB8500_INT_MAIN_CH_PLUG_DET, 685e098adedSMattias Wallin .end = AB8500_INT_MAIN_CH_PLUG_DET, 686e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 687e098adedSMattias Wallin }, 688e098adedSMattias Wallin { 689e098adedSMattias Wallin .name = "VBUS_DET_R", 690e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_R, 691e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_R, 692e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 693e098adedSMattias Wallin }, 694e098adedSMattias Wallin { 6956af75ecdSLinus Walleij .name = "VBUS_DET_F", 6966af75ecdSLinus Walleij .start = AB8500_INT_VBUS_DET_F, 6976af75ecdSLinus Walleij .end = AB8500_INT_VBUS_DET_F, 698e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 699e098adedSMattias Wallin }, 700e098adedSMattias Wallin { 7016af75ecdSLinus Walleij .name = "USB_LINK_STATUS", 7026af75ecdSLinus Walleij .start = AB8500_INT_USB_LINK_STATUS, 7036af75ecdSLinus Walleij .end = AB8500_INT_USB_LINK_STATUS, 7046af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7056af75ecdSLinus Walleij }, 7066af75ecdSLinus Walleij { 707e098adedSMattias Wallin .name = "VBUS_OVV", 708e098adedSMattias Wallin .start = AB8500_INT_VBUS_OVV, 709e098adedSMattias Wallin .end = AB8500_INT_VBUS_OVV, 710e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 711e098adedSMattias Wallin }, 712e098adedSMattias Wallin { 7136af75ecdSLinus Walleij .name = "USB_CH_TH_PROT_R", 7146af75ecdSLinus Walleij .start = AB8500_INT_USB_CH_TH_PROT_R, 7156af75ecdSLinus Walleij .end = AB8500_INT_USB_CH_TH_PROT_R, 716e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 717e098adedSMattias Wallin }, 718e098adedSMattias Wallin { 7196af75ecdSLinus Walleij .name = "USB_CH_TH_PROT_F", 7206af75ecdSLinus Walleij .start = AB8500_INT_USB_CH_TH_PROT_F, 7216af75ecdSLinus Walleij .end = AB8500_INT_USB_CH_TH_PROT_F, 722e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 723e098adedSMattias Wallin }, 724e098adedSMattias Wallin { 7256af75ecdSLinus Walleij .name = "MAIN_EXT_CH_NOT_OK", 7266af75ecdSLinus Walleij .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, 7276af75ecdSLinus Walleij .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, 7286af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7296af75ecdSLinus Walleij }, 7306af75ecdSLinus Walleij { 7316af75ecdSLinus Walleij .name = "MAIN_CH_TH_PROT_R", 7326af75ecdSLinus Walleij .start = AB8500_INT_MAIN_CH_TH_PROT_R, 7336af75ecdSLinus Walleij .end = AB8500_INT_MAIN_CH_TH_PROT_R, 7346af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7356af75ecdSLinus Walleij }, 7366af75ecdSLinus Walleij { 7376af75ecdSLinus Walleij .name = "MAIN_CH_TH_PROT_F", 7386af75ecdSLinus Walleij .start = AB8500_INT_MAIN_CH_TH_PROT_F, 7396af75ecdSLinus Walleij .end = AB8500_INT_MAIN_CH_TH_PROT_F, 7406af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7416af75ecdSLinus Walleij }, 7426af75ecdSLinus Walleij { 7436af75ecdSLinus Walleij .name = "USB_CHARGER_NOT_OKR", 744a982362cSBengt Jonsson .start = AB8500_INT_USB_CHARGER_NOT_OKR, 745a982362cSBengt Jonsson .end = AB8500_INT_USB_CHARGER_NOT_OKR, 7466af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7476af75ecdSLinus Walleij }, 7486af75ecdSLinus Walleij { 7496af75ecdSLinus Walleij .name = "CH_WD_EXP", 7506af75ecdSLinus Walleij .start = AB8500_INT_CH_WD_EXP, 7516af75ecdSLinus Walleij .end = AB8500_INT_CH_WD_EXP, 7526af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7536af75ecdSLinus Walleij }, 7546af75ecdSLinus Walleij }; 7556af75ecdSLinus Walleij 756a9e9ce4cSBill Pemberton static struct resource ab8500_btemp_resources[] = { 7576af75ecdSLinus Walleij { 7586af75ecdSLinus Walleij .name = "BAT_CTRL_INDB", 7596af75ecdSLinus Walleij .start = AB8500_INT_BAT_CTRL_INDB, 7606af75ecdSLinus Walleij .end = AB8500_INT_BAT_CTRL_INDB, 761e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 762e098adedSMattias Wallin }, 763e098adedSMattias Wallin { 764e098adedSMattias Wallin .name = "BTEMP_LOW", 765e098adedSMattias Wallin .start = AB8500_INT_BTEMP_LOW, 766e098adedSMattias Wallin .end = AB8500_INT_BTEMP_LOW, 767e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 768e098adedSMattias Wallin }, 769e098adedSMattias Wallin { 770e098adedSMattias Wallin .name = "BTEMP_HIGH", 771e098adedSMattias Wallin .start = AB8500_INT_BTEMP_HIGH, 772e098adedSMattias Wallin .end = AB8500_INT_BTEMP_HIGH, 773e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 774e098adedSMattias Wallin }, 775e098adedSMattias Wallin { 7766af75ecdSLinus Walleij .name = "BTEMP_LOW_MEDIUM", 7776af75ecdSLinus Walleij .start = AB8500_INT_BTEMP_LOW_MEDIUM, 7786af75ecdSLinus Walleij .end = AB8500_INT_BTEMP_LOW_MEDIUM, 779e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 780e098adedSMattias Wallin }, 781e098adedSMattias Wallin { 7826af75ecdSLinus Walleij .name = "BTEMP_MEDIUM_HIGH", 7836af75ecdSLinus Walleij .start = AB8500_INT_BTEMP_MEDIUM_HIGH, 7846af75ecdSLinus Walleij .end = AB8500_INT_BTEMP_MEDIUM_HIGH, 785e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 786e098adedSMattias Wallin }, 787e098adedSMattias Wallin }; 788e098adedSMattias Wallin 789a9e9ce4cSBill Pemberton static struct resource ab8500_fg_resources[] = { 7906af75ecdSLinus Walleij { 7916af75ecdSLinus Walleij .name = "NCONV_ACCU", 7926af75ecdSLinus Walleij .start = AB8500_INT_CCN_CONV_ACC, 7936af75ecdSLinus Walleij .end = AB8500_INT_CCN_CONV_ACC, 7946af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7956af75ecdSLinus Walleij }, 7966af75ecdSLinus Walleij { 7976af75ecdSLinus Walleij .name = "BATT_OVV", 7986af75ecdSLinus Walleij .start = AB8500_INT_BATT_OVV, 7996af75ecdSLinus Walleij .end = AB8500_INT_BATT_OVV, 8006af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8016af75ecdSLinus Walleij }, 8026af75ecdSLinus Walleij { 8036af75ecdSLinus Walleij .name = "LOW_BAT_F", 8046af75ecdSLinus Walleij .start = AB8500_INT_LOW_BAT_F, 8056af75ecdSLinus Walleij .end = AB8500_INT_LOW_BAT_F, 8066af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8076af75ecdSLinus Walleij }, 8086af75ecdSLinus Walleij { 8096af75ecdSLinus Walleij .name = "LOW_BAT_R", 8106af75ecdSLinus Walleij .start = AB8500_INT_LOW_BAT_R, 8116af75ecdSLinus Walleij .end = AB8500_INT_LOW_BAT_R, 8126af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8136af75ecdSLinus Walleij }, 8146af75ecdSLinus Walleij { 8156af75ecdSLinus Walleij .name = "CC_INT_CALIB", 8166af75ecdSLinus Walleij .start = AB8500_INT_CC_INT_CALIB, 8176af75ecdSLinus Walleij .end = AB8500_INT_CC_INT_CALIB, 8186af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8196af75ecdSLinus Walleij }, 820a982362cSBengt Jonsson { 821a982362cSBengt Jonsson .name = "CCEOC", 822a982362cSBengt Jonsson .start = AB8500_INT_CCEOC, 823a982362cSBengt Jonsson .end = AB8500_INT_CCEOC, 824a982362cSBengt Jonsson .flags = IORESOURCE_IRQ, 825a982362cSBengt Jonsson }, 8266af75ecdSLinus Walleij }; 8276af75ecdSLinus Walleij 828a9e9ce4cSBill Pemberton static struct resource ab8500_chargalg_resources[] = {}; 8296af75ecdSLinus Walleij 830df720647SAxel Lin #ifdef CONFIG_DEBUG_FS 831a9e9ce4cSBill Pemberton static struct resource ab8500_debug_resources[] = { 832e098adedSMattias Wallin { 833e098adedSMattias Wallin .name = "IRQ_FIRST", 834e098adedSMattias Wallin .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, 835e098adedSMattias Wallin .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, 836e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 837e098adedSMattias Wallin }, 838e098adedSMattias Wallin { 839e098adedSMattias Wallin .name = "IRQ_LAST", 840a982362cSBengt Jonsson .start = AB8500_INT_XTAL32K_KO, 841a982362cSBengt Jonsson .end = AB8500_INT_XTAL32K_KO, 842e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 843e098adedSMattias Wallin }, 844e098adedSMattias Wallin }; 845df720647SAxel Lin #endif 846e098adedSMattias Wallin 847a9e9ce4cSBill Pemberton static struct resource ab8500_usb_resources[] = { 848e098adedSMattias Wallin { 849e098adedSMattias Wallin .name = "ID_WAKEUP_R", 850e098adedSMattias Wallin .start = AB8500_INT_ID_WAKEUP_R, 851e098adedSMattias Wallin .end = AB8500_INT_ID_WAKEUP_R, 852e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 853e098adedSMattias Wallin }, 854e098adedSMattias Wallin { 855e098adedSMattias Wallin .name = "ID_WAKEUP_F", 856e098adedSMattias Wallin .start = AB8500_INT_ID_WAKEUP_F, 857e098adedSMattias Wallin .end = AB8500_INT_ID_WAKEUP_F, 858e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 859e098adedSMattias Wallin }, 860e098adedSMattias Wallin { 861e098adedSMattias Wallin .name = "VBUS_DET_F", 862e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_F, 863e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_F, 864e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 865e098adedSMattias Wallin }, 866e098adedSMattias Wallin { 867e098adedSMattias Wallin .name = "VBUS_DET_R", 868e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_R, 869e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_R, 870e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 871e098adedSMattias Wallin }, 87292d50a41SMattias Wallin { 87392d50a41SMattias Wallin .name = "USB_LINK_STATUS", 87492d50a41SMattias Wallin .start = AB8500_INT_USB_LINK_STATUS, 87592d50a41SMattias Wallin .end = AB8500_INT_USB_LINK_STATUS, 87692d50a41SMattias Wallin .flags = IORESOURCE_IRQ, 87792d50a41SMattias Wallin }, 8786af75ecdSLinus Walleij { 8796af75ecdSLinus Walleij .name = "USB_ADP_PROBE_PLUG", 8806af75ecdSLinus Walleij .start = AB8500_INT_ADP_PROBE_PLUG, 8816af75ecdSLinus Walleij .end = AB8500_INT_ADP_PROBE_PLUG, 8826af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8836af75ecdSLinus Walleij }, 8846af75ecdSLinus Walleij { 8856af75ecdSLinus Walleij .name = "USB_ADP_PROBE_UNPLUG", 8866af75ecdSLinus Walleij .start = AB8500_INT_ADP_PROBE_UNPLUG, 8876af75ecdSLinus Walleij .end = AB8500_INT_ADP_PROBE_UNPLUG, 8886af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8896af75ecdSLinus Walleij }, 890e098adedSMattias Wallin }; 891e098adedSMattias Wallin 892a9e9ce4cSBill Pemberton static struct resource ab8505_iddet_resources[] = { 89344f72e53SVirupax Sadashivpetimath { 89444f72e53SVirupax Sadashivpetimath .name = "KeyDeglitch", 89544f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KEYDEGLITCH, 89644f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KEYDEGLITCH, 89744f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 89844f72e53SVirupax Sadashivpetimath }, 89944f72e53SVirupax Sadashivpetimath { 90044f72e53SVirupax Sadashivpetimath .name = "KP", 90144f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KP, 90244f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KP, 90344f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 90444f72e53SVirupax Sadashivpetimath }, 90544f72e53SVirupax Sadashivpetimath { 90644f72e53SVirupax Sadashivpetimath .name = "IKP", 90744f72e53SVirupax Sadashivpetimath .start = AB8505_INT_IKP, 90844f72e53SVirupax Sadashivpetimath .end = AB8505_INT_IKP, 90944f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 91044f72e53SVirupax Sadashivpetimath }, 91144f72e53SVirupax Sadashivpetimath { 91244f72e53SVirupax Sadashivpetimath .name = "IKR", 91344f72e53SVirupax Sadashivpetimath .start = AB8505_INT_IKR, 91444f72e53SVirupax Sadashivpetimath .end = AB8505_INT_IKR, 91544f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 91644f72e53SVirupax Sadashivpetimath }, 91744f72e53SVirupax Sadashivpetimath { 91844f72e53SVirupax Sadashivpetimath .name = "KeyStuck", 91944f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KEYSTUCK, 92044f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KEYSTUCK, 92144f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 92244f72e53SVirupax Sadashivpetimath }, 92344f72e53SVirupax Sadashivpetimath }; 92444f72e53SVirupax Sadashivpetimath 925a9e9ce4cSBill Pemberton static struct resource ab8500_temp_resources[] = { 926e098adedSMattias Wallin { 927e098adedSMattias Wallin .name = "AB8500_TEMP_WARM", 928e098adedSMattias Wallin .start = AB8500_INT_TEMP_WARM, 929e098adedSMattias Wallin .end = AB8500_INT_TEMP_WARM, 930e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 931e098adedSMattias Wallin }, 932e098adedSMattias Wallin }; 933e098adedSMattias Wallin 934a9e9ce4cSBill Pemberton static struct mfd_cell abx500_common_devs[] = { 9355814fc35SMattias Wallin #ifdef CONFIG_DEBUG_FS 9365814fc35SMattias Wallin { 9375814fc35SMattias Wallin .name = "ab8500-debug", 938bad76991SLee Jones .of_compatible = "stericsson,ab8500-debug", 939e098adedSMattias Wallin .num_resources = ARRAY_SIZE(ab8500_debug_resources), 940e098adedSMattias Wallin .resources = ab8500_debug_resources, 9415814fc35SMattias Wallin }, 9425814fc35SMattias Wallin #endif 94362579266SRabin Vincent { 944e098adedSMattias Wallin .name = "ab8500-sysctrl", 945bad76991SLee Jones .of_compatible = "stericsson,ab8500-sysctrl", 946e098adedSMattias Wallin }, 947e098adedSMattias Wallin { 948e098adedSMattias Wallin .name = "ab8500-regulator", 949bad76991SLee Jones .of_compatible = "stericsson,ab8500-regulator", 950e098adedSMattias Wallin }, 951e098adedSMattias Wallin { 952916a871cSUlf Hansson .name = "abx500-clk", 953916a871cSUlf Hansson .of_compatible = "stericsson,abx500-clk", 954916a871cSUlf Hansson }, 955916a871cSUlf Hansson { 95662579266SRabin Vincent .name = "ab8500-gpadc", 957bad76991SLee Jones .of_compatible = "stericsson,ab8500-gpadc", 95862579266SRabin Vincent .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), 95962579266SRabin Vincent .resources = ab8500_gpadc_resources, 96062579266SRabin Vincent }, 96162579266SRabin Vincent { 96262579266SRabin Vincent .name = "ab8500-rtc", 963bad76991SLee Jones .of_compatible = "stericsson,ab8500-rtc", 96462579266SRabin Vincent .num_resources = ARRAY_SIZE(ab8500_rtc_resources), 96562579266SRabin Vincent .resources = ab8500_rtc_resources, 96662579266SRabin Vincent }, 967f0f05b1cSArun Murthy { 9686af75ecdSLinus Walleij .name = "ab8500-acc-det", 969bad76991SLee Jones .of_compatible = "stericsson,ab8500-acc-det", 9706af75ecdSLinus Walleij .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources), 9716af75ecdSLinus Walleij .resources = ab8500_av_acc_detect_resources, 9726af75ecdSLinus Walleij }, 9736af75ecdSLinus Walleij { 974e098adedSMattias Wallin .name = "ab8500-poweron-key", 975bad76991SLee Jones .of_compatible = "stericsson,ab8500-poweron-key", 976e098adedSMattias Wallin .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), 977e098adedSMattias Wallin .resources = ab8500_poweronkey_db_resources, 978e098adedSMattias Wallin }, 979e098adedSMattias Wallin { 980f0f05b1cSArun Murthy .name = "ab8500-pwm", 981bad76991SLee Jones .of_compatible = "stericsson,ab8500-pwm", 982f0f05b1cSArun Murthy .id = 1, 983f0f05b1cSArun Murthy }, 984f0f05b1cSArun Murthy { 985f0f05b1cSArun Murthy .name = "ab8500-pwm", 986bad76991SLee Jones .of_compatible = "stericsson,ab8500-pwm", 987f0f05b1cSArun Murthy .id = 2, 988f0f05b1cSArun Murthy }, 989f0f05b1cSArun Murthy { 990f0f05b1cSArun Murthy .name = "ab8500-pwm", 991bad76991SLee Jones .of_compatible = "stericsson,ab8500-pwm", 992f0f05b1cSArun Murthy .id = 3, 993f0f05b1cSArun Murthy }, 994bad76991SLee Jones { 995bad76991SLee Jones .name = "ab8500-leds", 996bad76991SLee Jones .of_compatible = "stericsson,ab8500-leds", 997bad76991SLee Jones }, 99877686517SSundar R Iyer { 999e098adedSMattias Wallin .name = "ab8500-denc", 1000bad76991SLee Jones .of_compatible = "stericsson,ab8500-denc", 1001e098adedSMattias Wallin }, 1002e098adedSMattias Wallin { 1003e098adedSMattias Wallin .name = "ab8500-temp", 1004bad76991SLee Jones .of_compatible = "stericsson,ab8500-temp", 1005e098adedSMattias Wallin .num_resources = ARRAY_SIZE(ab8500_temp_resources), 1006e098adedSMattias Wallin .resources = ab8500_temp_resources, 100777686517SSundar R Iyer }, 100862579266SRabin Vincent }; 100962579266SRabin Vincent 1010a9e9ce4cSBill Pemberton static struct mfd_cell ab8500_bm_devs[] = { 10116ef9418cSRickard Andersson { 10126ef9418cSRickard Andersson .name = "ab8500-charger", 10134aef72dbSRajanikanth H.V .of_compatible = "stericsson,ab8500-charger", 10146ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_charger_resources), 10156ef9418cSRickard Andersson .resources = ab8500_charger_resources, 10164aef72dbSRajanikanth H.V #ifndef CONFIG_OF 10174aef72dbSRajanikanth H.V .platform_data = &ab8500_bm_data, 10184aef72dbSRajanikanth H.V .pdata_size = sizeof(ab8500_bm_data), 10194aef72dbSRajanikanth H.V #endif 10206ef9418cSRickard Andersson }, 10216ef9418cSRickard Andersson { 10226ef9418cSRickard Andersson .name = "ab8500-btemp", 1023bd9e8ab2SRajanikanth H.V .of_compatible = "stericsson,ab8500-btemp", 10246ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_btemp_resources), 10256ef9418cSRickard Andersson .resources = ab8500_btemp_resources, 1026bd9e8ab2SRajanikanth H.V #ifndef CONFIG_OF 1027bd9e8ab2SRajanikanth H.V .platform_data = &ab8500_bm_data, 1028bd9e8ab2SRajanikanth H.V .pdata_size = sizeof(ab8500_bm_data), 1029bd9e8ab2SRajanikanth H.V #endif 10306ef9418cSRickard Andersson }, 10316ef9418cSRickard Andersson { 10326ef9418cSRickard Andersson .name = "ab8500-fg", 1033e0f1abebSRajanikanth H.V .of_compatible = "stericsson,ab8500-fg", 10346ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_fg_resources), 10356ef9418cSRickard Andersson .resources = ab8500_fg_resources, 1036e0f1abebSRajanikanth H.V #ifndef CONFIG_OF 1037e0f1abebSRajanikanth H.V .platform_data = &ab8500_bm_data, 1038e0f1abebSRajanikanth H.V .pdata_size = sizeof(ab8500_bm_data), 1039e0f1abebSRajanikanth H.V #endif 10406ef9418cSRickard Andersson }, 10416ef9418cSRickard Andersson { 10426ef9418cSRickard Andersson .name = "ab8500-chargalg", 1043a12810abSRajanikanth H.V .of_compatible = "stericsson,ab8500-chargalg", 10446ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_chargalg_resources), 10456ef9418cSRickard Andersson .resources = ab8500_chargalg_resources, 1046a12810abSRajanikanth H.V #ifndef CONFIG_OF 1047a12810abSRajanikanth H.V .platform_data = &ab8500_bm_data, 1048a12810abSRajanikanth H.V .pdata_size = sizeof(ab8500_bm_data), 1049a12810abSRajanikanth H.V #endif 10506ef9418cSRickard Andersson }, 10516ef9418cSRickard Andersson }; 10526ef9418cSRickard Andersson 1053a9e9ce4cSBill Pemberton static struct mfd_cell ab8500_devs[] = { 1054d6255529SLinus Walleij { 1055d6255529SLinus Walleij .name = "ab8500-gpio", 1056bad76991SLee Jones .of_compatible = "stericsson,ab8500-gpio", 1057d6255529SLinus Walleij }, 1058d6255529SLinus Walleij { 1059d6255529SLinus Walleij .name = "ab8500-usb", 1060bad76991SLee Jones .of_compatible = "stericsson,ab8500-usb", 1061d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab8500_usb_resources), 1062d6255529SLinus Walleij .resources = ab8500_usb_resources, 1063d6255529SLinus Walleij }, 106444f72e53SVirupax Sadashivpetimath { 106544f72e53SVirupax Sadashivpetimath .name = "ab8500-codec", 106681a21cddSLee Jones .of_compatible = "stericsson,ab8500-codec", 106744f72e53SVirupax Sadashivpetimath }, 1068d6255529SLinus Walleij }; 1069d6255529SLinus Walleij 1070a9e9ce4cSBill Pemberton static struct mfd_cell ab9540_devs[] = { 1071d6255529SLinus Walleij { 1072d6255529SLinus Walleij .name = "ab8500-gpio", 1073d6255529SLinus Walleij }, 1074d6255529SLinus Walleij { 1075d6255529SLinus Walleij .name = "ab9540-usb", 1076d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab8500_usb_resources), 1077d6255529SLinus Walleij .resources = ab8500_usb_resources, 1078d6255529SLinus Walleij }, 107944f72e53SVirupax Sadashivpetimath { 108044f72e53SVirupax Sadashivpetimath .name = "ab9540-codec", 108144f72e53SVirupax Sadashivpetimath }, 108244f72e53SVirupax Sadashivpetimath }; 108344f72e53SVirupax Sadashivpetimath 108444f72e53SVirupax Sadashivpetimath /* Device list common to ab9540 and ab8505 */ 1085a9e9ce4cSBill Pemberton static struct mfd_cell ab9540_ab8505_devs[] = { 108644f72e53SVirupax Sadashivpetimath { 108744f72e53SVirupax Sadashivpetimath .name = "ab-iddet", 108844f72e53SVirupax Sadashivpetimath .num_resources = ARRAY_SIZE(ab8505_iddet_resources), 108944f72e53SVirupax Sadashivpetimath .resources = ab8505_iddet_resources, 109044f72e53SVirupax Sadashivpetimath }, 1091d6255529SLinus Walleij }; 1092d6255529SLinus Walleij 1093cca69b67SMattias Wallin static ssize_t show_chip_id(struct device *dev, 1094cca69b67SMattias Wallin struct device_attribute *attr, char *buf) 1095cca69b67SMattias Wallin { 1096cca69b67SMattias Wallin struct ab8500 *ab8500; 1097cca69b67SMattias Wallin 1098cca69b67SMattias Wallin ab8500 = dev_get_drvdata(dev); 1099cca69b67SMattias Wallin return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); 1100cca69b67SMattias Wallin } 1101cca69b67SMattias Wallin 1102e5c238c3SMattias Wallin /* 1103e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 1104e5c238c3SMattias Wallin * 0x01 Swoff bit programming 1105e5c238c3SMattias Wallin * 0x02 Thermal protection activation 1106e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 1107e5c238c3SMattias Wallin * 0x08 Watchdog expired 1108e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 1109e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 1110e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 1111e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 1112e5c238c3SMattias Wallin */ 1113e5c238c3SMattias Wallin static ssize_t show_switch_off_status(struct device *dev, 1114e5c238c3SMattias Wallin struct device_attribute *attr, char *buf) 1115e5c238c3SMattias Wallin { 1116e5c238c3SMattias Wallin int ret; 1117e5c238c3SMattias Wallin u8 value; 1118e5c238c3SMattias Wallin struct ab8500 *ab8500; 1119e5c238c3SMattias Wallin 1120e5c238c3SMattias Wallin ab8500 = dev_get_drvdata(dev); 1121e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 1122e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 1123e5c238c3SMattias Wallin if (ret < 0) 1124e5c238c3SMattias Wallin return ret; 1125e5c238c3SMattias Wallin return sprintf(buf, "%#x\n", value); 1126e5c238c3SMattias Wallin } 1127e5c238c3SMattias Wallin 1128b4a31037SAndrew Lynn /* 1129b4a31037SAndrew Lynn * ab8500 has turned on due to (TURN_ON_STATUS): 1130b4a31037SAndrew Lynn * 0x01 PORnVbat 1131b4a31037SAndrew Lynn * 0x02 PonKey1dbF 1132b4a31037SAndrew Lynn * 0x04 PonKey2dbF 1133b4a31037SAndrew Lynn * 0x08 RTCAlarm 1134b4a31037SAndrew Lynn * 0x10 MainChDet 1135b4a31037SAndrew Lynn * 0x20 VbusDet 1136b4a31037SAndrew Lynn * 0x40 UsbIDDetect 1137b4a31037SAndrew Lynn * 0x80 Reserved 1138b4a31037SAndrew Lynn */ 1139b4a31037SAndrew Lynn static ssize_t show_turn_on_status(struct device *dev, 1140b4a31037SAndrew Lynn struct device_attribute *attr, char *buf) 1141b4a31037SAndrew Lynn { 1142b4a31037SAndrew Lynn int ret; 1143b4a31037SAndrew Lynn u8 value; 1144b4a31037SAndrew Lynn struct ab8500 *ab8500; 1145b4a31037SAndrew Lynn 1146b4a31037SAndrew Lynn ab8500 = dev_get_drvdata(dev); 1147b4a31037SAndrew Lynn ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 1148b4a31037SAndrew Lynn AB8500_TURN_ON_STATUS, &value); 1149b4a31037SAndrew Lynn if (ret < 0) 1150b4a31037SAndrew Lynn return ret; 1151b4a31037SAndrew Lynn return sprintf(buf, "%#x\n", value); 1152b4a31037SAndrew Lynn } 1153b4a31037SAndrew Lynn 1154d6255529SLinus Walleij static ssize_t show_ab9540_dbbrstn(struct device *dev, 1155d6255529SLinus Walleij struct device_attribute *attr, char *buf) 1156d6255529SLinus Walleij { 1157d6255529SLinus Walleij struct ab8500 *ab8500; 1158d6255529SLinus Walleij int ret; 1159d6255529SLinus Walleij u8 value; 1160d6255529SLinus Walleij 1161d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 1162d6255529SLinus Walleij 1163d6255529SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2, 1164d6255529SLinus Walleij AB9540_MODEM_CTRL2_REG, &value); 1165d6255529SLinus Walleij if (ret < 0) 1166d6255529SLinus Walleij return ret; 1167d6255529SLinus Walleij 1168d6255529SLinus Walleij return sprintf(buf, "%d\n", 1169d6255529SLinus Walleij (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0); 1170d6255529SLinus Walleij } 1171d6255529SLinus Walleij 1172d6255529SLinus Walleij static ssize_t store_ab9540_dbbrstn(struct device *dev, 1173d6255529SLinus Walleij struct device_attribute *attr, const char *buf, size_t count) 1174d6255529SLinus Walleij { 1175d6255529SLinus Walleij struct ab8500 *ab8500; 1176d6255529SLinus Walleij int ret = count; 1177d6255529SLinus Walleij int err; 1178d6255529SLinus Walleij u8 bitvalues; 1179d6255529SLinus Walleij 1180d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 1181d6255529SLinus Walleij 1182d6255529SLinus Walleij if (count > 0) { 1183d6255529SLinus Walleij switch (buf[0]) { 1184d6255529SLinus Walleij case '0': 1185d6255529SLinus Walleij bitvalues = 0; 1186d6255529SLinus Walleij break; 1187d6255529SLinus Walleij case '1': 1188d6255529SLinus Walleij bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT; 1189d6255529SLinus Walleij break; 1190d6255529SLinus Walleij default: 1191d6255529SLinus Walleij goto exit; 1192d6255529SLinus Walleij } 1193d6255529SLinus Walleij 1194d6255529SLinus Walleij err = mask_and_set_register_interruptible(ab8500, 1195d6255529SLinus Walleij AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG, 1196d6255529SLinus Walleij AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues); 1197d6255529SLinus Walleij if (err) 1198d6255529SLinus Walleij dev_info(ab8500->dev, 1199d6255529SLinus Walleij "Failed to set DBBRSTN %c, err %#x\n", 1200d6255529SLinus Walleij buf[0], err); 1201d6255529SLinus Walleij } 1202d6255529SLinus Walleij 1203d6255529SLinus Walleij exit: 1204d6255529SLinus Walleij return ret; 1205d6255529SLinus Walleij } 1206d6255529SLinus Walleij 1207cca69b67SMattias Wallin static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); 1208e5c238c3SMattias Wallin static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL); 1209b4a31037SAndrew Lynn static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL); 1210d6255529SLinus Walleij static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR, 1211d6255529SLinus Walleij show_ab9540_dbbrstn, store_ab9540_dbbrstn); 1212cca69b67SMattias Wallin 1213cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = { 1214cca69b67SMattias Wallin &dev_attr_chip_id.attr, 1215e5c238c3SMattias Wallin &dev_attr_switch_off_status.attr, 1216b4a31037SAndrew Lynn &dev_attr_turn_on_status.attr, 1217cca69b67SMattias Wallin NULL, 1218cca69b67SMattias Wallin }; 1219cca69b67SMattias Wallin 1220d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = { 1221d6255529SLinus Walleij &dev_attr_chip_id.attr, 1222d6255529SLinus Walleij &dev_attr_switch_off_status.attr, 1223d6255529SLinus Walleij &dev_attr_turn_on_status.attr, 1224d6255529SLinus Walleij &dev_attr_dbbrstn.attr, 1225d6255529SLinus Walleij NULL, 1226d6255529SLinus Walleij }; 1227d6255529SLinus Walleij 1228cca69b67SMattias Wallin static struct attribute_group ab8500_attr_group = { 1229cca69b67SMattias Wallin .attrs = ab8500_sysfs_entries, 1230cca69b67SMattias Wallin }; 1231cca69b67SMattias Wallin 1232d6255529SLinus Walleij static struct attribute_group ab9540_attr_group = { 1233d6255529SLinus Walleij .attrs = ab9540_sysfs_entries, 1234d6255529SLinus Walleij }; 1235d6255529SLinus Walleij 1236f791be49SBill Pemberton static int ab8500_probe(struct platform_device *pdev) 123762579266SRabin Vincent { 1238b04c530cSJonas Aaberg static char *switch_off_status[] = { 1239b04c530cSJonas Aaberg "Swoff bit programming", 1240b04c530cSJonas Aaberg "Thermal protection activation", 1241b04c530cSJonas Aaberg "Vbat lower then BattOk falling threshold", 1242b04c530cSJonas Aaberg "Watchdog expired", 1243b04c530cSJonas Aaberg "Non presence of 32kHz clock", 1244b04c530cSJonas Aaberg "Battery level lower than power on reset threshold", 1245b04c530cSJonas Aaberg "Power on key 1 pressed longer than 10 seconds", 1246b04c530cSJonas Aaberg "DB8500 thermal shutdown"}; 1247d28f1db8SLee Jones struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev); 1248d28f1db8SLee Jones const struct platform_device_id *platid = platform_get_device_id(pdev); 12496bc4a568SLee Jones enum ab8500_version version = AB8500_VERSION_UNDEFINED; 12506bc4a568SLee Jones struct device_node *np = pdev->dev.of_node; 1251d28f1db8SLee Jones struct ab8500 *ab8500; 1252d28f1db8SLee Jones struct resource *resource; 125362579266SRabin Vincent int ret; 125462579266SRabin Vincent int i; 125547c16975SMattias Wallin u8 value; 125662579266SRabin Vincent 12578c4203cbSLee Jones ab8500 = devm_kzalloc(&pdev->dev, sizeof *ab8500, GFP_KERNEL); 1258d28f1db8SLee Jones if (!ab8500) 1259d28f1db8SLee Jones return -ENOMEM; 1260d28f1db8SLee Jones 126162579266SRabin Vincent if (plat) 126262579266SRabin Vincent ab8500->irq_base = plat->irq_base; 126362579266SRabin Vincent 1264d28f1db8SLee Jones ab8500->dev = &pdev->dev; 1265d28f1db8SLee Jones 1266d28f1db8SLee Jones resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 12678c4203cbSLee Jones if (!resource) 12688c4203cbSLee Jones return -ENODEV; 1269d28f1db8SLee Jones 1270d28f1db8SLee Jones ab8500->irq = resource->start; 1271d28f1db8SLee Jones 1272822672a7SLee Jones ab8500->read = ab8500_prcmu_read; 1273822672a7SLee Jones ab8500->write = ab8500_prcmu_write; 1274822672a7SLee Jones ab8500->write_masked = ab8500_prcmu_write_masked; 1275d28f1db8SLee Jones 127662579266SRabin Vincent mutex_init(&ab8500->lock); 127762579266SRabin Vincent mutex_init(&ab8500->irq_lock); 1278112a80d2SJonas Aaberg atomic_set(&ab8500->transfer_ongoing, 0); 127962579266SRabin Vincent 1280d28f1db8SLee Jones platform_set_drvdata(pdev, ab8500); 1281d28f1db8SLee Jones 12826bc4a568SLee Jones if (platid) 12836bc4a568SLee Jones version = platid->driver_data; 12846bc4a568SLee Jones 12850f620837SLinus Walleij if (version != AB8500_VERSION_UNDEFINED) 12860f620837SLinus Walleij ab8500->version = version; 12870f620837SLinus Walleij else { 12880f620837SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_MISC, 12890f620837SLinus Walleij AB8500_IC_NAME_REG, &value); 12900f620837SLinus Walleij if (ret < 0) 12918c4203cbSLee Jones return ret; 12920f620837SLinus Walleij 12930f620837SLinus Walleij ab8500->version = value; 12940f620837SLinus Walleij } 12950f620837SLinus Walleij 129647c16975SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_MISC, 129747c16975SMattias Wallin AB8500_REV_REG, &value); 129862579266SRabin Vincent if (ret < 0) 12998c4203cbSLee Jones return ret; 130062579266SRabin Vincent 130147c16975SMattias Wallin ab8500->chip_id = value; 130262579266SRabin Vincent 13030f620837SLinus Walleij dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n", 13040f620837SLinus Walleij ab8500_version_str[ab8500->version], 13050f620837SLinus Walleij ab8500->chip_id >> 4, 13060f620837SLinus Walleij ab8500->chip_id & 0x0F); 13070f620837SLinus Walleij 1308d6255529SLinus Walleij /* Configure AB8500 or AB9540 IRQ */ 1309a982362cSBengt Jonsson if (is_ab9540(ab8500) || is_ab8505(ab8500)) { 1310d6255529SLinus Walleij ab8500->mask_size = AB9540_NUM_IRQ_REGS; 1311d6255529SLinus Walleij ab8500->irq_reg_offset = ab9540_irq_regoffset; 1312d6255529SLinus Walleij } else { 13132ced445eSLinus Walleij ab8500->mask_size = AB8500_NUM_IRQ_REGS; 13142ced445eSLinus Walleij ab8500->irq_reg_offset = ab8500_irq_regoffset; 1315d6255529SLinus Walleij } 13168c4203cbSLee Jones ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size, GFP_KERNEL); 13172ced445eSLinus Walleij if (!ab8500->mask) 13182ced445eSLinus Walleij return -ENOMEM; 13198c4203cbSLee Jones ab8500->oldmask = devm_kzalloc(&pdev->dev, ab8500->mask_size, GFP_KERNEL); 13208c4203cbSLee Jones if (!ab8500->oldmask) 13218c4203cbSLee Jones return -ENOMEM; 13228c4203cbSLee Jones 1323e5c238c3SMattias Wallin /* 1324e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 1325e5c238c3SMattias Wallin * 0x01 Swoff bit programming 1326e5c238c3SMattias Wallin * 0x02 Thermal protection activation 1327e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 1328e5c238c3SMattias Wallin * 0x08 Watchdog expired 1329e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 1330e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 1331e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 1332e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 1333e5c238c3SMattias Wallin */ 1334e5c238c3SMattias Wallin 1335e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 1336e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 1337e5c238c3SMattias Wallin if (ret < 0) 1338e5c238c3SMattias Wallin return ret; 1339b04c530cSJonas Aaberg dev_info(ab8500->dev, "switch off cause(s) (%#x): ", value); 1340b04c530cSJonas Aaberg 1341b04c530cSJonas Aaberg if (value) { 1342b04c530cSJonas Aaberg for (i = 0; i < ARRAY_SIZE(switch_off_status); i++) { 1343b04c530cSJonas Aaberg if (value & 1) 1344b04c530cSJonas Aaberg printk(KERN_CONT " \"%s\"", 1345b04c530cSJonas Aaberg switch_off_status[i]); 1346b04c530cSJonas Aaberg value = value >> 1; 1347b04c530cSJonas Aaberg 1348b04c530cSJonas Aaberg } 1349b04c530cSJonas Aaberg printk(KERN_CONT "\n"); 1350b04c530cSJonas Aaberg } else { 1351b04c530cSJonas Aaberg printk(KERN_CONT " None\n"); 1352b04c530cSJonas Aaberg } 1353e5c238c3SMattias Wallin 135462579266SRabin Vincent if (plat && plat->init) 135562579266SRabin Vincent plat->init(ab8500); 135662579266SRabin Vincent 135762579266SRabin Vincent /* Clear and mask all interrupts */ 13582ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 13590f620837SLinus Walleij /* 13600f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 13610f620837SLinus Walleij * 2.0 13620f620837SLinus Walleij */ 13630f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 13640f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 136592d50a41SMattias Wallin continue; 136662579266SRabin Vincent 136747c16975SMattias Wallin get_register_interruptible(ab8500, AB8500_INTERRUPT, 13682ced445eSLinus Walleij AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i], 136992d50a41SMattias Wallin &value); 137047c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, 13712ced445eSLinus Walleij AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff); 137262579266SRabin Vincent } 137362579266SRabin Vincent 137447c16975SMattias Wallin ret = abx500_register_ops(ab8500->dev, &ab8500_ops); 137547c16975SMattias Wallin if (ret) 13768c4203cbSLee Jones return ret; 137747c16975SMattias Wallin 13782ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) 137962579266SRabin Vincent ab8500->mask[i] = ab8500->oldmask[i] = 0xff; 138062579266SRabin Vincent 138106e589efSLee Jones ret = ab8500_irq_init(ab8500, np); 138262579266SRabin Vincent if (ret) 13838c4203cbSLee Jones return ret; 138462579266SRabin Vincent 13857ccfe9b1SMichel JAOUEN /* Activate this feature only in ab9540 */ 13867ccfe9b1SMichel JAOUEN /* till tests are done on ab8500 1p2 or later*/ 138706e589efSLee Jones if (is_ab9540(ab8500)) { 13888c4203cbSLee Jones ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL, 13897ccfe9b1SMichel JAOUEN ab8500_hierarchical_irq, 13907ccfe9b1SMichel JAOUEN IRQF_ONESHOT | IRQF_NO_SUSPEND, 13917ccfe9b1SMichel JAOUEN "ab8500", ab8500); 139206e589efSLee Jones } 139306e589efSLee Jones else { 13948c4203cbSLee Jones ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL, 13957ccfe9b1SMichel JAOUEN ab8500_irq, 13964f079985SMattias Wallin IRQF_ONESHOT | IRQF_NO_SUSPEND, 13974f079985SMattias Wallin "ab8500", ab8500); 139862579266SRabin Vincent if (ret) 13998c4203cbSLee Jones return ret; 140062579266SRabin Vincent } 140162579266SRabin Vincent 1402d6255529SLinus Walleij ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs, 1403d6255529SLinus Walleij ARRAY_SIZE(abx500_common_devs), NULL, 140455692af5SMark Brown ab8500->irq_base, ab8500->domain); 1405d6255529SLinus Walleij if (ret) 14068c4203cbSLee Jones return ret; 1407d6255529SLinus Walleij 1408d6255529SLinus Walleij if (is_ab9540(ab8500)) 1409d6255529SLinus Walleij ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, 1410d6255529SLinus Walleij ARRAY_SIZE(ab9540_devs), NULL, 141155692af5SMark Brown ab8500->irq_base, ab8500->domain); 1412d6255529SLinus Walleij else 1413549931f9SSundar R Iyer ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, 141444f72e53SVirupax Sadashivpetimath ARRAY_SIZE(ab8500_devs), NULL, 141555692af5SMark Brown ab8500->irq_base, ab8500->domain); 14166bc4a568SLee Jones if (ret) 14178c4203cbSLee Jones return ret; 141844f72e53SVirupax Sadashivpetimath 141944f72e53SVirupax Sadashivpetimath if (is_ab9540(ab8500) || is_ab8505(ab8500)) 142044f72e53SVirupax Sadashivpetimath ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs, 142144f72e53SVirupax Sadashivpetimath ARRAY_SIZE(ab9540_ab8505_devs), NULL, 142255692af5SMark Brown ab8500->irq_base, ab8500->domain); 142362579266SRabin Vincent if (ret) 14248c4203cbSLee Jones return ret; 142562579266SRabin Vincent 14266ef9418cSRickard Andersson if (!no_bm) { 14276ef9418cSRickard Andersson /* Add battery management devices */ 14286ef9418cSRickard Andersson ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, 14296ef9418cSRickard Andersson ARRAY_SIZE(ab8500_bm_devs), NULL, 143055692af5SMark Brown ab8500->irq_base, ab8500->domain); 14316ef9418cSRickard Andersson if (ret) 14326ef9418cSRickard Andersson dev_err(ab8500->dev, "error adding bm devices\n"); 14336ef9418cSRickard Andersson } 14346ef9418cSRickard Andersson 1435d6255529SLinus Walleij if (is_ab9540(ab8500)) 1436d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1437d6255529SLinus Walleij &ab9540_attr_group); 1438d6255529SLinus Walleij else 1439d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1440d6255529SLinus Walleij &ab8500_attr_group); 1441cca69b67SMattias Wallin if (ret) 1442cca69b67SMattias Wallin dev_err(ab8500->dev, "error creating sysfs entries\n"); 144306e589efSLee Jones 144462579266SRabin Vincent return ret; 144562579266SRabin Vincent } 144662579266SRabin Vincent 14474740f73fSBill Pemberton static int ab8500_remove(struct platform_device *pdev) 144862579266SRabin Vincent { 1449d28f1db8SLee Jones struct ab8500 *ab8500 = platform_get_drvdata(pdev); 1450d28f1db8SLee Jones 1451d6255529SLinus Walleij if (is_ab9540(ab8500)) 1452d6255529SLinus Walleij sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group); 1453d6255529SLinus Walleij else 1454cca69b67SMattias Wallin sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group); 145506e589efSLee Jones 145662579266SRabin Vincent mfd_remove_devices(ab8500->dev); 145762579266SRabin Vincent 145862579266SRabin Vincent return 0; 145962579266SRabin Vincent } 146062579266SRabin Vincent 1461d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = { 1462d28f1db8SLee Jones { "ab8500-core", AB8500_VERSION_AB8500 }, 1463d28f1db8SLee Jones { "ab8505-i2c", AB8500_VERSION_AB8505 }, 1464d28f1db8SLee Jones { "ab9540-i2c", AB8500_VERSION_AB9540 }, 1465d28f1db8SLee Jones { "ab8540-i2c", AB8500_VERSION_AB8540 }, 1466d28f1db8SLee Jones { } 1467d28f1db8SLee Jones }; 1468d28f1db8SLee Jones 1469d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = { 1470d28f1db8SLee Jones .driver = { 1471d28f1db8SLee Jones .name = "ab8500-core", 1472d28f1db8SLee Jones .owner = THIS_MODULE, 1473d28f1db8SLee Jones }, 1474d28f1db8SLee Jones .probe = ab8500_probe, 147584449216SBill Pemberton .remove = ab8500_remove, 1476d28f1db8SLee Jones .id_table = ab8500_id, 1477d28f1db8SLee Jones }; 1478d28f1db8SLee Jones 1479d28f1db8SLee Jones static int __init ab8500_core_init(void) 1480d28f1db8SLee Jones { 1481d28f1db8SLee Jones return platform_driver_register(&ab8500_core_driver); 1482d28f1db8SLee Jones } 1483d28f1db8SLee Jones 1484d28f1db8SLee Jones static void __exit ab8500_core_exit(void) 1485d28f1db8SLee Jones { 1486d28f1db8SLee Jones platform_driver_unregister(&ab8500_core_driver); 1487d28f1db8SLee Jones } 1488ba7cbc3eSLee Jones core_initcall(ab8500_core_init); 1489d28f1db8SLee Jones module_exit(ab8500_core_exit); 1490d28f1db8SLee Jones 1491adceed62SMattias Wallin MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent"); 149262579266SRabin Vincent MODULE_DESCRIPTION("AB8500 MFD core"); 149362579266SRabin Vincent MODULE_LICENSE("GPL v2"); 1494