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, 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 475*80633f05SLee Jones /** 476*80633f05SLee Jones * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ 477*80633f05SLee Jones * 478*80633f05SLee Jones * @ab8500: ab8500_irq controller to operate on. 479*80633f05SLee Jones * @irq: index of the interrupt requested in the chip IRQs 480*80633f05SLee Jones * 481*80633f05SLee Jones * Useful for drivers to request their own IRQs. 482*80633f05SLee Jones */ 483*80633f05SLee Jones static int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq) 484*80633f05SLee Jones { 485*80633f05SLee Jones if (!ab8500) 486*80633f05SLee Jones return -EINVAL; 487*80633f05SLee Jones 488*80633f05SLee Jones return irq_create_mapping(ab8500->domain, irq); 489*80633f05SLee Jones } 490*80633f05SLee Jones 49162579266SRabin Vincent static irqreturn_t ab8500_irq(int irq, void *dev) 49262579266SRabin Vincent { 49362579266SRabin Vincent struct ab8500 *ab8500 = dev; 49462579266SRabin Vincent int i; 49562579266SRabin Vincent 49662579266SRabin Vincent dev_vdbg(ab8500->dev, "interrupt\n"); 49762579266SRabin Vincent 498112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 499112a80d2SJonas Aaberg 5002ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 5012ced445eSLinus Walleij int regoffset = ab8500->irq_reg_offset[i]; 50262579266SRabin Vincent int status; 50347c16975SMattias Wallin u8 value; 50462579266SRabin Vincent 5050f620837SLinus Walleij /* 5060f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 5070f620837SLinus Walleij * 2.0 5080f620837SLinus Walleij */ 5090f620837SLinus Walleij if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500)) 51092d50a41SMattias Wallin continue; 51192d50a41SMattias Wallin 51247c16975SMattias Wallin status = get_register_interruptible(ab8500, AB8500_INTERRUPT, 51347c16975SMattias Wallin AB8500_IT_LATCH1_REG + regoffset, &value); 51447c16975SMattias Wallin if (status < 0 || value == 0) 51562579266SRabin Vincent continue; 51662579266SRabin Vincent 51762579266SRabin Vincent do { 51888aec4f7SMattias Wallin int bit = __ffs(value); 51962579266SRabin Vincent int line = i * 8 + bit; 52062579266SRabin Vincent 52162579266SRabin Vincent handle_nested_irq(ab8500->irq_base + line); 52247c16975SMattias Wallin value &= ~(1 << bit); 523112a80d2SJonas Aaberg 52447c16975SMattias Wallin } while (value); 52562579266SRabin Vincent } 526112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 52762579266SRabin Vincent return IRQ_HANDLED; 52862579266SRabin Vincent } 52962579266SRabin Vincent 53006e589efSLee Jones static int ab8500_irq_map(struct irq_domain *d, unsigned int virq, 53106e589efSLee Jones irq_hw_number_t hwirq) 53206e589efSLee Jones { 53306e589efSLee Jones struct ab8500 *ab8500 = d->host_data; 53406e589efSLee Jones 53506e589efSLee Jones if (!ab8500) 53606e589efSLee Jones return -EINVAL; 53706e589efSLee Jones 53806e589efSLee Jones irq_set_chip_data(virq, ab8500); 53906e589efSLee Jones irq_set_chip_and_handler(virq, &ab8500_irq_chip, 54006e589efSLee Jones handle_simple_irq); 54106e589efSLee Jones irq_set_nested_thread(virq, 1); 54206e589efSLee Jones #ifdef CONFIG_ARM 54306e589efSLee Jones set_irq_flags(virq, IRQF_VALID); 54406e589efSLee Jones #else 54506e589efSLee Jones irq_set_noprobe(virq); 54606e589efSLee Jones #endif 54762579266SRabin Vincent 54862579266SRabin Vincent return 0; 54962579266SRabin Vincent } 55062579266SRabin Vincent 55106e589efSLee Jones static struct irq_domain_ops ab8500_irq_ops = { 55206e589efSLee Jones .map = ab8500_irq_map, 55306e589efSLee Jones .xlate = irq_domain_xlate_twocell, 55406e589efSLee Jones }; 55506e589efSLee Jones 55606e589efSLee Jones static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np) 55762579266SRabin Vincent { 5582ced445eSLinus Walleij int num_irqs; 55962579266SRabin Vincent 560d6255529SLinus Walleij if (is_ab9540(ab8500)) 561d6255529SLinus Walleij num_irqs = AB9540_NR_IRQS; 562a982362cSBengt Jonsson else if (is_ab8505(ab8500)) 563a982362cSBengt Jonsson num_irqs = AB8505_NR_IRQS; 564d6255529SLinus Walleij else 5652ced445eSLinus Walleij num_irqs = AB8500_NR_IRQS; 5662ced445eSLinus Walleij 56706e589efSLee Jones if (ab8500->irq_base) { 56806e589efSLee Jones ab8500->domain = irq_domain_add_legacy( 56906e589efSLee Jones NULL, num_irqs, ab8500->irq_base, 57006e589efSLee Jones 0, &ab8500_irq_ops, ab8500); 57162579266SRabin Vincent } 57206e589efSLee Jones else { 57306e589efSLee Jones ab8500->domain = irq_domain_add_linear( 57406e589efSLee Jones np, num_irqs, &ab8500_irq_ops, ab8500); 57506e589efSLee Jones } 57606e589efSLee Jones 57706e589efSLee Jones if (!ab8500->domain) { 57806e589efSLee Jones dev_err(ab8500->dev, "Failed to create irqdomain\n"); 57906e589efSLee Jones return -ENOSYS; 58006e589efSLee Jones } 58106e589efSLee Jones 58206e589efSLee Jones return 0; 58362579266SRabin Vincent } 58462579266SRabin Vincent 585112a80d2SJonas Aaberg int ab8500_suspend(struct ab8500 *ab8500) 586112a80d2SJonas Aaberg { 587112a80d2SJonas Aaberg if (atomic_read(&ab8500->transfer_ongoing)) 588112a80d2SJonas Aaberg return -EINVAL; 589112a80d2SJonas Aaberg else 590112a80d2SJonas Aaberg return 0; 591112a80d2SJonas Aaberg } 592112a80d2SJonas Aaberg 593d6255529SLinus Walleij /* AB8500 GPIO Resources */ 5945cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_gpio_resources[] = { 5950cb3fcd7SBibek Basu { 5960cb3fcd7SBibek Basu .name = "GPIO_INT6", 5970cb3fcd7SBibek Basu .start = AB8500_INT_GPIO6R, 5980cb3fcd7SBibek Basu .end = AB8500_INT_GPIO41F, 5990cb3fcd7SBibek Basu .flags = IORESOURCE_IRQ, 6000cb3fcd7SBibek Basu } 6010cb3fcd7SBibek Basu }; 6020cb3fcd7SBibek Basu 603d6255529SLinus Walleij /* AB9540 GPIO Resources */ 604d6255529SLinus Walleij static struct resource __devinitdata ab9540_gpio_resources[] = { 605d6255529SLinus Walleij { 606d6255529SLinus Walleij .name = "GPIO_INT6", 607d6255529SLinus Walleij .start = AB8500_INT_GPIO6R, 608d6255529SLinus Walleij .end = AB8500_INT_GPIO41F, 609d6255529SLinus Walleij .flags = IORESOURCE_IRQ, 610d6255529SLinus Walleij }, 611d6255529SLinus Walleij { 612d6255529SLinus Walleij .name = "GPIO_INT14", 613d6255529SLinus Walleij .start = AB9540_INT_GPIO50R, 614d6255529SLinus Walleij .end = AB9540_INT_GPIO54R, 615d6255529SLinus Walleij .flags = IORESOURCE_IRQ, 616d6255529SLinus Walleij }, 617d6255529SLinus Walleij { 618d6255529SLinus Walleij .name = "GPIO_INT15", 619d6255529SLinus Walleij .start = AB9540_INT_GPIO50F, 620d6255529SLinus Walleij .end = AB9540_INT_GPIO54F, 621d6255529SLinus Walleij .flags = IORESOURCE_IRQ, 622d6255529SLinus Walleij } 623d6255529SLinus Walleij }; 624d6255529SLinus Walleij 6255cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_gpadc_resources[] = { 62662579266SRabin Vincent { 62762579266SRabin Vincent .name = "HW_CONV_END", 62862579266SRabin Vincent .start = AB8500_INT_GP_HW_ADC_CONV_END, 62962579266SRabin Vincent .end = AB8500_INT_GP_HW_ADC_CONV_END, 63062579266SRabin Vincent .flags = IORESOURCE_IRQ, 63162579266SRabin Vincent }, 63262579266SRabin Vincent { 63362579266SRabin Vincent .name = "SW_CONV_END", 63462579266SRabin Vincent .start = AB8500_INT_GP_SW_ADC_CONV_END, 63562579266SRabin Vincent .end = AB8500_INT_GP_SW_ADC_CONV_END, 63662579266SRabin Vincent .flags = IORESOURCE_IRQ, 63762579266SRabin Vincent }, 63862579266SRabin Vincent }; 63962579266SRabin Vincent 6405cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_rtc_resources[] = { 64162579266SRabin Vincent { 64262579266SRabin Vincent .name = "60S", 64362579266SRabin Vincent .start = AB8500_INT_RTC_60S, 64462579266SRabin Vincent .end = AB8500_INT_RTC_60S, 64562579266SRabin Vincent .flags = IORESOURCE_IRQ, 64662579266SRabin Vincent }, 64762579266SRabin Vincent { 64862579266SRabin Vincent .name = "ALARM", 64962579266SRabin Vincent .start = AB8500_INT_RTC_ALARM, 65062579266SRabin Vincent .end = AB8500_INT_RTC_ALARM, 65162579266SRabin Vincent .flags = IORESOURCE_IRQ, 65262579266SRabin Vincent }, 65362579266SRabin Vincent }; 65462579266SRabin Vincent 6555cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_poweronkey_db_resources[] = { 65677686517SSundar R Iyer { 65777686517SSundar R Iyer .name = "ONKEY_DBF", 65877686517SSundar R Iyer .start = AB8500_INT_PON_KEY1DB_F, 65977686517SSundar R Iyer .end = AB8500_INT_PON_KEY1DB_F, 66077686517SSundar R Iyer .flags = IORESOURCE_IRQ, 66177686517SSundar R Iyer }, 66277686517SSundar R Iyer { 66377686517SSundar R Iyer .name = "ONKEY_DBR", 66477686517SSundar R Iyer .start = AB8500_INT_PON_KEY1DB_R, 66577686517SSundar R Iyer .end = AB8500_INT_PON_KEY1DB_R, 66677686517SSundar R Iyer .flags = IORESOURCE_IRQ, 66777686517SSundar R Iyer }, 66877686517SSundar R Iyer }; 66977686517SSundar R Iyer 6706af75ecdSLinus Walleij static struct resource __devinitdata ab8500_av_acc_detect_resources[] = { 671e098adedSMattias Wallin { 6726af75ecdSLinus Walleij .name = "ACC_DETECT_1DB_F", 6736af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_1DB_F, 6746af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_1DB_F, 675e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 676e098adedSMattias Wallin }, 677e098adedSMattias Wallin { 6786af75ecdSLinus Walleij .name = "ACC_DETECT_1DB_R", 6796af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_1DB_R, 6806af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_1DB_R, 681e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 682e098adedSMattias Wallin }, 683e098adedSMattias Wallin { 6846af75ecdSLinus Walleij .name = "ACC_DETECT_21DB_F", 6856af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_21DB_F, 6866af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_21DB_F, 6876af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 6886af75ecdSLinus Walleij }, 6896af75ecdSLinus Walleij { 6906af75ecdSLinus Walleij .name = "ACC_DETECT_21DB_R", 6916af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_21DB_R, 6926af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_21DB_R, 6936af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 6946af75ecdSLinus Walleij }, 6956af75ecdSLinus Walleij { 6966af75ecdSLinus Walleij .name = "ACC_DETECT_22DB_F", 6976af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_22DB_F, 6986af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_22DB_F, 6996af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7006af75ecdSLinus Walleij }, 7016af75ecdSLinus Walleij { 7026af75ecdSLinus Walleij .name = "ACC_DETECT_22DB_R", 7036af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_22DB_R, 7046af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_22DB_R, 7056af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7066af75ecdSLinus Walleij }, 7076af75ecdSLinus Walleij }; 7086af75ecdSLinus Walleij 7096af75ecdSLinus Walleij static struct resource __devinitdata ab8500_charger_resources[] = { 7106af75ecdSLinus Walleij { 711e098adedSMattias Wallin .name = "MAIN_CH_UNPLUG_DET", 712e098adedSMattias Wallin .start = AB8500_INT_MAIN_CH_UNPLUG_DET, 713e098adedSMattias Wallin .end = AB8500_INT_MAIN_CH_UNPLUG_DET, 714e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 715e098adedSMattias Wallin }, 716e098adedSMattias Wallin { 717e098adedSMattias Wallin .name = "MAIN_CHARGE_PLUG_DET", 718e098adedSMattias Wallin .start = AB8500_INT_MAIN_CH_PLUG_DET, 719e098adedSMattias Wallin .end = AB8500_INT_MAIN_CH_PLUG_DET, 720e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 721e098adedSMattias Wallin }, 722e098adedSMattias Wallin { 723e098adedSMattias Wallin .name = "VBUS_DET_R", 724e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_R, 725e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_R, 726e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 727e098adedSMattias Wallin }, 728e098adedSMattias Wallin { 7296af75ecdSLinus Walleij .name = "VBUS_DET_F", 7306af75ecdSLinus Walleij .start = AB8500_INT_VBUS_DET_F, 7316af75ecdSLinus Walleij .end = AB8500_INT_VBUS_DET_F, 732e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 733e098adedSMattias Wallin }, 734e098adedSMattias Wallin { 7356af75ecdSLinus Walleij .name = "USB_LINK_STATUS", 7366af75ecdSLinus Walleij .start = AB8500_INT_USB_LINK_STATUS, 7376af75ecdSLinus Walleij .end = AB8500_INT_USB_LINK_STATUS, 7386af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7396af75ecdSLinus Walleij }, 7406af75ecdSLinus Walleij { 741e098adedSMattias Wallin .name = "VBUS_OVV", 742e098adedSMattias Wallin .start = AB8500_INT_VBUS_OVV, 743e098adedSMattias Wallin .end = AB8500_INT_VBUS_OVV, 744e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 745e098adedSMattias Wallin }, 746e098adedSMattias Wallin { 7476af75ecdSLinus Walleij .name = "USB_CH_TH_PROT_R", 7486af75ecdSLinus Walleij .start = AB8500_INT_USB_CH_TH_PROT_R, 7496af75ecdSLinus Walleij .end = AB8500_INT_USB_CH_TH_PROT_R, 750e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 751e098adedSMattias Wallin }, 752e098adedSMattias Wallin { 7536af75ecdSLinus Walleij .name = "USB_CH_TH_PROT_F", 7546af75ecdSLinus Walleij .start = AB8500_INT_USB_CH_TH_PROT_F, 7556af75ecdSLinus Walleij .end = AB8500_INT_USB_CH_TH_PROT_F, 756e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 757e098adedSMattias Wallin }, 758e098adedSMattias Wallin { 7596af75ecdSLinus Walleij .name = "MAIN_EXT_CH_NOT_OK", 7606af75ecdSLinus Walleij .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, 7616af75ecdSLinus Walleij .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, 7626af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7636af75ecdSLinus Walleij }, 7646af75ecdSLinus Walleij { 7656af75ecdSLinus Walleij .name = "MAIN_CH_TH_PROT_R", 7666af75ecdSLinus Walleij .start = AB8500_INT_MAIN_CH_TH_PROT_R, 7676af75ecdSLinus Walleij .end = AB8500_INT_MAIN_CH_TH_PROT_R, 7686af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7696af75ecdSLinus Walleij }, 7706af75ecdSLinus Walleij { 7716af75ecdSLinus Walleij .name = "MAIN_CH_TH_PROT_F", 7726af75ecdSLinus Walleij .start = AB8500_INT_MAIN_CH_TH_PROT_F, 7736af75ecdSLinus Walleij .end = AB8500_INT_MAIN_CH_TH_PROT_F, 7746af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7756af75ecdSLinus Walleij }, 7766af75ecdSLinus Walleij { 7776af75ecdSLinus Walleij .name = "USB_CHARGER_NOT_OKR", 778a982362cSBengt Jonsson .start = AB8500_INT_USB_CHARGER_NOT_OKR, 779a982362cSBengt Jonsson .end = AB8500_INT_USB_CHARGER_NOT_OKR, 7806af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7816af75ecdSLinus Walleij }, 7826af75ecdSLinus Walleij { 7836af75ecdSLinus Walleij .name = "CH_WD_EXP", 7846af75ecdSLinus Walleij .start = AB8500_INT_CH_WD_EXP, 7856af75ecdSLinus Walleij .end = AB8500_INT_CH_WD_EXP, 7866af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7876af75ecdSLinus Walleij }, 7886af75ecdSLinus Walleij }; 7896af75ecdSLinus Walleij 7906af75ecdSLinus Walleij static struct resource __devinitdata ab8500_btemp_resources[] = { 7916af75ecdSLinus Walleij { 7926af75ecdSLinus Walleij .name = "BAT_CTRL_INDB", 7936af75ecdSLinus Walleij .start = AB8500_INT_BAT_CTRL_INDB, 7946af75ecdSLinus Walleij .end = AB8500_INT_BAT_CTRL_INDB, 795e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 796e098adedSMattias Wallin }, 797e098adedSMattias Wallin { 798e098adedSMattias Wallin .name = "BTEMP_LOW", 799e098adedSMattias Wallin .start = AB8500_INT_BTEMP_LOW, 800e098adedSMattias Wallin .end = AB8500_INT_BTEMP_LOW, 801e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 802e098adedSMattias Wallin }, 803e098adedSMattias Wallin { 804e098adedSMattias Wallin .name = "BTEMP_HIGH", 805e098adedSMattias Wallin .start = AB8500_INT_BTEMP_HIGH, 806e098adedSMattias Wallin .end = AB8500_INT_BTEMP_HIGH, 807e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 808e098adedSMattias Wallin }, 809e098adedSMattias Wallin { 8106af75ecdSLinus Walleij .name = "BTEMP_LOW_MEDIUM", 8116af75ecdSLinus Walleij .start = AB8500_INT_BTEMP_LOW_MEDIUM, 8126af75ecdSLinus Walleij .end = AB8500_INT_BTEMP_LOW_MEDIUM, 813e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 814e098adedSMattias Wallin }, 815e098adedSMattias Wallin { 8166af75ecdSLinus Walleij .name = "BTEMP_MEDIUM_HIGH", 8176af75ecdSLinus Walleij .start = AB8500_INT_BTEMP_MEDIUM_HIGH, 8186af75ecdSLinus Walleij .end = AB8500_INT_BTEMP_MEDIUM_HIGH, 819e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 820e098adedSMattias Wallin }, 821e098adedSMattias Wallin }; 822e098adedSMattias Wallin 8236af75ecdSLinus Walleij static struct resource __devinitdata ab8500_fg_resources[] = { 8246af75ecdSLinus Walleij { 8256af75ecdSLinus Walleij .name = "NCONV_ACCU", 8266af75ecdSLinus Walleij .start = AB8500_INT_CCN_CONV_ACC, 8276af75ecdSLinus Walleij .end = AB8500_INT_CCN_CONV_ACC, 8286af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8296af75ecdSLinus Walleij }, 8306af75ecdSLinus Walleij { 8316af75ecdSLinus Walleij .name = "BATT_OVV", 8326af75ecdSLinus Walleij .start = AB8500_INT_BATT_OVV, 8336af75ecdSLinus Walleij .end = AB8500_INT_BATT_OVV, 8346af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8356af75ecdSLinus Walleij }, 8366af75ecdSLinus Walleij { 8376af75ecdSLinus Walleij .name = "LOW_BAT_F", 8386af75ecdSLinus Walleij .start = AB8500_INT_LOW_BAT_F, 8396af75ecdSLinus Walleij .end = AB8500_INT_LOW_BAT_F, 8406af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8416af75ecdSLinus Walleij }, 8426af75ecdSLinus Walleij { 8436af75ecdSLinus Walleij .name = "LOW_BAT_R", 8446af75ecdSLinus Walleij .start = AB8500_INT_LOW_BAT_R, 8456af75ecdSLinus Walleij .end = AB8500_INT_LOW_BAT_R, 8466af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8476af75ecdSLinus Walleij }, 8486af75ecdSLinus Walleij { 8496af75ecdSLinus Walleij .name = "CC_INT_CALIB", 8506af75ecdSLinus Walleij .start = AB8500_INT_CC_INT_CALIB, 8516af75ecdSLinus Walleij .end = AB8500_INT_CC_INT_CALIB, 8526af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8536af75ecdSLinus Walleij }, 854a982362cSBengt Jonsson { 855a982362cSBengt Jonsson .name = "CCEOC", 856a982362cSBengt Jonsson .start = AB8500_INT_CCEOC, 857a982362cSBengt Jonsson .end = AB8500_INT_CCEOC, 858a982362cSBengt Jonsson .flags = IORESOURCE_IRQ, 859a982362cSBengt Jonsson }, 8606af75ecdSLinus Walleij }; 8616af75ecdSLinus Walleij 8626af75ecdSLinus Walleij static struct resource __devinitdata ab8500_chargalg_resources[] = {}; 8636af75ecdSLinus Walleij 864df720647SAxel Lin #ifdef CONFIG_DEBUG_FS 8655cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_debug_resources[] = { 866e098adedSMattias Wallin { 867e098adedSMattias Wallin .name = "IRQ_FIRST", 868e098adedSMattias Wallin .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, 869e098adedSMattias Wallin .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, 870e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 871e098adedSMattias Wallin }, 872e098adedSMattias Wallin { 873e098adedSMattias Wallin .name = "IRQ_LAST", 874a982362cSBengt Jonsson .start = AB8500_INT_XTAL32K_KO, 875a982362cSBengt Jonsson .end = AB8500_INT_XTAL32K_KO, 876e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 877e098adedSMattias Wallin }, 878e098adedSMattias Wallin }; 879df720647SAxel Lin #endif 880e098adedSMattias Wallin 8815cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_usb_resources[] = { 882e098adedSMattias Wallin { 883e098adedSMattias Wallin .name = "ID_WAKEUP_R", 884e098adedSMattias Wallin .start = AB8500_INT_ID_WAKEUP_R, 885e098adedSMattias Wallin .end = AB8500_INT_ID_WAKEUP_R, 886e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 887e098adedSMattias Wallin }, 888e098adedSMattias Wallin { 889e098adedSMattias Wallin .name = "ID_WAKEUP_F", 890e098adedSMattias Wallin .start = AB8500_INT_ID_WAKEUP_F, 891e098adedSMattias Wallin .end = AB8500_INT_ID_WAKEUP_F, 892e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 893e098adedSMattias Wallin }, 894e098adedSMattias Wallin { 895e098adedSMattias Wallin .name = "VBUS_DET_F", 896e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_F, 897e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_F, 898e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 899e098adedSMattias Wallin }, 900e098adedSMattias Wallin { 901e098adedSMattias Wallin .name = "VBUS_DET_R", 902e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_R, 903e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_R, 904e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 905e098adedSMattias Wallin }, 90692d50a41SMattias Wallin { 90792d50a41SMattias Wallin .name = "USB_LINK_STATUS", 90892d50a41SMattias Wallin .start = AB8500_INT_USB_LINK_STATUS, 90992d50a41SMattias Wallin .end = AB8500_INT_USB_LINK_STATUS, 91092d50a41SMattias Wallin .flags = IORESOURCE_IRQ, 91192d50a41SMattias Wallin }, 9126af75ecdSLinus Walleij { 9136af75ecdSLinus Walleij .name = "USB_ADP_PROBE_PLUG", 9146af75ecdSLinus Walleij .start = AB8500_INT_ADP_PROBE_PLUG, 9156af75ecdSLinus Walleij .end = AB8500_INT_ADP_PROBE_PLUG, 9166af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 9176af75ecdSLinus Walleij }, 9186af75ecdSLinus Walleij { 9196af75ecdSLinus Walleij .name = "USB_ADP_PROBE_UNPLUG", 9206af75ecdSLinus Walleij .start = AB8500_INT_ADP_PROBE_UNPLUG, 9216af75ecdSLinus Walleij .end = AB8500_INT_ADP_PROBE_UNPLUG, 9226af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 9236af75ecdSLinus Walleij }, 924e098adedSMattias Wallin }; 925e098adedSMattias Wallin 92644f72e53SVirupax Sadashivpetimath static struct resource __devinitdata ab8505_iddet_resources[] = { 92744f72e53SVirupax Sadashivpetimath { 92844f72e53SVirupax Sadashivpetimath .name = "KeyDeglitch", 92944f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KEYDEGLITCH, 93044f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KEYDEGLITCH, 93144f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 93244f72e53SVirupax Sadashivpetimath }, 93344f72e53SVirupax Sadashivpetimath { 93444f72e53SVirupax Sadashivpetimath .name = "KP", 93544f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KP, 93644f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KP, 93744f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 93844f72e53SVirupax Sadashivpetimath }, 93944f72e53SVirupax Sadashivpetimath { 94044f72e53SVirupax Sadashivpetimath .name = "IKP", 94144f72e53SVirupax Sadashivpetimath .start = AB8505_INT_IKP, 94244f72e53SVirupax Sadashivpetimath .end = AB8505_INT_IKP, 94344f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 94444f72e53SVirupax Sadashivpetimath }, 94544f72e53SVirupax Sadashivpetimath { 94644f72e53SVirupax Sadashivpetimath .name = "IKR", 94744f72e53SVirupax Sadashivpetimath .start = AB8505_INT_IKR, 94844f72e53SVirupax Sadashivpetimath .end = AB8505_INT_IKR, 94944f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 95044f72e53SVirupax Sadashivpetimath }, 95144f72e53SVirupax Sadashivpetimath { 95244f72e53SVirupax Sadashivpetimath .name = "KeyStuck", 95344f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KEYSTUCK, 95444f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KEYSTUCK, 95544f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 95644f72e53SVirupax Sadashivpetimath }, 95744f72e53SVirupax Sadashivpetimath }; 95844f72e53SVirupax Sadashivpetimath 9595cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_temp_resources[] = { 960e098adedSMattias Wallin { 961e098adedSMattias Wallin .name = "AB8500_TEMP_WARM", 962e098adedSMattias Wallin .start = AB8500_INT_TEMP_WARM, 963e098adedSMattias Wallin .end = AB8500_INT_TEMP_WARM, 964e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 965e098adedSMattias Wallin }, 966e098adedSMattias Wallin }; 967e098adedSMattias Wallin 968d6255529SLinus Walleij static struct mfd_cell __devinitdata abx500_common_devs[] = { 9695814fc35SMattias Wallin #ifdef CONFIG_DEBUG_FS 9705814fc35SMattias Wallin { 9715814fc35SMattias Wallin .name = "ab8500-debug", 972bad76991SLee Jones .of_compatible = "stericsson,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", 979bad76991SLee Jones .of_compatible = "stericsson,ab8500-sysctrl", 980e098adedSMattias Wallin }, 981e098adedSMattias Wallin { 982e098adedSMattias Wallin .name = "ab8500-regulator", 983bad76991SLee Jones .of_compatible = "stericsson,ab8500-regulator", 984e098adedSMattias Wallin }, 985e098adedSMattias Wallin { 98662579266SRabin Vincent .name = "ab8500-gpadc", 987bad76991SLee Jones .of_compatible = "stericsson,ab8500-gpadc", 98862579266SRabin Vincent .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), 98962579266SRabin Vincent .resources = ab8500_gpadc_resources, 99062579266SRabin Vincent }, 99162579266SRabin Vincent { 99262579266SRabin Vincent .name = "ab8500-rtc", 993bad76991SLee Jones .of_compatible = "stericsson,ab8500-rtc", 99462579266SRabin Vincent .num_resources = ARRAY_SIZE(ab8500_rtc_resources), 99562579266SRabin Vincent .resources = ab8500_rtc_resources, 99662579266SRabin Vincent }, 997f0f05b1cSArun Murthy { 9986af75ecdSLinus Walleij .name = "ab8500-acc-det", 999bad76991SLee Jones .of_compatible = "stericsson,ab8500-acc-det", 10006af75ecdSLinus Walleij .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources), 10016af75ecdSLinus Walleij .resources = ab8500_av_acc_detect_resources, 10026af75ecdSLinus Walleij }, 10036af75ecdSLinus Walleij { 1004e098adedSMattias Wallin .name = "ab8500-poweron-key", 1005bad76991SLee Jones .of_compatible = "stericsson,ab8500-poweron-key", 1006e098adedSMattias Wallin .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), 1007e098adedSMattias Wallin .resources = ab8500_poweronkey_db_resources, 1008e098adedSMattias Wallin }, 1009e098adedSMattias Wallin { 1010f0f05b1cSArun Murthy .name = "ab8500-pwm", 1011bad76991SLee Jones .of_compatible = "stericsson,ab8500-pwm", 1012f0f05b1cSArun Murthy .id = 1, 1013f0f05b1cSArun Murthy }, 1014f0f05b1cSArun Murthy { 1015f0f05b1cSArun Murthy .name = "ab8500-pwm", 1016bad76991SLee Jones .of_compatible = "stericsson,ab8500-pwm", 1017f0f05b1cSArun Murthy .id = 2, 1018f0f05b1cSArun Murthy }, 1019f0f05b1cSArun Murthy { 1020f0f05b1cSArun Murthy .name = "ab8500-pwm", 1021bad76991SLee Jones .of_compatible = "stericsson,ab8500-pwm", 1022f0f05b1cSArun Murthy .id = 3, 1023f0f05b1cSArun Murthy }, 1024bad76991SLee Jones { 1025bad76991SLee Jones .name = "ab8500-leds", 1026bad76991SLee Jones .of_compatible = "stericsson,ab8500-leds", 1027bad76991SLee Jones }, 102877686517SSundar R Iyer { 1029e098adedSMattias Wallin .name = "ab8500-denc", 1030bad76991SLee Jones .of_compatible = "stericsson,ab8500-denc", 1031e098adedSMattias Wallin }, 1032e098adedSMattias Wallin { 1033e098adedSMattias Wallin .name = "ab8500-temp", 1034bad76991SLee Jones .of_compatible = "stericsson,ab8500-temp", 1035e098adedSMattias Wallin .num_resources = ARRAY_SIZE(ab8500_temp_resources), 1036e098adedSMattias Wallin .resources = ab8500_temp_resources, 103777686517SSundar R Iyer }, 103862579266SRabin Vincent }; 103962579266SRabin Vincent 10406ef9418cSRickard Andersson static struct mfd_cell __devinitdata ab8500_bm_devs[] = { 10416ef9418cSRickard Andersson { 10426ef9418cSRickard Andersson .name = "ab8500-charger", 10436ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_charger_resources), 10446ef9418cSRickard Andersson .resources = ab8500_charger_resources, 10456ef9418cSRickard Andersson }, 10466ef9418cSRickard Andersson { 10476ef9418cSRickard Andersson .name = "ab8500-btemp", 10486ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_btemp_resources), 10496ef9418cSRickard Andersson .resources = ab8500_btemp_resources, 10506ef9418cSRickard Andersson }, 10516ef9418cSRickard Andersson { 10526ef9418cSRickard Andersson .name = "ab8500-fg", 10536ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_fg_resources), 10546ef9418cSRickard Andersson .resources = ab8500_fg_resources, 10556ef9418cSRickard Andersson }, 10566ef9418cSRickard Andersson { 10576ef9418cSRickard Andersson .name = "ab8500-chargalg", 10586ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_chargalg_resources), 10596ef9418cSRickard Andersson .resources = ab8500_chargalg_resources, 10606ef9418cSRickard Andersson }, 10616ef9418cSRickard Andersson }; 10626ef9418cSRickard Andersson 1063d6255529SLinus Walleij static struct mfd_cell __devinitdata ab8500_devs[] = { 1064d6255529SLinus Walleij { 1065d6255529SLinus Walleij .name = "ab8500-gpio", 1066bad76991SLee Jones .of_compatible = "stericsson,ab8500-gpio", 1067d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab8500_gpio_resources), 1068d6255529SLinus Walleij .resources = ab8500_gpio_resources, 1069d6255529SLinus Walleij }, 1070d6255529SLinus Walleij { 1071d6255529SLinus Walleij .name = "ab8500-usb", 1072bad76991SLee Jones .of_compatible = "stericsson,ab8500-usb", 1073d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab8500_usb_resources), 1074d6255529SLinus Walleij .resources = ab8500_usb_resources, 1075d6255529SLinus Walleij }, 107644f72e53SVirupax Sadashivpetimath { 107744f72e53SVirupax Sadashivpetimath .name = "ab8500-codec", 107844f72e53SVirupax Sadashivpetimath }, 1079d6255529SLinus Walleij }; 1080d6255529SLinus Walleij 1081d6255529SLinus Walleij static struct mfd_cell __devinitdata ab9540_devs[] = { 1082d6255529SLinus Walleij { 1083d6255529SLinus Walleij .name = "ab8500-gpio", 1084d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab9540_gpio_resources), 1085d6255529SLinus Walleij .resources = ab9540_gpio_resources, 1086d6255529SLinus Walleij }, 1087d6255529SLinus Walleij { 1088d6255529SLinus Walleij .name = "ab9540-usb", 1089d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab8500_usb_resources), 1090d6255529SLinus Walleij .resources = ab8500_usb_resources, 1091d6255529SLinus Walleij }, 109244f72e53SVirupax Sadashivpetimath { 109344f72e53SVirupax Sadashivpetimath .name = "ab9540-codec", 109444f72e53SVirupax Sadashivpetimath }, 109544f72e53SVirupax Sadashivpetimath }; 109644f72e53SVirupax Sadashivpetimath 109744f72e53SVirupax Sadashivpetimath /* Device list common to ab9540 and ab8505 */ 109844f72e53SVirupax Sadashivpetimath static struct mfd_cell __devinitdata ab9540_ab8505_devs[] = { 109944f72e53SVirupax Sadashivpetimath { 110044f72e53SVirupax Sadashivpetimath .name = "ab-iddet", 110144f72e53SVirupax Sadashivpetimath .num_resources = ARRAY_SIZE(ab8505_iddet_resources), 110244f72e53SVirupax Sadashivpetimath .resources = ab8505_iddet_resources, 110344f72e53SVirupax Sadashivpetimath }, 1104d6255529SLinus Walleij }; 1105d6255529SLinus Walleij 1106cca69b67SMattias Wallin static ssize_t show_chip_id(struct device *dev, 1107cca69b67SMattias Wallin struct device_attribute *attr, char *buf) 1108cca69b67SMattias Wallin { 1109cca69b67SMattias Wallin struct ab8500 *ab8500; 1110cca69b67SMattias Wallin 1111cca69b67SMattias Wallin ab8500 = dev_get_drvdata(dev); 1112cca69b67SMattias Wallin return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); 1113cca69b67SMattias Wallin } 1114cca69b67SMattias Wallin 1115e5c238c3SMattias Wallin /* 1116e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 1117e5c238c3SMattias Wallin * 0x01 Swoff bit programming 1118e5c238c3SMattias Wallin * 0x02 Thermal protection activation 1119e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 1120e5c238c3SMattias Wallin * 0x08 Watchdog expired 1121e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 1122e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 1123e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 1124e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 1125e5c238c3SMattias Wallin */ 1126e5c238c3SMattias Wallin static ssize_t show_switch_off_status(struct device *dev, 1127e5c238c3SMattias Wallin struct device_attribute *attr, char *buf) 1128e5c238c3SMattias Wallin { 1129e5c238c3SMattias Wallin int ret; 1130e5c238c3SMattias Wallin u8 value; 1131e5c238c3SMattias Wallin struct ab8500 *ab8500; 1132e5c238c3SMattias Wallin 1133e5c238c3SMattias Wallin ab8500 = dev_get_drvdata(dev); 1134e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 1135e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 1136e5c238c3SMattias Wallin if (ret < 0) 1137e5c238c3SMattias Wallin return ret; 1138e5c238c3SMattias Wallin return sprintf(buf, "%#x\n", value); 1139e5c238c3SMattias Wallin } 1140e5c238c3SMattias Wallin 1141b4a31037SAndrew Lynn /* 1142b4a31037SAndrew Lynn * ab8500 has turned on due to (TURN_ON_STATUS): 1143b4a31037SAndrew Lynn * 0x01 PORnVbat 1144b4a31037SAndrew Lynn * 0x02 PonKey1dbF 1145b4a31037SAndrew Lynn * 0x04 PonKey2dbF 1146b4a31037SAndrew Lynn * 0x08 RTCAlarm 1147b4a31037SAndrew Lynn * 0x10 MainChDet 1148b4a31037SAndrew Lynn * 0x20 VbusDet 1149b4a31037SAndrew Lynn * 0x40 UsbIDDetect 1150b4a31037SAndrew Lynn * 0x80 Reserved 1151b4a31037SAndrew Lynn */ 1152b4a31037SAndrew Lynn static ssize_t show_turn_on_status(struct device *dev, 1153b4a31037SAndrew Lynn struct device_attribute *attr, char *buf) 1154b4a31037SAndrew Lynn { 1155b4a31037SAndrew Lynn int ret; 1156b4a31037SAndrew Lynn u8 value; 1157b4a31037SAndrew Lynn struct ab8500 *ab8500; 1158b4a31037SAndrew Lynn 1159b4a31037SAndrew Lynn ab8500 = dev_get_drvdata(dev); 1160b4a31037SAndrew Lynn ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 1161b4a31037SAndrew Lynn AB8500_TURN_ON_STATUS, &value); 1162b4a31037SAndrew Lynn if (ret < 0) 1163b4a31037SAndrew Lynn return ret; 1164b4a31037SAndrew Lynn return sprintf(buf, "%#x\n", value); 1165b4a31037SAndrew Lynn } 1166b4a31037SAndrew Lynn 1167d6255529SLinus Walleij static ssize_t show_ab9540_dbbrstn(struct device *dev, 1168d6255529SLinus Walleij struct device_attribute *attr, char *buf) 1169d6255529SLinus Walleij { 1170d6255529SLinus Walleij struct ab8500 *ab8500; 1171d6255529SLinus Walleij int ret; 1172d6255529SLinus Walleij u8 value; 1173d6255529SLinus Walleij 1174d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 1175d6255529SLinus Walleij 1176d6255529SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2, 1177d6255529SLinus Walleij AB9540_MODEM_CTRL2_REG, &value); 1178d6255529SLinus Walleij if (ret < 0) 1179d6255529SLinus Walleij return ret; 1180d6255529SLinus Walleij 1181d6255529SLinus Walleij return sprintf(buf, "%d\n", 1182d6255529SLinus Walleij (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0); 1183d6255529SLinus Walleij } 1184d6255529SLinus Walleij 1185d6255529SLinus Walleij static ssize_t store_ab9540_dbbrstn(struct device *dev, 1186d6255529SLinus Walleij struct device_attribute *attr, const char *buf, size_t count) 1187d6255529SLinus Walleij { 1188d6255529SLinus Walleij struct ab8500 *ab8500; 1189d6255529SLinus Walleij int ret = count; 1190d6255529SLinus Walleij int err; 1191d6255529SLinus Walleij u8 bitvalues; 1192d6255529SLinus Walleij 1193d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 1194d6255529SLinus Walleij 1195d6255529SLinus Walleij if (count > 0) { 1196d6255529SLinus Walleij switch (buf[0]) { 1197d6255529SLinus Walleij case '0': 1198d6255529SLinus Walleij bitvalues = 0; 1199d6255529SLinus Walleij break; 1200d6255529SLinus Walleij case '1': 1201d6255529SLinus Walleij bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT; 1202d6255529SLinus Walleij break; 1203d6255529SLinus Walleij default: 1204d6255529SLinus Walleij goto exit; 1205d6255529SLinus Walleij } 1206d6255529SLinus Walleij 1207d6255529SLinus Walleij err = mask_and_set_register_interruptible(ab8500, 1208d6255529SLinus Walleij AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG, 1209d6255529SLinus Walleij AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues); 1210d6255529SLinus Walleij if (err) 1211d6255529SLinus Walleij dev_info(ab8500->dev, 1212d6255529SLinus Walleij "Failed to set DBBRSTN %c, err %#x\n", 1213d6255529SLinus Walleij buf[0], err); 1214d6255529SLinus Walleij } 1215d6255529SLinus Walleij 1216d6255529SLinus Walleij exit: 1217d6255529SLinus Walleij return ret; 1218d6255529SLinus Walleij } 1219d6255529SLinus Walleij 1220cca69b67SMattias Wallin static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); 1221e5c238c3SMattias Wallin static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL); 1222b4a31037SAndrew Lynn static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL); 1223d6255529SLinus Walleij static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR, 1224d6255529SLinus Walleij show_ab9540_dbbrstn, store_ab9540_dbbrstn); 1225cca69b67SMattias Wallin 1226cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = { 1227cca69b67SMattias Wallin &dev_attr_chip_id.attr, 1228e5c238c3SMattias Wallin &dev_attr_switch_off_status.attr, 1229b4a31037SAndrew Lynn &dev_attr_turn_on_status.attr, 1230cca69b67SMattias Wallin NULL, 1231cca69b67SMattias Wallin }; 1232cca69b67SMattias Wallin 1233d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = { 1234d6255529SLinus Walleij &dev_attr_chip_id.attr, 1235d6255529SLinus Walleij &dev_attr_switch_off_status.attr, 1236d6255529SLinus Walleij &dev_attr_turn_on_status.attr, 1237d6255529SLinus Walleij &dev_attr_dbbrstn.attr, 1238d6255529SLinus Walleij NULL, 1239d6255529SLinus Walleij }; 1240d6255529SLinus Walleij 1241cca69b67SMattias Wallin static struct attribute_group ab8500_attr_group = { 1242cca69b67SMattias Wallin .attrs = ab8500_sysfs_entries, 1243cca69b67SMattias Wallin }; 1244cca69b67SMattias Wallin 1245d6255529SLinus Walleij static struct attribute_group ab9540_attr_group = { 1246d6255529SLinus Walleij .attrs = ab9540_sysfs_entries, 1247d6255529SLinus Walleij }; 1248d6255529SLinus Walleij 1249d28f1db8SLee Jones static int __devinit ab8500_probe(struct platform_device *pdev) 125062579266SRabin Vincent { 1251b04c530cSJonas Aaberg static char *switch_off_status[] = { 1252b04c530cSJonas Aaberg "Swoff bit programming", 1253b04c530cSJonas Aaberg "Thermal protection activation", 1254b04c530cSJonas Aaberg "Vbat lower then BattOk falling threshold", 1255b04c530cSJonas Aaberg "Watchdog expired", 1256b04c530cSJonas Aaberg "Non presence of 32kHz clock", 1257b04c530cSJonas Aaberg "Battery level lower than power on reset threshold", 1258b04c530cSJonas Aaberg "Power on key 1 pressed longer than 10 seconds", 1259b04c530cSJonas Aaberg "DB8500 thermal shutdown"}; 1260d28f1db8SLee Jones struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev); 1261d28f1db8SLee Jones const struct platform_device_id *platid = platform_get_device_id(pdev); 12626bc4a568SLee Jones enum ab8500_version version = AB8500_VERSION_UNDEFINED; 12636bc4a568SLee Jones struct device_node *np = pdev->dev.of_node; 1264d28f1db8SLee Jones struct ab8500 *ab8500; 1265d28f1db8SLee Jones struct resource *resource; 126662579266SRabin Vincent int ret; 126762579266SRabin Vincent int i; 126847c16975SMattias Wallin u8 value; 126962579266SRabin Vincent 1270d28f1db8SLee Jones ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL); 1271d28f1db8SLee Jones if (!ab8500) 1272d28f1db8SLee Jones return -ENOMEM; 1273d28f1db8SLee Jones 127462579266SRabin Vincent if (plat) 127562579266SRabin Vincent ab8500->irq_base = plat->irq_base; 127662579266SRabin Vincent 1277d28f1db8SLee Jones ab8500->dev = &pdev->dev; 1278d28f1db8SLee Jones 1279d28f1db8SLee Jones resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 1280d28f1db8SLee Jones if (!resource) { 1281d28f1db8SLee Jones ret = -ENODEV; 1282d28f1db8SLee Jones goto out_free_ab8500; 1283d28f1db8SLee Jones } 1284d28f1db8SLee Jones 1285d28f1db8SLee Jones ab8500->irq = resource->start; 1286d28f1db8SLee Jones 1287822672a7SLee Jones ab8500->read = ab8500_prcmu_read; 1288822672a7SLee Jones ab8500->write = ab8500_prcmu_write; 1289822672a7SLee Jones ab8500->write_masked = ab8500_prcmu_write_masked; 1290d28f1db8SLee Jones 129162579266SRabin Vincent mutex_init(&ab8500->lock); 129262579266SRabin Vincent mutex_init(&ab8500->irq_lock); 1293112a80d2SJonas Aaberg atomic_set(&ab8500->transfer_ongoing, 0); 129462579266SRabin Vincent 1295d28f1db8SLee Jones platform_set_drvdata(pdev, ab8500); 1296d28f1db8SLee Jones 12976bc4a568SLee Jones if (platid) 12986bc4a568SLee Jones version = platid->driver_data; 12996bc4a568SLee Jones 13000f620837SLinus Walleij if (version != AB8500_VERSION_UNDEFINED) 13010f620837SLinus Walleij ab8500->version = version; 13020f620837SLinus Walleij else { 13030f620837SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_MISC, 13040f620837SLinus Walleij AB8500_IC_NAME_REG, &value); 13050f620837SLinus Walleij if (ret < 0) 1306d28f1db8SLee Jones goto out_free_ab8500; 13070f620837SLinus Walleij 13080f620837SLinus Walleij ab8500->version = value; 13090f620837SLinus Walleij } 13100f620837SLinus Walleij 131147c16975SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_MISC, 131247c16975SMattias Wallin AB8500_REV_REG, &value); 131362579266SRabin Vincent if (ret < 0) 1314d28f1db8SLee Jones goto out_free_ab8500; 131562579266SRabin Vincent 131647c16975SMattias Wallin ab8500->chip_id = value; 131762579266SRabin Vincent 13180f620837SLinus Walleij dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n", 13190f620837SLinus Walleij ab8500_version_str[ab8500->version], 13200f620837SLinus Walleij ab8500->chip_id >> 4, 13210f620837SLinus Walleij ab8500->chip_id & 0x0F); 13220f620837SLinus Walleij 1323d6255529SLinus Walleij /* Configure AB8500 or AB9540 IRQ */ 1324a982362cSBengt Jonsson if (is_ab9540(ab8500) || is_ab8505(ab8500)) { 1325d6255529SLinus Walleij ab8500->mask_size = AB9540_NUM_IRQ_REGS; 1326d6255529SLinus Walleij ab8500->irq_reg_offset = ab9540_irq_regoffset; 1327d6255529SLinus Walleij } else { 13282ced445eSLinus Walleij ab8500->mask_size = AB8500_NUM_IRQ_REGS; 13292ced445eSLinus Walleij ab8500->irq_reg_offset = ab8500_irq_regoffset; 1330d6255529SLinus Walleij } 13312ced445eSLinus Walleij ab8500->mask = kzalloc(ab8500->mask_size, GFP_KERNEL); 13322ced445eSLinus Walleij if (!ab8500->mask) 13332ced445eSLinus Walleij return -ENOMEM; 13342ced445eSLinus Walleij ab8500->oldmask = kzalloc(ab8500->mask_size, GFP_KERNEL); 13352ced445eSLinus Walleij if (!ab8500->oldmask) { 13362ced445eSLinus Walleij ret = -ENOMEM; 13372ced445eSLinus Walleij goto out_freemask; 13382ced445eSLinus Walleij } 1339e5c238c3SMattias Wallin /* 1340e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 1341e5c238c3SMattias Wallin * 0x01 Swoff bit programming 1342e5c238c3SMattias Wallin * 0x02 Thermal protection activation 1343e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 1344e5c238c3SMattias Wallin * 0x08 Watchdog expired 1345e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 1346e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 1347e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 1348e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 1349e5c238c3SMattias Wallin */ 1350e5c238c3SMattias Wallin 1351e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 1352e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 1353e5c238c3SMattias Wallin if (ret < 0) 1354e5c238c3SMattias Wallin return ret; 1355b04c530cSJonas Aaberg dev_info(ab8500->dev, "switch off cause(s) (%#x): ", value); 1356b04c530cSJonas Aaberg 1357b04c530cSJonas Aaberg if (value) { 1358b04c530cSJonas Aaberg for (i = 0; i < ARRAY_SIZE(switch_off_status); i++) { 1359b04c530cSJonas Aaberg if (value & 1) 1360b04c530cSJonas Aaberg printk(KERN_CONT " \"%s\"", 1361b04c530cSJonas Aaberg switch_off_status[i]); 1362b04c530cSJonas Aaberg value = value >> 1; 1363b04c530cSJonas Aaberg 1364b04c530cSJonas Aaberg } 1365b04c530cSJonas Aaberg printk(KERN_CONT "\n"); 1366b04c530cSJonas Aaberg } else { 1367b04c530cSJonas Aaberg printk(KERN_CONT " None\n"); 1368b04c530cSJonas Aaberg } 1369e5c238c3SMattias Wallin 137062579266SRabin Vincent if (plat && plat->init) 137162579266SRabin Vincent plat->init(ab8500); 137262579266SRabin Vincent 137362579266SRabin Vincent /* Clear and mask all interrupts */ 13742ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 13750f620837SLinus Walleij /* 13760f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 13770f620837SLinus Walleij * 2.0 13780f620837SLinus Walleij */ 13790f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 13800f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 138192d50a41SMattias Wallin continue; 138262579266SRabin Vincent 138347c16975SMattias Wallin get_register_interruptible(ab8500, AB8500_INTERRUPT, 13842ced445eSLinus Walleij AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i], 138592d50a41SMattias Wallin &value); 138647c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, 13872ced445eSLinus Walleij AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff); 138862579266SRabin Vincent } 138962579266SRabin Vincent 139047c16975SMattias Wallin ret = abx500_register_ops(ab8500->dev, &ab8500_ops); 139147c16975SMattias Wallin if (ret) 13922ced445eSLinus Walleij goto out_freeoldmask; 139347c16975SMattias Wallin 13942ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) 139562579266SRabin Vincent ab8500->mask[i] = ab8500->oldmask[i] = 0xff; 139662579266SRabin Vincent 139706e589efSLee Jones ret = ab8500_irq_init(ab8500, np); 139862579266SRabin Vincent if (ret) 13992ced445eSLinus Walleij goto out_freeoldmask; 140062579266SRabin Vincent 14017ccfe9b1SMichel JAOUEN /* Activate this feature only in ab9540 */ 14027ccfe9b1SMichel JAOUEN /* till tests are done on ab8500 1p2 or later*/ 140306e589efSLee Jones if (is_ab9540(ab8500)) { 14047ccfe9b1SMichel JAOUEN ret = request_threaded_irq(ab8500->irq, NULL, 14057ccfe9b1SMichel JAOUEN ab8500_hierarchical_irq, 14067ccfe9b1SMichel JAOUEN IRQF_ONESHOT | IRQF_NO_SUSPEND, 14077ccfe9b1SMichel JAOUEN "ab8500", ab8500); 140806e589efSLee Jones } 140906e589efSLee Jones else { 14107ccfe9b1SMichel JAOUEN ret = request_threaded_irq(ab8500->irq, NULL, 14117ccfe9b1SMichel JAOUEN ab8500_irq, 14124f079985SMattias Wallin IRQF_ONESHOT | IRQF_NO_SUSPEND, 14134f079985SMattias Wallin "ab8500", ab8500); 141462579266SRabin Vincent if (ret) 141506e589efSLee Jones goto out_freeoldmask; 141662579266SRabin Vincent } 141762579266SRabin Vincent 1418d6255529SLinus Walleij ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs, 1419d6255529SLinus Walleij ARRAY_SIZE(abx500_common_devs), NULL, 142055692af5SMark Brown ab8500->irq_base, ab8500->domain); 1421d6255529SLinus Walleij if (ret) 1422d6255529SLinus Walleij goto out_freeirq; 1423d6255529SLinus Walleij 1424d6255529SLinus Walleij if (is_ab9540(ab8500)) 1425d6255529SLinus Walleij ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, 1426d6255529SLinus Walleij ARRAY_SIZE(ab9540_devs), NULL, 142755692af5SMark Brown ab8500->irq_base, ab8500->domain); 1428d6255529SLinus Walleij else 1429549931f9SSundar R Iyer ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, 143044f72e53SVirupax Sadashivpetimath ARRAY_SIZE(ab8500_devs), NULL, 143155692af5SMark Brown ab8500->irq_base, ab8500->domain); 14326bc4a568SLee Jones if (ret) 14336bc4a568SLee Jones goto out_freeirq; 143444f72e53SVirupax Sadashivpetimath 143544f72e53SVirupax Sadashivpetimath if (is_ab9540(ab8500) || is_ab8505(ab8500)) 143644f72e53SVirupax Sadashivpetimath ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs, 143744f72e53SVirupax Sadashivpetimath ARRAY_SIZE(ab9540_ab8505_devs), NULL, 143855692af5SMark Brown ab8500->irq_base, ab8500->domain); 143962579266SRabin Vincent if (ret) 144062579266SRabin Vincent goto out_freeirq; 144162579266SRabin Vincent 14426ef9418cSRickard Andersson if (!no_bm) { 14436ef9418cSRickard Andersson /* Add battery management devices */ 14446ef9418cSRickard Andersson ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, 14456ef9418cSRickard Andersson ARRAY_SIZE(ab8500_bm_devs), NULL, 144655692af5SMark Brown ab8500->irq_base, ab8500->domain); 14476ef9418cSRickard Andersson if (ret) 14486ef9418cSRickard Andersson dev_err(ab8500->dev, "error adding bm devices\n"); 14496ef9418cSRickard Andersson } 14506ef9418cSRickard Andersson 1451d6255529SLinus Walleij if (is_ab9540(ab8500)) 1452d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1453d6255529SLinus Walleij &ab9540_attr_group); 1454d6255529SLinus Walleij else 1455d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1456d6255529SLinus Walleij &ab8500_attr_group); 1457cca69b67SMattias Wallin if (ret) 1458cca69b67SMattias Wallin dev_err(ab8500->dev, "error creating sysfs entries\n"); 145906e589efSLee Jones 146062579266SRabin Vincent return ret; 146162579266SRabin Vincent 146262579266SRabin Vincent out_freeirq: 146362579266SRabin Vincent free_irq(ab8500->irq, ab8500); 14642ced445eSLinus Walleij out_freeoldmask: 14652ced445eSLinus Walleij kfree(ab8500->oldmask); 14662ced445eSLinus Walleij out_freemask: 14672ced445eSLinus Walleij kfree(ab8500->mask); 1468d28f1db8SLee Jones out_free_ab8500: 1469d28f1db8SLee Jones kfree(ab8500); 14706d95b7fdSLinus Walleij 147162579266SRabin Vincent return ret; 147262579266SRabin Vincent } 147362579266SRabin Vincent 1474d28f1db8SLee Jones static int __devexit ab8500_remove(struct platform_device *pdev) 147562579266SRabin Vincent { 1476d28f1db8SLee Jones struct ab8500 *ab8500 = platform_get_drvdata(pdev); 1477d28f1db8SLee Jones 1478d6255529SLinus Walleij if (is_ab9540(ab8500)) 1479d6255529SLinus Walleij sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group); 1480d6255529SLinus Walleij else 1481cca69b67SMattias Wallin sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group); 148206e589efSLee Jones 148362579266SRabin Vincent mfd_remove_devices(ab8500->dev); 148462579266SRabin Vincent free_irq(ab8500->irq, ab8500); 148506e589efSLee Jones 14862ced445eSLinus Walleij kfree(ab8500->oldmask); 14872ced445eSLinus Walleij kfree(ab8500->mask); 1488d28f1db8SLee Jones kfree(ab8500); 148962579266SRabin Vincent 149062579266SRabin Vincent return 0; 149162579266SRabin Vincent } 149262579266SRabin Vincent 1493d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = { 1494d28f1db8SLee Jones { "ab8500-core", AB8500_VERSION_AB8500 }, 1495d28f1db8SLee Jones { "ab8505-i2c", AB8500_VERSION_AB8505 }, 1496d28f1db8SLee Jones { "ab9540-i2c", AB8500_VERSION_AB9540 }, 1497d28f1db8SLee Jones { "ab8540-i2c", AB8500_VERSION_AB8540 }, 1498d28f1db8SLee Jones { } 1499d28f1db8SLee Jones }; 1500d28f1db8SLee Jones 1501d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = { 1502d28f1db8SLee Jones .driver = { 1503d28f1db8SLee Jones .name = "ab8500-core", 1504d28f1db8SLee Jones .owner = THIS_MODULE, 1505d28f1db8SLee Jones }, 1506d28f1db8SLee Jones .probe = ab8500_probe, 1507d28f1db8SLee Jones .remove = __devexit_p(ab8500_remove), 1508d28f1db8SLee Jones .id_table = ab8500_id, 1509d28f1db8SLee Jones }; 1510d28f1db8SLee Jones 1511d28f1db8SLee Jones static int __init ab8500_core_init(void) 1512d28f1db8SLee Jones { 1513d28f1db8SLee Jones return platform_driver_register(&ab8500_core_driver); 1514d28f1db8SLee Jones } 1515d28f1db8SLee Jones 1516d28f1db8SLee Jones static void __exit ab8500_core_exit(void) 1517d28f1db8SLee Jones { 1518d28f1db8SLee Jones platform_driver_unregister(&ab8500_core_driver); 1519d28f1db8SLee Jones } 1520ba7cbc3eSLee Jones core_initcall(ab8500_core_init); 1521d28f1db8SLee Jones module_exit(ab8500_core_exit); 1522d28f1db8SLee Jones 1523adceed62SMattias Wallin MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent"); 152462579266SRabin Vincent MODULE_DESCRIPTION("AB8500 MFD core"); 152562579266SRabin Vincent MODULE_LICENSE("GPL v2"); 1526