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> 1462579266SRabin Vincent #include <linux/delay.h> 1562579266SRabin Vincent #include <linux/interrupt.h> 1662579266SRabin Vincent #include <linux/module.h> 1762579266SRabin Vincent #include <linux/platform_device.h> 1862579266SRabin Vincent #include <linux/mfd/core.h> 1947c16975SMattias Wallin #include <linux/mfd/abx500.h> 20ee66e653SLinus Walleij #include <linux/mfd/abx500/ab8500.h> 21d28f1db8SLee Jones #include <linux/mfd/dbx500-prcmu.h> 22549931f9SSundar R Iyer #include <linux/regulator/ab8500.h> 23*6bc4a568SLee Jones #include <linux/of.h> 24*6bc4a568SLee Jones #include <linux/of_device.h> 2562579266SRabin Vincent 2662579266SRabin Vincent /* 2762579266SRabin Vincent * Interrupt register offsets 2862579266SRabin Vincent * Bank : 0x0E 2962579266SRabin Vincent */ 3047c16975SMattias Wallin #define AB8500_IT_SOURCE1_REG 0x00 3147c16975SMattias Wallin #define AB8500_IT_SOURCE2_REG 0x01 3247c16975SMattias Wallin #define AB8500_IT_SOURCE3_REG 0x02 3347c16975SMattias Wallin #define AB8500_IT_SOURCE4_REG 0x03 3447c16975SMattias Wallin #define AB8500_IT_SOURCE5_REG 0x04 3547c16975SMattias Wallin #define AB8500_IT_SOURCE6_REG 0x05 3647c16975SMattias Wallin #define AB8500_IT_SOURCE7_REG 0x06 3747c16975SMattias Wallin #define AB8500_IT_SOURCE8_REG 0x07 38d6255529SLinus Walleij #define AB9540_IT_SOURCE13_REG 0x0C 3947c16975SMattias Wallin #define AB8500_IT_SOURCE19_REG 0x12 4047c16975SMattias Wallin #define AB8500_IT_SOURCE20_REG 0x13 4147c16975SMattias Wallin #define AB8500_IT_SOURCE21_REG 0x14 4247c16975SMattias Wallin #define AB8500_IT_SOURCE22_REG 0x15 4347c16975SMattias Wallin #define AB8500_IT_SOURCE23_REG 0x16 4447c16975SMattias Wallin #define AB8500_IT_SOURCE24_REG 0x17 4562579266SRabin Vincent 4662579266SRabin Vincent /* 4762579266SRabin Vincent * latch registers 4862579266SRabin Vincent */ 4947c16975SMattias Wallin #define AB8500_IT_LATCH1_REG 0x20 5047c16975SMattias Wallin #define AB8500_IT_LATCH2_REG 0x21 5147c16975SMattias Wallin #define AB8500_IT_LATCH3_REG 0x22 5247c16975SMattias Wallin #define AB8500_IT_LATCH4_REG 0x23 5347c16975SMattias Wallin #define AB8500_IT_LATCH5_REG 0x24 5447c16975SMattias Wallin #define AB8500_IT_LATCH6_REG 0x25 5547c16975SMattias Wallin #define AB8500_IT_LATCH7_REG 0x26 5647c16975SMattias Wallin #define AB8500_IT_LATCH8_REG 0x27 5747c16975SMattias Wallin #define AB8500_IT_LATCH9_REG 0x28 5847c16975SMattias Wallin #define AB8500_IT_LATCH10_REG 0x29 5992d50a41SMattias Wallin #define AB8500_IT_LATCH12_REG 0x2B 60d6255529SLinus Walleij #define AB9540_IT_LATCH13_REG 0x2C 6147c16975SMattias Wallin #define AB8500_IT_LATCH19_REG 0x32 6247c16975SMattias Wallin #define AB8500_IT_LATCH20_REG 0x33 6347c16975SMattias Wallin #define AB8500_IT_LATCH21_REG 0x34 6447c16975SMattias Wallin #define AB8500_IT_LATCH22_REG 0x35 6547c16975SMattias Wallin #define AB8500_IT_LATCH23_REG 0x36 6647c16975SMattias Wallin #define AB8500_IT_LATCH24_REG 0x37 6762579266SRabin Vincent 6862579266SRabin Vincent /* 6962579266SRabin Vincent * mask registers 7062579266SRabin Vincent */ 7162579266SRabin Vincent 7247c16975SMattias Wallin #define AB8500_IT_MASK1_REG 0x40 7347c16975SMattias Wallin #define AB8500_IT_MASK2_REG 0x41 7447c16975SMattias Wallin #define AB8500_IT_MASK3_REG 0x42 7547c16975SMattias Wallin #define AB8500_IT_MASK4_REG 0x43 7647c16975SMattias Wallin #define AB8500_IT_MASK5_REG 0x44 7747c16975SMattias Wallin #define AB8500_IT_MASK6_REG 0x45 7847c16975SMattias Wallin #define AB8500_IT_MASK7_REG 0x46 7947c16975SMattias Wallin #define AB8500_IT_MASK8_REG 0x47 8047c16975SMattias Wallin #define AB8500_IT_MASK9_REG 0x48 8147c16975SMattias Wallin #define AB8500_IT_MASK10_REG 0x49 8247c16975SMattias Wallin #define AB8500_IT_MASK11_REG 0x4A 8347c16975SMattias Wallin #define AB8500_IT_MASK12_REG 0x4B 8447c16975SMattias Wallin #define AB8500_IT_MASK13_REG 0x4C 8547c16975SMattias Wallin #define AB8500_IT_MASK14_REG 0x4D 8647c16975SMattias Wallin #define AB8500_IT_MASK15_REG 0x4E 8747c16975SMattias Wallin #define AB8500_IT_MASK16_REG 0x4F 8847c16975SMattias Wallin #define AB8500_IT_MASK17_REG 0x50 8947c16975SMattias Wallin #define AB8500_IT_MASK18_REG 0x51 9047c16975SMattias Wallin #define AB8500_IT_MASK19_REG 0x52 9147c16975SMattias Wallin #define AB8500_IT_MASK20_REG 0x53 9247c16975SMattias Wallin #define AB8500_IT_MASK21_REG 0x54 9347c16975SMattias Wallin #define AB8500_IT_MASK22_REG 0x55 9447c16975SMattias Wallin #define AB8500_IT_MASK23_REG 0x56 9547c16975SMattias Wallin #define AB8500_IT_MASK24_REG 0x57 9662579266SRabin Vincent 977ccfe9b1SMichel JAOUEN /* 987ccfe9b1SMichel JAOUEN * latch hierarchy registers 997ccfe9b1SMichel JAOUEN */ 1007ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER1_REG 0x60 1017ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER2_REG 0x61 1027ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER3_REG 0x62 1037ccfe9b1SMichel JAOUEN 1047ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER_NUM 3 1057ccfe9b1SMichel JAOUEN 10647c16975SMattias Wallin #define AB8500_REV_REG 0x80 1070f620837SLinus Walleij #define AB8500_IC_NAME_REG 0x82 108e5c238c3SMattias Wallin #define AB8500_SWITCH_OFF_STATUS 0x00 10962579266SRabin Vincent 110b4a31037SAndrew Lynn #define AB8500_TURN_ON_STATUS 0x00 111b4a31037SAndrew Lynn 1126ef9418cSRickard Andersson static bool no_bm; /* No battery management */ 1136ef9418cSRickard Andersson module_param(no_bm, bool, S_IRUGO); 1146ef9418cSRickard Andersson 115d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_REG 0x23 116d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2) 117d6255529SLinus Walleij 11862579266SRabin Vincent /* 11962579266SRabin Vincent * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt 1202ced445eSLinus Walleij * numbers are indexed into this array with (num / 8). The interupts are 1212ced445eSLinus Walleij * defined in linux/mfd/ab8500.h 12262579266SRabin Vincent * 12362579266SRabin Vincent * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at 12462579266SRabin Vincent * offset 0. 12562579266SRabin Vincent */ 1262ced445eSLinus Walleij /* AB8500 support */ 12762579266SRabin Vincent static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { 12892d50a41SMattias Wallin 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12962579266SRabin Vincent }; 13062579266SRabin Vincent 131d6255529SLinus Walleij /* AB9540 support */ 132d6255529SLinus Walleij static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = { 133d6255529SLinus Walleij 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 134d6255529SLinus Walleij }; 135d6255529SLinus Walleij 1360f620837SLinus Walleij static const char ab8500_version_str[][7] = { 1370f620837SLinus Walleij [AB8500_VERSION_AB8500] = "AB8500", 1380f620837SLinus Walleij [AB8500_VERSION_AB8505] = "AB8505", 1390f620837SLinus Walleij [AB8500_VERSION_AB9540] = "AB9540", 1400f620837SLinus Walleij [AB8500_VERSION_AB8540] = "AB8540", 1410f620837SLinus Walleij }; 1420f620837SLinus Walleij 143d28f1db8SLee Jones static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data) 144d28f1db8SLee Jones { 145d28f1db8SLee Jones int ret; 146d28f1db8SLee Jones 147d28f1db8SLee Jones ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 148d28f1db8SLee Jones if (ret < 0) 149d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 150d28f1db8SLee Jones return ret; 151d28f1db8SLee Jones } 152d28f1db8SLee Jones 153d28f1db8SLee Jones static int ab8500_i2c_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask, 154d28f1db8SLee Jones u8 data) 155d28f1db8SLee Jones { 156d28f1db8SLee Jones int ret; 157d28f1db8SLee Jones 158d28f1db8SLee Jones ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 159d28f1db8SLee Jones &mask, 1); 160d28f1db8SLee Jones if (ret < 0) 161d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 162d28f1db8SLee Jones return ret; 163d28f1db8SLee Jones } 164d28f1db8SLee Jones 165d28f1db8SLee Jones static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr) 166d28f1db8SLee Jones { 167d28f1db8SLee Jones int ret; 168d28f1db8SLee Jones u8 data; 169d28f1db8SLee Jones 170d28f1db8SLee Jones ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 171d28f1db8SLee Jones if (ret < 0) { 172d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 173d28f1db8SLee Jones return ret; 174d28f1db8SLee Jones } 175d28f1db8SLee Jones return (int)data; 176d28f1db8SLee Jones } 177d28f1db8SLee Jones 17847c16975SMattias Wallin static int ab8500_get_chip_id(struct device *dev) 17947c16975SMattias Wallin { 1806bce7bf1SMattias Wallin struct ab8500 *ab8500; 1816bce7bf1SMattias Wallin 1826bce7bf1SMattias Wallin if (!dev) 1836bce7bf1SMattias Wallin return -EINVAL; 1846bce7bf1SMattias Wallin ab8500 = dev_get_drvdata(dev->parent); 1856bce7bf1SMattias Wallin return ab8500 ? (int)ab8500->chip_id : -EINVAL; 18647c16975SMattias Wallin } 18747c16975SMattias Wallin 18847c16975SMattias Wallin static int set_register_interruptible(struct ab8500 *ab8500, u8 bank, 18947c16975SMattias Wallin u8 reg, u8 data) 19062579266SRabin Vincent { 19162579266SRabin Vincent int ret; 19247c16975SMattias Wallin /* 19347c16975SMattias Wallin * Put the u8 bank and u8 register together into a an u16. 19447c16975SMattias Wallin * The bank on higher 8 bits and register in lower 8 bits. 19547c16975SMattias Wallin * */ 19647c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 19762579266SRabin Vincent 19862579266SRabin Vincent dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data); 19962579266SRabin Vincent 200392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 20147c16975SMattias Wallin 20247c16975SMattias Wallin ret = ab8500->write(ab8500, addr, data); 20347c16975SMattias Wallin if (ret < 0) 20447c16975SMattias Wallin dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 20547c16975SMattias Wallin addr, ret); 20647c16975SMattias Wallin mutex_unlock(&ab8500->lock); 20747c16975SMattias Wallin 20847c16975SMattias Wallin return ret; 20947c16975SMattias Wallin } 21047c16975SMattias Wallin 21147c16975SMattias Wallin static int ab8500_set_register(struct device *dev, u8 bank, 21247c16975SMattias Wallin u8 reg, u8 value) 21347c16975SMattias Wallin { 214112a80d2SJonas Aaberg int ret; 21547c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 21647c16975SMattias Wallin 217112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 218112a80d2SJonas Aaberg ret = set_register_interruptible(ab8500, bank, reg, value); 219112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 220112a80d2SJonas Aaberg return ret; 22147c16975SMattias Wallin } 22247c16975SMattias Wallin 22347c16975SMattias Wallin static int get_register_interruptible(struct ab8500 *ab8500, u8 bank, 22447c16975SMattias Wallin u8 reg, u8 *value) 22547c16975SMattias Wallin { 22647c16975SMattias Wallin int ret; 22747c16975SMattias Wallin /* put the u8 bank and u8 reg together into a an u16. 22847c16975SMattias Wallin * bank on higher 8 bits and reg in lower */ 22947c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 23047c16975SMattias Wallin 231392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 23247c16975SMattias Wallin 23347c16975SMattias Wallin ret = ab8500->read(ab8500, addr); 23447c16975SMattias Wallin if (ret < 0) 23547c16975SMattias Wallin dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 23647c16975SMattias Wallin addr, ret); 23747c16975SMattias Wallin else 23847c16975SMattias Wallin *value = ret; 23947c16975SMattias Wallin 24047c16975SMattias Wallin mutex_unlock(&ab8500->lock); 24147c16975SMattias Wallin dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret); 24247c16975SMattias Wallin 24347c16975SMattias Wallin return ret; 24447c16975SMattias Wallin } 24547c16975SMattias Wallin 24647c16975SMattias Wallin static int ab8500_get_register(struct device *dev, u8 bank, 24747c16975SMattias Wallin u8 reg, u8 *value) 24847c16975SMattias Wallin { 249112a80d2SJonas Aaberg int ret; 25047c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 25147c16975SMattias Wallin 252112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 253112a80d2SJonas Aaberg ret = get_register_interruptible(ab8500, bank, reg, value); 254112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 255112a80d2SJonas Aaberg return ret; 25647c16975SMattias Wallin } 25747c16975SMattias Wallin 25847c16975SMattias Wallin static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank, 25947c16975SMattias Wallin u8 reg, u8 bitmask, u8 bitvalues) 26047c16975SMattias Wallin { 26147c16975SMattias Wallin int ret; 26247c16975SMattias Wallin /* put the u8 bank and u8 reg together into a an u16. 26347c16975SMattias Wallin * bank on higher 8 bits and reg in lower */ 26447c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 26547c16975SMattias Wallin 266392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 26747c16975SMattias Wallin 268bc628fd1SMattias Nilsson if (ab8500->write_masked == NULL) { 269bc628fd1SMattias Nilsson u8 data; 270bc628fd1SMattias Nilsson 27147c16975SMattias Wallin ret = ab8500->read(ab8500, addr); 27247c16975SMattias Wallin if (ret < 0) { 27347c16975SMattias Wallin dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 27447c16975SMattias Wallin addr, ret); 27547c16975SMattias Wallin goto out; 27647c16975SMattias Wallin } 27747c16975SMattias Wallin 27847c16975SMattias Wallin data = (u8)ret; 27947c16975SMattias Wallin data = (~bitmask & data) | (bitmask & bitvalues); 28047c16975SMattias Wallin 28162579266SRabin Vincent ret = ab8500->write(ab8500, addr, data); 28262579266SRabin Vincent if (ret < 0) 28362579266SRabin Vincent dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 28462579266SRabin Vincent addr, ret); 28562579266SRabin Vincent 286bc628fd1SMattias Nilsson dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, 287bc628fd1SMattias Nilsson data); 288bc628fd1SMattias Nilsson goto out; 289bc628fd1SMattias Nilsson } 290bc628fd1SMattias Nilsson ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues); 291bc628fd1SMattias Nilsson if (ret < 0) 292bc628fd1SMattias Nilsson dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr, 293bc628fd1SMattias Nilsson ret); 29462579266SRabin Vincent out: 29562579266SRabin Vincent mutex_unlock(&ab8500->lock); 29662579266SRabin Vincent return ret; 29762579266SRabin Vincent } 29847c16975SMattias Wallin 29947c16975SMattias Wallin static int ab8500_mask_and_set_register(struct device *dev, 30047c16975SMattias Wallin u8 bank, u8 reg, u8 bitmask, u8 bitvalues) 30147c16975SMattias Wallin { 302112a80d2SJonas Aaberg int ret; 30347c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 30447c16975SMattias Wallin 305112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 306112a80d2SJonas Aaberg ret= mask_and_set_register_interruptible(ab8500, bank, reg, 30747c16975SMattias Wallin bitmask, bitvalues); 308112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 309112a80d2SJonas Aaberg return ret; 31047c16975SMattias Wallin } 31147c16975SMattias Wallin 31247c16975SMattias Wallin static struct abx500_ops ab8500_ops = { 31347c16975SMattias Wallin .get_chip_id = ab8500_get_chip_id, 31447c16975SMattias Wallin .get_register = ab8500_get_register, 31547c16975SMattias Wallin .set_register = ab8500_set_register, 31647c16975SMattias Wallin .get_register_page = NULL, 31747c16975SMattias Wallin .set_register_page = NULL, 31847c16975SMattias Wallin .mask_and_set_register = ab8500_mask_and_set_register, 31947c16975SMattias Wallin .event_registers_startup_state_get = NULL, 32047c16975SMattias Wallin .startup_irq_enabled = NULL, 32147c16975SMattias Wallin }; 32262579266SRabin Vincent 3239505a0a0SMark Brown static void ab8500_irq_lock(struct irq_data *data) 32462579266SRabin Vincent { 3259505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 32662579266SRabin Vincent 32762579266SRabin Vincent mutex_lock(&ab8500->irq_lock); 328112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 32962579266SRabin Vincent } 33062579266SRabin Vincent 3319505a0a0SMark Brown static void ab8500_irq_sync_unlock(struct irq_data *data) 33262579266SRabin Vincent { 3339505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 33462579266SRabin Vincent int i; 33562579266SRabin Vincent 3362ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 33762579266SRabin Vincent u8 old = ab8500->oldmask[i]; 33862579266SRabin Vincent u8 new = ab8500->mask[i]; 33962579266SRabin Vincent int reg; 34062579266SRabin Vincent 34162579266SRabin Vincent if (new == old) 34262579266SRabin Vincent continue; 34362579266SRabin Vincent 3440f620837SLinus Walleij /* 3450f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 3460f620837SLinus Walleij * 2.0 3470f620837SLinus Walleij */ 3480f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 3490f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 35092d50a41SMattias Wallin continue; 35192d50a41SMattias Wallin 35262579266SRabin Vincent ab8500->oldmask[i] = new; 35362579266SRabin Vincent 3542ced445eSLinus Walleij reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i]; 35547c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new); 35662579266SRabin Vincent } 357112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 35862579266SRabin Vincent mutex_unlock(&ab8500->irq_lock); 35962579266SRabin Vincent } 36062579266SRabin Vincent 3619505a0a0SMark Brown static void ab8500_irq_mask(struct irq_data *data) 36262579266SRabin Vincent { 3639505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 3649505a0a0SMark Brown int offset = data->irq - ab8500->irq_base; 36562579266SRabin Vincent int index = offset / 8; 36662579266SRabin Vincent int mask = 1 << (offset % 8); 36762579266SRabin Vincent 36862579266SRabin Vincent ab8500->mask[index] |= mask; 36962579266SRabin Vincent } 37062579266SRabin Vincent 3719505a0a0SMark Brown static void ab8500_irq_unmask(struct irq_data *data) 37262579266SRabin Vincent { 3739505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 3749505a0a0SMark Brown int offset = data->irq - ab8500->irq_base; 37562579266SRabin Vincent int index = offset / 8; 37662579266SRabin Vincent int mask = 1 << (offset % 8); 37762579266SRabin Vincent 37862579266SRabin Vincent ab8500->mask[index] &= ~mask; 37962579266SRabin Vincent } 38062579266SRabin Vincent 38162579266SRabin Vincent static struct irq_chip ab8500_irq_chip = { 38262579266SRabin Vincent .name = "ab8500", 3839505a0a0SMark Brown .irq_bus_lock = ab8500_irq_lock, 3849505a0a0SMark Brown .irq_bus_sync_unlock = ab8500_irq_sync_unlock, 3859505a0a0SMark Brown .irq_mask = ab8500_irq_mask, 386e6f9306eSVirupax Sadashivpetimath .irq_disable = ab8500_irq_mask, 3879505a0a0SMark Brown .irq_unmask = ab8500_irq_unmask, 38862579266SRabin Vincent }; 38962579266SRabin Vincent 3907ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, 3917ccfe9b1SMichel JAOUEN int latch_offset, u8 latch_val) 3927ccfe9b1SMichel JAOUEN { 3937ccfe9b1SMichel JAOUEN int int_bit = __ffs(latch_val); 3947ccfe9b1SMichel JAOUEN int line, i; 3957ccfe9b1SMichel JAOUEN 3967ccfe9b1SMichel JAOUEN do { 3977ccfe9b1SMichel JAOUEN int_bit = __ffs(latch_val); 3987ccfe9b1SMichel JAOUEN 3997ccfe9b1SMichel JAOUEN for (i = 0; i < ab8500->mask_size; i++) 4007ccfe9b1SMichel JAOUEN if (ab8500->irq_reg_offset[i] == latch_offset) 4017ccfe9b1SMichel JAOUEN break; 4027ccfe9b1SMichel JAOUEN 4037ccfe9b1SMichel JAOUEN if (i >= ab8500->mask_size) { 4047ccfe9b1SMichel JAOUEN dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", 4057ccfe9b1SMichel JAOUEN latch_offset); 4067ccfe9b1SMichel JAOUEN return -ENXIO; 4077ccfe9b1SMichel JAOUEN } 4087ccfe9b1SMichel JAOUEN 4097ccfe9b1SMichel JAOUEN line = (i << 3) + int_bit; 4107ccfe9b1SMichel JAOUEN latch_val &= ~(1 << int_bit); 4117ccfe9b1SMichel JAOUEN 4127ccfe9b1SMichel JAOUEN handle_nested_irq(ab8500->irq_base + line); 4137ccfe9b1SMichel JAOUEN } while (latch_val); 4147ccfe9b1SMichel JAOUEN 4157ccfe9b1SMichel JAOUEN return 0; 4167ccfe9b1SMichel JAOUEN } 4177ccfe9b1SMichel JAOUEN 4187ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500, 4197ccfe9b1SMichel JAOUEN int hier_offset, u8 hier_val) 4207ccfe9b1SMichel JAOUEN { 4217ccfe9b1SMichel JAOUEN int latch_bit, status; 4227ccfe9b1SMichel JAOUEN u8 latch_offset, latch_val; 4237ccfe9b1SMichel JAOUEN 4247ccfe9b1SMichel JAOUEN do { 4257ccfe9b1SMichel JAOUEN latch_bit = __ffs(hier_val); 4267ccfe9b1SMichel JAOUEN latch_offset = (hier_offset << 3) + latch_bit; 4277ccfe9b1SMichel JAOUEN 4287ccfe9b1SMichel JAOUEN /* Fix inconsistent ITFromLatch25 bit mapping... */ 4297ccfe9b1SMichel JAOUEN if (unlikely(latch_offset == 17)) 4307ccfe9b1SMichel JAOUEN latch_offset = 24; 4317ccfe9b1SMichel JAOUEN 4327ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, 4337ccfe9b1SMichel JAOUEN AB8500_INTERRUPT, 4347ccfe9b1SMichel JAOUEN AB8500_IT_LATCH1_REG + latch_offset, 4357ccfe9b1SMichel JAOUEN &latch_val); 4367ccfe9b1SMichel JAOUEN if (status < 0 || latch_val == 0) 4377ccfe9b1SMichel JAOUEN goto discard; 4387ccfe9b1SMichel JAOUEN 4397ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_line(ab8500, 4407ccfe9b1SMichel JAOUEN latch_offset, latch_val); 4417ccfe9b1SMichel JAOUEN if (status < 0) 4427ccfe9b1SMichel JAOUEN return status; 4437ccfe9b1SMichel JAOUEN discard: 4447ccfe9b1SMichel JAOUEN hier_val &= ~(1 << latch_bit); 4457ccfe9b1SMichel JAOUEN } while (hier_val); 4467ccfe9b1SMichel JAOUEN 4477ccfe9b1SMichel JAOUEN return 0; 4487ccfe9b1SMichel JAOUEN } 4497ccfe9b1SMichel JAOUEN 4507ccfe9b1SMichel JAOUEN static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev) 4517ccfe9b1SMichel JAOUEN { 4527ccfe9b1SMichel JAOUEN struct ab8500 *ab8500 = dev; 4537ccfe9b1SMichel JAOUEN u8 i; 4547ccfe9b1SMichel JAOUEN 4557ccfe9b1SMichel JAOUEN dev_vdbg(ab8500->dev, "interrupt\n"); 4567ccfe9b1SMichel JAOUEN 4577ccfe9b1SMichel JAOUEN /* Hierarchical interrupt version */ 4587ccfe9b1SMichel JAOUEN for (i = 0; i < AB8500_IT_LATCHHIER_NUM; i++) { 4597ccfe9b1SMichel JAOUEN int status; 4607ccfe9b1SMichel JAOUEN u8 hier_val; 4617ccfe9b1SMichel JAOUEN 4627ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, AB8500_INTERRUPT, 4637ccfe9b1SMichel JAOUEN AB8500_IT_LATCHHIER1_REG + i, &hier_val); 4647ccfe9b1SMichel JAOUEN if (status < 0 || hier_val == 0) 4657ccfe9b1SMichel JAOUEN continue; 4667ccfe9b1SMichel JAOUEN 4677ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val); 4687ccfe9b1SMichel JAOUEN if (status < 0) 4697ccfe9b1SMichel JAOUEN break; 4707ccfe9b1SMichel JAOUEN } 4717ccfe9b1SMichel JAOUEN return IRQ_HANDLED; 4727ccfe9b1SMichel JAOUEN } 4737ccfe9b1SMichel JAOUEN 47462579266SRabin Vincent static irqreturn_t ab8500_irq(int irq, void *dev) 47562579266SRabin Vincent { 47662579266SRabin Vincent struct ab8500 *ab8500 = dev; 47762579266SRabin Vincent int i; 47862579266SRabin Vincent 47962579266SRabin Vincent dev_vdbg(ab8500->dev, "interrupt\n"); 48062579266SRabin Vincent 481112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 482112a80d2SJonas Aaberg 4832ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 4842ced445eSLinus Walleij int regoffset = ab8500->irq_reg_offset[i]; 48562579266SRabin Vincent int status; 48647c16975SMattias Wallin u8 value; 48762579266SRabin Vincent 4880f620837SLinus Walleij /* 4890f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 4900f620837SLinus Walleij * 2.0 4910f620837SLinus Walleij */ 4920f620837SLinus Walleij if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500)) 49392d50a41SMattias Wallin continue; 49492d50a41SMattias Wallin 49547c16975SMattias Wallin status = get_register_interruptible(ab8500, AB8500_INTERRUPT, 49647c16975SMattias Wallin AB8500_IT_LATCH1_REG + regoffset, &value); 49747c16975SMattias Wallin if (status < 0 || value == 0) 49862579266SRabin Vincent continue; 49962579266SRabin Vincent 50062579266SRabin Vincent do { 50188aec4f7SMattias Wallin int bit = __ffs(value); 50262579266SRabin Vincent int line = i * 8 + bit; 50362579266SRabin Vincent 50462579266SRabin Vincent handle_nested_irq(ab8500->irq_base + line); 50547c16975SMattias Wallin value &= ~(1 << bit); 506112a80d2SJonas Aaberg 50747c16975SMattias Wallin } while (value); 50862579266SRabin Vincent } 509112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 51062579266SRabin Vincent return IRQ_HANDLED; 51162579266SRabin Vincent } 51262579266SRabin Vincent 51362579266SRabin Vincent static int ab8500_irq_init(struct ab8500 *ab8500) 51462579266SRabin Vincent { 51562579266SRabin Vincent int base = ab8500->irq_base; 51662579266SRabin Vincent int irq; 5172ced445eSLinus Walleij int num_irqs; 51862579266SRabin Vincent 519d6255529SLinus Walleij if (is_ab9540(ab8500)) 520d6255529SLinus Walleij num_irqs = AB9540_NR_IRQS; 521a982362cSBengt Jonsson else if (is_ab8505(ab8500)) 522a982362cSBengt Jonsson num_irqs = AB8505_NR_IRQS; 523d6255529SLinus Walleij else 5242ced445eSLinus Walleij num_irqs = AB8500_NR_IRQS; 5252ced445eSLinus Walleij 5262ced445eSLinus Walleij for (irq = base; irq < base + num_irqs; irq++) { 527d5bb1221SThomas Gleixner irq_set_chip_data(irq, ab8500); 528d5bb1221SThomas Gleixner irq_set_chip_and_handler(irq, &ab8500_irq_chip, 52962579266SRabin Vincent handle_simple_irq); 530d5bb1221SThomas Gleixner irq_set_nested_thread(irq, 1); 53162579266SRabin Vincent #ifdef CONFIG_ARM 53262579266SRabin Vincent set_irq_flags(irq, IRQF_VALID); 53362579266SRabin Vincent #else 534d5bb1221SThomas Gleixner irq_set_noprobe(irq); 53562579266SRabin Vincent #endif 53662579266SRabin Vincent } 53762579266SRabin Vincent 53862579266SRabin Vincent return 0; 53962579266SRabin Vincent } 54062579266SRabin Vincent 54162579266SRabin Vincent static void ab8500_irq_remove(struct ab8500 *ab8500) 54262579266SRabin Vincent { 54362579266SRabin Vincent int base = ab8500->irq_base; 54462579266SRabin Vincent int irq; 5452ced445eSLinus Walleij int num_irqs; 54662579266SRabin Vincent 547d6255529SLinus Walleij if (is_ab9540(ab8500)) 548d6255529SLinus Walleij num_irqs = AB9540_NR_IRQS; 549a982362cSBengt Jonsson else if (is_ab8505(ab8500)) 550a982362cSBengt Jonsson num_irqs = AB8505_NR_IRQS; 551d6255529SLinus Walleij else 5522ced445eSLinus Walleij num_irqs = AB8500_NR_IRQS; 5532ced445eSLinus Walleij 5542ced445eSLinus Walleij for (irq = base; irq < base + num_irqs; irq++) { 55562579266SRabin Vincent #ifdef CONFIG_ARM 55662579266SRabin Vincent set_irq_flags(irq, 0); 55762579266SRabin Vincent #endif 558d5bb1221SThomas Gleixner irq_set_chip_and_handler(irq, NULL, NULL); 559d5bb1221SThomas Gleixner irq_set_chip_data(irq, NULL); 56062579266SRabin Vincent } 56162579266SRabin Vincent } 56262579266SRabin Vincent 563112a80d2SJonas Aaberg int ab8500_suspend(struct ab8500 *ab8500) 564112a80d2SJonas Aaberg { 565112a80d2SJonas Aaberg if (atomic_read(&ab8500->transfer_ongoing)) 566112a80d2SJonas Aaberg return -EINVAL; 567112a80d2SJonas Aaberg else 568112a80d2SJonas Aaberg return 0; 569112a80d2SJonas Aaberg } 570112a80d2SJonas Aaberg 571d6255529SLinus Walleij /* AB8500 GPIO Resources */ 5725cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_gpio_resources[] = { 5730cb3fcd7SBibek Basu { 5740cb3fcd7SBibek Basu .name = "GPIO_INT6", 5750cb3fcd7SBibek Basu .start = AB8500_INT_GPIO6R, 5760cb3fcd7SBibek Basu .end = AB8500_INT_GPIO41F, 5770cb3fcd7SBibek Basu .flags = IORESOURCE_IRQ, 5780cb3fcd7SBibek Basu } 5790cb3fcd7SBibek Basu }; 5800cb3fcd7SBibek Basu 581d6255529SLinus Walleij /* AB9540 GPIO Resources */ 582d6255529SLinus Walleij static struct resource __devinitdata ab9540_gpio_resources[] = { 583d6255529SLinus Walleij { 584d6255529SLinus Walleij .name = "GPIO_INT6", 585d6255529SLinus Walleij .start = AB8500_INT_GPIO6R, 586d6255529SLinus Walleij .end = AB8500_INT_GPIO41F, 587d6255529SLinus Walleij .flags = IORESOURCE_IRQ, 588d6255529SLinus Walleij }, 589d6255529SLinus Walleij { 590d6255529SLinus Walleij .name = "GPIO_INT14", 591d6255529SLinus Walleij .start = AB9540_INT_GPIO50R, 592d6255529SLinus Walleij .end = AB9540_INT_GPIO54R, 593d6255529SLinus Walleij .flags = IORESOURCE_IRQ, 594d6255529SLinus Walleij }, 595d6255529SLinus Walleij { 596d6255529SLinus Walleij .name = "GPIO_INT15", 597d6255529SLinus Walleij .start = AB9540_INT_GPIO50F, 598d6255529SLinus Walleij .end = AB9540_INT_GPIO54F, 599d6255529SLinus Walleij .flags = IORESOURCE_IRQ, 600d6255529SLinus Walleij } 601d6255529SLinus Walleij }; 602d6255529SLinus Walleij 6035cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_gpadc_resources[] = { 60462579266SRabin Vincent { 60562579266SRabin Vincent .name = "HW_CONV_END", 60662579266SRabin Vincent .start = AB8500_INT_GP_HW_ADC_CONV_END, 60762579266SRabin Vincent .end = AB8500_INT_GP_HW_ADC_CONV_END, 60862579266SRabin Vincent .flags = IORESOURCE_IRQ, 60962579266SRabin Vincent }, 61062579266SRabin Vincent { 61162579266SRabin Vincent .name = "SW_CONV_END", 61262579266SRabin Vincent .start = AB8500_INT_GP_SW_ADC_CONV_END, 61362579266SRabin Vincent .end = AB8500_INT_GP_SW_ADC_CONV_END, 61462579266SRabin Vincent .flags = IORESOURCE_IRQ, 61562579266SRabin Vincent }, 61662579266SRabin Vincent }; 61762579266SRabin Vincent 6185cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_rtc_resources[] = { 61962579266SRabin Vincent { 62062579266SRabin Vincent .name = "60S", 62162579266SRabin Vincent .start = AB8500_INT_RTC_60S, 62262579266SRabin Vincent .end = AB8500_INT_RTC_60S, 62362579266SRabin Vincent .flags = IORESOURCE_IRQ, 62462579266SRabin Vincent }, 62562579266SRabin Vincent { 62662579266SRabin Vincent .name = "ALARM", 62762579266SRabin Vincent .start = AB8500_INT_RTC_ALARM, 62862579266SRabin Vincent .end = AB8500_INT_RTC_ALARM, 62962579266SRabin Vincent .flags = IORESOURCE_IRQ, 63062579266SRabin Vincent }, 63162579266SRabin Vincent }; 63262579266SRabin Vincent 6335cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_poweronkey_db_resources[] = { 63477686517SSundar R Iyer { 63577686517SSundar R Iyer .name = "ONKEY_DBF", 63677686517SSundar R Iyer .start = AB8500_INT_PON_KEY1DB_F, 63777686517SSundar R Iyer .end = AB8500_INT_PON_KEY1DB_F, 63877686517SSundar R Iyer .flags = IORESOURCE_IRQ, 63977686517SSundar R Iyer }, 64077686517SSundar R Iyer { 64177686517SSundar R Iyer .name = "ONKEY_DBR", 64277686517SSundar R Iyer .start = AB8500_INT_PON_KEY1DB_R, 64377686517SSundar R Iyer .end = AB8500_INT_PON_KEY1DB_R, 64477686517SSundar R Iyer .flags = IORESOURCE_IRQ, 64577686517SSundar R Iyer }, 64677686517SSundar R Iyer }; 64777686517SSundar R Iyer 6486af75ecdSLinus Walleij static struct resource __devinitdata ab8500_av_acc_detect_resources[] = { 649e098adedSMattias Wallin { 6506af75ecdSLinus Walleij .name = "ACC_DETECT_1DB_F", 6516af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_1DB_F, 6526af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_1DB_F, 653e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 654e098adedSMattias Wallin }, 655e098adedSMattias Wallin { 6566af75ecdSLinus Walleij .name = "ACC_DETECT_1DB_R", 6576af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_1DB_R, 6586af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_1DB_R, 659e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 660e098adedSMattias Wallin }, 661e098adedSMattias Wallin { 6626af75ecdSLinus Walleij .name = "ACC_DETECT_21DB_F", 6636af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_21DB_F, 6646af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_21DB_F, 6656af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 6666af75ecdSLinus Walleij }, 6676af75ecdSLinus Walleij { 6686af75ecdSLinus Walleij .name = "ACC_DETECT_21DB_R", 6696af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_21DB_R, 6706af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_21DB_R, 6716af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 6726af75ecdSLinus Walleij }, 6736af75ecdSLinus Walleij { 6746af75ecdSLinus Walleij .name = "ACC_DETECT_22DB_F", 6756af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_22DB_F, 6766af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_22DB_F, 6776af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 6786af75ecdSLinus Walleij }, 6796af75ecdSLinus Walleij { 6806af75ecdSLinus Walleij .name = "ACC_DETECT_22DB_R", 6816af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_22DB_R, 6826af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_22DB_R, 6836af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 6846af75ecdSLinus Walleij }, 6856af75ecdSLinus Walleij }; 6866af75ecdSLinus Walleij 6876af75ecdSLinus Walleij static struct resource __devinitdata ab8500_charger_resources[] = { 6886af75ecdSLinus Walleij { 689e098adedSMattias Wallin .name = "MAIN_CH_UNPLUG_DET", 690e098adedSMattias Wallin .start = AB8500_INT_MAIN_CH_UNPLUG_DET, 691e098adedSMattias Wallin .end = AB8500_INT_MAIN_CH_UNPLUG_DET, 692e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 693e098adedSMattias Wallin }, 694e098adedSMattias Wallin { 695e098adedSMattias Wallin .name = "MAIN_CHARGE_PLUG_DET", 696e098adedSMattias Wallin .start = AB8500_INT_MAIN_CH_PLUG_DET, 697e098adedSMattias Wallin .end = AB8500_INT_MAIN_CH_PLUG_DET, 698e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 699e098adedSMattias Wallin }, 700e098adedSMattias Wallin { 701e098adedSMattias Wallin .name = "VBUS_DET_R", 702e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_R, 703e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_R, 704e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 705e098adedSMattias Wallin }, 706e098adedSMattias Wallin { 7076af75ecdSLinus Walleij .name = "VBUS_DET_F", 7086af75ecdSLinus Walleij .start = AB8500_INT_VBUS_DET_F, 7096af75ecdSLinus Walleij .end = AB8500_INT_VBUS_DET_F, 710e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 711e098adedSMattias Wallin }, 712e098adedSMattias Wallin { 7136af75ecdSLinus Walleij .name = "USB_LINK_STATUS", 7146af75ecdSLinus Walleij .start = AB8500_INT_USB_LINK_STATUS, 7156af75ecdSLinus Walleij .end = AB8500_INT_USB_LINK_STATUS, 7166af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7176af75ecdSLinus Walleij }, 7186af75ecdSLinus Walleij { 719e098adedSMattias Wallin .name = "VBUS_OVV", 720e098adedSMattias Wallin .start = AB8500_INT_VBUS_OVV, 721e098adedSMattias Wallin .end = AB8500_INT_VBUS_OVV, 722e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 723e098adedSMattias Wallin }, 724e098adedSMattias Wallin { 7256af75ecdSLinus Walleij .name = "USB_CH_TH_PROT_R", 7266af75ecdSLinus Walleij .start = AB8500_INT_USB_CH_TH_PROT_R, 7276af75ecdSLinus Walleij .end = AB8500_INT_USB_CH_TH_PROT_R, 728e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 729e098adedSMattias Wallin }, 730e098adedSMattias Wallin { 7316af75ecdSLinus Walleij .name = "USB_CH_TH_PROT_F", 7326af75ecdSLinus Walleij .start = AB8500_INT_USB_CH_TH_PROT_F, 7336af75ecdSLinus Walleij .end = AB8500_INT_USB_CH_TH_PROT_F, 734e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 735e098adedSMattias Wallin }, 736e098adedSMattias Wallin { 7376af75ecdSLinus Walleij .name = "MAIN_EXT_CH_NOT_OK", 7386af75ecdSLinus Walleij .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, 7396af75ecdSLinus Walleij .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, 7406af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7416af75ecdSLinus Walleij }, 7426af75ecdSLinus Walleij { 7436af75ecdSLinus Walleij .name = "MAIN_CH_TH_PROT_R", 7446af75ecdSLinus Walleij .start = AB8500_INT_MAIN_CH_TH_PROT_R, 7456af75ecdSLinus Walleij .end = AB8500_INT_MAIN_CH_TH_PROT_R, 7466af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7476af75ecdSLinus Walleij }, 7486af75ecdSLinus Walleij { 7496af75ecdSLinus Walleij .name = "MAIN_CH_TH_PROT_F", 7506af75ecdSLinus Walleij .start = AB8500_INT_MAIN_CH_TH_PROT_F, 7516af75ecdSLinus Walleij .end = AB8500_INT_MAIN_CH_TH_PROT_F, 7526af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7536af75ecdSLinus Walleij }, 7546af75ecdSLinus Walleij { 7556af75ecdSLinus Walleij .name = "USB_CHARGER_NOT_OKR", 756a982362cSBengt Jonsson .start = AB8500_INT_USB_CHARGER_NOT_OKR, 757a982362cSBengt Jonsson .end = AB8500_INT_USB_CHARGER_NOT_OKR, 7586af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7596af75ecdSLinus Walleij }, 7606af75ecdSLinus Walleij { 7616af75ecdSLinus Walleij .name = "CH_WD_EXP", 7626af75ecdSLinus Walleij .start = AB8500_INT_CH_WD_EXP, 7636af75ecdSLinus Walleij .end = AB8500_INT_CH_WD_EXP, 7646af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7656af75ecdSLinus Walleij }, 7666af75ecdSLinus Walleij }; 7676af75ecdSLinus Walleij 7686af75ecdSLinus Walleij static struct resource __devinitdata ab8500_btemp_resources[] = { 7696af75ecdSLinus Walleij { 7706af75ecdSLinus Walleij .name = "BAT_CTRL_INDB", 7716af75ecdSLinus Walleij .start = AB8500_INT_BAT_CTRL_INDB, 7726af75ecdSLinus Walleij .end = AB8500_INT_BAT_CTRL_INDB, 773e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 774e098adedSMattias Wallin }, 775e098adedSMattias Wallin { 776e098adedSMattias Wallin .name = "BTEMP_LOW", 777e098adedSMattias Wallin .start = AB8500_INT_BTEMP_LOW, 778e098adedSMattias Wallin .end = AB8500_INT_BTEMP_LOW, 779e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 780e098adedSMattias Wallin }, 781e098adedSMattias Wallin { 782e098adedSMattias Wallin .name = "BTEMP_HIGH", 783e098adedSMattias Wallin .start = AB8500_INT_BTEMP_HIGH, 784e098adedSMattias Wallin .end = AB8500_INT_BTEMP_HIGH, 785e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 786e098adedSMattias Wallin }, 787e098adedSMattias Wallin { 7886af75ecdSLinus Walleij .name = "BTEMP_LOW_MEDIUM", 7896af75ecdSLinus Walleij .start = AB8500_INT_BTEMP_LOW_MEDIUM, 7906af75ecdSLinus Walleij .end = AB8500_INT_BTEMP_LOW_MEDIUM, 791e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 792e098adedSMattias Wallin }, 793e098adedSMattias Wallin { 7946af75ecdSLinus Walleij .name = "BTEMP_MEDIUM_HIGH", 7956af75ecdSLinus Walleij .start = AB8500_INT_BTEMP_MEDIUM_HIGH, 7966af75ecdSLinus Walleij .end = AB8500_INT_BTEMP_MEDIUM_HIGH, 797e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 798e098adedSMattias Wallin }, 799e098adedSMattias Wallin }; 800e098adedSMattias Wallin 8016af75ecdSLinus Walleij static struct resource __devinitdata ab8500_fg_resources[] = { 8026af75ecdSLinus Walleij { 8036af75ecdSLinus Walleij .name = "NCONV_ACCU", 8046af75ecdSLinus Walleij .start = AB8500_INT_CCN_CONV_ACC, 8056af75ecdSLinus Walleij .end = AB8500_INT_CCN_CONV_ACC, 8066af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8076af75ecdSLinus Walleij }, 8086af75ecdSLinus Walleij { 8096af75ecdSLinus Walleij .name = "BATT_OVV", 8106af75ecdSLinus Walleij .start = AB8500_INT_BATT_OVV, 8116af75ecdSLinus Walleij .end = AB8500_INT_BATT_OVV, 8126af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8136af75ecdSLinus Walleij }, 8146af75ecdSLinus Walleij { 8156af75ecdSLinus Walleij .name = "LOW_BAT_F", 8166af75ecdSLinus Walleij .start = AB8500_INT_LOW_BAT_F, 8176af75ecdSLinus Walleij .end = AB8500_INT_LOW_BAT_F, 8186af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8196af75ecdSLinus Walleij }, 8206af75ecdSLinus Walleij { 8216af75ecdSLinus Walleij .name = "LOW_BAT_R", 8226af75ecdSLinus Walleij .start = AB8500_INT_LOW_BAT_R, 8236af75ecdSLinus Walleij .end = AB8500_INT_LOW_BAT_R, 8246af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8256af75ecdSLinus Walleij }, 8266af75ecdSLinus Walleij { 8276af75ecdSLinus Walleij .name = "CC_INT_CALIB", 8286af75ecdSLinus Walleij .start = AB8500_INT_CC_INT_CALIB, 8296af75ecdSLinus Walleij .end = AB8500_INT_CC_INT_CALIB, 8306af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8316af75ecdSLinus Walleij }, 832a982362cSBengt Jonsson { 833a982362cSBengt Jonsson .name = "CCEOC", 834a982362cSBengt Jonsson .start = AB8500_INT_CCEOC, 835a982362cSBengt Jonsson .end = AB8500_INT_CCEOC, 836a982362cSBengt Jonsson .flags = IORESOURCE_IRQ, 837a982362cSBengt Jonsson }, 8386af75ecdSLinus Walleij }; 8396af75ecdSLinus Walleij 8406af75ecdSLinus Walleij static struct resource __devinitdata ab8500_chargalg_resources[] = {}; 8416af75ecdSLinus Walleij 842df720647SAxel Lin #ifdef CONFIG_DEBUG_FS 8435cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_debug_resources[] = { 844e098adedSMattias Wallin { 845e098adedSMattias Wallin .name = "IRQ_FIRST", 846e098adedSMattias Wallin .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, 847e098adedSMattias Wallin .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, 848e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 849e098adedSMattias Wallin }, 850e098adedSMattias Wallin { 851e098adedSMattias Wallin .name = "IRQ_LAST", 852a982362cSBengt Jonsson .start = AB8500_INT_XTAL32K_KO, 853a982362cSBengt Jonsson .end = AB8500_INT_XTAL32K_KO, 854e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 855e098adedSMattias Wallin }, 856e098adedSMattias Wallin }; 857df720647SAxel Lin #endif 858e098adedSMattias Wallin 8595cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_usb_resources[] = { 860e098adedSMattias Wallin { 861e098adedSMattias Wallin .name = "ID_WAKEUP_R", 862e098adedSMattias Wallin .start = AB8500_INT_ID_WAKEUP_R, 863e098adedSMattias Wallin .end = AB8500_INT_ID_WAKEUP_R, 864e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 865e098adedSMattias Wallin }, 866e098adedSMattias Wallin { 867e098adedSMattias Wallin .name = "ID_WAKEUP_F", 868e098adedSMattias Wallin .start = AB8500_INT_ID_WAKEUP_F, 869e098adedSMattias Wallin .end = AB8500_INT_ID_WAKEUP_F, 870e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 871e098adedSMattias Wallin }, 872e098adedSMattias Wallin { 873e098adedSMattias Wallin .name = "VBUS_DET_F", 874e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_F, 875e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_F, 876e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 877e098adedSMattias Wallin }, 878e098adedSMattias Wallin { 879e098adedSMattias Wallin .name = "VBUS_DET_R", 880e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_R, 881e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_R, 882e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 883e098adedSMattias Wallin }, 88492d50a41SMattias Wallin { 88592d50a41SMattias Wallin .name = "USB_LINK_STATUS", 88692d50a41SMattias Wallin .start = AB8500_INT_USB_LINK_STATUS, 88792d50a41SMattias Wallin .end = AB8500_INT_USB_LINK_STATUS, 88892d50a41SMattias Wallin .flags = IORESOURCE_IRQ, 88992d50a41SMattias Wallin }, 8906af75ecdSLinus Walleij { 8916af75ecdSLinus Walleij .name = "USB_ADP_PROBE_PLUG", 8926af75ecdSLinus Walleij .start = AB8500_INT_ADP_PROBE_PLUG, 8936af75ecdSLinus Walleij .end = AB8500_INT_ADP_PROBE_PLUG, 8946af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8956af75ecdSLinus Walleij }, 8966af75ecdSLinus Walleij { 8976af75ecdSLinus Walleij .name = "USB_ADP_PROBE_UNPLUG", 8986af75ecdSLinus Walleij .start = AB8500_INT_ADP_PROBE_UNPLUG, 8996af75ecdSLinus Walleij .end = AB8500_INT_ADP_PROBE_UNPLUG, 9006af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 9016af75ecdSLinus Walleij }, 902e098adedSMattias Wallin }; 903e098adedSMattias Wallin 90444f72e53SVirupax Sadashivpetimath static struct resource __devinitdata ab8505_iddet_resources[] = { 90544f72e53SVirupax Sadashivpetimath { 90644f72e53SVirupax Sadashivpetimath .name = "KeyDeglitch", 90744f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KEYDEGLITCH, 90844f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KEYDEGLITCH, 90944f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 91044f72e53SVirupax Sadashivpetimath }, 91144f72e53SVirupax Sadashivpetimath { 91244f72e53SVirupax Sadashivpetimath .name = "KP", 91344f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KP, 91444f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KP, 91544f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 91644f72e53SVirupax Sadashivpetimath }, 91744f72e53SVirupax Sadashivpetimath { 91844f72e53SVirupax Sadashivpetimath .name = "IKP", 91944f72e53SVirupax Sadashivpetimath .start = AB8505_INT_IKP, 92044f72e53SVirupax Sadashivpetimath .end = AB8505_INT_IKP, 92144f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 92244f72e53SVirupax Sadashivpetimath }, 92344f72e53SVirupax Sadashivpetimath { 92444f72e53SVirupax Sadashivpetimath .name = "IKR", 92544f72e53SVirupax Sadashivpetimath .start = AB8505_INT_IKR, 92644f72e53SVirupax Sadashivpetimath .end = AB8505_INT_IKR, 92744f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 92844f72e53SVirupax Sadashivpetimath }, 92944f72e53SVirupax Sadashivpetimath { 93044f72e53SVirupax Sadashivpetimath .name = "KeyStuck", 93144f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KEYSTUCK, 93244f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KEYSTUCK, 93344f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 93444f72e53SVirupax Sadashivpetimath }, 93544f72e53SVirupax Sadashivpetimath }; 93644f72e53SVirupax Sadashivpetimath 9375cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_temp_resources[] = { 938e098adedSMattias Wallin { 939e098adedSMattias Wallin .name = "AB8500_TEMP_WARM", 940e098adedSMattias Wallin .start = AB8500_INT_TEMP_WARM, 941e098adedSMattias Wallin .end = AB8500_INT_TEMP_WARM, 942e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 943e098adedSMattias Wallin }, 944e098adedSMattias Wallin }; 945e098adedSMattias Wallin 946d6255529SLinus Walleij static struct mfd_cell __devinitdata abx500_common_devs[] = { 9475814fc35SMattias Wallin #ifdef CONFIG_DEBUG_FS 9485814fc35SMattias Wallin { 9495814fc35SMattias Wallin .name = "ab8500-debug", 950e098adedSMattias Wallin .num_resources = ARRAY_SIZE(ab8500_debug_resources), 951e098adedSMattias Wallin .resources = ab8500_debug_resources, 9525814fc35SMattias Wallin }, 9535814fc35SMattias Wallin #endif 95462579266SRabin Vincent { 955e098adedSMattias Wallin .name = "ab8500-sysctrl", 956e098adedSMattias Wallin }, 957e098adedSMattias Wallin { 958e098adedSMattias Wallin .name = "ab8500-regulator", 959e098adedSMattias Wallin }, 960e098adedSMattias Wallin { 96162579266SRabin Vincent .name = "ab8500-gpadc", 96262579266SRabin Vincent .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), 96362579266SRabin Vincent .resources = ab8500_gpadc_resources, 96462579266SRabin Vincent }, 96562579266SRabin Vincent { 96662579266SRabin Vincent .name = "ab8500-rtc", 96762579266SRabin Vincent .num_resources = ARRAY_SIZE(ab8500_rtc_resources), 96862579266SRabin Vincent .resources = ab8500_rtc_resources, 96962579266SRabin Vincent }, 970f0f05b1cSArun Murthy { 9716af75ecdSLinus Walleij .name = "ab8500-acc-det", 9726af75ecdSLinus Walleij .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources), 9736af75ecdSLinus Walleij .resources = ab8500_av_acc_detect_resources, 9746af75ecdSLinus Walleij }, 9756af75ecdSLinus Walleij { 976e098adedSMattias Wallin .name = "ab8500-poweron-key", 977e098adedSMattias Wallin .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), 978e098adedSMattias Wallin .resources = ab8500_poweronkey_db_resources, 979e098adedSMattias Wallin }, 980e098adedSMattias Wallin { 981f0f05b1cSArun Murthy .name = "ab8500-pwm", 982f0f05b1cSArun Murthy .id = 1, 983f0f05b1cSArun Murthy }, 984f0f05b1cSArun Murthy { 985f0f05b1cSArun Murthy .name = "ab8500-pwm", 986f0f05b1cSArun Murthy .id = 2, 987f0f05b1cSArun Murthy }, 988f0f05b1cSArun Murthy { 989f0f05b1cSArun Murthy .name = "ab8500-pwm", 990f0f05b1cSArun Murthy .id = 3, 991f0f05b1cSArun Murthy }, 992e098adedSMattias Wallin { .name = "ab8500-leds", }, 99377686517SSundar R Iyer { 994e098adedSMattias Wallin .name = "ab8500-denc", 995e098adedSMattias Wallin }, 996e098adedSMattias Wallin { 997e098adedSMattias Wallin .name = "ab8500-temp", 998e098adedSMattias Wallin .num_resources = ARRAY_SIZE(ab8500_temp_resources), 999e098adedSMattias Wallin .resources = ab8500_temp_resources, 100077686517SSundar R Iyer }, 100162579266SRabin Vincent }; 100262579266SRabin Vincent 10036ef9418cSRickard Andersson static struct mfd_cell __devinitdata ab8500_bm_devs[] = { 10046ef9418cSRickard Andersson { 10056ef9418cSRickard Andersson .name = "ab8500-charger", 10066ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_charger_resources), 10076ef9418cSRickard Andersson .resources = ab8500_charger_resources, 10086ef9418cSRickard Andersson }, 10096ef9418cSRickard Andersson { 10106ef9418cSRickard Andersson .name = "ab8500-btemp", 10116ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_btemp_resources), 10126ef9418cSRickard Andersson .resources = ab8500_btemp_resources, 10136ef9418cSRickard Andersson }, 10146ef9418cSRickard Andersson { 10156ef9418cSRickard Andersson .name = "ab8500-fg", 10166ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_fg_resources), 10176ef9418cSRickard Andersson .resources = ab8500_fg_resources, 10186ef9418cSRickard Andersson }, 10196ef9418cSRickard Andersson { 10206ef9418cSRickard Andersson .name = "ab8500-chargalg", 10216ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_chargalg_resources), 10226ef9418cSRickard Andersson .resources = ab8500_chargalg_resources, 10236ef9418cSRickard Andersson }, 10246ef9418cSRickard Andersson }; 10256ef9418cSRickard Andersson 1026d6255529SLinus Walleij static struct mfd_cell __devinitdata ab8500_devs[] = { 1027d6255529SLinus Walleij { 1028d6255529SLinus Walleij .name = "ab8500-gpio", 1029d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab8500_gpio_resources), 1030d6255529SLinus Walleij .resources = ab8500_gpio_resources, 1031d6255529SLinus Walleij }, 1032d6255529SLinus Walleij { 1033d6255529SLinus Walleij .name = "ab8500-usb", 1034d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab8500_usb_resources), 1035d6255529SLinus Walleij .resources = ab8500_usb_resources, 1036d6255529SLinus Walleij }, 103744f72e53SVirupax Sadashivpetimath { 103844f72e53SVirupax Sadashivpetimath .name = "ab8500-codec", 103944f72e53SVirupax Sadashivpetimath }, 1040d6255529SLinus Walleij }; 1041d6255529SLinus Walleij 1042d6255529SLinus Walleij static struct mfd_cell __devinitdata ab9540_devs[] = { 1043d6255529SLinus Walleij { 1044d6255529SLinus Walleij .name = "ab8500-gpio", 1045d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab9540_gpio_resources), 1046d6255529SLinus Walleij .resources = ab9540_gpio_resources, 1047d6255529SLinus Walleij }, 1048d6255529SLinus Walleij { 1049d6255529SLinus Walleij .name = "ab9540-usb", 1050d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab8500_usb_resources), 1051d6255529SLinus Walleij .resources = ab8500_usb_resources, 1052d6255529SLinus Walleij }, 105344f72e53SVirupax Sadashivpetimath { 105444f72e53SVirupax Sadashivpetimath .name = "ab9540-codec", 105544f72e53SVirupax Sadashivpetimath }, 105644f72e53SVirupax Sadashivpetimath }; 105744f72e53SVirupax Sadashivpetimath 105844f72e53SVirupax Sadashivpetimath /* Device list common to ab9540 and ab8505 */ 105944f72e53SVirupax Sadashivpetimath static struct mfd_cell __devinitdata ab9540_ab8505_devs[] = { 106044f72e53SVirupax Sadashivpetimath { 106144f72e53SVirupax Sadashivpetimath .name = "ab-iddet", 106244f72e53SVirupax Sadashivpetimath .num_resources = ARRAY_SIZE(ab8505_iddet_resources), 106344f72e53SVirupax Sadashivpetimath .resources = ab8505_iddet_resources, 106444f72e53SVirupax Sadashivpetimath }, 1065d6255529SLinus Walleij }; 1066d6255529SLinus Walleij 1067cca69b67SMattias Wallin static ssize_t show_chip_id(struct device *dev, 1068cca69b67SMattias Wallin struct device_attribute *attr, char *buf) 1069cca69b67SMattias Wallin { 1070cca69b67SMattias Wallin struct ab8500 *ab8500; 1071cca69b67SMattias Wallin 1072cca69b67SMattias Wallin ab8500 = dev_get_drvdata(dev); 1073cca69b67SMattias Wallin return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); 1074cca69b67SMattias Wallin } 1075cca69b67SMattias Wallin 1076e5c238c3SMattias Wallin /* 1077e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 1078e5c238c3SMattias Wallin * 0x01 Swoff bit programming 1079e5c238c3SMattias Wallin * 0x02 Thermal protection activation 1080e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 1081e5c238c3SMattias Wallin * 0x08 Watchdog expired 1082e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 1083e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 1084e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 1085e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 1086e5c238c3SMattias Wallin */ 1087e5c238c3SMattias Wallin static ssize_t show_switch_off_status(struct device *dev, 1088e5c238c3SMattias Wallin struct device_attribute *attr, char *buf) 1089e5c238c3SMattias Wallin { 1090e5c238c3SMattias Wallin int ret; 1091e5c238c3SMattias Wallin u8 value; 1092e5c238c3SMattias Wallin struct ab8500 *ab8500; 1093e5c238c3SMattias Wallin 1094e5c238c3SMattias Wallin ab8500 = dev_get_drvdata(dev); 1095e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 1096e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 1097e5c238c3SMattias Wallin if (ret < 0) 1098e5c238c3SMattias Wallin return ret; 1099e5c238c3SMattias Wallin return sprintf(buf, "%#x\n", value); 1100e5c238c3SMattias Wallin } 1101e5c238c3SMattias Wallin 1102b4a31037SAndrew Lynn /* 1103b4a31037SAndrew Lynn * ab8500 has turned on due to (TURN_ON_STATUS): 1104b4a31037SAndrew Lynn * 0x01 PORnVbat 1105b4a31037SAndrew Lynn * 0x02 PonKey1dbF 1106b4a31037SAndrew Lynn * 0x04 PonKey2dbF 1107b4a31037SAndrew Lynn * 0x08 RTCAlarm 1108b4a31037SAndrew Lynn * 0x10 MainChDet 1109b4a31037SAndrew Lynn * 0x20 VbusDet 1110b4a31037SAndrew Lynn * 0x40 UsbIDDetect 1111b4a31037SAndrew Lynn * 0x80 Reserved 1112b4a31037SAndrew Lynn */ 1113b4a31037SAndrew Lynn static ssize_t show_turn_on_status(struct device *dev, 1114b4a31037SAndrew Lynn struct device_attribute *attr, char *buf) 1115b4a31037SAndrew Lynn { 1116b4a31037SAndrew Lynn int ret; 1117b4a31037SAndrew Lynn u8 value; 1118b4a31037SAndrew Lynn struct ab8500 *ab8500; 1119b4a31037SAndrew Lynn 1120b4a31037SAndrew Lynn ab8500 = dev_get_drvdata(dev); 1121b4a31037SAndrew Lynn ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 1122b4a31037SAndrew Lynn AB8500_TURN_ON_STATUS, &value); 1123b4a31037SAndrew Lynn if (ret < 0) 1124b4a31037SAndrew Lynn return ret; 1125b4a31037SAndrew Lynn return sprintf(buf, "%#x\n", value); 1126b4a31037SAndrew Lynn } 1127b4a31037SAndrew Lynn 1128d6255529SLinus Walleij static ssize_t show_ab9540_dbbrstn(struct device *dev, 1129d6255529SLinus Walleij struct device_attribute *attr, char *buf) 1130d6255529SLinus Walleij { 1131d6255529SLinus Walleij struct ab8500 *ab8500; 1132d6255529SLinus Walleij int ret; 1133d6255529SLinus Walleij u8 value; 1134d6255529SLinus Walleij 1135d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 1136d6255529SLinus Walleij 1137d6255529SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2, 1138d6255529SLinus Walleij AB9540_MODEM_CTRL2_REG, &value); 1139d6255529SLinus Walleij if (ret < 0) 1140d6255529SLinus Walleij return ret; 1141d6255529SLinus Walleij 1142d6255529SLinus Walleij return sprintf(buf, "%d\n", 1143d6255529SLinus Walleij (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0); 1144d6255529SLinus Walleij } 1145d6255529SLinus Walleij 1146d6255529SLinus Walleij static ssize_t store_ab9540_dbbrstn(struct device *dev, 1147d6255529SLinus Walleij struct device_attribute *attr, const char *buf, size_t count) 1148d6255529SLinus Walleij { 1149d6255529SLinus Walleij struct ab8500 *ab8500; 1150d6255529SLinus Walleij int ret = count; 1151d6255529SLinus Walleij int err; 1152d6255529SLinus Walleij u8 bitvalues; 1153d6255529SLinus Walleij 1154d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 1155d6255529SLinus Walleij 1156d6255529SLinus Walleij if (count > 0) { 1157d6255529SLinus Walleij switch (buf[0]) { 1158d6255529SLinus Walleij case '0': 1159d6255529SLinus Walleij bitvalues = 0; 1160d6255529SLinus Walleij break; 1161d6255529SLinus Walleij case '1': 1162d6255529SLinus Walleij bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT; 1163d6255529SLinus Walleij break; 1164d6255529SLinus Walleij default: 1165d6255529SLinus Walleij goto exit; 1166d6255529SLinus Walleij } 1167d6255529SLinus Walleij 1168d6255529SLinus Walleij err = mask_and_set_register_interruptible(ab8500, 1169d6255529SLinus Walleij AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG, 1170d6255529SLinus Walleij AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues); 1171d6255529SLinus Walleij if (err) 1172d6255529SLinus Walleij dev_info(ab8500->dev, 1173d6255529SLinus Walleij "Failed to set DBBRSTN %c, err %#x\n", 1174d6255529SLinus Walleij buf[0], err); 1175d6255529SLinus Walleij } 1176d6255529SLinus Walleij 1177d6255529SLinus Walleij exit: 1178d6255529SLinus Walleij return ret; 1179d6255529SLinus Walleij } 1180d6255529SLinus Walleij 1181cca69b67SMattias Wallin static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); 1182e5c238c3SMattias Wallin static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL); 1183b4a31037SAndrew Lynn static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL); 1184d6255529SLinus Walleij static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR, 1185d6255529SLinus Walleij show_ab9540_dbbrstn, store_ab9540_dbbrstn); 1186cca69b67SMattias Wallin 1187cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = { 1188cca69b67SMattias Wallin &dev_attr_chip_id.attr, 1189e5c238c3SMattias Wallin &dev_attr_switch_off_status.attr, 1190b4a31037SAndrew Lynn &dev_attr_turn_on_status.attr, 1191cca69b67SMattias Wallin NULL, 1192cca69b67SMattias Wallin }; 1193cca69b67SMattias Wallin 1194d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = { 1195d6255529SLinus Walleij &dev_attr_chip_id.attr, 1196d6255529SLinus Walleij &dev_attr_switch_off_status.attr, 1197d6255529SLinus Walleij &dev_attr_turn_on_status.attr, 1198d6255529SLinus Walleij &dev_attr_dbbrstn.attr, 1199d6255529SLinus Walleij NULL, 1200d6255529SLinus Walleij }; 1201d6255529SLinus Walleij 1202cca69b67SMattias Wallin static struct attribute_group ab8500_attr_group = { 1203cca69b67SMattias Wallin .attrs = ab8500_sysfs_entries, 1204cca69b67SMattias Wallin }; 1205cca69b67SMattias Wallin 1206d6255529SLinus Walleij static struct attribute_group ab9540_attr_group = { 1207d6255529SLinus Walleij .attrs = ab9540_sysfs_entries, 1208d6255529SLinus Walleij }; 1209d6255529SLinus Walleij 1210*6bc4a568SLee Jones static const struct of_device_id ab8500_match[] = { 1211*6bc4a568SLee Jones { 1212*6bc4a568SLee Jones .compatible = "stericsson,ab8500", 1213*6bc4a568SLee Jones .data = (void *)AB8500_VERSION_AB8500, 1214*6bc4a568SLee Jones }, 1215*6bc4a568SLee Jones {}, 1216*6bc4a568SLee Jones }; 1217*6bc4a568SLee Jones 1218d28f1db8SLee Jones static int __devinit ab8500_probe(struct platform_device *pdev) 121962579266SRabin Vincent { 1220d28f1db8SLee Jones struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev); 1221d28f1db8SLee Jones const struct platform_device_id *platid = platform_get_device_id(pdev); 1222*6bc4a568SLee Jones enum ab8500_version version = AB8500_VERSION_UNDEFINED; 1223*6bc4a568SLee Jones struct device_node *np = pdev->dev.of_node; 1224d28f1db8SLee Jones struct ab8500 *ab8500; 1225d28f1db8SLee Jones struct resource *resource; 122662579266SRabin Vincent int ret; 122762579266SRabin Vincent int i; 122847c16975SMattias Wallin u8 value; 122962579266SRabin Vincent 1230d28f1db8SLee Jones ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL); 1231d28f1db8SLee Jones if (!ab8500) 1232d28f1db8SLee Jones return -ENOMEM; 1233d28f1db8SLee Jones 123462579266SRabin Vincent if (plat) 123562579266SRabin Vincent ab8500->irq_base = plat->irq_base; 1236*6bc4a568SLee Jones else if (np) 1237*6bc4a568SLee Jones ret = of_property_read_u32(np, "stericsson,irq-base", &ab8500->irq_base); 1238*6bc4a568SLee Jones 1239*6bc4a568SLee Jones if (!ab8500->irq_base) { 1240*6bc4a568SLee Jones dev_info(&pdev->dev, "couldn't find irq-base\n"); 1241*6bc4a568SLee Jones ret = -EINVAL; 1242*6bc4a568SLee Jones goto out_free_ab8500; 1243*6bc4a568SLee Jones } 124462579266SRabin Vincent 1245d28f1db8SLee Jones ab8500->dev = &pdev->dev; 1246d28f1db8SLee Jones 1247d28f1db8SLee Jones resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 1248d28f1db8SLee Jones if (!resource) { 1249d28f1db8SLee Jones ret = -ENODEV; 1250d28f1db8SLee Jones goto out_free_ab8500; 1251d28f1db8SLee Jones } 1252d28f1db8SLee Jones 1253d28f1db8SLee Jones ab8500->irq = resource->start; 1254d28f1db8SLee Jones 1255d28f1db8SLee Jones ab8500->read = ab8500_i2c_read; 1256d28f1db8SLee Jones ab8500->write = ab8500_i2c_write; 1257d28f1db8SLee Jones ab8500->write_masked = ab8500_i2c_write_masked; 1258d28f1db8SLee Jones 125962579266SRabin Vincent mutex_init(&ab8500->lock); 126062579266SRabin Vincent mutex_init(&ab8500->irq_lock); 1261112a80d2SJonas Aaberg atomic_set(&ab8500->transfer_ongoing, 0); 126262579266SRabin Vincent 1263d28f1db8SLee Jones platform_set_drvdata(pdev, ab8500); 1264d28f1db8SLee Jones 1265*6bc4a568SLee Jones if (platid) 1266*6bc4a568SLee Jones version = platid->driver_data; 1267*6bc4a568SLee Jones else if (np) 1268*6bc4a568SLee Jones version = (unsigned int) 1269*6bc4a568SLee Jones of_match_device(ab8500_match, &pdev->dev)->data; 1270*6bc4a568SLee Jones 12710f620837SLinus Walleij if (version != AB8500_VERSION_UNDEFINED) 12720f620837SLinus Walleij ab8500->version = version; 12730f620837SLinus Walleij else { 12740f620837SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_MISC, 12750f620837SLinus Walleij AB8500_IC_NAME_REG, &value); 12760f620837SLinus Walleij if (ret < 0) 1277d28f1db8SLee Jones goto out_free_ab8500; 12780f620837SLinus Walleij 12790f620837SLinus Walleij ab8500->version = value; 12800f620837SLinus Walleij } 12810f620837SLinus Walleij 128247c16975SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_MISC, 128347c16975SMattias Wallin AB8500_REV_REG, &value); 128462579266SRabin Vincent if (ret < 0) 1285d28f1db8SLee Jones goto out_free_ab8500; 128662579266SRabin Vincent 128747c16975SMattias Wallin ab8500->chip_id = value; 128862579266SRabin Vincent 12890f620837SLinus Walleij dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n", 12900f620837SLinus Walleij ab8500_version_str[ab8500->version], 12910f620837SLinus Walleij ab8500->chip_id >> 4, 12920f620837SLinus Walleij ab8500->chip_id & 0x0F); 12930f620837SLinus Walleij 1294d6255529SLinus Walleij /* Configure AB8500 or AB9540 IRQ */ 1295a982362cSBengt Jonsson if (is_ab9540(ab8500) || is_ab8505(ab8500)) { 1296d6255529SLinus Walleij ab8500->mask_size = AB9540_NUM_IRQ_REGS; 1297d6255529SLinus Walleij ab8500->irq_reg_offset = ab9540_irq_regoffset; 1298d6255529SLinus Walleij } else { 12992ced445eSLinus Walleij ab8500->mask_size = AB8500_NUM_IRQ_REGS; 13002ced445eSLinus Walleij ab8500->irq_reg_offset = ab8500_irq_regoffset; 1301d6255529SLinus Walleij } 13022ced445eSLinus Walleij ab8500->mask = kzalloc(ab8500->mask_size, GFP_KERNEL); 13032ced445eSLinus Walleij if (!ab8500->mask) 13042ced445eSLinus Walleij return -ENOMEM; 13052ced445eSLinus Walleij ab8500->oldmask = kzalloc(ab8500->mask_size, GFP_KERNEL); 13062ced445eSLinus Walleij if (!ab8500->oldmask) { 13072ced445eSLinus Walleij ret = -ENOMEM; 13082ced445eSLinus Walleij goto out_freemask; 13092ced445eSLinus Walleij } 1310e5c238c3SMattias Wallin /* 1311e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 1312e5c238c3SMattias Wallin * 0x01 Swoff bit programming 1313e5c238c3SMattias Wallin * 0x02 Thermal protection activation 1314e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 1315e5c238c3SMattias Wallin * 0x08 Watchdog expired 1316e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 1317e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 1318e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 1319e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 1320e5c238c3SMattias Wallin */ 1321e5c238c3SMattias Wallin 1322e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 1323e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 1324e5c238c3SMattias Wallin if (ret < 0) 1325e5c238c3SMattias Wallin return ret; 1326e5c238c3SMattias Wallin dev_info(ab8500->dev, "switch off status: %#x", value); 1327e5c238c3SMattias Wallin 132862579266SRabin Vincent if (plat && plat->init) 132962579266SRabin Vincent plat->init(ab8500); 133062579266SRabin Vincent 133162579266SRabin Vincent /* Clear and mask all interrupts */ 13322ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 13330f620837SLinus Walleij /* 13340f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 13350f620837SLinus Walleij * 2.0 13360f620837SLinus Walleij */ 13370f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 13380f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 133992d50a41SMattias Wallin continue; 134062579266SRabin Vincent 134147c16975SMattias Wallin get_register_interruptible(ab8500, AB8500_INTERRUPT, 13422ced445eSLinus Walleij AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i], 134392d50a41SMattias Wallin &value); 134447c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, 13452ced445eSLinus Walleij AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff); 134662579266SRabin Vincent } 134762579266SRabin Vincent 134847c16975SMattias Wallin ret = abx500_register_ops(ab8500->dev, &ab8500_ops); 134947c16975SMattias Wallin if (ret) 13502ced445eSLinus Walleij goto out_freeoldmask; 135147c16975SMattias Wallin 13522ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) 135362579266SRabin Vincent ab8500->mask[i] = ab8500->oldmask[i] = 0xff; 135462579266SRabin Vincent 135562579266SRabin Vincent if (ab8500->irq_base) { 135662579266SRabin Vincent ret = ab8500_irq_init(ab8500); 135762579266SRabin Vincent if (ret) 13582ced445eSLinus Walleij goto out_freeoldmask; 135962579266SRabin Vincent 13607ccfe9b1SMichel JAOUEN /* Activate this feature only in ab9540 */ 13617ccfe9b1SMichel JAOUEN /* till tests are done on ab8500 1p2 or later*/ 13627ccfe9b1SMichel JAOUEN if (is_ab9540(ab8500)) 13637ccfe9b1SMichel JAOUEN ret = request_threaded_irq(ab8500->irq, NULL, 13647ccfe9b1SMichel JAOUEN ab8500_hierarchical_irq, 13657ccfe9b1SMichel JAOUEN IRQF_ONESHOT | IRQF_NO_SUSPEND, 13667ccfe9b1SMichel JAOUEN "ab8500", ab8500); 13677ccfe9b1SMichel JAOUEN else 13687ccfe9b1SMichel JAOUEN ret = request_threaded_irq(ab8500->irq, NULL, 13697ccfe9b1SMichel JAOUEN ab8500_irq, 13704f079985SMattias Wallin IRQF_ONESHOT | IRQF_NO_SUSPEND, 13714f079985SMattias Wallin "ab8500", ab8500); 137262579266SRabin Vincent if (ret) 137362579266SRabin Vincent goto out_removeirq; 137462579266SRabin Vincent } 137562579266SRabin Vincent 1376*6bc4a568SLee Jones if (!np) { 1377d6255529SLinus Walleij ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs, 1378d6255529SLinus Walleij ARRAY_SIZE(abx500_common_devs), NULL, 1379d6255529SLinus Walleij ab8500->irq_base); 1380d6255529SLinus Walleij 1381d6255529SLinus Walleij if (ret) 1382d6255529SLinus Walleij goto out_freeirq; 1383d6255529SLinus Walleij 1384d6255529SLinus Walleij if (is_ab9540(ab8500)) 1385d6255529SLinus Walleij ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, 1386d6255529SLinus Walleij ARRAY_SIZE(ab9540_devs), NULL, 1387d6255529SLinus Walleij ab8500->irq_base); 1388d6255529SLinus Walleij else 1389549931f9SSundar R Iyer ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, 139044f72e53SVirupax Sadashivpetimath ARRAY_SIZE(ab8500_devs), NULL, 139162579266SRabin Vincent ab8500->irq_base); 1392*6bc4a568SLee Jones if (ret) 1393*6bc4a568SLee Jones goto out_freeirq; 139444f72e53SVirupax Sadashivpetimath 139544f72e53SVirupax Sadashivpetimath if (is_ab9540(ab8500) || is_ab8505(ab8500)) 139644f72e53SVirupax Sadashivpetimath ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs, 139744f72e53SVirupax Sadashivpetimath ARRAY_SIZE(ab9540_ab8505_devs), NULL, 139844f72e53SVirupax Sadashivpetimath ab8500->irq_base); 139962579266SRabin Vincent if (ret) 140062579266SRabin Vincent goto out_freeirq; 1401*6bc4a568SLee Jones } 140262579266SRabin Vincent 14036ef9418cSRickard Andersson if (!no_bm) { 14046ef9418cSRickard Andersson /* Add battery management devices */ 14056ef9418cSRickard Andersson ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, 14066ef9418cSRickard Andersson ARRAY_SIZE(ab8500_bm_devs), NULL, 14076ef9418cSRickard Andersson ab8500->irq_base); 14086ef9418cSRickard Andersson if (ret) 14096ef9418cSRickard Andersson dev_err(ab8500->dev, "error adding bm devices\n"); 14106ef9418cSRickard Andersson } 14116ef9418cSRickard Andersson 1412d6255529SLinus Walleij if (is_ab9540(ab8500)) 1413d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1414d6255529SLinus Walleij &ab9540_attr_group); 1415d6255529SLinus Walleij else 1416d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1417d6255529SLinus Walleij &ab8500_attr_group); 1418cca69b67SMattias Wallin if (ret) 1419cca69b67SMattias Wallin dev_err(ab8500->dev, "error creating sysfs entries\n"); 1420d6255529SLinus Walleij else 142162579266SRabin Vincent return ret; 142262579266SRabin Vincent 142362579266SRabin Vincent out_freeirq: 14246d95b7fdSLinus Walleij if (ab8500->irq_base) 142562579266SRabin Vincent free_irq(ab8500->irq, ab8500); 142662579266SRabin Vincent out_removeirq: 14276d95b7fdSLinus Walleij if (ab8500->irq_base) 142862579266SRabin Vincent ab8500_irq_remove(ab8500); 14292ced445eSLinus Walleij out_freeoldmask: 14302ced445eSLinus Walleij kfree(ab8500->oldmask); 14312ced445eSLinus Walleij out_freemask: 14322ced445eSLinus Walleij kfree(ab8500->mask); 1433d28f1db8SLee Jones out_free_ab8500: 1434d28f1db8SLee Jones kfree(ab8500); 14356d95b7fdSLinus Walleij 143662579266SRabin Vincent return ret; 143762579266SRabin Vincent } 143862579266SRabin Vincent 1439d28f1db8SLee Jones static int __devexit ab8500_remove(struct platform_device *pdev) 144062579266SRabin Vincent { 1441d28f1db8SLee Jones struct ab8500 *ab8500 = platform_get_drvdata(pdev); 1442d28f1db8SLee Jones 1443d6255529SLinus Walleij if (is_ab9540(ab8500)) 1444d6255529SLinus Walleij sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group); 1445d6255529SLinus Walleij else 1446cca69b67SMattias Wallin sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group); 144762579266SRabin Vincent mfd_remove_devices(ab8500->dev); 144862579266SRabin Vincent if (ab8500->irq_base) { 144962579266SRabin Vincent free_irq(ab8500->irq, ab8500); 145062579266SRabin Vincent ab8500_irq_remove(ab8500); 145162579266SRabin Vincent } 14522ced445eSLinus Walleij kfree(ab8500->oldmask); 14532ced445eSLinus Walleij kfree(ab8500->mask); 1454d28f1db8SLee Jones kfree(ab8500); 145562579266SRabin Vincent 145662579266SRabin Vincent return 0; 145762579266SRabin Vincent } 145862579266SRabin Vincent 1459d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = { 1460d28f1db8SLee Jones { "ab8500-core", AB8500_VERSION_AB8500 }, 1461d28f1db8SLee Jones { "ab8505-i2c", AB8500_VERSION_AB8505 }, 1462d28f1db8SLee Jones { "ab9540-i2c", AB8500_VERSION_AB9540 }, 1463d28f1db8SLee Jones { "ab8540-i2c", AB8500_VERSION_AB8540 }, 1464d28f1db8SLee Jones { } 1465d28f1db8SLee Jones }; 1466d28f1db8SLee Jones 1467d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = { 1468d28f1db8SLee Jones .driver = { 1469d28f1db8SLee Jones .name = "ab8500-core", 1470d28f1db8SLee Jones .owner = THIS_MODULE, 1471*6bc4a568SLee Jones .of_match_table = ab8500_match, 1472d28f1db8SLee Jones }, 1473d28f1db8SLee Jones .probe = ab8500_probe, 1474d28f1db8SLee Jones .remove = __devexit_p(ab8500_remove), 1475d28f1db8SLee Jones .id_table = ab8500_id, 1476d28f1db8SLee Jones }; 1477d28f1db8SLee Jones 1478d28f1db8SLee Jones static int __init ab8500_core_init(void) 1479d28f1db8SLee Jones { 1480d28f1db8SLee Jones return platform_driver_register(&ab8500_core_driver); 1481d28f1db8SLee Jones } 1482d28f1db8SLee Jones 1483d28f1db8SLee Jones static void __exit ab8500_core_exit(void) 1484d28f1db8SLee Jones { 1485d28f1db8SLee Jones platform_driver_unregister(&ab8500_core_driver); 1486d28f1db8SLee Jones } 1487d28f1db8SLee Jones arch_initcall(ab8500_core_init); 1488d28f1db8SLee Jones module_exit(ab8500_core_exit); 1489d28f1db8SLee Jones 1490adceed62SMattias Wallin MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent"); 149162579266SRabin Vincent MODULE_DESCRIPTION("AB8500 MFD core"); 149262579266SRabin Vincent MODULE_LICENSE("GPL v2"); 1493