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> 21*d28f1db8SLee Jones #include <linux/mfd/dbx500-prcmu.h> 22549931f9SSundar R Iyer #include <linux/regulator/ab8500.h> 2362579266SRabin Vincent 2462579266SRabin Vincent /* 2562579266SRabin Vincent * Interrupt register offsets 2662579266SRabin Vincent * Bank : 0x0E 2762579266SRabin Vincent */ 2847c16975SMattias Wallin #define AB8500_IT_SOURCE1_REG 0x00 2947c16975SMattias Wallin #define AB8500_IT_SOURCE2_REG 0x01 3047c16975SMattias Wallin #define AB8500_IT_SOURCE3_REG 0x02 3147c16975SMattias Wallin #define AB8500_IT_SOURCE4_REG 0x03 3247c16975SMattias Wallin #define AB8500_IT_SOURCE5_REG 0x04 3347c16975SMattias Wallin #define AB8500_IT_SOURCE6_REG 0x05 3447c16975SMattias Wallin #define AB8500_IT_SOURCE7_REG 0x06 3547c16975SMattias Wallin #define AB8500_IT_SOURCE8_REG 0x07 36d6255529SLinus Walleij #define AB9540_IT_SOURCE13_REG 0x0C 3747c16975SMattias Wallin #define AB8500_IT_SOURCE19_REG 0x12 3847c16975SMattias Wallin #define AB8500_IT_SOURCE20_REG 0x13 3947c16975SMattias Wallin #define AB8500_IT_SOURCE21_REG 0x14 4047c16975SMattias Wallin #define AB8500_IT_SOURCE22_REG 0x15 4147c16975SMattias Wallin #define AB8500_IT_SOURCE23_REG 0x16 4247c16975SMattias Wallin #define AB8500_IT_SOURCE24_REG 0x17 4362579266SRabin Vincent 4462579266SRabin Vincent /* 4562579266SRabin Vincent * latch registers 4662579266SRabin Vincent */ 4747c16975SMattias Wallin #define AB8500_IT_LATCH1_REG 0x20 4847c16975SMattias Wallin #define AB8500_IT_LATCH2_REG 0x21 4947c16975SMattias Wallin #define AB8500_IT_LATCH3_REG 0x22 5047c16975SMattias Wallin #define AB8500_IT_LATCH4_REG 0x23 5147c16975SMattias Wallin #define AB8500_IT_LATCH5_REG 0x24 5247c16975SMattias Wallin #define AB8500_IT_LATCH6_REG 0x25 5347c16975SMattias Wallin #define AB8500_IT_LATCH7_REG 0x26 5447c16975SMattias Wallin #define AB8500_IT_LATCH8_REG 0x27 5547c16975SMattias Wallin #define AB8500_IT_LATCH9_REG 0x28 5647c16975SMattias Wallin #define AB8500_IT_LATCH10_REG 0x29 5792d50a41SMattias Wallin #define AB8500_IT_LATCH12_REG 0x2B 58d6255529SLinus Walleij #define AB9540_IT_LATCH13_REG 0x2C 5947c16975SMattias Wallin #define AB8500_IT_LATCH19_REG 0x32 6047c16975SMattias Wallin #define AB8500_IT_LATCH20_REG 0x33 6147c16975SMattias Wallin #define AB8500_IT_LATCH21_REG 0x34 6247c16975SMattias Wallin #define AB8500_IT_LATCH22_REG 0x35 6347c16975SMattias Wallin #define AB8500_IT_LATCH23_REG 0x36 6447c16975SMattias Wallin #define AB8500_IT_LATCH24_REG 0x37 6562579266SRabin Vincent 6662579266SRabin Vincent /* 6762579266SRabin Vincent * mask registers 6862579266SRabin Vincent */ 6962579266SRabin Vincent 7047c16975SMattias Wallin #define AB8500_IT_MASK1_REG 0x40 7147c16975SMattias Wallin #define AB8500_IT_MASK2_REG 0x41 7247c16975SMattias Wallin #define AB8500_IT_MASK3_REG 0x42 7347c16975SMattias Wallin #define AB8500_IT_MASK4_REG 0x43 7447c16975SMattias Wallin #define AB8500_IT_MASK5_REG 0x44 7547c16975SMattias Wallin #define AB8500_IT_MASK6_REG 0x45 7647c16975SMattias Wallin #define AB8500_IT_MASK7_REG 0x46 7747c16975SMattias Wallin #define AB8500_IT_MASK8_REG 0x47 7847c16975SMattias Wallin #define AB8500_IT_MASK9_REG 0x48 7947c16975SMattias Wallin #define AB8500_IT_MASK10_REG 0x49 8047c16975SMattias Wallin #define AB8500_IT_MASK11_REG 0x4A 8147c16975SMattias Wallin #define AB8500_IT_MASK12_REG 0x4B 8247c16975SMattias Wallin #define AB8500_IT_MASK13_REG 0x4C 8347c16975SMattias Wallin #define AB8500_IT_MASK14_REG 0x4D 8447c16975SMattias Wallin #define AB8500_IT_MASK15_REG 0x4E 8547c16975SMattias Wallin #define AB8500_IT_MASK16_REG 0x4F 8647c16975SMattias Wallin #define AB8500_IT_MASK17_REG 0x50 8747c16975SMattias Wallin #define AB8500_IT_MASK18_REG 0x51 8847c16975SMattias Wallin #define AB8500_IT_MASK19_REG 0x52 8947c16975SMattias Wallin #define AB8500_IT_MASK20_REG 0x53 9047c16975SMattias Wallin #define AB8500_IT_MASK21_REG 0x54 9147c16975SMattias Wallin #define AB8500_IT_MASK22_REG 0x55 9247c16975SMattias Wallin #define AB8500_IT_MASK23_REG 0x56 9347c16975SMattias Wallin #define AB8500_IT_MASK24_REG 0x57 9462579266SRabin Vincent 957ccfe9b1SMichel JAOUEN /* 967ccfe9b1SMichel JAOUEN * latch hierarchy registers 977ccfe9b1SMichel JAOUEN */ 987ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER1_REG 0x60 997ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER2_REG 0x61 1007ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER3_REG 0x62 1017ccfe9b1SMichel JAOUEN 1027ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER_NUM 3 1037ccfe9b1SMichel JAOUEN 10447c16975SMattias Wallin #define AB8500_REV_REG 0x80 1050f620837SLinus Walleij #define AB8500_IC_NAME_REG 0x82 106e5c238c3SMattias Wallin #define AB8500_SWITCH_OFF_STATUS 0x00 10762579266SRabin Vincent 108b4a31037SAndrew Lynn #define AB8500_TURN_ON_STATUS 0x00 109b4a31037SAndrew Lynn 1106ef9418cSRickard Andersson static bool no_bm; /* No battery management */ 1116ef9418cSRickard Andersson module_param(no_bm, bool, S_IRUGO); 1126ef9418cSRickard Andersson 113d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_REG 0x23 114d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2) 115d6255529SLinus Walleij 11662579266SRabin Vincent /* 11762579266SRabin Vincent * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt 1182ced445eSLinus Walleij * numbers are indexed into this array with (num / 8). The interupts are 1192ced445eSLinus Walleij * defined in linux/mfd/ab8500.h 12062579266SRabin Vincent * 12162579266SRabin Vincent * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at 12262579266SRabin Vincent * offset 0. 12362579266SRabin Vincent */ 1242ced445eSLinus Walleij /* AB8500 support */ 12562579266SRabin Vincent static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { 12692d50a41SMattias Wallin 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12762579266SRabin Vincent }; 12862579266SRabin Vincent 129d6255529SLinus Walleij /* AB9540 support */ 130d6255529SLinus Walleij static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = { 131d6255529SLinus Walleij 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 132d6255529SLinus Walleij }; 133d6255529SLinus Walleij 1340f620837SLinus Walleij static const char ab8500_version_str[][7] = { 1350f620837SLinus Walleij [AB8500_VERSION_AB8500] = "AB8500", 1360f620837SLinus Walleij [AB8500_VERSION_AB8505] = "AB8505", 1370f620837SLinus Walleij [AB8500_VERSION_AB9540] = "AB9540", 1380f620837SLinus Walleij [AB8500_VERSION_AB8540] = "AB8540", 1390f620837SLinus Walleij }; 1400f620837SLinus Walleij 141*d28f1db8SLee Jones static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data) 142*d28f1db8SLee Jones { 143*d28f1db8SLee Jones int ret; 144*d28f1db8SLee Jones 145*d28f1db8SLee Jones ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 146*d28f1db8SLee Jones if (ret < 0) 147*d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 148*d28f1db8SLee Jones return ret; 149*d28f1db8SLee Jones } 150*d28f1db8SLee Jones 151*d28f1db8SLee Jones static int ab8500_i2c_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask, 152*d28f1db8SLee Jones u8 data) 153*d28f1db8SLee Jones { 154*d28f1db8SLee Jones int ret; 155*d28f1db8SLee Jones 156*d28f1db8SLee Jones ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 157*d28f1db8SLee Jones &mask, 1); 158*d28f1db8SLee Jones if (ret < 0) 159*d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 160*d28f1db8SLee Jones return ret; 161*d28f1db8SLee Jones } 162*d28f1db8SLee Jones 163*d28f1db8SLee Jones static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr) 164*d28f1db8SLee Jones { 165*d28f1db8SLee Jones int ret; 166*d28f1db8SLee Jones u8 data; 167*d28f1db8SLee Jones 168*d28f1db8SLee Jones ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 169*d28f1db8SLee Jones if (ret < 0) { 170*d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 171*d28f1db8SLee Jones return ret; 172*d28f1db8SLee Jones } 173*d28f1db8SLee Jones return (int)data; 174*d28f1db8SLee Jones } 175*d28f1db8SLee Jones 17647c16975SMattias Wallin static int ab8500_get_chip_id(struct device *dev) 17747c16975SMattias Wallin { 1786bce7bf1SMattias Wallin struct ab8500 *ab8500; 1796bce7bf1SMattias Wallin 1806bce7bf1SMattias Wallin if (!dev) 1816bce7bf1SMattias Wallin return -EINVAL; 1826bce7bf1SMattias Wallin ab8500 = dev_get_drvdata(dev->parent); 1836bce7bf1SMattias Wallin return ab8500 ? (int)ab8500->chip_id : -EINVAL; 18447c16975SMattias Wallin } 18547c16975SMattias Wallin 18647c16975SMattias Wallin static int set_register_interruptible(struct ab8500 *ab8500, u8 bank, 18747c16975SMattias Wallin u8 reg, u8 data) 18862579266SRabin Vincent { 18962579266SRabin Vincent int ret; 19047c16975SMattias Wallin /* 19147c16975SMattias Wallin * Put the u8 bank and u8 register together into a an u16. 19247c16975SMattias Wallin * The bank on higher 8 bits and register in lower 8 bits. 19347c16975SMattias Wallin * */ 19447c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 19562579266SRabin Vincent 19662579266SRabin Vincent dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data); 19762579266SRabin Vincent 198392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 19947c16975SMattias Wallin 20047c16975SMattias Wallin ret = ab8500->write(ab8500, addr, data); 20147c16975SMattias Wallin if (ret < 0) 20247c16975SMattias Wallin dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 20347c16975SMattias Wallin addr, ret); 20447c16975SMattias Wallin mutex_unlock(&ab8500->lock); 20547c16975SMattias Wallin 20647c16975SMattias Wallin return ret; 20747c16975SMattias Wallin } 20847c16975SMattias Wallin 20947c16975SMattias Wallin static int ab8500_set_register(struct device *dev, u8 bank, 21047c16975SMattias Wallin u8 reg, u8 value) 21147c16975SMattias Wallin { 212112a80d2SJonas Aaberg int ret; 21347c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 21447c16975SMattias Wallin 215112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 216112a80d2SJonas Aaberg ret = set_register_interruptible(ab8500, bank, reg, value); 217112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 218112a80d2SJonas Aaberg return ret; 21947c16975SMattias Wallin } 22047c16975SMattias Wallin 22147c16975SMattias Wallin static int get_register_interruptible(struct ab8500 *ab8500, u8 bank, 22247c16975SMattias Wallin u8 reg, u8 *value) 22347c16975SMattias Wallin { 22447c16975SMattias Wallin int ret; 22547c16975SMattias Wallin /* put the u8 bank and u8 reg together into a an u16. 22647c16975SMattias Wallin * bank on higher 8 bits and reg in lower */ 22747c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 22847c16975SMattias Wallin 229392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 23047c16975SMattias Wallin 23147c16975SMattias Wallin ret = ab8500->read(ab8500, addr); 23247c16975SMattias Wallin if (ret < 0) 23347c16975SMattias Wallin dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 23447c16975SMattias Wallin addr, ret); 23547c16975SMattias Wallin else 23647c16975SMattias Wallin *value = ret; 23747c16975SMattias Wallin 23847c16975SMattias Wallin mutex_unlock(&ab8500->lock); 23947c16975SMattias Wallin dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret); 24047c16975SMattias Wallin 24147c16975SMattias Wallin return ret; 24247c16975SMattias Wallin } 24347c16975SMattias Wallin 24447c16975SMattias Wallin static int ab8500_get_register(struct device *dev, u8 bank, 24547c16975SMattias Wallin u8 reg, u8 *value) 24647c16975SMattias Wallin { 247112a80d2SJonas Aaberg int ret; 24847c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 24947c16975SMattias Wallin 250112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 251112a80d2SJonas Aaberg ret = get_register_interruptible(ab8500, bank, reg, value); 252112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 253112a80d2SJonas Aaberg return ret; 25447c16975SMattias Wallin } 25547c16975SMattias Wallin 25647c16975SMattias Wallin static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank, 25747c16975SMattias Wallin u8 reg, u8 bitmask, u8 bitvalues) 25847c16975SMattias Wallin { 25947c16975SMattias Wallin int ret; 26047c16975SMattias Wallin /* put the u8 bank and u8 reg together into a an u16. 26147c16975SMattias Wallin * bank on higher 8 bits and reg in lower */ 26247c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 26347c16975SMattias Wallin 264392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 26547c16975SMattias Wallin 266bc628fd1SMattias Nilsson if (ab8500->write_masked == NULL) { 267bc628fd1SMattias Nilsson u8 data; 268bc628fd1SMattias Nilsson 26947c16975SMattias Wallin ret = ab8500->read(ab8500, addr); 27047c16975SMattias Wallin if (ret < 0) { 27147c16975SMattias Wallin dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 27247c16975SMattias Wallin addr, ret); 27347c16975SMattias Wallin goto out; 27447c16975SMattias Wallin } 27547c16975SMattias Wallin 27647c16975SMattias Wallin data = (u8)ret; 27747c16975SMattias Wallin data = (~bitmask & data) | (bitmask & bitvalues); 27847c16975SMattias Wallin 27962579266SRabin Vincent ret = ab8500->write(ab8500, addr, data); 28062579266SRabin Vincent if (ret < 0) 28162579266SRabin Vincent dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 28262579266SRabin Vincent addr, ret); 28362579266SRabin Vincent 284bc628fd1SMattias Nilsson dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, 285bc628fd1SMattias Nilsson data); 286bc628fd1SMattias Nilsson goto out; 287bc628fd1SMattias Nilsson } 288bc628fd1SMattias Nilsson ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues); 289bc628fd1SMattias Nilsson if (ret < 0) 290bc628fd1SMattias Nilsson dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr, 291bc628fd1SMattias Nilsson ret); 29262579266SRabin Vincent out: 29362579266SRabin Vincent mutex_unlock(&ab8500->lock); 29462579266SRabin Vincent return ret; 29562579266SRabin Vincent } 29647c16975SMattias Wallin 29747c16975SMattias Wallin static int ab8500_mask_and_set_register(struct device *dev, 29847c16975SMattias Wallin u8 bank, u8 reg, u8 bitmask, u8 bitvalues) 29947c16975SMattias Wallin { 300112a80d2SJonas Aaberg int ret; 30147c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 30247c16975SMattias Wallin 303112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 304112a80d2SJonas Aaberg ret= mask_and_set_register_interruptible(ab8500, bank, reg, 30547c16975SMattias Wallin bitmask, bitvalues); 306112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 307112a80d2SJonas Aaberg return ret; 30847c16975SMattias Wallin } 30947c16975SMattias Wallin 31047c16975SMattias Wallin static struct abx500_ops ab8500_ops = { 31147c16975SMattias Wallin .get_chip_id = ab8500_get_chip_id, 31247c16975SMattias Wallin .get_register = ab8500_get_register, 31347c16975SMattias Wallin .set_register = ab8500_set_register, 31447c16975SMattias Wallin .get_register_page = NULL, 31547c16975SMattias Wallin .set_register_page = NULL, 31647c16975SMattias Wallin .mask_and_set_register = ab8500_mask_and_set_register, 31747c16975SMattias Wallin .event_registers_startup_state_get = NULL, 31847c16975SMattias Wallin .startup_irq_enabled = NULL, 31947c16975SMattias Wallin }; 32062579266SRabin Vincent 3219505a0a0SMark Brown static void ab8500_irq_lock(struct irq_data *data) 32262579266SRabin Vincent { 3239505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 32462579266SRabin Vincent 32562579266SRabin Vincent mutex_lock(&ab8500->irq_lock); 326112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 32762579266SRabin Vincent } 32862579266SRabin Vincent 3299505a0a0SMark Brown static void ab8500_irq_sync_unlock(struct irq_data *data) 33062579266SRabin Vincent { 3319505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 33262579266SRabin Vincent int i; 33362579266SRabin Vincent 3342ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 33562579266SRabin Vincent u8 old = ab8500->oldmask[i]; 33662579266SRabin Vincent u8 new = ab8500->mask[i]; 33762579266SRabin Vincent int reg; 33862579266SRabin Vincent 33962579266SRabin Vincent if (new == old) 34062579266SRabin Vincent continue; 34162579266SRabin Vincent 3420f620837SLinus Walleij /* 3430f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 3440f620837SLinus Walleij * 2.0 3450f620837SLinus Walleij */ 3460f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 3470f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 34892d50a41SMattias Wallin continue; 34992d50a41SMattias Wallin 35062579266SRabin Vincent ab8500->oldmask[i] = new; 35162579266SRabin Vincent 3522ced445eSLinus Walleij reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i]; 35347c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new); 35462579266SRabin Vincent } 355112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 35662579266SRabin Vincent mutex_unlock(&ab8500->irq_lock); 35762579266SRabin Vincent } 35862579266SRabin Vincent 3599505a0a0SMark Brown static void ab8500_irq_mask(struct irq_data *data) 36062579266SRabin Vincent { 3619505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 3629505a0a0SMark Brown int offset = data->irq - ab8500->irq_base; 36362579266SRabin Vincent int index = offset / 8; 36462579266SRabin Vincent int mask = 1 << (offset % 8); 36562579266SRabin Vincent 36662579266SRabin Vincent ab8500->mask[index] |= mask; 36762579266SRabin Vincent } 36862579266SRabin Vincent 3699505a0a0SMark Brown static void ab8500_irq_unmask(struct irq_data *data) 37062579266SRabin Vincent { 3719505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 3729505a0a0SMark Brown int offset = data->irq - ab8500->irq_base; 37362579266SRabin Vincent int index = offset / 8; 37462579266SRabin Vincent int mask = 1 << (offset % 8); 37562579266SRabin Vincent 37662579266SRabin Vincent ab8500->mask[index] &= ~mask; 37762579266SRabin Vincent } 37862579266SRabin Vincent 37962579266SRabin Vincent static struct irq_chip ab8500_irq_chip = { 38062579266SRabin Vincent .name = "ab8500", 3819505a0a0SMark Brown .irq_bus_lock = ab8500_irq_lock, 3829505a0a0SMark Brown .irq_bus_sync_unlock = ab8500_irq_sync_unlock, 3839505a0a0SMark Brown .irq_mask = ab8500_irq_mask, 384e6f9306eSVirupax Sadashivpetimath .irq_disable = ab8500_irq_mask, 3859505a0a0SMark Brown .irq_unmask = ab8500_irq_unmask, 38662579266SRabin Vincent }; 38762579266SRabin Vincent 3887ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, 3897ccfe9b1SMichel JAOUEN int latch_offset, u8 latch_val) 3907ccfe9b1SMichel JAOUEN { 3917ccfe9b1SMichel JAOUEN int int_bit = __ffs(latch_val); 3927ccfe9b1SMichel JAOUEN int line, i; 3937ccfe9b1SMichel JAOUEN 3947ccfe9b1SMichel JAOUEN do { 3957ccfe9b1SMichel JAOUEN int_bit = __ffs(latch_val); 3967ccfe9b1SMichel JAOUEN 3977ccfe9b1SMichel JAOUEN for (i = 0; i < ab8500->mask_size; i++) 3987ccfe9b1SMichel JAOUEN if (ab8500->irq_reg_offset[i] == latch_offset) 3997ccfe9b1SMichel JAOUEN break; 4007ccfe9b1SMichel JAOUEN 4017ccfe9b1SMichel JAOUEN if (i >= ab8500->mask_size) { 4027ccfe9b1SMichel JAOUEN dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", 4037ccfe9b1SMichel JAOUEN latch_offset); 4047ccfe9b1SMichel JAOUEN return -ENXIO; 4057ccfe9b1SMichel JAOUEN } 4067ccfe9b1SMichel JAOUEN 4077ccfe9b1SMichel JAOUEN line = (i << 3) + int_bit; 4087ccfe9b1SMichel JAOUEN latch_val &= ~(1 << int_bit); 4097ccfe9b1SMichel JAOUEN 4107ccfe9b1SMichel JAOUEN handle_nested_irq(ab8500->irq_base + line); 4117ccfe9b1SMichel JAOUEN } while (latch_val); 4127ccfe9b1SMichel JAOUEN 4137ccfe9b1SMichel JAOUEN return 0; 4147ccfe9b1SMichel JAOUEN } 4157ccfe9b1SMichel JAOUEN 4167ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500, 4177ccfe9b1SMichel JAOUEN int hier_offset, u8 hier_val) 4187ccfe9b1SMichel JAOUEN { 4197ccfe9b1SMichel JAOUEN int latch_bit, status; 4207ccfe9b1SMichel JAOUEN u8 latch_offset, latch_val; 4217ccfe9b1SMichel JAOUEN 4227ccfe9b1SMichel JAOUEN do { 4237ccfe9b1SMichel JAOUEN latch_bit = __ffs(hier_val); 4247ccfe9b1SMichel JAOUEN latch_offset = (hier_offset << 3) + latch_bit; 4257ccfe9b1SMichel JAOUEN 4267ccfe9b1SMichel JAOUEN /* Fix inconsistent ITFromLatch25 bit mapping... */ 4277ccfe9b1SMichel JAOUEN if (unlikely(latch_offset == 17)) 4287ccfe9b1SMichel JAOUEN latch_offset = 24; 4297ccfe9b1SMichel JAOUEN 4307ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, 4317ccfe9b1SMichel JAOUEN AB8500_INTERRUPT, 4327ccfe9b1SMichel JAOUEN AB8500_IT_LATCH1_REG + latch_offset, 4337ccfe9b1SMichel JAOUEN &latch_val); 4347ccfe9b1SMichel JAOUEN if (status < 0 || latch_val == 0) 4357ccfe9b1SMichel JAOUEN goto discard; 4367ccfe9b1SMichel JAOUEN 4377ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_line(ab8500, 4387ccfe9b1SMichel JAOUEN latch_offset, latch_val); 4397ccfe9b1SMichel JAOUEN if (status < 0) 4407ccfe9b1SMichel JAOUEN return status; 4417ccfe9b1SMichel JAOUEN discard: 4427ccfe9b1SMichel JAOUEN hier_val &= ~(1 << latch_bit); 4437ccfe9b1SMichel JAOUEN } while (hier_val); 4447ccfe9b1SMichel JAOUEN 4457ccfe9b1SMichel JAOUEN return 0; 4467ccfe9b1SMichel JAOUEN } 4477ccfe9b1SMichel JAOUEN 4487ccfe9b1SMichel JAOUEN static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev) 4497ccfe9b1SMichel JAOUEN { 4507ccfe9b1SMichel JAOUEN struct ab8500 *ab8500 = dev; 4517ccfe9b1SMichel JAOUEN u8 i; 4527ccfe9b1SMichel JAOUEN 4537ccfe9b1SMichel JAOUEN dev_vdbg(ab8500->dev, "interrupt\n"); 4547ccfe9b1SMichel JAOUEN 4557ccfe9b1SMichel JAOUEN /* Hierarchical interrupt version */ 4567ccfe9b1SMichel JAOUEN for (i = 0; i < AB8500_IT_LATCHHIER_NUM; i++) { 4577ccfe9b1SMichel JAOUEN int status; 4587ccfe9b1SMichel JAOUEN u8 hier_val; 4597ccfe9b1SMichel JAOUEN 4607ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, AB8500_INTERRUPT, 4617ccfe9b1SMichel JAOUEN AB8500_IT_LATCHHIER1_REG + i, &hier_val); 4627ccfe9b1SMichel JAOUEN if (status < 0 || hier_val == 0) 4637ccfe9b1SMichel JAOUEN continue; 4647ccfe9b1SMichel JAOUEN 4657ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val); 4667ccfe9b1SMichel JAOUEN if (status < 0) 4677ccfe9b1SMichel JAOUEN break; 4687ccfe9b1SMichel JAOUEN } 4697ccfe9b1SMichel JAOUEN return IRQ_HANDLED; 4707ccfe9b1SMichel JAOUEN } 4717ccfe9b1SMichel JAOUEN 47262579266SRabin Vincent static irqreturn_t ab8500_irq(int irq, void *dev) 47362579266SRabin Vincent { 47462579266SRabin Vincent struct ab8500 *ab8500 = dev; 47562579266SRabin Vincent int i; 47662579266SRabin Vincent 47762579266SRabin Vincent dev_vdbg(ab8500->dev, "interrupt\n"); 47862579266SRabin Vincent 479112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 480112a80d2SJonas Aaberg 4812ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 4822ced445eSLinus Walleij int regoffset = ab8500->irq_reg_offset[i]; 48362579266SRabin Vincent int status; 48447c16975SMattias Wallin u8 value; 48562579266SRabin Vincent 4860f620837SLinus Walleij /* 4870f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 4880f620837SLinus Walleij * 2.0 4890f620837SLinus Walleij */ 4900f620837SLinus Walleij if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500)) 49192d50a41SMattias Wallin continue; 49292d50a41SMattias Wallin 49347c16975SMattias Wallin status = get_register_interruptible(ab8500, AB8500_INTERRUPT, 49447c16975SMattias Wallin AB8500_IT_LATCH1_REG + regoffset, &value); 49547c16975SMattias Wallin if (status < 0 || value == 0) 49662579266SRabin Vincent continue; 49762579266SRabin Vincent 49862579266SRabin Vincent do { 49988aec4f7SMattias Wallin int bit = __ffs(value); 50062579266SRabin Vincent int line = i * 8 + bit; 50162579266SRabin Vincent 50262579266SRabin Vincent handle_nested_irq(ab8500->irq_base + line); 50347c16975SMattias Wallin value &= ~(1 << bit); 504112a80d2SJonas Aaberg 50547c16975SMattias Wallin } while (value); 50662579266SRabin Vincent } 507112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 50862579266SRabin Vincent return IRQ_HANDLED; 50962579266SRabin Vincent } 51062579266SRabin Vincent 51162579266SRabin Vincent static int ab8500_irq_init(struct ab8500 *ab8500) 51262579266SRabin Vincent { 51362579266SRabin Vincent int base = ab8500->irq_base; 51462579266SRabin Vincent int irq; 5152ced445eSLinus Walleij int num_irqs; 51662579266SRabin Vincent 517d6255529SLinus Walleij if (is_ab9540(ab8500)) 518d6255529SLinus Walleij num_irqs = AB9540_NR_IRQS; 519a982362cSBengt Jonsson else if (is_ab8505(ab8500)) 520a982362cSBengt Jonsson num_irqs = AB8505_NR_IRQS; 521d6255529SLinus Walleij else 5222ced445eSLinus Walleij num_irqs = AB8500_NR_IRQS; 5232ced445eSLinus Walleij 5242ced445eSLinus Walleij for (irq = base; irq < base + num_irqs; irq++) { 525d5bb1221SThomas Gleixner irq_set_chip_data(irq, ab8500); 526d5bb1221SThomas Gleixner irq_set_chip_and_handler(irq, &ab8500_irq_chip, 52762579266SRabin Vincent handle_simple_irq); 528d5bb1221SThomas Gleixner irq_set_nested_thread(irq, 1); 52962579266SRabin Vincent #ifdef CONFIG_ARM 53062579266SRabin Vincent set_irq_flags(irq, IRQF_VALID); 53162579266SRabin Vincent #else 532d5bb1221SThomas Gleixner irq_set_noprobe(irq); 53362579266SRabin Vincent #endif 53462579266SRabin Vincent } 53562579266SRabin Vincent 53662579266SRabin Vincent return 0; 53762579266SRabin Vincent } 53862579266SRabin Vincent 53962579266SRabin Vincent static void ab8500_irq_remove(struct ab8500 *ab8500) 54062579266SRabin Vincent { 54162579266SRabin Vincent int base = ab8500->irq_base; 54262579266SRabin Vincent int irq; 5432ced445eSLinus Walleij int num_irqs; 54462579266SRabin Vincent 545d6255529SLinus Walleij if (is_ab9540(ab8500)) 546d6255529SLinus Walleij num_irqs = AB9540_NR_IRQS; 547a982362cSBengt Jonsson else if (is_ab8505(ab8500)) 548a982362cSBengt Jonsson num_irqs = AB8505_NR_IRQS; 549d6255529SLinus Walleij else 5502ced445eSLinus Walleij num_irqs = AB8500_NR_IRQS; 5512ced445eSLinus Walleij 5522ced445eSLinus Walleij for (irq = base; irq < base + num_irqs; irq++) { 55362579266SRabin Vincent #ifdef CONFIG_ARM 55462579266SRabin Vincent set_irq_flags(irq, 0); 55562579266SRabin Vincent #endif 556d5bb1221SThomas Gleixner irq_set_chip_and_handler(irq, NULL, NULL); 557d5bb1221SThomas Gleixner irq_set_chip_data(irq, NULL); 55862579266SRabin Vincent } 55962579266SRabin Vincent } 56062579266SRabin Vincent 561112a80d2SJonas Aaberg int ab8500_suspend(struct ab8500 *ab8500) 562112a80d2SJonas Aaberg { 563112a80d2SJonas Aaberg if (atomic_read(&ab8500->transfer_ongoing)) 564112a80d2SJonas Aaberg return -EINVAL; 565112a80d2SJonas Aaberg else 566112a80d2SJonas Aaberg return 0; 567112a80d2SJonas Aaberg } 568112a80d2SJonas Aaberg 569d6255529SLinus Walleij /* AB8500 GPIO Resources */ 5705cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_gpio_resources[] = { 5710cb3fcd7SBibek Basu { 5720cb3fcd7SBibek Basu .name = "GPIO_INT6", 5730cb3fcd7SBibek Basu .start = AB8500_INT_GPIO6R, 5740cb3fcd7SBibek Basu .end = AB8500_INT_GPIO41F, 5750cb3fcd7SBibek Basu .flags = IORESOURCE_IRQ, 5760cb3fcd7SBibek Basu } 5770cb3fcd7SBibek Basu }; 5780cb3fcd7SBibek Basu 579d6255529SLinus Walleij /* AB9540 GPIO Resources */ 580d6255529SLinus Walleij static struct resource __devinitdata ab9540_gpio_resources[] = { 581d6255529SLinus Walleij { 582d6255529SLinus Walleij .name = "GPIO_INT6", 583d6255529SLinus Walleij .start = AB8500_INT_GPIO6R, 584d6255529SLinus Walleij .end = AB8500_INT_GPIO41F, 585d6255529SLinus Walleij .flags = IORESOURCE_IRQ, 586d6255529SLinus Walleij }, 587d6255529SLinus Walleij { 588d6255529SLinus Walleij .name = "GPIO_INT14", 589d6255529SLinus Walleij .start = AB9540_INT_GPIO50R, 590d6255529SLinus Walleij .end = AB9540_INT_GPIO54R, 591d6255529SLinus Walleij .flags = IORESOURCE_IRQ, 592d6255529SLinus Walleij }, 593d6255529SLinus Walleij { 594d6255529SLinus Walleij .name = "GPIO_INT15", 595d6255529SLinus Walleij .start = AB9540_INT_GPIO50F, 596d6255529SLinus Walleij .end = AB9540_INT_GPIO54F, 597d6255529SLinus Walleij .flags = IORESOURCE_IRQ, 598d6255529SLinus Walleij } 599d6255529SLinus Walleij }; 600d6255529SLinus Walleij 6015cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_gpadc_resources[] = { 60262579266SRabin Vincent { 60362579266SRabin Vincent .name = "HW_CONV_END", 60462579266SRabin Vincent .start = AB8500_INT_GP_HW_ADC_CONV_END, 60562579266SRabin Vincent .end = AB8500_INT_GP_HW_ADC_CONV_END, 60662579266SRabin Vincent .flags = IORESOURCE_IRQ, 60762579266SRabin Vincent }, 60862579266SRabin Vincent { 60962579266SRabin Vincent .name = "SW_CONV_END", 61062579266SRabin Vincent .start = AB8500_INT_GP_SW_ADC_CONV_END, 61162579266SRabin Vincent .end = AB8500_INT_GP_SW_ADC_CONV_END, 61262579266SRabin Vincent .flags = IORESOURCE_IRQ, 61362579266SRabin Vincent }, 61462579266SRabin Vincent }; 61562579266SRabin Vincent 6165cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_rtc_resources[] = { 61762579266SRabin Vincent { 61862579266SRabin Vincent .name = "60S", 61962579266SRabin Vincent .start = AB8500_INT_RTC_60S, 62062579266SRabin Vincent .end = AB8500_INT_RTC_60S, 62162579266SRabin Vincent .flags = IORESOURCE_IRQ, 62262579266SRabin Vincent }, 62362579266SRabin Vincent { 62462579266SRabin Vincent .name = "ALARM", 62562579266SRabin Vincent .start = AB8500_INT_RTC_ALARM, 62662579266SRabin Vincent .end = AB8500_INT_RTC_ALARM, 62762579266SRabin Vincent .flags = IORESOURCE_IRQ, 62862579266SRabin Vincent }, 62962579266SRabin Vincent }; 63062579266SRabin Vincent 6315cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_poweronkey_db_resources[] = { 63277686517SSundar R Iyer { 63377686517SSundar R Iyer .name = "ONKEY_DBF", 63477686517SSundar R Iyer .start = AB8500_INT_PON_KEY1DB_F, 63577686517SSundar R Iyer .end = AB8500_INT_PON_KEY1DB_F, 63677686517SSundar R Iyer .flags = IORESOURCE_IRQ, 63777686517SSundar R Iyer }, 63877686517SSundar R Iyer { 63977686517SSundar R Iyer .name = "ONKEY_DBR", 64077686517SSundar R Iyer .start = AB8500_INT_PON_KEY1DB_R, 64177686517SSundar R Iyer .end = AB8500_INT_PON_KEY1DB_R, 64277686517SSundar R Iyer .flags = IORESOURCE_IRQ, 64377686517SSundar R Iyer }, 64477686517SSundar R Iyer }; 64577686517SSundar R Iyer 6466af75ecdSLinus Walleij static struct resource __devinitdata ab8500_av_acc_detect_resources[] = { 647e098adedSMattias Wallin { 6486af75ecdSLinus Walleij .name = "ACC_DETECT_1DB_F", 6496af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_1DB_F, 6506af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_1DB_F, 651e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 652e098adedSMattias Wallin }, 653e098adedSMattias Wallin { 6546af75ecdSLinus Walleij .name = "ACC_DETECT_1DB_R", 6556af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_1DB_R, 6566af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_1DB_R, 657e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 658e098adedSMattias Wallin }, 659e098adedSMattias Wallin { 6606af75ecdSLinus Walleij .name = "ACC_DETECT_21DB_F", 6616af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_21DB_F, 6626af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_21DB_F, 6636af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 6646af75ecdSLinus Walleij }, 6656af75ecdSLinus Walleij { 6666af75ecdSLinus Walleij .name = "ACC_DETECT_21DB_R", 6676af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_21DB_R, 6686af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_21DB_R, 6696af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 6706af75ecdSLinus Walleij }, 6716af75ecdSLinus Walleij { 6726af75ecdSLinus Walleij .name = "ACC_DETECT_22DB_F", 6736af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_22DB_F, 6746af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_22DB_F, 6756af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 6766af75ecdSLinus Walleij }, 6776af75ecdSLinus Walleij { 6786af75ecdSLinus Walleij .name = "ACC_DETECT_22DB_R", 6796af75ecdSLinus Walleij .start = AB8500_INT_ACC_DETECT_22DB_R, 6806af75ecdSLinus Walleij .end = AB8500_INT_ACC_DETECT_22DB_R, 6816af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 6826af75ecdSLinus Walleij }, 6836af75ecdSLinus Walleij }; 6846af75ecdSLinus Walleij 6856af75ecdSLinus Walleij static struct resource __devinitdata ab8500_charger_resources[] = { 6866af75ecdSLinus Walleij { 687e098adedSMattias Wallin .name = "MAIN_CH_UNPLUG_DET", 688e098adedSMattias Wallin .start = AB8500_INT_MAIN_CH_UNPLUG_DET, 689e098adedSMattias Wallin .end = AB8500_INT_MAIN_CH_UNPLUG_DET, 690e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 691e098adedSMattias Wallin }, 692e098adedSMattias Wallin { 693e098adedSMattias Wallin .name = "MAIN_CHARGE_PLUG_DET", 694e098adedSMattias Wallin .start = AB8500_INT_MAIN_CH_PLUG_DET, 695e098adedSMattias Wallin .end = AB8500_INT_MAIN_CH_PLUG_DET, 696e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 697e098adedSMattias Wallin }, 698e098adedSMattias Wallin { 699e098adedSMattias Wallin .name = "VBUS_DET_R", 700e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_R, 701e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_R, 702e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 703e098adedSMattias Wallin }, 704e098adedSMattias Wallin { 7056af75ecdSLinus Walleij .name = "VBUS_DET_F", 7066af75ecdSLinus Walleij .start = AB8500_INT_VBUS_DET_F, 7076af75ecdSLinus Walleij .end = AB8500_INT_VBUS_DET_F, 708e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 709e098adedSMattias Wallin }, 710e098adedSMattias Wallin { 7116af75ecdSLinus Walleij .name = "USB_LINK_STATUS", 7126af75ecdSLinus Walleij .start = AB8500_INT_USB_LINK_STATUS, 7136af75ecdSLinus Walleij .end = AB8500_INT_USB_LINK_STATUS, 7146af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7156af75ecdSLinus Walleij }, 7166af75ecdSLinus Walleij { 717e098adedSMattias Wallin .name = "VBUS_OVV", 718e098adedSMattias Wallin .start = AB8500_INT_VBUS_OVV, 719e098adedSMattias Wallin .end = AB8500_INT_VBUS_OVV, 720e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 721e098adedSMattias Wallin }, 722e098adedSMattias Wallin { 7236af75ecdSLinus Walleij .name = "USB_CH_TH_PROT_R", 7246af75ecdSLinus Walleij .start = AB8500_INT_USB_CH_TH_PROT_R, 7256af75ecdSLinus Walleij .end = AB8500_INT_USB_CH_TH_PROT_R, 726e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 727e098adedSMattias Wallin }, 728e098adedSMattias Wallin { 7296af75ecdSLinus Walleij .name = "USB_CH_TH_PROT_F", 7306af75ecdSLinus Walleij .start = AB8500_INT_USB_CH_TH_PROT_F, 7316af75ecdSLinus Walleij .end = AB8500_INT_USB_CH_TH_PROT_F, 732e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 733e098adedSMattias Wallin }, 734e098adedSMattias Wallin { 7356af75ecdSLinus Walleij .name = "MAIN_EXT_CH_NOT_OK", 7366af75ecdSLinus Walleij .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, 7376af75ecdSLinus Walleij .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, 7386af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7396af75ecdSLinus Walleij }, 7406af75ecdSLinus Walleij { 7416af75ecdSLinus Walleij .name = "MAIN_CH_TH_PROT_R", 7426af75ecdSLinus Walleij .start = AB8500_INT_MAIN_CH_TH_PROT_R, 7436af75ecdSLinus Walleij .end = AB8500_INT_MAIN_CH_TH_PROT_R, 7446af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7456af75ecdSLinus Walleij }, 7466af75ecdSLinus Walleij { 7476af75ecdSLinus Walleij .name = "MAIN_CH_TH_PROT_F", 7486af75ecdSLinus Walleij .start = AB8500_INT_MAIN_CH_TH_PROT_F, 7496af75ecdSLinus Walleij .end = AB8500_INT_MAIN_CH_TH_PROT_F, 7506af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7516af75ecdSLinus Walleij }, 7526af75ecdSLinus Walleij { 7536af75ecdSLinus Walleij .name = "USB_CHARGER_NOT_OKR", 754a982362cSBengt Jonsson .start = AB8500_INT_USB_CHARGER_NOT_OKR, 755a982362cSBengt Jonsson .end = AB8500_INT_USB_CHARGER_NOT_OKR, 7566af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7576af75ecdSLinus Walleij }, 7586af75ecdSLinus Walleij { 7596af75ecdSLinus Walleij .name = "CH_WD_EXP", 7606af75ecdSLinus Walleij .start = AB8500_INT_CH_WD_EXP, 7616af75ecdSLinus Walleij .end = AB8500_INT_CH_WD_EXP, 7626af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 7636af75ecdSLinus Walleij }, 7646af75ecdSLinus Walleij }; 7656af75ecdSLinus Walleij 7666af75ecdSLinus Walleij static struct resource __devinitdata ab8500_btemp_resources[] = { 7676af75ecdSLinus Walleij { 7686af75ecdSLinus Walleij .name = "BAT_CTRL_INDB", 7696af75ecdSLinus Walleij .start = AB8500_INT_BAT_CTRL_INDB, 7706af75ecdSLinus Walleij .end = AB8500_INT_BAT_CTRL_INDB, 771e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 772e098adedSMattias Wallin }, 773e098adedSMattias Wallin { 774e098adedSMattias Wallin .name = "BTEMP_LOW", 775e098adedSMattias Wallin .start = AB8500_INT_BTEMP_LOW, 776e098adedSMattias Wallin .end = AB8500_INT_BTEMP_LOW, 777e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 778e098adedSMattias Wallin }, 779e098adedSMattias Wallin { 780e098adedSMattias Wallin .name = "BTEMP_HIGH", 781e098adedSMattias Wallin .start = AB8500_INT_BTEMP_HIGH, 782e098adedSMattias Wallin .end = AB8500_INT_BTEMP_HIGH, 783e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 784e098adedSMattias Wallin }, 785e098adedSMattias Wallin { 7866af75ecdSLinus Walleij .name = "BTEMP_LOW_MEDIUM", 7876af75ecdSLinus Walleij .start = AB8500_INT_BTEMP_LOW_MEDIUM, 7886af75ecdSLinus Walleij .end = AB8500_INT_BTEMP_LOW_MEDIUM, 789e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 790e098adedSMattias Wallin }, 791e098adedSMattias Wallin { 7926af75ecdSLinus Walleij .name = "BTEMP_MEDIUM_HIGH", 7936af75ecdSLinus Walleij .start = AB8500_INT_BTEMP_MEDIUM_HIGH, 7946af75ecdSLinus Walleij .end = AB8500_INT_BTEMP_MEDIUM_HIGH, 795e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 796e098adedSMattias Wallin }, 797e098adedSMattias Wallin }; 798e098adedSMattias Wallin 7996af75ecdSLinus Walleij static struct resource __devinitdata ab8500_fg_resources[] = { 8006af75ecdSLinus Walleij { 8016af75ecdSLinus Walleij .name = "NCONV_ACCU", 8026af75ecdSLinus Walleij .start = AB8500_INT_CCN_CONV_ACC, 8036af75ecdSLinus Walleij .end = AB8500_INT_CCN_CONV_ACC, 8046af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8056af75ecdSLinus Walleij }, 8066af75ecdSLinus Walleij { 8076af75ecdSLinus Walleij .name = "BATT_OVV", 8086af75ecdSLinus Walleij .start = AB8500_INT_BATT_OVV, 8096af75ecdSLinus Walleij .end = AB8500_INT_BATT_OVV, 8106af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8116af75ecdSLinus Walleij }, 8126af75ecdSLinus Walleij { 8136af75ecdSLinus Walleij .name = "LOW_BAT_F", 8146af75ecdSLinus Walleij .start = AB8500_INT_LOW_BAT_F, 8156af75ecdSLinus Walleij .end = AB8500_INT_LOW_BAT_F, 8166af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8176af75ecdSLinus Walleij }, 8186af75ecdSLinus Walleij { 8196af75ecdSLinus Walleij .name = "LOW_BAT_R", 8206af75ecdSLinus Walleij .start = AB8500_INT_LOW_BAT_R, 8216af75ecdSLinus Walleij .end = AB8500_INT_LOW_BAT_R, 8226af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8236af75ecdSLinus Walleij }, 8246af75ecdSLinus Walleij { 8256af75ecdSLinus Walleij .name = "CC_INT_CALIB", 8266af75ecdSLinus Walleij .start = AB8500_INT_CC_INT_CALIB, 8276af75ecdSLinus Walleij .end = AB8500_INT_CC_INT_CALIB, 8286af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8296af75ecdSLinus Walleij }, 830a982362cSBengt Jonsson { 831a982362cSBengt Jonsson .name = "CCEOC", 832a982362cSBengt Jonsson .start = AB8500_INT_CCEOC, 833a982362cSBengt Jonsson .end = AB8500_INT_CCEOC, 834a982362cSBengt Jonsson .flags = IORESOURCE_IRQ, 835a982362cSBengt Jonsson }, 8366af75ecdSLinus Walleij }; 8376af75ecdSLinus Walleij 8386af75ecdSLinus Walleij static struct resource __devinitdata ab8500_chargalg_resources[] = {}; 8396af75ecdSLinus Walleij 840df720647SAxel Lin #ifdef CONFIG_DEBUG_FS 8415cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_debug_resources[] = { 842e098adedSMattias Wallin { 843e098adedSMattias Wallin .name = "IRQ_FIRST", 844e098adedSMattias Wallin .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, 845e098adedSMattias Wallin .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, 846e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 847e098adedSMattias Wallin }, 848e098adedSMattias Wallin { 849e098adedSMattias Wallin .name = "IRQ_LAST", 850a982362cSBengt Jonsson .start = AB8500_INT_XTAL32K_KO, 851a982362cSBengt Jonsson .end = AB8500_INT_XTAL32K_KO, 852e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 853e098adedSMattias Wallin }, 854e098adedSMattias Wallin }; 855df720647SAxel Lin #endif 856e098adedSMattias Wallin 8575cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_usb_resources[] = { 858e098adedSMattias Wallin { 859e098adedSMattias Wallin .name = "ID_WAKEUP_R", 860e098adedSMattias Wallin .start = AB8500_INT_ID_WAKEUP_R, 861e098adedSMattias Wallin .end = AB8500_INT_ID_WAKEUP_R, 862e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 863e098adedSMattias Wallin }, 864e098adedSMattias Wallin { 865e098adedSMattias Wallin .name = "ID_WAKEUP_F", 866e098adedSMattias Wallin .start = AB8500_INT_ID_WAKEUP_F, 867e098adedSMattias Wallin .end = AB8500_INT_ID_WAKEUP_F, 868e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 869e098adedSMattias Wallin }, 870e098adedSMattias Wallin { 871e098adedSMattias Wallin .name = "VBUS_DET_F", 872e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_F, 873e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_F, 874e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 875e098adedSMattias Wallin }, 876e098adedSMattias Wallin { 877e098adedSMattias Wallin .name = "VBUS_DET_R", 878e098adedSMattias Wallin .start = AB8500_INT_VBUS_DET_R, 879e098adedSMattias Wallin .end = AB8500_INT_VBUS_DET_R, 880e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 881e098adedSMattias Wallin }, 88292d50a41SMattias Wallin { 88392d50a41SMattias Wallin .name = "USB_LINK_STATUS", 88492d50a41SMattias Wallin .start = AB8500_INT_USB_LINK_STATUS, 88592d50a41SMattias Wallin .end = AB8500_INT_USB_LINK_STATUS, 88692d50a41SMattias Wallin .flags = IORESOURCE_IRQ, 88792d50a41SMattias Wallin }, 8886af75ecdSLinus Walleij { 8896af75ecdSLinus Walleij .name = "USB_ADP_PROBE_PLUG", 8906af75ecdSLinus Walleij .start = AB8500_INT_ADP_PROBE_PLUG, 8916af75ecdSLinus Walleij .end = AB8500_INT_ADP_PROBE_PLUG, 8926af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8936af75ecdSLinus Walleij }, 8946af75ecdSLinus Walleij { 8956af75ecdSLinus Walleij .name = "USB_ADP_PROBE_UNPLUG", 8966af75ecdSLinus Walleij .start = AB8500_INT_ADP_PROBE_UNPLUG, 8976af75ecdSLinus Walleij .end = AB8500_INT_ADP_PROBE_UNPLUG, 8986af75ecdSLinus Walleij .flags = IORESOURCE_IRQ, 8996af75ecdSLinus Walleij }, 900e098adedSMattias Wallin }; 901e098adedSMattias Wallin 90244f72e53SVirupax Sadashivpetimath static struct resource __devinitdata ab8505_iddet_resources[] = { 90344f72e53SVirupax Sadashivpetimath { 90444f72e53SVirupax Sadashivpetimath .name = "KeyDeglitch", 90544f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KEYDEGLITCH, 90644f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KEYDEGLITCH, 90744f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 90844f72e53SVirupax Sadashivpetimath }, 90944f72e53SVirupax Sadashivpetimath { 91044f72e53SVirupax Sadashivpetimath .name = "KP", 91144f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KP, 91244f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KP, 91344f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 91444f72e53SVirupax Sadashivpetimath }, 91544f72e53SVirupax Sadashivpetimath { 91644f72e53SVirupax Sadashivpetimath .name = "IKP", 91744f72e53SVirupax Sadashivpetimath .start = AB8505_INT_IKP, 91844f72e53SVirupax Sadashivpetimath .end = AB8505_INT_IKP, 91944f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 92044f72e53SVirupax Sadashivpetimath }, 92144f72e53SVirupax Sadashivpetimath { 92244f72e53SVirupax Sadashivpetimath .name = "IKR", 92344f72e53SVirupax Sadashivpetimath .start = AB8505_INT_IKR, 92444f72e53SVirupax Sadashivpetimath .end = AB8505_INT_IKR, 92544f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 92644f72e53SVirupax Sadashivpetimath }, 92744f72e53SVirupax Sadashivpetimath { 92844f72e53SVirupax Sadashivpetimath .name = "KeyStuck", 92944f72e53SVirupax Sadashivpetimath .start = AB8505_INT_KEYSTUCK, 93044f72e53SVirupax Sadashivpetimath .end = AB8505_INT_KEYSTUCK, 93144f72e53SVirupax Sadashivpetimath .flags = IORESOURCE_IRQ, 93244f72e53SVirupax Sadashivpetimath }, 93344f72e53SVirupax Sadashivpetimath }; 93444f72e53SVirupax Sadashivpetimath 9355cef8df5SRobert Rosengren static struct resource __devinitdata ab8500_temp_resources[] = { 936e098adedSMattias Wallin { 937e098adedSMattias Wallin .name = "AB8500_TEMP_WARM", 938e098adedSMattias Wallin .start = AB8500_INT_TEMP_WARM, 939e098adedSMattias Wallin .end = AB8500_INT_TEMP_WARM, 940e098adedSMattias Wallin .flags = IORESOURCE_IRQ, 941e098adedSMattias Wallin }, 942e098adedSMattias Wallin }; 943e098adedSMattias Wallin 944d6255529SLinus Walleij static struct mfd_cell __devinitdata abx500_common_devs[] = { 9455814fc35SMattias Wallin #ifdef CONFIG_DEBUG_FS 9465814fc35SMattias Wallin { 9475814fc35SMattias Wallin .name = "ab8500-debug", 948e098adedSMattias Wallin .num_resources = ARRAY_SIZE(ab8500_debug_resources), 949e098adedSMattias Wallin .resources = ab8500_debug_resources, 9505814fc35SMattias Wallin }, 9515814fc35SMattias Wallin #endif 95262579266SRabin Vincent { 953e098adedSMattias Wallin .name = "ab8500-sysctrl", 954e098adedSMattias Wallin }, 955e098adedSMattias Wallin { 956e098adedSMattias Wallin .name = "ab8500-regulator", 957e098adedSMattias Wallin }, 958e098adedSMattias Wallin { 95962579266SRabin Vincent .name = "ab8500-gpadc", 96062579266SRabin Vincent .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), 96162579266SRabin Vincent .resources = ab8500_gpadc_resources, 96262579266SRabin Vincent }, 96362579266SRabin Vincent { 96462579266SRabin Vincent .name = "ab8500-rtc", 96562579266SRabin Vincent .num_resources = ARRAY_SIZE(ab8500_rtc_resources), 96662579266SRabin Vincent .resources = ab8500_rtc_resources, 96762579266SRabin Vincent }, 968f0f05b1cSArun Murthy { 9696af75ecdSLinus Walleij .name = "ab8500-acc-det", 9706af75ecdSLinus Walleij .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources), 9716af75ecdSLinus Walleij .resources = ab8500_av_acc_detect_resources, 9726af75ecdSLinus Walleij }, 9736af75ecdSLinus Walleij { 974e098adedSMattias Wallin .name = "ab8500-poweron-key", 975e098adedSMattias Wallin .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), 976e098adedSMattias Wallin .resources = ab8500_poweronkey_db_resources, 977e098adedSMattias Wallin }, 978e098adedSMattias Wallin { 979f0f05b1cSArun Murthy .name = "ab8500-pwm", 980f0f05b1cSArun Murthy .id = 1, 981f0f05b1cSArun Murthy }, 982f0f05b1cSArun Murthy { 983f0f05b1cSArun Murthy .name = "ab8500-pwm", 984f0f05b1cSArun Murthy .id = 2, 985f0f05b1cSArun Murthy }, 986f0f05b1cSArun Murthy { 987f0f05b1cSArun Murthy .name = "ab8500-pwm", 988f0f05b1cSArun Murthy .id = 3, 989f0f05b1cSArun Murthy }, 990e098adedSMattias Wallin { .name = "ab8500-leds", }, 99177686517SSundar R Iyer { 992e098adedSMattias Wallin .name = "ab8500-denc", 993e098adedSMattias Wallin }, 994e098adedSMattias Wallin { 995e098adedSMattias Wallin .name = "ab8500-temp", 996e098adedSMattias Wallin .num_resources = ARRAY_SIZE(ab8500_temp_resources), 997e098adedSMattias Wallin .resources = ab8500_temp_resources, 99877686517SSundar R Iyer }, 99962579266SRabin Vincent }; 100062579266SRabin Vincent 10016ef9418cSRickard Andersson static struct mfd_cell __devinitdata ab8500_bm_devs[] = { 10026ef9418cSRickard Andersson { 10036ef9418cSRickard Andersson .name = "ab8500-charger", 10046ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_charger_resources), 10056ef9418cSRickard Andersson .resources = ab8500_charger_resources, 10066ef9418cSRickard Andersson }, 10076ef9418cSRickard Andersson { 10086ef9418cSRickard Andersson .name = "ab8500-btemp", 10096ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_btemp_resources), 10106ef9418cSRickard Andersson .resources = ab8500_btemp_resources, 10116ef9418cSRickard Andersson }, 10126ef9418cSRickard Andersson { 10136ef9418cSRickard Andersson .name = "ab8500-fg", 10146ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_fg_resources), 10156ef9418cSRickard Andersson .resources = ab8500_fg_resources, 10166ef9418cSRickard Andersson }, 10176ef9418cSRickard Andersson { 10186ef9418cSRickard Andersson .name = "ab8500-chargalg", 10196ef9418cSRickard Andersson .num_resources = ARRAY_SIZE(ab8500_chargalg_resources), 10206ef9418cSRickard Andersson .resources = ab8500_chargalg_resources, 10216ef9418cSRickard Andersson }, 10226ef9418cSRickard Andersson }; 10236ef9418cSRickard Andersson 1024d6255529SLinus Walleij static struct mfd_cell __devinitdata ab8500_devs[] = { 1025d6255529SLinus Walleij { 1026d6255529SLinus Walleij .name = "ab8500-gpio", 1027d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab8500_gpio_resources), 1028d6255529SLinus Walleij .resources = ab8500_gpio_resources, 1029d6255529SLinus Walleij }, 1030d6255529SLinus Walleij { 1031d6255529SLinus Walleij .name = "ab8500-usb", 1032d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab8500_usb_resources), 1033d6255529SLinus Walleij .resources = ab8500_usb_resources, 1034d6255529SLinus Walleij }, 103544f72e53SVirupax Sadashivpetimath { 103644f72e53SVirupax Sadashivpetimath .name = "ab8500-codec", 103744f72e53SVirupax Sadashivpetimath }, 1038d6255529SLinus Walleij }; 1039d6255529SLinus Walleij 1040d6255529SLinus Walleij static struct mfd_cell __devinitdata ab9540_devs[] = { 1041d6255529SLinus Walleij { 1042d6255529SLinus Walleij .name = "ab8500-gpio", 1043d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab9540_gpio_resources), 1044d6255529SLinus Walleij .resources = ab9540_gpio_resources, 1045d6255529SLinus Walleij }, 1046d6255529SLinus Walleij { 1047d6255529SLinus Walleij .name = "ab9540-usb", 1048d6255529SLinus Walleij .num_resources = ARRAY_SIZE(ab8500_usb_resources), 1049d6255529SLinus Walleij .resources = ab8500_usb_resources, 1050d6255529SLinus Walleij }, 105144f72e53SVirupax Sadashivpetimath { 105244f72e53SVirupax Sadashivpetimath .name = "ab9540-codec", 105344f72e53SVirupax Sadashivpetimath }, 105444f72e53SVirupax Sadashivpetimath }; 105544f72e53SVirupax Sadashivpetimath 105644f72e53SVirupax Sadashivpetimath /* Device list common to ab9540 and ab8505 */ 105744f72e53SVirupax Sadashivpetimath static struct mfd_cell __devinitdata ab9540_ab8505_devs[] = { 105844f72e53SVirupax Sadashivpetimath { 105944f72e53SVirupax Sadashivpetimath .name = "ab-iddet", 106044f72e53SVirupax Sadashivpetimath .num_resources = ARRAY_SIZE(ab8505_iddet_resources), 106144f72e53SVirupax Sadashivpetimath .resources = ab8505_iddet_resources, 106244f72e53SVirupax Sadashivpetimath }, 1063d6255529SLinus Walleij }; 1064d6255529SLinus Walleij 1065cca69b67SMattias Wallin static ssize_t show_chip_id(struct device *dev, 1066cca69b67SMattias Wallin struct device_attribute *attr, char *buf) 1067cca69b67SMattias Wallin { 1068cca69b67SMattias Wallin struct ab8500 *ab8500; 1069cca69b67SMattias Wallin 1070cca69b67SMattias Wallin ab8500 = dev_get_drvdata(dev); 1071cca69b67SMattias Wallin return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); 1072cca69b67SMattias Wallin } 1073cca69b67SMattias Wallin 1074e5c238c3SMattias Wallin /* 1075e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 1076e5c238c3SMattias Wallin * 0x01 Swoff bit programming 1077e5c238c3SMattias Wallin * 0x02 Thermal protection activation 1078e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 1079e5c238c3SMattias Wallin * 0x08 Watchdog expired 1080e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 1081e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 1082e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 1083e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 1084e5c238c3SMattias Wallin */ 1085e5c238c3SMattias Wallin static ssize_t show_switch_off_status(struct device *dev, 1086e5c238c3SMattias Wallin struct device_attribute *attr, char *buf) 1087e5c238c3SMattias Wallin { 1088e5c238c3SMattias Wallin int ret; 1089e5c238c3SMattias Wallin u8 value; 1090e5c238c3SMattias Wallin struct ab8500 *ab8500; 1091e5c238c3SMattias Wallin 1092e5c238c3SMattias Wallin ab8500 = dev_get_drvdata(dev); 1093e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 1094e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 1095e5c238c3SMattias Wallin if (ret < 0) 1096e5c238c3SMattias Wallin return ret; 1097e5c238c3SMattias Wallin return sprintf(buf, "%#x\n", value); 1098e5c238c3SMattias Wallin } 1099e5c238c3SMattias Wallin 1100b4a31037SAndrew Lynn /* 1101b4a31037SAndrew Lynn * ab8500 has turned on due to (TURN_ON_STATUS): 1102b4a31037SAndrew Lynn * 0x01 PORnVbat 1103b4a31037SAndrew Lynn * 0x02 PonKey1dbF 1104b4a31037SAndrew Lynn * 0x04 PonKey2dbF 1105b4a31037SAndrew Lynn * 0x08 RTCAlarm 1106b4a31037SAndrew Lynn * 0x10 MainChDet 1107b4a31037SAndrew Lynn * 0x20 VbusDet 1108b4a31037SAndrew Lynn * 0x40 UsbIDDetect 1109b4a31037SAndrew Lynn * 0x80 Reserved 1110b4a31037SAndrew Lynn */ 1111b4a31037SAndrew Lynn static ssize_t show_turn_on_status(struct device *dev, 1112b4a31037SAndrew Lynn struct device_attribute *attr, char *buf) 1113b4a31037SAndrew Lynn { 1114b4a31037SAndrew Lynn int ret; 1115b4a31037SAndrew Lynn u8 value; 1116b4a31037SAndrew Lynn struct ab8500 *ab8500; 1117b4a31037SAndrew Lynn 1118b4a31037SAndrew Lynn ab8500 = dev_get_drvdata(dev); 1119b4a31037SAndrew Lynn ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 1120b4a31037SAndrew Lynn AB8500_TURN_ON_STATUS, &value); 1121b4a31037SAndrew Lynn if (ret < 0) 1122b4a31037SAndrew Lynn return ret; 1123b4a31037SAndrew Lynn return sprintf(buf, "%#x\n", value); 1124b4a31037SAndrew Lynn } 1125b4a31037SAndrew Lynn 1126d6255529SLinus Walleij static ssize_t show_ab9540_dbbrstn(struct device *dev, 1127d6255529SLinus Walleij struct device_attribute *attr, char *buf) 1128d6255529SLinus Walleij { 1129d6255529SLinus Walleij struct ab8500 *ab8500; 1130d6255529SLinus Walleij int ret; 1131d6255529SLinus Walleij u8 value; 1132d6255529SLinus Walleij 1133d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 1134d6255529SLinus Walleij 1135d6255529SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2, 1136d6255529SLinus Walleij AB9540_MODEM_CTRL2_REG, &value); 1137d6255529SLinus Walleij if (ret < 0) 1138d6255529SLinus Walleij return ret; 1139d6255529SLinus Walleij 1140d6255529SLinus Walleij return sprintf(buf, "%d\n", 1141d6255529SLinus Walleij (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0); 1142d6255529SLinus Walleij } 1143d6255529SLinus Walleij 1144d6255529SLinus Walleij static ssize_t store_ab9540_dbbrstn(struct device *dev, 1145d6255529SLinus Walleij struct device_attribute *attr, const char *buf, size_t count) 1146d6255529SLinus Walleij { 1147d6255529SLinus Walleij struct ab8500 *ab8500; 1148d6255529SLinus Walleij int ret = count; 1149d6255529SLinus Walleij int err; 1150d6255529SLinus Walleij u8 bitvalues; 1151d6255529SLinus Walleij 1152d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 1153d6255529SLinus Walleij 1154d6255529SLinus Walleij if (count > 0) { 1155d6255529SLinus Walleij switch (buf[0]) { 1156d6255529SLinus Walleij case '0': 1157d6255529SLinus Walleij bitvalues = 0; 1158d6255529SLinus Walleij break; 1159d6255529SLinus Walleij case '1': 1160d6255529SLinus Walleij bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT; 1161d6255529SLinus Walleij break; 1162d6255529SLinus Walleij default: 1163d6255529SLinus Walleij goto exit; 1164d6255529SLinus Walleij } 1165d6255529SLinus Walleij 1166d6255529SLinus Walleij err = mask_and_set_register_interruptible(ab8500, 1167d6255529SLinus Walleij AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG, 1168d6255529SLinus Walleij AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues); 1169d6255529SLinus Walleij if (err) 1170d6255529SLinus Walleij dev_info(ab8500->dev, 1171d6255529SLinus Walleij "Failed to set DBBRSTN %c, err %#x\n", 1172d6255529SLinus Walleij buf[0], err); 1173d6255529SLinus Walleij } 1174d6255529SLinus Walleij 1175d6255529SLinus Walleij exit: 1176d6255529SLinus Walleij return ret; 1177d6255529SLinus Walleij } 1178d6255529SLinus Walleij 1179cca69b67SMattias Wallin static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); 1180e5c238c3SMattias Wallin static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL); 1181b4a31037SAndrew Lynn static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL); 1182d6255529SLinus Walleij static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR, 1183d6255529SLinus Walleij show_ab9540_dbbrstn, store_ab9540_dbbrstn); 1184cca69b67SMattias Wallin 1185cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = { 1186cca69b67SMattias Wallin &dev_attr_chip_id.attr, 1187e5c238c3SMattias Wallin &dev_attr_switch_off_status.attr, 1188b4a31037SAndrew Lynn &dev_attr_turn_on_status.attr, 1189cca69b67SMattias Wallin NULL, 1190cca69b67SMattias Wallin }; 1191cca69b67SMattias Wallin 1192d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = { 1193d6255529SLinus Walleij &dev_attr_chip_id.attr, 1194d6255529SLinus Walleij &dev_attr_switch_off_status.attr, 1195d6255529SLinus Walleij &dev_attr_turn_on_status.attr, 1196d6255529SLinus Walleij &dev_attr_dbbrstn.attr, 1197d6255529SLinus Walleij NULL, 1198d6255529SLinus Walleij }; 1199d6255529SLinus Walleij 1200cca69b67SMattias Wallin static struct attribute_group ab8500_attr_group = { 1201cca69b67SMattias Wallin .attrs = ab8500_sysfs_entries, 1202cca69b67SMattias Wallin }; 1203cca69b67SMattias Wallin 1204d6255529SLinus Walleij static struct attribute_group ab9540_attr_group = { 1205d6255529SLinus Walleij .attrs = ab9540_sysfs_entries, 1206d6255529SLinus Walleij }; 1207d6255529SLinus Walleij 1208*d28f1db8SLee Jones static int __devinit ab8500_probe(struct platform_device *pdev) 120962579266SRabin Vincent { 1210*d28f1db8SLee Jones struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev); 1211*d28f1db8SLee Jones const struct platform_device_id *platid = platform_get_device_id(pdev); 1212*d28f1db8SLee Jones enum ab8500_version version = platid->driver_data; 1213*d28f1db8SLee Jones struct ab8500 *ab8500; 1214*d28f1db8SLee Jones struct resource *resource; 121562579266SRabin Vincent int ret; 121662579266SRabin Vincent int i; 121747c16975SMattias Wallin u8 value; 121862579266SRabin Vincent 1219*d28f1db8SLee Jones ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL); 1220*d28f1db8SLee Jones if (!ab8500) 1221*d28f1db8SLee Jones return -ENOMEM; 1222*d28f1db8SLee Jones 122362579266SRabin Vincent if (plat) 122462579266SRabin Vincent ab8500->irq_base = plat->irq_base; 122562579266SRabin Vincent 1226*d28f1db8SLee Jones ab8500->dev = &pdev->dev; 1227*d28f1db8SLee Jones 1228*d28f1db8SLee Jones resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 1229*d28f1db8SLee Jones if (!resource) { 1230*d28f1db8SLee Jones ret = -ENODEV; 1231*d28f1db8SLee Jones goto out_free_ab8500; 1232*d28f1db8SLee Jones } 1233*d28f1db8SLee Jones 1234*d28f1db8SLee Jones ab8500->irq = resource->start; 1235*d28f1db8SLee Jones 1236*d28f1db8SLee Jones ab8500->read = ab8500_i2c_read; 1237*d28f1db8SLee Jones ab8500->write = ab8500_i2c_write; 1238*d28f1db8SLee Jones ab8500->write_masked = ab8500_i2c_write_masked; 1239*d28f1db8SLee Jones 124062579266SRabin Vincent mutex_init(&ab8500->lock); 124162579266SRabin Vincent mutex_init(&ab8500->irq_lock); 1242112a80d2SJonas Aaberg atomic_set(&ab8500->transfer_ongoing, 0); 124362579266SRabin Vincent 1244*d28f1db8SLee Jones platform_set_drvdata(pdev, ab8500); 1245*d28f1db8SLee Jones 12460f620837SLinus Walleij if (version != AB8500_VERSION_UNDEFINED) 12470f620837SLinus Walleij ab8500->version = version; 12480f620837SLinus Walleij else { 12490f620837SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_MISC, 12500f620837SLinus Walleij AB8500_IC_NAME_REG, &value); 12510f620837SLinus Walleij if (ret < 0) 1252*d28f1db8SLee Jones goto out_free_ab8500; 12530f620837SLinus Walleij 12540f620837SLinus Walleij ab8500->version = value; 12550f620837SLinus Walleij } 12560f620837SLinus Walleij 125747c16975SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_MISC, 125847c16975SMattias Wallin AB8500_REV_REG, &value); 125962579266SRabin Vincent if (ret < 0) 1260*d28f1db8SLee Jones goto out_free_ab8500; 126162579266SRabin Vincent 126247c16975SMattias Wallin ab8500->chip_id = value; 126362579266SRabin Vincent 12640f620837SLinus Walleij dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n", 12650f620837SLinus Walleij ab8500_version_str[ab8500->version], 12660f620837SLinus Walleij ab8500->chip_id >> 4, 12670f620837SLinus Walleij ab8500->chip_id & 0x0F); 12680f620837SLinus Walleij 1269d6255529SLinus Walleij /* Configure AB8500 or AB9540 IRQ */ 1270a982362cSBengt Jonsson if (is_ab9540(ab8500) || is_ab8505(ab8500)) { 1271d6255529SLinus Walleij ab8500->mask_size = AB9540_NUM_IRQ_REGS; 1272d6255529SLinus Walleij ab8500->irq_reg_offset = ab9540_irq_regoffset; 1273d6255529SLinus Walleij } else { 12742ced445eSLinus Walleij ab8500->mask_size = AB8500_NUM_IRQ_REGS; 12752ced445eSLinus Walleij ab8500->irq_reg_offset = ab8500_irq_regoffset; 1276d6255529SLinus Walleij } 12772ced445eSLinus Walleij ab8500->mask = kzalloc(ab8500->mask_size, GFP_KERNEL); 12782ced445eSLinus Walleij if (!ab8500->mask) 12792ced445eSLinus Walleij return -ENOMEM; 12802ced445eSLinus Walleij ab8500->oldmask = kzalloc(ab8500->mask_size, GFP_KERNEL); 12812ced445eSLinus Walleij if (!ab8500->oldmask) { 12822ced445eSLinus Walleij ret = -ENOMEM; 12832ced445eSLinus Walleij goto out_freemask; 12842ced445eSLinus Walleij } 1285e5c238c3SMattias Wallin /* 1286e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 1287e5c238c3SMattias Wallin * 0x01 Swoff bit programming 1288e5c238c3SMattias Wallin * 0x02 Thermal protection activation 1289e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 1290e5c238c3SMattias Wallin * 0x08 Watchdog expired 1291e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 1292e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 1293e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 1294e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 1295e5c238c3SMattias Wallin */ 1296e5c238c3SMattias Wallin 1297e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 1298e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 1299e5c238c3SMattias Wallin if (ret < 0) 1300e5c238c3SMattias Wallin return ret; 1301e5c238c3SMattias Wallin dev_info(ab8500->dev, "switch off status: %#x", value); 1302e5c238c3SMattias Wallin 130362579266SRabin Vincent if (plat && plat->init) 130462579266SRabin Vincent plat->init(ab8500); 130562579266SRabin Vincent 130662579266SRabin Vincent /* Clear and mask all interrupts */ 13072ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 13080f620837SLinus Walleij /* 13090f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 13100f620837SLinus Walleij * 2.0 13110f620837SLinus Walleij */ 13120f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 13130f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 131492d50a41SMattias Wallin continue; 131562579266SRabin Vincent 131647c16975SMattias Wallin get_register_interruptible(ab8500, AB8500_INTERRUPT, 13172ced445eSLinus Walleij AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i], 131892d50a41SMattias Wallin &value); 131947c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, 13202ced445eSLinus Walleij AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff); 132162579266SRabin Vincent } 132262579266SRabin Vincent 132347c16975SMattias Wallin ret = abx500_register_ops(ab8500->dev, &ab8500_ops); 132447c16975SMattias Wallin if (ret) 13252ced445eSLinus Walleij goto out_freeoldmask; 132647c16975SMattias Wallin 13272ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) 132862579266SRabin Vincent ab8500->mask[i] = ab8500->oldmask[i] = 0xff; 132962579266SRabin Vincent 133062579266SRabin Vincent if (ab8500->irq_base) { 133162579266SRabin Vincent ret = ab8500_irq_init(ab8500); 133262579266SRabin Vincent if (ret) 13332ced445eSLinus Walleij goto out_freeoldmask; 133462579266SRabin Vincent 13357ccfe9b1SMichel JAOUEN /* Activate this feature only in ab9540 */ 13367ccfe9b1SMichel JAOUEN /* till tests are done on ab8500 1p2 or later*/ 13377ccfe9b1SMichel JAOUEN if (is_ab9540(ab8500)) 13387ccfe9b1SMichel JAOUEN ret = request_threaded_irq(ab8500->irq, NULL, 13397ccfe9b1SMichel JAOUEN ab8500_hierarchical_irq, 13407ccfe9b1SMichel JAOUEN IRQF_ONESHOT | IRQF_NO_SUSPEND, 13417ccfe9b1SMichel JAOUEN "ab8500", ab8500); 13427ccfe9b1SMichel JAOUEN else 13437ccfe9b1SMichel JAOUEN ret = request_threaded_irq(ab8500->irq, NULL, 13447ccfe9b1SMichel JAOUEN ab8500_irq, 13454f079985SMattias Wallin IRQF_ONESHOT | IRQF_NO_SUSPEND, 13464f079985SMattias Wallin "ab8500", ab8500); 134762579266SRabin Vincent if (ret) 134862579266SRabin Vincent goto out_removeirq; 134962579266SRabin Vincent } 135062579266SRabin Vincent 1351d6255529SLinus Walleij ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs, 1352d6255529SLinus Walleij ARRAY_SIZE(abx500_common_devs), NULL, 1353d6255529SLinus Walleij ab8500->irq_base); 1354d6255529SLinus Walleij 1355d6255529SLinus Walleij if (ret) 1356d6255529SLinus Walleij goto out_freeirq; 1357d6255529SLinus Walleij 1358d6255529SLinus Walleij if (is_ab9540(ab8500)) 1359d6255529SLinus Walleij ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, 1360d6255529SLinus Walleij ARRAY_SIZE(ab9540_devs), NULL, 1361d6255529SLinus Walleij ab8500->irq_base); 1362d6255529SLinus Walleij else 1363549931f9SSundar R Iyer ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, 136444f72e53SVirupax Sadashivpetimath ARRAY_SIZE(ab8500_devs), NULL, 136562579266SRabin Vincent ab8500->irq_base); 136644f72e53SVirupax Sadashivpetimath 136744f72e53SVirupax Sadashivpetimath if (is_ab9540(ab8500) || is_ab8505(ab8500)) 136844f72e53SVirupax Sadashivpetimath ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs, 136944f72e53SVirupax Sadashivpetimath ARRAY_SIZE(ab9540_ab8505_devs), NULL, 137044f72e53SVirupax Sadashivpetimath ab8500->irq_base); 137144f72e53SVirupax Sadashivpetimath 137262579266SRabin Vincent if (ret) 137362579266SRabin Vincent goto out_freeirq; 137462579266SRabin Vincent 13756ef9418cSRickard Andersson if (!no_bm) { 13766ef9418cSRickard Andersson /* Add battery management devices */ 13776ef9418cSRickard Andersson ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, 13786ef9418cSRickard Andersson ARRAY_SIZE(ab8500_bm_devs), NULL, 13796ef9418cSRickard Andersson ab8500->irq_base); 13806ef9418cSRickard Andersson if (ret) 13816ef9418cSRickard Andersson dev_err(ab8500->dev, "error adding bm devices\n"); 13826ef9418cSRickard Andersson } 13836ef9418cSRickard Andersson 1384d6255529SLinus Walleij if (is_ab9540(ab8500)) 1385d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1386d6255529SLinus Walleij &ab9540_attr_group); 1387d6255529SLinus Walleij else 1388d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1389d6255529SLinus Walleij &ab8500_attr_group); 1390cca69b67SMattias Wallin if (ret) 1391cca69b67SMattias Wallin dev_err(ab8500->dev, "error creating sysfs entries\n"); 1392d6255529SLinus Walleij else 139362579266SRabin Vincent return ret; 139462579266SRabin Vincent 139562579266SRabin Vincent out_freeirq: 13966d95b7fdSLinus Walleij if (ab8500->irq_base) 139762579266SRabin Vincent free_irq(ab8500->irq, ab8500); 139862579266SRabin Vincent out_removeirq: 13996d95b7fdSLinus Walleij if (ab8500->irq_base) 140062579266SRabin Vincent ab8500_irq_remove(ab8500); 14012ced445eSLinus Walleij out_freeoldmask: 14022ced445eSLinus Walleij kfree(ab8500->oldmask); 14032ced445eSLinus Walleij out_freemask: 14042ced445eSLinus Walleij kfree(ab8500->mask); 1405*d28f1db8SLee Jones out_free_ab8500: 1406*d28f1db8SLee Jones kfree(ab8500); 14076d95b7fdSLinus Walleij 140862579266SRabin Vincent return ret; 140962579266SRabin Vincent } 141062579266SRabin Vincent 1411*d28f1db8SLee Jones static int __devexit ab8500_remove(struct platform_device *pdev) 141262579266SRabin Vincent { 1413*d28f1db8SLee Jones struct ab8500 *ab8500 = platform_get_drvdata(pdev); 1414*d28f1db8SLee Jones 1415d6255529SLinus Walleij if (is_ab9540(ab8500)) 1416d6255529SLinus Walleij sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group); 1417d6255529SLinus Walleij else 1418cca69b67SMattias Wallin sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group); 141962579266SRabin Vincent mfd_remove_devices(ab8500->dev); 142062579266SRabin Vincent if (ab8500->irq_base) { 142162579266SRabin Vincent free_irq(ab8500->irq, ab8500); 142262579266SRabin Vincent ab8500_irq_remove(ab8500); 142362579266SRabin Vincent } 14242ced445eSLinus Walleij kfree(ab8500->oldmask); 14252ced445eSLinus Walleij kfree(ab8500->mask); 1426*d28f1db8SLee Jones kfree(ab8500); 142762579266SRabin Vincent 142862579266SRabin Vincent return 0; 142962579266SRabin Vincent } 143062579266SRabin Vincent 1431*d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = { 1432*d28f1db8SLee Jones { "ab8500-core", AB8500_VERSION_AB8500 }, 1433*d28f1db8SLee Jones { "ab8505-i2c", AB8500_VERSION_AB8505 }, 1434*d28f1db8SLee Jones { "ab9540-i2c", AB8500_VERSION_AB9540 }, 1435*d28f1db8SLee Jones { "ab8540-i2c", AB8500_VERSION_AB8540 }, 1436*d28f1db8SLee Jones { } 1437*d28f1db8SLee Jones }; 1438*d28f1db8SLee Jones 1439*d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = { 1440*d28f1db8SLee Jones .driver = { 1441*d28f1db8SLee Jones .name = "ab8500-core", 1442*d28f1db8SLee Jones .owner = THIS_MODULE, 1443*d28f1db8SLee Jones }, 1444*d28f1db8SLee Jones .probe = ab8500_probe, 1445*d28f1db8SLee Jones .remove = __devexit_p(ab8500_remove), 1446*d28f1db8SLee Jones .id_table = ab8500_id, 1447*d28f1db8SLee Jones }; 1448*d28f1db8SLee Jones 1449*d28f1db8SLee Jones static int __init ab8500_core_init(void) 1450*d28f1db8SLee Jones { 1451*d28f1db8SLee Jones return platform_driver_register(&ab8500_core_driver); 1452*d28f1db8SLee Jones } 1453*d28f1db8SLee Jones 1454*d28f1db8SLee Jones static void __exit ab8500_core_exit(void) 1455*d28f1db8SLee Jones { 1456*d28f1db8SLee Jones platform_driver_unregister(&ab8500_core_driver); 1457*d28f1db8SLee Jones } 1458*d28f1db8SLee Jones arch_initcall(ab8500_core_init); 1459*d28f1db8SLee Jones module_exit(ab8500_core_exit); 1460*d28f1db8SLee Jones 1461adceed62SMattias Wallin MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent"); 146262579266SRabin Vincent MODULE_DESCRIPTION("AB8500 MFD core"); 146362579266SRabin Vincent MODULE_LICENSE("GPL v2"); 1464