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 144*822672a7SLee 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 154*822672a7SLee 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 166*822672a7SLee 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, 32247c16975SMattias Wallin }; 32362579266SRabin Vincent 3249505a0a0SMark Brown static void ab8500_irq_lock(struct irq_data *data) 32562579266SRabin Vincent { 3269505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 32762579266SRabin Vincent 32862579266SRabin Vincent mutex_lock(&ab8500->irq_lock); 329112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 33062579266SRabin Vincent } 33162579266SRabin Vincent 3329505a0a0SMark Brown static void ab8500_irq_sync_unlock(struct irq_data *data) 33362579266SRabin Vincent { 3349505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 33562579266SRabin Vincent int i; 33662579266SRabin Vincent 3372ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 33862579266SRabin Vincent u8 old = ab8500->oldmask[i]; 33962579266SRabin Vincent u8 new = ab8500->mask[i]; 34062579266SRabin Vincent int reg; 34162579266SRabin Vincent 34262579266SRabin Vincent if (new == old) 34362579266SRabin Vincent continue; 34462579266SRabin Vincent 3450f620837SLinus Walleij /* 3460f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 3470f620837SLinus Walleij * 2.0 3480f620837SLinus Walleij */ 3490f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 3500f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 35192d50a41SMattias Wallin continue; 35292d50a41SMattias Wallin 35362579266SRabin Vincent ab8500->oldmask[i] = new; 35462579266SRabin Vincent 3552ced445eSLinus Walleij reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i]; 35647c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new); 35762579266SRabin Vincent } 358112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 35962579266SRabin Vincent mutex_unlock(&ab8500->irq_lock); 36062579266SRabin Vincent } 36162579266SRabin Vincent 3629505a0a0SMark Brown static void ab8500_irq_mask(struct irq_data *data) 36362579266SRabin Vincent { 3649505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 36506e589efSLee Jones int offset = data->hwirq; 36662579266SRabin Vincent int index = offset / 8; 36762579266SRabin Vincent int mask = 1 << (offset % 8); 36862579266SRabin Vincent 36962579266SRabin Vincent ab8500->mask[index] |= mask; 37062579266SRabin Vincent } 37162579266SRabin Vincent 3729505a0a0SMark Brown static void ab8500_irq_unmask(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; 38062579266SRabin Vincent } 38162579266SRabin Vincent 38262579266SRabin Vincent static struct irq_chip ab8500_irq_chip = { 38362579266SRabin Vincent .name = "ab8500", 3849505a0a0SMark Brown .irq_bus_lock = ab8500_irq_lock, 3859505a0a0SMark Brown .irq_bus_sync_unlock = ab8500_irq_sync_unlock, 3869505a0a0SMark Brown .irq_mask = ab8500_irq_mask, 387e6f9306eSVirupax Sadashivpetimath .irq_disable = ab8500_irq_mask, 3889505a0a0SMark Brown .irq_unmask = ab8500_irq_unmask, 38962579266SRabin Vincent }; 39062579266SRabin Vincent 3917ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, 3927ccfe9b1SMichel JAOUEN int latch_offset, u8 latch_val) 3937ccfe9b1SMichel JAOUEN { 3947ccfe9b1SMichel JAOUEN int int_bit = __ffs(latch_val); 3957ccfe9b1SMichel JAOUEN int line, i; 3967ccfe9b1SMichel JAOUEN 3977ccfe9b1SMichel JAOUEN do { 3987ccfe9b1SMichel JAOUEN int_bit = __ffs(latch_val); 3997ccfe9b1SMichel JAOUEN 4007ccfe9b1SMichel JAOUEN for (i = 0; i < ab8500->mask_size; i++) 4017ccfe9b1SMichel JAOUEN if (ab8500->irq_reg_offset[i] == latch_offset) 4027ccfe9b1SMichel JAOUEN break; 4037ccfe9b1SMichel JAOUEN 4047ccfe9b1SMichel JAOUEN if (i >= ab8500->mask_size) { 4057ccfe9b1SMichel JAOUEN dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", 4067ccfe9b1SMichel JAOUEN latch_offset); 4077ccfe9b1SMichel JAOUEN return -ENXIO; 4087ccfe9b1SMichel JAOUEN } 4097ccfe9b1SMichel JAOUEN 4107ccfe9b1SMichel JAOUEN line = (i << 3) + int_bit; 4117ccfe9b1SMichel JAOUEN latch_val &= ~(1 << int_bit); 4127ccfe9b1SMichel JAOUEN 4137ccfe9b1SMichel JAOUEN handle_nested_irq(ab8500->irq_base + line); 4147ccfe9b1SMichel JAOUEN } while (latch_val); 4157ccfe9b1SMichel JAOUEN 4167ccfe9b1SMichel JAOUEN return 0; 4177ccfe9b1SMichel JAOUEN } 4187ccfe9b1SMichel JAOUEN 4197ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500, 4207ccfe9b1SMichel JAOUEN int hier_offset, u8 hier_val) 4217ccfe9b1SMichel JAOUEN { 4227ccfe9b1SMichel JAOUEN int latch_bit, status; 4237ccfe9b1SMichel JAOUEN u8 latch_offset, latch_val; 4247ccfe9b1SMichel JAOUEN 4257ccfe9b1SMichel JAOUEN do { 4267ccfe9b1SMichel JAOUEN latch_bit = __ffs(hier_val); 4277ccfe9b1SMichel JAOUEN latch_offset = (hier_offset << 3) + latch_bit; 4287ccfe9b1SMichel JAOUEN 4297ccfe9b1SMichel JAOUEN /* Fix inconsistent ITFromLatch25 bit mapping... */ 4307ccfe9b1SMichel JAOUEN if (unlikely(latch_offset == 17)) 4317ccfe9b1SMichel JAOUEN latch_offset = 24; 4327ccfe9b1SMichel JAOUEN 4337ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, 4347ccfe9b1SMichel JAOUEN AB8500_INTERRUPT, 4357ccfe9b1SMichel JAOUEN AB8500_IT_LATCH1_REG + latch_offset, 4367ccfe9b1SMichel JAOUEN &latch_val); 4377ccfe9b1SMichel JAOUEN if (status < 0 || latch_val == 0) 4387ccfe9b1SMichel JAOUEN goto discard; 4397ccfe9b1SMichel JAOUEN 4407ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_line(ab8500, 4417ccfe9b1SMichel JAOUEN latch_offset, latch_val); 4427ccfe9b1SMichel JAOUEN if (status < 0) 4437ccfe9b1SMichel JAOUEN return status; 4447ccfe9b1SMichel JAOUEN discard: 4457ccfe9b1SMichel JAOUEN hier_val &= ~(1 << latch_bit); 4467ccfe9b1SMichel JAOUEN } while (hier_val); 4477ccfe9b1SMichel JAOUEN 4487ccfe9b1SMichel JAOUEN return 0; 4497ccfe9b1SMichel JAOUEN } 4507ccfe9b1SMichel JAOUEN 4517ccfe9b1SMichel JAOUEN static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev) 4527ccfe9b1SMichel JAOUEN { 4537ccfe9b1SMichel JAOUEN struct ab8500 *ab8500 = dev; 4547ccfe9b1SMichel JAOUEN u8 i; 4557ccfe9b1SMichel JAOUEN 4567ccfe9b1SMichel JAOUEN dev_vdbg(ab8500->dev, "interrupt\n"); 4577ccfe9b1SMichel JAOUEN 4587ccfe9b1SMichel JAOUEN /* Hierarchical interrupt version */ 4597ccfe9b1SMichel JAOUEN for (i = 0; i < AB8500_IT_LATCHHIER_NUM; i++) { 4607ccfe9b1SMichel JAOUEN int status; 4617ccfe9b1SMichel JAOUEN u8 hier_val; 4627ccfe9b1SMichel JAOUEN 4637ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, AB8500_INTERRUPT, 4647ccfe9b1SMichel JAOUEN AB8500_IT_LATCHHIER1_REG + i, &hier_val); 4657ccfe9b1SMichel JAOUEN if (status < 0 || hier_val == 0) 4667ccfe9b1SMichel JAOUEN continue; 4677ccfe9b1SMichel JAOUEN 4687ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val); 4697ccfe9b1SMichel JAOUEN if (status < 0) 4707ccfe9b1SMichel JAOUEN break; 4717ccfe9b1SMichel JAOUEN } 4727ccfe9b1SMichel JAOUEN return IRQ_HANDLED; 4737ccfe9b1SMichel JAOUEN } 4747ccfe9b1SMichel JAOUEN 47562579266SRabin Vincent static irqreturn_t ab8500_irq(int irq, void *dev) 47662579266SRabin Vincent { 47762579266SRabin Vincent struct ab8500 *ab8500 = dev; 47862579266SRabin Vincent int i; 47962579266SRabin Vincent 48062579266SRabin Vincent dev_vdbg(ab8500->dev, "interrupt\n"); 48162579266SRabin Vincent 482112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 483112a80d2SJonas Aaberg 4842ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 4852ced445eSLinus Walleij int regoffset = ab8500->irq_reg_offset[i]; 48662579266SRabin Vincent int status; 48747c16975SMattias Wallin u8 value; 48862579266SRabin Vincent 4890f620837SLinus Walleij /* 4900f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 4910f620837SLinus Walleij * 2.0 4920f620837SLinus Walleij */ 4930f620837SLinus Walleij if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500)) 49492d50a41SMattias Wallin continue; 49592d50a41SMattias Wallin 49647c16975SMattias Wallin status = get_register_interruptible(ab8500, AB8500_INTERRUPT, 49747c16975SMattias Wallin AB8500_IT_LATCH1_REG + regoffset, &value); 49847c16975SMattias Wallin if (status < 0 || value == 0) 49962579266SRabin Vincent continue; 50062579266SRabin Vincent 50162579266SRabin Vincent do { 50288aec4f7SMattias Wallin int bit = __ffs(value); 50362579266SRabin Vincent int line = i * 8 + bit; 50462579266SRabin Vincent 50562579266SRabin Vincent handle_nested_irq(ab8500->irq_base + line); 50647c16975SMattias Wallin value &= ~(1 << bit); 507112a80d2SJonas Aaberg 50847c16975SMattias Wallin } while (value); 50962579266SRabin Vincent } 510112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 51162579266SRabin Vincent return IRQ_HANDLED; 51262579266SRabin Vincent } 51362579266SRabin Vincent 51406e589efSLee Jones /** 51506e589efSLee Jones * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ 51606e589efSLee Jones * 51706e589efSLee Jones * @ab8500: ab8500_irq controller to operate on. 51806e589efSLee Jones * @irq: index of the interrupt requested in the chip IRQs 51906e589efSLee Jones * 52006e589efSLee Jones * Useful for drivers to request their own IRQs. 52106e589efSLee Jones */ 52206e589efSLee Jones int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq) 52362579266SRabin Vincent { 52406e589efSLee Jones if (!ab8500) 52506e589efSLee Jones return -EINVAL; 52662579266SRabin Vincent 52706e589efSLee Jones return irq_create_mapping(ab8500->domain, irq); 52862579266SRabin Vincent } 52906e589efSLee Jones EXPORT_SYMBOL_GPL(ab8500_irq_get_virq); 53006e589efSLee Jones 53106e589efSLee Jones static int ab8500_irq_map(struct irq_domain *d, unsigned int virq, 53206e589efSLee Jones irq_hw_number_t hwirq) 53306e589efSLee Jones { 53406e589efSLee Jones struct ab8500 *ab8500 = d->host_data; 53506e589efSLee Jones 53606e589efSLee Jones if (!ab8500) 53706e589efSLee Jones return -EINVAL; 53806e589efSLee Jones 53906e589efSLee Jones irq_set_chip_data(virq, ab8500); 54006e589efSLee Jones irq_set_chip_and_handler(virq, &ab8500_irq_chip, 54106e589efSLee Jones handle_simple_irq); 54206e589efSLee Jones irq_set_nested_thread(virq, 1); 54306e589efSLee Jones #ifdef CONFIG_ARM 54406e589efSLee Jones set_irq_flags(virq, IRQF_VALID); 54506e589efSLee Jones #else 54606e589efSLee Jones irq_set_noprobe(virq); 54706e589efSLee Jones #endif 54862579266SRabin Vincent 54962579266SRabin Vincent return 0; 55062579266SRabin Vincent } 55162579266SRabin Vincent 55206e589efSLee Jones static struct irq_domain_ops ab8500_irq_ops = { 55306e589efSLee Jones .map = ab8500_irq_map, 55406e589efSLee Jones .xlate = irq_domain_xlate_twocell, 55506e589efSLee Jones }; 55606e589efSLee Jones 55706e589efSLee Jones static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np) 55862579266SRabin Vincent { 5592ced445eSLinus Walleij int num_irqs; 56062579266SRabin Vincent 561d6255529SLinus Walleij if (is_ab9540(ab8500)) 562d6255529SLinus Walleij num_irqs = AB9540_NR_IRQS; 563a982362cSBengt Jonsson else if (is_ab8505(ab8500)) 564a982362cSBengt Jonsson num_irqs = AB8505_NR_IRQS; 565d6255529SLinus Walleij else 5662ced445eSLinus Walleij num_irqs = AB8500_NR_IRQS; 5672ced445eSLinus Walleij 56806e589efSLee Jones if (ab8500->irq_base) { 56906e589efSLee Jones ab8500->domain = irq_domain_add_legacy( 57006e589efSLee Jones NULL, num_irqs, ab8500->irq_base, 57106e589efSLee Jones 0, &ab8500_irq_ops, ab8500); 57262579266SRabin Vincent } 57306e589efSLee Jones else { 57406e589efSLee Jones ab8500->domain = irq_domain_add_linear( 57506e589efSLee Jones np, num_irqs, &ab8500_irq_ops, ab8500); 57606e589efSLee Jones } 57706e589efSLee Jones 57806e589efSLee Jones if (!ab8500->domain) { 57906e589efSLee Jones dev_err(ab8500->dev, "Failed to create irqdomain\n"); 58006e589efSLee Jones return -ENOSYS; 58106e589efSLee Jones } 58206e589efSLee Jones 58306e589efSLee Jones return 0; 58462579266SRabin Vincent } 58562579266SRabin Vincent 586112a80d2SJonas Aaberg int ab8500_suspend(struct ab8500 *ab8500) 587112a80d2SJonas Aaberg { 588112a80d2SJonas Aaberg if (atomic_read(&ab8500->transfer_ongoing)) 589112a80d2SJonas Aaberg return -EINVAL; 590112a80d2SJonas Aaberg else 591112a80d2SJonas Aaberg return 0; 592112a80d2SJonas Aaberg } 593112a80d2SJonas Aaberg 594d6255529SLinus Walleij /* AB8500 GPIO Resources */ 5955cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_gpio_resources[] = { 5960cb3fcd7SBibek Basu { 5970cb3fcd7SBibek Basu .name = "GPIO_INT6", 5980cb3fcd7SBibek Basu .start = AB8500_INT_GPIO6R, 5990cb3fcd7SBibek Basu .end = AB8500_INT_GPIO41F, 6000cb3fcd7SBibek Basu .flags = IORESOURCE_IRQ, 6010cb3fcd7SBibek Basu } 6020cb3fcd7SBibek Basu }; 6030cb3fcd7SBibek Basu 604d6255529SLinus Walleij /* AB9540 GPIO Resources */ 605d6255529SLinus Walleij static struct resource __devinitdata ab9540_gpio_resources[] = { 606d6255529SLinus Walleij { 607d6255529SLinus Walleij .name = "GPIO_INT6", 608d6255529SLinus Walleij .start = AB8500_INT_GPIO6R, 609d6255529SLinus Walleij .end = AB8500_INT_GPIO41F, 610d6255529SLinus Walleij .flags = IORESOURCE_IRQ, 611d6255529SLinus Walleij }, 612d6255529SLinus Walleij { 613d6255529SLinus Walleij .name = "GPIO_INT14", 614d6255529SLinus Walleij .start = AB9540_INT_GPIO50R, 615d6255529SLinus Walleij .end = AB9540_INT_GPIO54R, 616d6255529SLinus Walleij .flags = IORESOURCE_IRQ, 617d6255529SLinus Walleij }, 618d6255529SLinus Walleij { 619d6255529SLinus Walleij .name = "GPIO_INT15", 620d6255529SLinus Walleij .start = AB9540_INT_GPIO50F, 621d6255529SLinus Walleij .end = AB9540_INT_GPIO54F, 622d6255529SLinus Walleij .flags = IORESOURCE_IRQ, 623d6255529SLinus Walleij } 624d6255529SLinus Walleij }; 625d6255529SLinus Walleij 6265cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_gpadc_resources[] = { 62762579266SRabin Vincent { 62862579266SRabin Vincent .name = "HW_CONV_END", 62962579266SRabin Vincent .start = AB8500_INT_GP_HW_ADC_CONV_END, 63062579266SRabin Vincent .end = AB8500_INT_GP_HW_ADC_CONV_END, 63162579266SRabin Vincent .flags = IORESOURCE_IRQ, 63262579266SRabin Vincent }, 63362579266SRabin Vincent { 63462579266SRabin Vincent .name = "SW_CONV_END", 63562579266SRabin Vincent .start = AB8500_INT_GP_SW_ADC_CONV_END, 63662579266SRabin Vincent .end = AB8500_INT_GP_SW_ADC_CONV_END, 63762579266SRabin Vincent .flags = IORESOURCE_IRQ, 63862579266SRabin Vincent }, 63962579266SRabin Vincent }; 64062579266SRabin Vincent 6415cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_rtc_resources[] = { 64262579266SRabin Vincent { 64362579266SRabin Vincent .name = "60S", 64462579266SRabin Vincent .start = AB8500_INT_RTC_60S, 64562579266SRabin Vincent .end = AB8500_INT_RTC_60S, 64662579266SRabin Vincent .flags = IORESOURCE_IRQ, 64762579266SRabin Vincent }, 64862579266SRabin Vincent { 64962579266SRabin Vincent .name = "ALARM", 65062579266SRabin Vincent .start = AB8500_INT_RTC_ALARM, 65162579266SRabin Vincent .end = AB8500_INT_RTC_ALARM, 65262579266SRabin Vincent .flags = IORESOURCE_IRQ, 65362579266SRabin Vincent }, 65462579266SRabin Vincent }; 65562579266SRabin Vincent 6565cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_poweronkey_db_resources[] = { 65777686517SSundar R Iyer { 65877686517SSundar R Iyer .name = "ONKEY_DBF", 65977686517SSundar R Iyer .start = AB8500_INT_PON_KEY1DB_F, 66077686517SSundar R Iyer .end = AB8500_INT_PON_KEY1DB_F, 66177686517SSundar R Iyer .flags = IORESOURCE_IRQ, 66277686517SSundar R Iyer }, 66377686517SSundar R Iyer { 66477686517SSundar R Iyer .name = "ONKEY_DBR", 66577686517SSundar R Iyer .start = AB8500_INT_PON_KEY1DB_R, 66677686517SSundar R Iyer .end = AB8500_INT_PON_KEY1DB_R, 66777686517SSundar R Iyer .flags = IORESOURCE_IRQ, 66877686517SSundar R Iyer }, 66977686517SSundar R Iyer }; 67077686517SSundar R Iyer 6716af75ecdSLinus Walleij static struct resource __devinitdata ab8500_av_acc_detect_resources[] = { 672e098adedSMattias Wallin { 6736af75ecdSLinus Walleij .name = "ACC_DETECT_1DB_F", 6746af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_1DB_F, 6756af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_1DB_F, 676e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 677e098adedSMattias Wallin }, 678e098adedSMattias Wallin { 6796af75ecdSLinus Walleij .name = "ACC_DETECT_1DB_R", 6806af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_1DB_R, 6816af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_1DB_R, 682e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 683e098adedSMattias Wallin }, 684e098adedSMattias Wallin { 6856af75ecdSLinus Walleij .name = "ACC_DETECT_21DB_F", 6866af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_21DB_F, 6876af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_21DB_F, 6886af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 6896af75ecdSLinus Walleij }, 6906af75ecdSLinus Walleij { 6916af75ecdSLinus Walleij .name = "ACC_DETECT_21DB_R", 6926af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_21DB_R, 6936af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_21DB_R, 6946af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 6956af75ecdSLinus Walleij }, 6966af75ecdSLinus Walleij { 6976af75ecdSLinus Walleij .name = "ACC_DETECT_22DB_F", 6986af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_22DB_F, 6996af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_22DB_F, 7006af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7016af75ecdSLinus Walleij }, 7026af75ecdSLinus Walleij { 7036af75ecdSLinus Walleij .name = "ACC_DETECT_22DB_R", 7046af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_22DB_R, 7056af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_22DB_R, 7066af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7076af75ecdSLinus Walleij }, 7086af75ecdSLinus Walleij }; 7096af75ecdSLinus Walleij 7106af75ecdSLinus Walleij static struct resource __devinitdata ab8500_charger_resources[] = { 7116af75ecdSLinus Walleij { 712e098adedSMattias Wallin .name = "MAIN_CH_UNPLUG_DET", 713e098adedSMattias Wallin .start = AB8500_INT_MAIN_CH_UNPLUG_DET, 714e098adedSMattias Wallin .end = AB8500_INT_MAIN_CH_UNPLUG_DET, 715e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 716e098adedSMattias Wallin }, 717e098adedSMattias Wallin { 718e098adedSMattias Wallin .name = "MAIN_CHARGE_PLUG_DET", 719e098adedSMattias Wallin .start = AB8500_INT_MAIN_CH_PLUG_DET, 720e098adedSMattias Wallin .end = AB8500_INT_MAIN_CH_PLUG_DET, 721e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 722e098adedSMattias Wallin }, 723e098adedSMattias Wallin { 724e098adedSMattias Wallin .name = "VBUS_DET_R", 725e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_R, 726e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_R, 727e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 728e098adedSMattias Wallin }, 729e098adedSMattias Wallin { 7306af75ecdSLinus Walleij .name = "VBUS_DET_F", 7316af75ecdSLinus Walleij .start = AB8500_INT_VBUS_DET_F, 7326af75ecdSLinus Walleij .end = AB8500_INT_VBUS_DET_F, 733e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 734e098adedSMattias Wallin }, 735e098adedSMattias Wallin { 7366af75ecdSLinus Walleij .name = "USB_LINK_STATUS", 7376af75ecdSLinus Walleij .start = AB8500_INT_USB_LINK_STATUS, 7386af75ecdSLinus Walleij .end = AB8500_INT_USB_LINK_STATUS, 7396af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7406af75ecdSLinus Walleij }, 7416af75ecdSLinus Walleij { 742e098adedSMattias Wallin .name = "VBUS_OVV", 743e098adedSMattias Wallin .start = AB8500_INT_VBUS_OVV, 744e098adedSMattias Wallin .end = AB8500_INT_VBUS_OVV, 745e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 746e098adedSMattias Wallin }, 747e098adedSMattias Wallin { 7486af75ecdSLinus Walleij .name = "USB_CH_TH_PROT_R", 7496af75ecdSLinus Walleij .start = AB8500_INT_USB_CH_TH_PROT_R, 7506af75ecdSLinus Walleij .end = AB8500_INT_USB_CH_TH_PROT_R, 751e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 752e098adedSMattias Wallin }, 753e098adedSMattias Wallin { 7546af75ecdSLinus Walleij .name = "USB_CH_TH_PROT_F", 7556af75ecdSLinus Walleij .start = AB8500_INT_USB_CH_TH_PROT_F, 7566af75ecdSLinus Walleij .end = AB8500_INT_USB_CH_TH_PROT_F, 757e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 758e098adedSMattias Wallin }, 759e098adedSMattias Wallin { 7606af75ecdSLinus Walleij .name = "MAIN_EXT_CH_NOT_OK", 7616af75ecdSLinus Walleij .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, 7626af75ecdSLinus Walleij .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, 7636af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7646af75ecdSLinus Walleij }, 7656af75ecdSLinus Walleij { 7666af75ecdSLinus Walleij .name = "MAIN_CH_TH_PROT_R", 7676af75ecdSLinus Walleij .start = AB8500_INT_MAIN_CH_TH_PROT_R, 7686af75ecdSLinus Walleij .end = AB8500_INT_MAIN_CH_TH_PROT_R, 7696af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7706af75ecdSLinus Walleij }, 7716af75ecdSLinus Walleij { 7726af75ecdSLinus Walleij .name = "MAIN_CH_TH_PROT_F", 7736af75ecdSLinus Walleij .start = AB8500_INT_MAIN_CH_TH_PROT_F, 7746af75ecdSLinus Walleij .end = AB8500_INT_MAIN_CH_TH_PROT_F, 7756af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7766af75ecdSLinus Walleij }, 7776af75ecdSLinus Walleij { 7786af75ecdSLinus Walleij .name = "USB_CHARGER_NOT_OKR", 779a982362cSBengt Jonsson .start = AB8500_INT_USB_CHARGER_NOT_OKR, 780a982362cSBengt Jonsson .end = AB8500_INT_USB_CHARGER_NOT_OKR, 7816af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7826af75ecdSLinus Walleij }, 7836af75ecdSLinus Walleij { 7846af75ecdSLinus Walleij .name = "CH_WD_EXP", 7856af75ecdSLinus Walleij .start = AB8500_INT_CH_WD_EXP, 7866af75ecdSLinus Walleij .end = AB8500_INT_CH_WD_EXP, 7876af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7886af75ecdSLinus Walleij }, 7896af75ecdSLinus Walleij }; 7906af75ecdSLinus Walleij 7916af75ecdSLinus Walleij static struct resource __devinitdata ab8500_btemp_resources[] = { 7926af75ecdSLinus Walleij { 7936af75ecdSLinus Walleij .name = "BAT_CTRL_INDB", 7946af75ecdSLinus Walleij .start = AB8500_INT_BAT_CTRL_INDB, 7956af75ecdSLinus Walleij .end = AB8500_INT_BAT_CTRL_INDB, 796e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 797e098adedSMattias Wallin }, 798e098adedSMattias Wallin { 799e098adedSMattias Wallin .name = "BTEMP_LOW", 800e098adedSMattias Wallin .start = AB8500_INT_BTEMP_LOW, 801e098adedSMattias Wallin .end = AB8500_INT_BTEMP_LOW, 802e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 803e098adedSMattias Wallin }, 804e098adedSMattias Wallin { 805e098adedSMattias Wallin .name = "BTEMP_HIGH", 806e098adedSMattias Wallin .start = AB8500_INT_BTEMP_HIGH, 807e098adedSMattias Wallin .end = AB8500_INT_BTEMP_HIGH, 808e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 809e098adedSMattias Wallin }, 810e098adedSMattias Wallin { 8116af75ecdSLinus Walleij .name = "BTEMP_LOW_MEDIUM", 8126af75ecdSLinus Walleij .start = AB8500_INT_BTEMP_LOW_MEDIUM, 8136af75ecdSLinus Walleij .end = AB8500_INT_BTEMP_LOW_MEDIUM, 814e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 815e098adedSMattias Wallin }, 816e098adedSMattias Wallin { 8176af75ecdSLinus Walleij .name = "BTEMP_MEDIUM_HIGH", 8186af75ecdSLinus Walleij .start = AB8500_INT_BTEMP_MEDIUM_HIGH, 8196af75ecdSLinus Walleij .end = AB8500_INT_BTEMP_MEDIUM_HIGH, 820e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 821e098adedSMattias Wallin }, 822e098adedSMattias Wallin }; 823e098adedSMattias Wallin 8246af75ecdSLinus Walleij static struct resource __devinitdata ab8500_fg_resources[] = { 8256af75ecdSLinus Walleij { 8266af75ecdSLinus Walleij .name = "NCONV_ACCU", 8276af75ecdSLinus Walleij .start = AB8500_INT_CCN_CONV_ACC, 8286af75ecdSLinus Walleij .end = AB8500_INT_CCN_CONV_ACC, 8296af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8306af75ecdSLinus Walleij }, 8316af75ecdSLinus Walleij { 8326af75ecdSLinus Walleij .name = "BATT_OVV", 8336af75ecdSLinus Walleij .start = AB8500_INT_BATT_OVV, 8346af75ecdSLinus Walleij .end = AB8500_INT_BATT_OVV, 8356af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8366af75ecdSLinus Walleij }, 8376af75ecdSLinus Walleij { 8386af75ecdSLinus Walleij .name = "LOW_BAT_F", 8396af75ecdSLinus Walleij .start = AB8500_INT_LOW_BAT_F, 8406af75ecdSLinus Walleij .end = AB8500_INT_LOW_BAT_F, 8416af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8426af75ecdSLinus Walleij }, 8436af75ecdSLinus Walleij { 8446af75ecdSLinus Walleij .name = "LOW_BAT_R", 8456af75ecdSLinus Walleij .start = AB8500_INT_LOW_BAT_R, 8466af75ecdSLinus Walleij .end = AB8500_INT_LOW_BAT_R, 8476af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8486af75ecdSLinus Walleij }, 8496af75ecdSLinus Walleij { 8506af75ecdSLinus Walleij .name = "CC_INT_CALIB", 8516af75ecdSLinus Walleij .start = AB8500_INT_CC_INT_CALIB, 8526af75ecdSLinus Walleij .end = AB8500_INT_CC_INT_CALIB, 8536af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8546af75ecdSLinus Walleij }, 855a982362cSBengt Jonsson { 856a982362cSBengt Jonsson .name = "CCEOC", 857a982362cSBengt Jonsson .start = AB8500_INT_CCEOC, 858a982362cSBengt Jonsson .end = AB8500_INT_CCEOC, 859a982362cSBengt Jonsson .flags = IORESOURCE_IRQ, 860a982362cSBengt Jonsson }, 8616af75ecdSLinus Walleij }; 8626af75ecdSLinus Walleij 8636af75ecdSLinus Walleij static struct resource __devinitdata ab8500_chargalg_resources[] = {}; 8646af75ecdSLinus Walleij 865df720647SAxel Lin #ifdef CONFIG_DEBUG_FS 8665cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_debug_resources[] = { 867e098adedSMattias Wallin { 868e098adedSMattias Wallin .name = "IRQ_FIRST", 869e098adedSMattias Wallin .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, 870e098adedSMattias Wallin .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, 871e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 872e098adedSMattias Wallin }, 873e098adedSMattias Wallin { 874e098adedSMattias Wallin .name = "IRQ_LAST", 875a982362cSBengt Jonsson .start = AB8500_INT_XTAL32K_KO, 876a982362cSBengt Jonsson .end = AB8500_INT_XTAL32K_KO, 877e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 878e098adedSMattias Wallin }, 879e098adedSMattias Wallin }; 880df720647SAxel Lin #endif 881e098adedSMattias Wallin 8825cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_usb_resources[] = { 883e098adedSMattias Wallin { 884e098adedSMattias Wallin .name = "ID_WAKEUP_R", 885e098adedSMattias Wallin .start = AB8500_INT_ID_WAKEUP_R, 886e098adedSMattias Wallin .end = AB8500_INT_ID_WAKEUP_R, 887e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 888e098adedSMattias Wallin }, 889e098adedSMattias Wallin { 890e098adedSMattias Wallin .name = "ID_WAKEUP_F", 891e098adedSMattias Wallin .start = AB8500_INT_ID_WAKEUP_F, 892e098adedSMattias Wallin .end = AB8500_INT_ID_WAKEUP_F, 893e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 894e098adedSMattias Wallin }, 895e098adedSMattias Wallin { 896e098adedSMattias Wallin .name = "VBUS_DET_F", 897e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_F, 898e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_F, 899e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 900e098adedSMattias Wallin }, 901e098adedSMattias Wallin { 902e098adedSMattias Wallin .name = "VBUS_DET_R", 903e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_R, 904e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_R, 905e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 906e098adedSMattias Wallin }, 90792d50a41SMattias Wallin { 90892d50a41SMattias Wallin .name = "USB_LINK_STATUS", 90992d50a41SMattias Wallin .start = AB8500_INT_USB_LINK_STATUS, 91092d50a41SMattias Wallin .end = AB8500_INT_USB_LINK_STATUS, 91192d50a41SMattias Wallin .flags = IORESOURCE_IRQ, 91292d50a41SMattias Wallin }, 9136af75ecdSLinus Walleij { 9146af75ecdSLinus Walleij .name = "USB_ADP_PROBE_PLUG", 9156af75ecdSLinus Walleij .start = AB8500_INT_ADP_PROBE_PLUG, 9166af75ecdSLinus Walleij .end = AB8500_INT_ADP_PROBE_PLUG, 9176af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 9186af75ecdSLinus Walleij }, 9196af75ecdSLinus Walleij { 9206af75ecdSLinus Walleij .name = "USB_ADP_PROBE_UNPLUG", 9216af75ecdSLinus Walleij .start = AB8500_INT_ADP_PROBE_UNPLUG, 9226af75ecdSLinus Walleij .end = AB8500_INT_ADP_PROBE_UNPLUG, 9236af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 9246af75ecdSLinus Walleij }, 925e098adedSMattias Wallin }; 926e098adedSMattias Wallin 92744f72e53SVirupax Sadashivpetimath static struct resource __devinitdata ab8505_iddet_resources[] = { 92844f72e53SVirupax Sadashivpetimath { 92944f72e53SVirupax Sadashivpetimath .name = "KeyDeglitch", 93044f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KEYDEGLITCH, 93144f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KEYDEGLITCH, 93244f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 93344f72e53SVirupax Sadashivpetimath }, 93444f72e53SVirupax Sadashivpetimath { 93544f72e53SVirupax Sadashivpetimath .name = "KP", 93644f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KP, 93744f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KP, 93844f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 93944f72e53SVirupax Sadashivpetimath }, 94044f72e53SVirupax Sadashivpetimath { 94144f72e53SVirupax Sadashivpetimath .name = "IKP", 94244f72e53SVirupax Sadashivpetimath .start = AB8505_INT_IKP, 94344f72e53SVirupax Sadashivpetimath .end = AB8505_INT_IKP, 94444f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 94544f72e53SVirupax Sadashivpetimath }, 94644f72e53SVirupax Sadashivpetimath { 94744f72e53SVirupax Sadashivpetimath .name = "IKR", 94844f72e53SVirupax Sadashivpetimath .start = AB8505_INT_IKR, 94944f72e53SVirupax Sadashivpetimath .end = AB8505_INT_IKR, 95044f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 95144f72e53SVirupax Sadashivpetimath }, 95244f72e53SVirupax Sadashivpetimath { 95344f72e53SVirupax Sadashivpetimath .name = "KeyStuck", 95444f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KEYSTUCK, 95544f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KEYSTUCK, 95644f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 95744f72e53SVirupax Sadashivpetimath }, 95844f72e53SVirupax Sadashivpetimath }; 95944f72e53SVirupax Sadashivpetimath 9605cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_temp_resources[] = { 961e098adedSMattias Wallin { 962e098adedSMattias Wallin .name = "AB8500_TEMP_WARM", 963e098adedSMattias Wallin .start = AB8500_INT_TEMP_WARM, 964e098adedSMattias Wallin .end = AB8500_INT_TEMP_WARM, 965e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 966e098adedSMattias Wallin }, 967e098adedSMattias Wallin }; 968e098adedSMattias Wallin 969d6255529SLinus Walleij static struct mfd_cell __devinitdata abx500_common_devs[] = { 9705814fc35SMattias Wallin #ifdef CONFIG_DEBUG_FS 9715814fc35SMattias Wallin { 9725814fc35SMattias Wallin .name = "ab8500-debug", 973e098adedSMattias Wallin .num_resources = ARRAY_SIZE(ab8500_debug_resources), 974e098adedSMattias Wallin .resources = ab8500_debug_resources, 9755814fc35SMattias Wallin }, 9765814fc35SMattias Wallin #endif 97762579266SRabin Vincent { 978e098adedSMattias Wallin .name = "ab8500-sysctrl", 979e098adedSMattias Wallin }, 980e098adedSMattias Wallin { 981e098adedSMattias Wallin .name = "ab8500-regulator", 982e098adedSMattias Wallin }, 983e098adedSMattias Wallin { 98462579266SRabin Vincent .name = "ab8500-gpadc", 98562579266SRabin Vincent .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), 98662579266SRabin Vincent .resources = ab8500_gpadc_resources, 98762579266SRabin Vincent }, 98862579266SRabin Vincent { 98962579266SRabin Vincent .name = "ab8500-rtc", 99062579266SRabin Vincent .num_resources = ARRAY_SIZE(ab8500_rtc_resources), 99162579266SRabin Vincent .resources = ab8500_rtc_resources, 99262579266SRabin Vincent }, 993f0f05b1cSArun Murthy { 9946af75ecdSLinus Walleij .name = "ab8500-acc-det", 9956af75ecdSLinus Walleij .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources), 9966af75ecdSLinus Walleij .resources = ab8500_av_acc_detect_resources, 9976af75ecdSLinus Walleij }, 9986af75ecdSLinus Walleij { 999e098adedSMattias Wallin .name = "ab8500-poweron-key", 1000e098adedSMattias Wallin .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), 1001e098adedSMattias Wallin .resources = ab8500_poweronkey_db_resources, 1002e098adedSMattias Wallin }, 1003e098adedSMattias Wallin { 1004f0f05b1cSArun Murthy .name = "ab8500-pwm", 1005f0f05b1cSArun Murthy .id = 1, 1006f0f05b1cSArun Murthy }, 1007f0f05b1cSArun Murthy { 1008f0f05b1cSArun Murthy .name = "ab8500-pwm", 1009f0f05b1cSArun Murthy .id = 2, 1010f0f05b1cSArun Murthy }, 1011f0f05b1cSArun Murthy { 1012f0f05b1cSArun Murthy .name = "ab8500-pwm", 1013f0f05b1cSArun Murthy .id = 3, 1014f0f05b1cSArun Murthy }, 1015e098adedSMattias Wallin { .name = "ab8500-leds", }, 101677686517SSundar R Iyer { 1017e098adedSMattias Wallin .name = "ab8500-denc", 1018e098adedSMattias Wallin }, 1019e098adedSMattias Wallin { 1020e098adedSMattias Wallin .name = "ab8500-temp", 1021e098adedSMattias Wallin .num_resources = ARRAY_SIZE(ab8500_temp_resources), 1022e098adedSMattias Wallin .resources = ab8500_temp_resources, 102377686517SSundar R Iyer }, 102462579266SRabin Vincent }; 102562579266SRabin Vincent 10266ef9418cSRickard Andersson static struct mfd_cell __devinitdata ab8500_bm_devs[] = { 10276ef9418cSRickard Andersson { 10286ef9418cSRickard Andersson .name = "ab8500-charger", 10296ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_charger_resources), 10306ef9418cSRickard Andersson .resources = ab8500_charger_resources, 10316ef9418cSRickard Andersson }, 10326ef9418cSRickard Andersson { 10336ef9418cSRickard Andersson .name = "ab8500-btemp", 10346ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_btemp_resources), 10356ef9418cSRickard Andersson .resources = ab8500_btemp_resources, 10366ef9418cSRickard Andersson }, 10376ef9418cSRickard Andersson { 10386ef9418cSRickard Andersson .name = "ab8500-fg", 10396ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_fg_resources), 10406ef9418cSRickard Andersson .resources = ab8500_fg_resources, 10416ef9418cSRickard Andersson }, 10426ef9418cSRickard Andersson { 10436ef9418cSRickard Andersson .name = "ab8500-chargalg", 10446ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_chargalg_resources), 10456ef9418cSRickard Andersson .resources = ab8500_chargalg_resources, 10466ef9418cSRickard Andersson }, 10476ef9418cSRickard Andersson }; 10486ef9418cSRickard Andersson 1049d6255529SLinus Walleij static struct mfd_cell __devinitdata ab8500_devs[] = { 1050d6255529SLinus Walleij { 1051d6255529SLinus Walleij .name = "ab8500-gpio", 1052d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab8500_gpio_resources), 1053d6255529SLinus Walleij .resources = ab8500_gpio_resources, 1054d6255529SLinus Walleij }, 1055d6255529SLinus Walleij { 1056d6255529SLinus Walleij .name = "ab8500-usb", 1057d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab8500_usb_resources), 1058d6255529SLinus Walleij .resources = ab8500_usb_resources, 1059d6255529SLinus Walleij }, 106044f72e53SVirupax Sadashivpetimath { 106144f72e53SVirupax Sadashivpetimath .name = "ab8500-codec", 106244f72e53SVirupax Sadashivpetimath }, 1063d6255529SLinus Walleij }; 1064d6255529SLinus Walleij 1065d6255529SLinus Walleij static struct mfd_cell __devinitdata ab9540_devs[] = { 1066d6255529SLinus Walleij { 1067d6255529SLinus Walleij .name = "ab8500-gpio", 1068d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab9540_gpio_resources), 1069d6255529SLinus Walleij .resources = ab9540_gpio_resources, 1070d6255529SLinus Walleij }, 1071d6255529SLinus Walleij { 1072d6255529SLinus Walleij .name = "ab9540-usb", 1073d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab8500_usb_resources), 1074d6255529SLinus Walleij .resources = ab8500_usb_resources, 1075d6255529SLinus Walleij }, 107644f72e53SVirupax Sadashivpetimath { 107744f72e53SVirupax Sadashivpetimath .name = "ab9540-codec", 107844f72e53SVirupax Sadashivpetimath }, 107944f72e53SVirupax Sadashivpetimath }; 108044f72e53SVirupax Sadashivpetimath 108144f72e53SVirupax Sadashivpetimath /* Device list common to ab9540 and ab8505 */ 108244f72e53SVirupax Sadashivpetimath static struct mfd_cell __devinitdata ab9540_ab8505_devs[] = { 108344f72e53SVirupax Sadashivpetimath { 108444f72e53SVirupax Sadashivpetimath .name = "ab-iddet", 108544f72e53SVirupax Sadashivpetimath .num_resources = ARRAY_SIZE(ab8505_iddet_resources), 108644f72e53SVirupax Sadashivpetimath .resources = ab8505_iddet_resources, 108744f72e53SVirupax Sadashivpetimath }, 1088d6255529SLinus Walleij }; 1089d6255529SLinus Walleij 1090cca69b67SMattias Wallin static ssize_t show_chip_id(struct device *dev, 1091cca69b67SMattias Wallin struct device_attribute *attr, char *buf) 1092cca69b67SMattias Wallin { 1093cca69b67SMattias Wallin struct ab8500 *ab8500; 1094cca69b67SMattias Wallin 1095cca69b67SMattias Wallin ab8500 = dev_get_drvdata(dev); 1096cca69b67SMattias Wallin return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); 1097cca69b67SMattias Wallin } 1098cca69b67SMattias Wallin 1099e5c238c3SMattias Wallin /* 1100e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 1101e5c238c3SMattias Wallin * 0x01 Swoff bit programming 1102e5c238c3SMattias Wallin * 0x02 Thermal protection activation 1103e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 1104e5c238c3SMattias Wallin * 0x08 Watchdog expired 1105e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 1106e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 1107e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 1108e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 1109e5c238c3SMattias Wallin */ 1110e5c238c3SMattias Wallin static ssize_t show_switch_off_status(struct device *dev, 1111e5c238c3SMattias Wallin struct device_attribute *attr, char *buf) 1112e5c238c3SMattias Wallin { 1113e5c238c3SMattias Wallin int ret; 1114e5c238c3SMattias Wallin u8 value; 1115e5c238c3SMattias Wallin struct ab8500 *ab8500; 1116e5c238c3SMattias Wallin 1117e5c238c3SMattias Wallin ab8500 = dev_get_drvdata(dev); 1118e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 1119e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 1120e5c238c3SMattias Wallin if (ret < 0) 1121e5c238c3SMattias Wallin return ret; 1122e5c238c3SMattias Wallin return sprintf(buf, "%#x\n", value); 1123e5c238c3SMattias Wallin } 1124e5c238c3SMattias Wallin 1125b4a31037SAndrew Lynn /* 1126b4a31037SAndrew Lynn * ab8500 has turned on due to (TURN_ON_STATUS): 1127b4a31037SAndrew Lynn * 0x01 PORnVbat 1128b4a31037SAndrew Lynn * 0x02 PonKey1dbF 1129b4a31037SAndrew Lynn * 0x04 PonKey2dbF 1130b4a31037SAndrew Lynn * 0x08 RTCAlarm 1131b4a31037SAndrew Lynn * 0x10 MainChDet 1132b4a31037SAndrew Lynn * 0x20 VbusDet 1133b4a31037SAndrew Lynn * 0x40 UsbIDDetect 1134b4a31037SAndrew Lynn * 0x80 Reserved 1135b4a31037SAndrew Lynn */ 1136b4a31037SAndrew Lynn static ssize_t show_turn_on_status(struct device *dev, 1137b4a31037SAndrew Lynn struct device_attribute *attr, char *buf) 1138b4a31037SAndrew Lynn { 1139b4a31037SAndrew Lynn int ret; 1140b4a31037SAndrew Lynn u8 value; 1141b4a31037SAndrew Lynn struct ab8500 *ab8500; 1142b4a31037SAndrew Lynn 1143b4a31037SAndrew Lynn ab8500 = dev_get_drvdata(dev); 1144b4a31037SAndrew Lynn ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 1145b4a31037SAndrew Lynn AB8500_TURN_ON_STATUS, &value); 1146b4a31037SAndrew Lynn if (ret < 0) 1147b4a31037SAndrew Lynn return ret; 1148b4a31037SAndrew Lynn return sprintf(buf, "%#x\n", value); 1149b4a31037SAndrew Lynn } 1150b4a31037SAndrew Lynn 1151d6255529SLinus Walleij static ssize_t show_ab9540_dbbrstn(struct device *dev, 1152d6255529SLinus Walleij struct device_attribute *attr, char *buf) 1153d6255529SLinus Walleij { 1154d6255529SLinus Walleij struct ab8500 *ab8500; 1155d6255529SLinus Walleij int ret; 1156d6255529SLinus Walleij u8 value; 1157d6255529SLinus Walleij 1158d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 1159d6255529SLinus Walleij 1160d6255529SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2, 1161d6255529SLinus Walleij AB9540_MODEM_CTRL2_REG, &value); 1162d6255529SLinus Walleij if (ret < 0) 1163d6255529SLinus Walleij return ret; 1164d6255529SLinus Walleij 1165d6255529SLinus Walleij return sprintf(buf, "%d\n", 1166d6255529SLinus Walleij (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0); 1167d6255529SLinus Walleij } 1168d6255529SLinus Walleij 1169d6255529SLinus Walleij static ssize_t store_ab9540_dbbrstn(struct device *dev, 1170d6255529SLinus Walleij struct device_attribute *attr, const char *buf, size_t count) 1171d6255529SLinus Walleij { 1172d6255529SLinus Walleij struct ab8500 *ab8500; 1173d6255529SLinus Walleij int ret = count; 1174d6255529SLinus Walleij int err; 1175d6255529SLinus Walleij u8 bitvalues; 1176d6255529SLinus Walleij 1177d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 1178d6255529SLinus Walleij 1179d6255529SLinus Walleij if (count > 0) { 1180d6255529SLinus Walleij switch (buf[0]) { 1181d6255529SLinus Walleij case '0': 1182d6255529SLinus Walleij bitvalues = 0; 1183d6255529SLinus Walleij break; 1184d6255529SLinus Walleij case '1': 1185d6255529SLinus Walleij bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT; 1186d6255529SLinus Walleij break; 1187d6255529SLinus Walleij default: 1188d6255529SLinus Walleij goto exit; 1189d6255529SLinus Walleij } 1190d6255529SLinus Walleij 1191d6255529SLinus Walleij err = mask_and_set_register_interruptible(ab8500, 1192d6255529SLinus Walleij AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG, 1193d6255529SLinus Walleij AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues); 1194d6255529SLinus Walleij if (err) 1195d6255529SLinus Walleij dev_info(ab8500->dev, 1196d6255529SLinus Walleij "Failed to set DBBRSTN %c, err %#x\n", 1197d6255529SLinus Walleij buf[0], err); 1198d6255529SLinus Walleij } 1199d6255529SLinus Walleij 1200d6255529SLinus Walleij exit: 1201d6255529SLinus Walleij return ret; 1202d6255529SLinus Walleij } 1203d6255529SLinus Walleij 1204cca69b67SMattias Wallin static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); 1205e5c238c3SMattias Wallin static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL); 1206b4a31037SAndrew Lynn static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL); 1207d6255529SLinus Walleij static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR, 1208d6255529SLinus Walleij show_ab9540_dbbrstn, store_ab9540_dbbrstn); 1209cca69b67SMattias Wallin 1210cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = { 1211cca69b67SMattias Wallin &dev_attr_chip_id.attr, 1212e5c238c3SMattias Wallin &dev_attr_switch_off_status.attr, 1213b4a31037SAndrew Lynn &dev_attr_turn_on_status.attr, 1214cca69b67SMattias Wallin NULL, 1215cca69b67SMattias Wallin }; 1216cca69b67SMattias Wallin 1217d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = { 1218d6255529SLinus Walleij &dev_attr_chip_id.attr, 1219d6255529SLinus Walleij &dev_attr_switch_off_status.attr, 1220d6255529SLinus Walleij &dev_attr_turn_on_status.attr, 1221d6255529SLinus Walleij &dev_attr_dbbrstn.attr, 1222d6255529SLinus Walleij NULL, 1223d6255529SLinus Walleij }; 1224d6255529SLinus Walleij 1225cca69b67SMattias Wallin static struct attribute_group ab8500_attr_group = { 1226cca69b67SMattias Wallin .attrs = ab8500_sysfs_entries, 1227cca69b67SMattias Wallin }; 1228cca69b67SMattias Wallin 1229d6255529SLinus Walleij static struct attribute_group ab9540_attr_group = { 1230d6255529SLinus Walleij .attrs = ab9540_sysfs_entries, 1231d6255529SLinus Walleij }; 1232d6255529SLinus Walleij 12336bc4a568SLee Jones static const struct of_device_id ab8500_match[] = { 12346bc4a568SLee Jones { 12356bc4a568SLee Jones .compatible = "stericsson,ab8500", 12366bc4a568SLee Jones .data = (void *)AB8500_VERSION_AB8500, 12376bc4a568SLee Jones }, 12386bc4a568SLee Jones {}, 12396bc4a568SLee Jones }; 12406bc4a568SLee Jones 1241d28f1db8SLee Jones static int __devinit ab8500_probe(struct platform_device *pdev) 124262579266SRabin Vincent { 1243d28f1db8SLee Jones struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev); 1244d28f1db8SLee Jones const struct platform_device_id *platid = platform_get_device_id(pdev); 12456bc4a568SLee Jones enum ab8500_version version = AB8500_VERSION_UNDEFINED; 12466bc4a568SLee Jones struct device_node *np = pdev->dev.of_node; 1247d28f1db8SLee Jones struct ab8500 *ab8500; 1248d28f1db8SLee Jones struct resource *resource; 124962579266SRabin Vincent int ret; 125062579266SRabin Vincent int i; 125147c16975SMattias Wallin u8 value; 125262579266SRabin Vincent 1253d28f1db8SLee Jones ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL); 1254d28f1db8SLee Jones if (!ab8500) 1255d28f1db8SLee Jones return -ENOMEM; 1256d28f1db8SLee Jones 125762579266SRabin Vincent if (plat) 125862579266SRabin Vincent ab8500->irq_base = plat->irq_base; 125962579266SRabin Vincent 1260d28f1db8SLee Jones ab8500->dev = &pdev->dev; 1261d28f1db8SLee Jones 1262d28f1db8SLee Jones resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 1263d28f1db8SLee Jones if (!resource) { 1264d28f1db8SLee Jones ret = -ENODEV; 1265d28f1db8SLee Jones goto out_free_ab8500; 1266d28f1db8SLee Jones } 1267d28f1db8SLee Jones 1268d28f1db8SLee Jones ab8500->irq = resource->start; 1269d28f1db8SLee Jones 1270*822672a7SLee Jones ab8500->read = ab8500_prcmu_read; 1271*822672a7SLee Jones ab8500->write = ab8500_prcmu_write; 1272*822672a7SLee Jones ab8500->write_masked = ab8500_prcmu_write_masked; 1273d28f1db8SLee Jones 127462579266SRabin Vincent mutex_init(&ab8500->lock); 127562579266SRabin Vincent mutex_init(&ab8500->irq_lock); 1276112a80d2SJonas Aaberg atomic_set(&ab8500->transfer_ongoing, 0); 127762579266SRabin Vincent 1278d28f1db8SLee Jones platform_set_drvdata(pdev, ab8500); 1279d28f1db8SLee Jones 12806bc4a568SLee Jones if (platid) 12816bc4a568SLee Jones version = platid->driver_data; 12826bc4a568SLee Jones else if (np) 12836bc4a568SLee Jones version = (unsigned int) 12846bc4a568SLee Jones of_match_device(ab8500_match, &pdev->dev)->data; 12856bc4a568SLee Jones 12860f620837SLinus Walleij if (version != AB8500_VERSION_UNDEFINED) 12870f620837SLinus Walleij ab8500->version = version; 12880f620837SLinus Walleij else { 12890f620837SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_MISC, 12900f620837SLinus Walleij AB8500_IC_NAME_REG, &value); 12910f620837SLinus Walleij if (ret < 0) 1292d28f1db8SLee Jones goto out_free_ab8500; 12930f620837SLinus Walleij 12940f620837SLinus Walleij ab8500->version = value; 12950f620837SLinus Walleij } 12960f620837SLinus Walleij 129747c16975SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_MISC, 129847c16975SMattias Wallin AB8500_REV_REG, &value); 129962579266SRabin Vincent if (ret < 0) 1300d28f1db8SLee Jones goto out_free_ab8500; 130162579266SRabin Vincent 130247c16975SMattias Wallin ab8500->chip_id = value; 130362579266SRabin Vincent 13040f620837SLinus Walleij dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n", 13050f620837SLinus Walleij ab8500_version_str[ab8500->version], 13060f620837SLinus Walleij ab8500->chip_id >> 4, 13070f620837SLinus Walleij ab8500->chip_id & 0x0F); 13080f620837SLinus Walleij 1309d6255529SLinus Walleij /* Configure AB8500 or AB9540 IRQ */ 1310a982362cSBengt Jonsson if (is_ab9540(ab8500) || is_ab8505(ab8500)) { 1311d6255529SLinus Walleij ab8500->mask_size = AB9540_NUM_IRQ_REGS; 1312d6255529SLinus Walleij ab8500->irq_reg_offset = ab9540_irq_regoffset; 1313d6255529SLinus Walleij } else { 13142ced445eSLinus Walleij ab8500->mask_size = AB8500_NUM_IRQ_REGS; 13152ced445eSLinus Walleij ab8500->irq_reg_offset = ab8500_irq_regoffset; 1316d6255529SLinus Walleij } 13172ced445eSLinus Walleij ab8500->mask = kzalloc(ab8500->mask_size, GFP_KERNEL); 13182ced445eSLinus Walleij if (!ab8500->mask) 13192ced445eSLinus Walleij return -ENOMEM; 13202ced445eSLinus Walleij ab8500->oldmask = kzalloc(ab8500->mask_size, GFP_KERNEL); 13212ced445eSLinus Walleij if (!ab8500->oldmask) { 13222ced445eSLinus Walleij ret = -ENOMEM; 13232ced445eSLinus Walleij goto out_freemask; 13242ced445eSLinus Walleij } 1325e5c238c3SMattias Wallin /* 1326e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 1327e5c238c3SMattias Wallin * 0x01 Swoff bit programming 1328e5c238c3SMattias Wallin * 0x02 Thermal protection activation 1329e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 1330e5c238c3SMattias Wallin * 0x08 Watchdog expired 1331e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 1332e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 1333e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 1334e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 1335e5c238c3SMattias Wallin */ 1336e5c238c3SMattias Wallin 1337e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 1338e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 1339e5c238c3SMattias Wallin if (ret < 0) 1340e5c238c3SMattias Wallin return ret; 134106e589efSLee Jones dev_info(ab8500->dev, "switch off status: %#x\n", value); 1342e5c238c3SMattias Wallin 134362579266SRabin Vincent if (plat && plat->init) 134462579266SRabin Vincent plat->init(ab8500); 134562579266SRabin Vincent 134662579266SRabin Vincent /* Clear and mask all interrupts */ 13472ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 13480f620837SLinus Walleij /* 13490f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 13500f620837SLinus Walleij * 2.0 13510f620837SLinus Walleij */ 13520f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 13530f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 135492d50a41SMattias Wallin continue; 135562579266SRabin Vincent 135647c16975SMattias Wallin get_register_interruptible(ab8500, AB8500_INTERRUPT, 13572ced445eSLinus Walleij AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i], 135892d50a41SMattias Wallin &value); 135947c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, 13602ced445eSLinus Walleij AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff); 136162579266SRabin Vincent } 136262579266SRabin Vincent 136347c16975SMattias Wallin ret = abx500_register_ops(ab8500->dev, &ab8500_ops); 136447c16975SMattias Wallin if (ret) 13652ced445eSLinus Walleij goto out_freeoldmask; 136647c16975SMattias Wallin 13672ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) 136862579266SRabin Vincent ab8500->mask[i] = ab8500->oldmask[i] = 0xff; 136962579266SRabin Vincent 137006e589efSLee Jones ret = ab8500_irq_init(ab8500, np); 137162579266SRabin Vincent if (ret) 13722ced445eSLinus Walleij goto out_freeoldmask; 137362579266SRabin Vincent 13747ccfe9b1SMichel JAOUEN /* Activate this feature only in ab9540 */ 13757ccfe9b1SMichel JAOUEN /* till tests are done on ab8500 1p2 or later*/ 137606e589efSLee Jones if (is_ab9540(ab8500)) { 13777ccfe9b1SMichel JAOUEN ret = request_threaded_irq(ab8500->irq, NULL, 13787ccfe9b1SMichel JAOUEN ab8500_hierarchical_irq, 13797ccfe9b1SMichel JAOUEN IRQF_ONESHOT | IRQF_NO_SUSPEND, 13807ccfe9b1SMichel JAOUEN "ab8500", ab8500); 138106e589efSLee Jones } 138206e589efSLee Jones else { 13837ccfe9b1SMichel JAOUEN ret = request_threaded_irq(ab8500->irq, NULL, 13847ccfe9b1SMichel JAOUEN ab8500_irq, 13854f079985SMattias Wallin IRQF_ONESHOT | IRQF_NO_SUSPEND, 13864f079985SMattias Wallin "ab8500", ab8500); 138762579266SRabin Vincent if (ret) 138806e589efSLee Jones goto out_freeoldmask; 138962579266SRabin Vincent } 139062579266SRabin Vincent 13916bc4a568SLee Jones if (!np) { 1392d6255529SLinus Walleij ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs, 1393d6255529SLinus Walleij ARRAY_SIZE(abx500_common_devs), NULL, 1394d6255529SLinus Walleij ab8500->irq_base); 1395d6255529SLinus Walleij 1396d6255529SLinus Walleij if (ret) 1397d6255529SLinus Walleij goto out_freeirq; 1398d6255529SLinus Walleij 1399d6255529SLinus Walleij if (is_ab9540(ab8500)) 1400d6255529SLinus Walleij ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, 1401d6255529SLinus Walleij ARRAY_SIZE(ab9540_devs), NULL, 1402d6255529SLinus Walleij ab8500->irq_base); 1403d6255529SLinus Walleij else 1404549931f9SSundar R Iyer ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, 140544f72e53SVirupax Sadashivpetimath ARRAY_SIZE(ab8500_devs), NULL, 140662579266SRabin Vincent ab8500->irq_base); 14076bc4a568SLee Jones if (ret) 14086bc4a568SLee Jones goto out_freeirq; 140944f72e53SVirupax Sadashivpetimath 141044f72e53SVirupax Sadashivpetimath if (is_ab9540(ab8500) || is_ab8505(ab8500)) 141144f72e53SVirupax Sadashivpetimath ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs, 141244f72e53SVirupax Sadashivpetimath ARRAY_SIZE(ab9540_ab8505_devs), NULL, 141344f72e53SVirupax Sadashivpetimath ab8500->irq_base); 141462579266SRabin Vincent if (ret) 141562579266SRabin Vincent goto out_freeirq; 14166bc4a568SLee Jones } 141762579266SRabin Vincent 14186ef9418cSRickard Andersson if (!no_bm) { 14196ef9418cSRickard Andersson /* Add battery management devices */ 14206ef9418cSRickard Andersson ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, 14216ef9418cSRickard Andersson ARRAY_SIZE(ab8500_bm_devs), NULL, 14226ef9418cSRickard Andersson ab8500->irq_base); 14236ef9418cSRickard Andersson if (ret) 14246ef9418cSRickard Andersson dev_err(ab8500->dev, "error adding bm devices\n"); 14256ef9418cSRickard Andersson } 14266ef9418cSRickard Andersson 1427d6255529SLinus Walleij if (is_ab9540(ab8500)) 1428d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1429d6255529SLinus Walleij &ab9540_attr_group); 1430d6255529SLinus Walleij else 1431d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1432d6255529SLinus Walleij &ab8500_attr_group); 1433cca69b67SMattias Wallin if (ret) 1434cca69b67SMattias Wallin dev_err(ab8500->dev, "error creating sysfs entries\n"); 143506e589efSLee Jones 143662579266SRabin Vincent return ret; 143762579266SRabin Vincent 143862579266SRabin Vincent out_freeirq: 143962579266SRabin Vincent free_irq(ab8500->irq, ab8500); 14402ced445eSLinus Walleij out_freeoldmask: 14412ced445eSLinus Walleij kfree(ab8500->oldmask); 14422ced445eSLinus Walleij out_freemask: 14432ced445eSLinus Walleij kfree(ab8500->mask); 1444d28f1db8SLee Jones out_free_ab8500: 1445d28f1db8SLee Jones kfree(ab8500); 14466d95b7fdSLinus Walleij 144762579266SRabin Vincent return ret; 144862579266SRabin Vincent } 144962579266SRabin Vincent 1450d28f1db8SLee Jones static int __devexit ab8500_remove(struct platform_device *pdev) 145162579266SRabin Vincent { 1452d28f1db8SLee Jones struct ab8500 *ab8500 = platform_get_drvdata(pdev); 1453d28f1db8SLee Jones 1454d6255529SLinus Walleij if (is_ab9540(ab8500)) 1455d6255529SLinus Walleij sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group); 1456d6255529SLinus Walleij else 1457cca69b67SMattias Wallin sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group); 145806e589efSLee Jones 145962579266SRabin Vincent mfd_remove_devices(ab8500->dev); 146062579266SRabin Vincent free_irq(ab8500->irq, ab8500); 146106e589efSLee Jones 14622ced445eSLinus Walleij kfree(ab8500->oldmask); 14632ced445eSLinus Walleij kfree(ab8500->mask); 1464d28f1db8SLee Jones kfree(ab8500); 146562579266SRabin Vincent 146662579266SRabin Vincent return 0; 146762579266SRabin Vincent } 146862579266SRabin Vincent 1469d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = { 1470d28f1db8SLee Jones { "ab8500-core", AB8500_VERSION_AB8500 }, 1471d28f1db8SLee Jones { "ab8505-i2c", AB8500_VERSION_AB8505 }, 1472d28f1db8SLee Jones { "ab9540-i2c", AB8500_VERSION_AB9540 }, 1473d28f1db8SLee Jones { "ab8540-i2c", AB8500_VERSION_AB8540 }, 1474d28f1db8SLee Jones { } 1475d28f1db8SLee Jones }; 1476d28f1db8SLee Jones 1477d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = { 1478d28f1db8SLee Jones .driver = { 1479d28f1db8SLee Jones .name = "ab8500-core", 1480d28f1db8SLee Jones .owner = THIS_MODULE, 14816bc4a568SLee Jones .of_match_table = ab8500_match, 1482d28f1db8SLee Jones }, 1483d28f1db8SLee Jones .probe = ab8500_probe, 1484d28f1db8SLee Jones .remove = __devexit_p(ab8500_remove), 1485d28f1db8SLee Jones .id_table = ab8500_id, 1486d28f1db8SLee Jones }; 1487d28f1db8SLee Jones 1488d28f1db8SLee Jones static int __init ab8500_core_init(void) 1489d28f1db8SLee Jones { 1490d28f1db8SLee Jones return platform_driver_register(&ab8500_core_driver); 1491d28f1db8SLee Jones } 1492d28f1db8SLee Jones 1493d28f1db8SLee Jones static void __exit ab8500_core_exit(void) 1494d28f1db8SLee Jones { 1495d28f1db8SLee Jones platform_driver_unregister(&ab8500_core_driver); 1496d28f1db8SLee Jones } 1497d28f1db8SLee Jones arch_initcall(ab8500_core_init); 1498d28f1db8SLee Jones module_exit(ab8500_core_exit); 1499d28f1db8SLee Jones 1500adceed62SMattias Wallin MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent"); 150162579266SRabin Vincent MODULE_DESCRIPTION("AB8500 MFD core"); 150262579266SRabin Vincent MODULE_LICENSE("GPL v2"); 1503