10376148fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 262579266SRabin Vincent /* 362579266SRabin Vincent * Copyright (C) ST-Ericsson SA 2010 462579266SRabin Vincent * 562579266SRabin Vincent * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> 662579266SRabin Vincent * Author: Rabin Vincent <rabin.vincent@stericsson.com> 7adceed62SMattias Wallin * Author: Mattias Wallin <mattias.wallin@stericsson.com> 862579266SRabin Vincent */ 962579266SRabin Vincent 1062579266SRabin Vincent #include <linux/kernel.h> 1162579266SRabin Vincent #include <linux/slab.h> 1262579266SRabin Vincent #include <linux/init.h> 1362579266SRabin Vincent #include <linux/irq.h> 1406e589efSLee Jones #include <linux/irqdomain.h> 1562579266SRabin Vincent #include <linux/delay.h> 1662579266SRabin Vincent #include <linux/interrupt.h> 1731cbae22SPaul Gortmaker #include <linux/moduleparam.h> 1862579266SRabin Vincent #include <linux/platform_device.h> 1962579266SRabin Vincent #include <linux/mfd/core.h> 2047c16975SMattias Wallin #include <linux/mfd/abx500.h> 21ee66e653SLinus Walleij #include <linux/mfd/abx500/ab8500.h> 2200441b5eSLee Jones #include <linux/mfd/abx500/ab8500-bm.h> 23d28f1db8SLee Jones #include <linux/mfd/dbx500-prcmu.h> 24549931f9SSundar R Iyer #include <linux/regulator/ab8500.h> 256bc4a568SLee Jones #include <linux/of.h> 266bc4a568SLee Jones #include <linux/of_device.h> 2762579266SRabin Vincent 2862579266SRabin Vincent /* 2962579266SRabin Vincent * Interrupt register offsets 3062579266SRabin Vincent * Bank : 0x0E 3162579266SRabin Vincent */ 3247c16975SMattias Wallin #define AB8500_IT_SOURCE1_REG 0x00 3347c16975SMattias Wallin #define AB8500_IT_SOURCE2_REG 0x01 3447c16975SMattias Wallin #define AB8500_IT_SOURCE3_REG 0x02 3547c16975SMattias Wallin #define AB8500_IT_SOURCE4_REG 0x03 3647c16975SMattias Wallin #define AB8500_IT_SOURCE5_REG 0x04 3747c16975SMattias Wallin #define AB8500_IT_SOURCE6_REG 0x05 3847c16975SMattias Wallin #define AB8500_IT_SOURCE7_REG 0x06 3947c16975SMattias Wallin #define AB8500_IT_SOURCE8_REG 0x07 40d6255529SLinus Walleij #define AB9540_IT_SOURCE13_REG 0x0C 4147c16975SMattias Wallin #define AB8500_IT_SOURCE19_REG 0x12 4247c16975SMattias Wallin #define AB8500_IT_SOURCE20_REG 0x13 4347c16975SMattias Wallin #define AB8500_IT_SOURCE21_REG 0x14 4447c16975SMattias Wallin #define AB8500_IT_SOURCE22_REG 0x15 4547c16975SMattias Wallin #define AB8500_IT_SOURCE23_REG 0x16 4647c16975SMattias Wallin #define AB8500_IT_SOURCE24_REG 0x17 4762579266SRabin Vincent 4862579266SRabin Vincent /* 4962579266SRabin Vincent * latch registers 5062579266SRabin Vincent */ 5147c16975SMattias Wallin #define AB8500_IT_LATCH1_REG 0x20 5247c16975SMattias Wallin #define AB8500_IT_LATCH2_REG 0x21 5347c16975SMattias Wallin #define AB8500_IT_LATCH3_REG 0x22 5447c16975SMattias Wallin #define AB8500_IT_LATCH4_REG 0x23 5547c16975SMattias Wallin #define AB8500_IT_LATCH5_REG 0x24 5647c16975SMattias Wallin #define AB8500_IT_LATCH6_REG 0x25 5747c16975SMattias Wallin #define AB8500_IT_LATCH7_REG 0x26 5847c16975SMattias Wallin #define AB8500_IT_LATCH8_REG 0x27 5947c16975SMattias Wallin #define AB8500_IT_LATCH9_REG 0x28 6047c16975SMattias Wallin #define AB8500_IT_LATCH10_REG 0x29 6192d50a41SMattias Wallin #define AB8500_IT_LATCH12_REG 0x2B 62d6255529SLinus Walleij #define AB9540_IT_LATCH13_REG 0x2C 6347c16975SMattias Wallin #define AB8500_IT_LATCH19_REG 0x32 6447c16975SMattias Wallin #define AB8500_IT_LATCH20_REG 0x33 6547c16975SMattias Wallin #define AB8500_IT_LATCH21_REG 0x34 6647c16975SMattias Wallin #define AB8500_IT_LATCH22_REG 0x35 6747c16975SMattias Wallin #define AB8500_IT_LATCH23_REG 0x36 6847c16975SMattias Wallin #define AB8500_IT_LATCH24_REG 0x37 6962579266SRabin Vincent 7062579266SRabin Vincent /* 7162579266SRabin Vincent * mask registers 7262579266SRabin Vincent */ 7362579266SRabin Vincent 7447c16975SMattias Wallin #define AB8500_IT_MASK1_REG 0x40 7547c16975SMattias Wallin #define AB8500_IT_MASK2_REG 0x41 7647c16975SMattias Wallin #define AB8500_IT_MASK3_REG 0x42 7747c16975SMattias Wallin #define AB8500_IT_MASK4_REG 0x43 7847c16975SMattias Wallin #define AB8500_IT_MASK5_REG 0x44 7947c16975SMattias Wallin #define AB8500_IT_MASK6_REG 0x45 8047c16975SMattias Wallin #define AB8500_IT_MASK7_REG 0x46 8147c16975SMattias Wallin #define AB8500_IT_MASK8_REG 0x47 8247c16975SMattias Wallin #define AB8500_IT_MASK9_REG 0x48 8347c16975SMattias Wallin #define AB8500_IT_MASK10_REG 0x49 8447c16975SMattias Wallin #define AB8500_IT_MASK11_REG 0x4A 8547c16975SMattias Wallin #define AB8500_IT_MASK12_REG 0x4B 8647c16975SMattias Wallin #define AB8500_IT_MASK13_REG 0x4C 8747c16975SMattias Wallin #define AB8500_IT_MASK14_REG 0x4D 8847c16975SMattias Wallin #define AB8500_IT_MASK15_REG 0x4E 8947c16975SMattias Wallin #define AB8500_IT_MASK16_REG 0x4F 9047c16975SMattias Wallin #define AB8500_IT_MASK17_REG 0x50 9147c16975SMattias Wallin #define AB8500_IT_MASK18_REG 0x51 9247c16975SMattias Wallin #define AB8500_IT_MASK19_REG 0x52 9347c16975SMattias Wallin #define AB8500_IT_MASK20_REG 0x53 9447c16975SMattias Wallin #define AB8500_IT_MASK21_REG 0x54 9547c16975SMattias Wallin #define AB8500_IT_MASK22_REG 0x55 9647c16975SMattias Wallin #define AB8500_IT_MASK23_REG 0x56 9747c16975SMattias Wallin #define AB8500_IT_MASK24_REG 0x57 98a29264b6SLee Jones #define AB8500_IT_MASK25_REG 0x58 9962579266SRabin Vincent 1007ccfe9b1SMichel JAOUEN /* 1017ccfe9b1SMichel JAOUEN * latch hierarchy registers 1027ccfe9b1SMichel JAOUEN */ 1037ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER1_REG 0x60 1047ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER2_REG 0x61 1057ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER3_REG 0x62 1063e1a498fSLee Jones #define AB8540_IT_LATCHHIER4_REG 0x63 1077ccfe9b1SMichel JAOUEN 1087ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER_NUM 3 1093e1a498fSLee Jones #define AB8540_IT_LATCHHIER_NUM 4 1107ccfe9b1SMichel JAOUEN 11147c16975SMattias Wallin #define AB8500_REV_REG 0x80 1120f620837SLinus Walleij #define AB8500_IC_NAME_REG 0x82 113e5c238c3SMattias Wallin #define AB8500_SWITCH_OFF_STATUS 0x00 11462579266SRabin Vincent 115b4a31037SAndrew Lynn #define AB8500_TURN_ON_STATUS 0x00 11693ff722eSLee Jones #define AB8505_TURN_ON_STATUS_2 0x04 117b4a31037SAndrew Lynn 118f04a9d8aSRajkumar Kasirajan #define AB8500_CH_USBCH_STAT1_REG 0x02 119f04a9d8aSRajkumar Kasirajan #define VBUS_DET_DBNC100 0x02 120f04a9d8aSRajkumar Kasirajan #define VBUS_DET_DBNC1 0x01 121f04a9d8aSRajkumar Kasirajan 122f04a9d8aSRajkumar Kasirajan static DEFINE_SPINLOCK(on_stat_lock); 123f04a9d8aSRajkumar Kasirajan static u8 turn_on_stat_mask = 0xFF; 124f04a9d8aSRajkumar Kasirajan static u8 turn_on_stat_set; 1256ef9418cSRickard Andersson static bool no_bm; /* No battery management */ 12631cbae22SPaul Gortmaker /* 12731cbae22SPaul Gortmaker * not really modular, but the easiest way to keep compat with existing 12831cbae22SPaul Gortmaker * bootargs behaviour is to continue using module_param here. 12931cbae22SPaul Gortmaker */ 1306ef9418cSRickard Andersson module_param(no_bm, bool, S_IRUGO); 1316ef9418cSRickard Andersson 132d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_REG 0x23 133d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2) 134d6255529SLinus Walleij 13562579266SRabin Vincent /* 13662579266SRabin Vincent * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt 1372ced445eSLinus Walleij * numbers are indexed into this array with (num / 8). The interupts are 1382ced445eSLinus Walleij * defined in linux/mfd/ab8500.h 13962579266SRabin Vincent * 14062579266SRabin Vincent * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at 14162579266SRabin Vincent * offset 0. 14262579266SRabin Vincent */ 1432ced445eSLinus Walleij /* AB8500 support */ 14462579266SRabin Vincent static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { 14592d50a41SMattias Wallin 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 14662579266SRabin Vincent }; 14762579266SRabin Vincent 148a29264b6SLee Jones /* AB9540 / AB8505 support */ 149d6255529SLinus Walleij static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = { 150a29264b6SLee Jones 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23 151d6255529SLinus Walleij }; 152d6255529SLinus Walleij 1533e1a498fSLee Jones /* AB8540 support */ 1543e1a498fSLee Jones static const int ab8540_irq_regoffset[AB8540_NUM_IRQ_REGS] = { 1557ccf40b1SLee Jones 0, 1, 2, 3, 4, -1, -1, -1, -1, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 1567ccf40b1SLee Jones 23, 25, 26, 27, 28, 29, 30, 31, 1573e1a498fSLee Jones }; 1583e1a498fSLee Jones 1590f620837SLinus Walleij static const char ab8500_version_str[][7] = { 1600f620837SLinus Walleij [AB8500_VERSION_AB8500] = "AB8500", 1610f620837SLinus Walleij [AB8500_VERSION_AB8505] = "AB8505", 1620f620837SLinus Walleij [AB8500_VERSION_AB9540] = "AB9540", 1630f620837SLinus Walleij [AB8500_VERSION_AB8540] = "AB8540", 1640f620837SLinus Walleij }; 1650f620837SLinus Walleij 166822672a7SLee Jones static int ab8500_prcmu_write(struct ab8500 *ab8500, u16 addr, u8 data) 167d28f1db8SLee Jones { 168d28f1db8SLee Jones int ret; 169d28f1db8SLee Jones 170d28f1db8SLee Jones ret = prcmu_abb_write((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 176822672a7SLee Jones static int ab8500_prcmu_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask, 177d28f1db8SLee Jones u8 data) 178d28f1db8SLee Jones { 179d28f1db8SLee Jones int ret; 180d28f1db8SLee Jones 181d28f1db8SLee Jones ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 182d28f1db8SLee Jones &mask, 1); 183d28f1db8SLee Jones if (ret < 0) 184d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 185d28f1db8SLee Jones return ret; 186d28f1db8SLee Jones } 187d28f1db8SLee Jones 188822672a7SLee Jones static int ab8500_prcmu_read(struct ab8500 *ab8500, u16 addr) 189d28f1db8SLee Jones { 190d28f1db8SLee Jones int ret; 191d28f1db8SLee Jones u8 data; 192d28f1db8SLee Jones 193d28f1db8SLee Jones ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 194d28f1db8SLee Jones if (ret < 0) { 195d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 196d28f1db8SLee Jones return ret; 197d28f1db8SLee Jones } 198d28f1db8SLee Jones return (int)data; 199d28f1db8SLee Jones } 200d28f1db8SLee Jones 20147c16975SMattias Wallin static int ab8500_get_chip_id(struct device *dev) 20247c16975SMattias Wallin { 2036bce7bf1SMattias Wallin struct ab8500 *ab8500; 2046bce7bf1SMattias Wallin 2056bce7bf1SMattias Wallin if (!dev) 2066bce7bf1SMattias Wallin return -EINVAL; 2076bce7bf1SMattias Wallin ab8500 = dev_get_drvdata(dev->parent); 2086bce7bf1SMattias Wallin return ab8500 ? (int)ab8500->chip_id : -EINVAL; 20947c16975SMattias Wallin } 21047c16975SMattias Wallin 21147c16975SMattias Wallin static int set_register_interruptible(struct ab8500 *ab8500, u8 bank, 21247c16975SMattias Wallin u8 reg, u8 data) 21362579266SRabin Vincent { 21462579266SRabin Vincent int ret; 21547c16975SMattias Wallin /* 21647c16975SMattias Wallin * Put the u8 bank and u8 register together into a an u16. 21747c16975SMattias Wallin * The bank on higher 8 bits and register in lower 8 bits. 218500e69a1SLee Jones */ 21947c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 22062579266SRabin Vincent 22162579266SRabin Vincent dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data); 22262579266SRabin Vincent 223392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 22447c16975SMattias Wallin 22547c16975SMattias Wallin ret = ab8500->write(ab8500, addr, data); 22647c16975SMattias Wallin if (ret < 0) 22747c16975SMattias Wallin dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 22847c16975SMattias Wallin addr, ret); 22947c16975SMattias Wallin mutex_unlock(&ab8500->lock); 23047c16975SMattias Wallin 23147c16975SMattias Wallin return ret; 23247c16975SMattias Wallin } 23347c16975SMattias Wallin 23447c16975SMattias Wallin static int ab8500_set_register(struct device *dev, u8 bank, 23547c16975SMattias Wallin u8 reg, u8 value) 23647c16975SMattias Wallin { 237112a80d2SJonas Aaberg int ret; 23847c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 23947c16975SMattias Wallin 240112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 241112a80d2SJonas Aaberg ret = set_register_interruptible(ab8500, bank, reg, value); 242112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 243112a80d2SJonas Aaberg return ret; 24447c16975SMattias Wallin } 24547c16975SMattias Wallin 24647c16975SMattias Wallin static int get_register_interruptible(struct ab8500 *ab8500, u8 bank, 24747c16975SMattias Wallin u8 reg, u8 *value) 24847c16975SMattias Wallin { 24947c16975SMattias Wallin int ret; 25047c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 25147c16975SMattias Wallin 252392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 25347c16975SMattias Wallin 25447c16975SMattias Wallin ret = ab8500->read(ab8500, addr); 25547c16975SMattias Wallin if (ret < 0) 25647c16975SMattias Wallin dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 25747c16975SMattias Wallin addr, ret); 25847c16975SMattias Wallin else 25947c16975SMattias Wallin *value = ret; 26047c16975SMattias Wallin 26147c16975SMattias Wallin mutex_unlock(&ab8500->lock); 26247c16975SMattias Wallin dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret); 26347c16975SMattias Wallin 26410628e3eSDan Carpenter return (ret < 0) ? ret : 0; 26547c16975SMattias Wallin } 26647c16975SMattias Wallin 26747c16975SMattias Wallin static int ab8500_get_register(struct device *dev, u8 bank, 26847c16975SMattias Wallin u8 reg, u8 *value) 26947c16975SMattias Wallin { 270112a80d2SJonas Aaberg int ret; 27147c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 27247c16975SMattias Wallin 273112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 274112a80d2SJonas Aaberg ret = get_register_interruptible(ab8500, bank, reg, value); 275112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 276112a80d2SJonas Aaberg return ret; 27747c16975SMattias Wallin } 27847c16975SMattias Wallin 27947c16975SMattias Wallin static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank, 28047c16975SMattias Wallin u8 reg, u8 bitmask, u8 bitvalues) 28147c16975SMattias Wallin { 28247c16975SMattias Wallin int ret; 28347c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 28447c16975SMattias Wallin 285392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 28647c16975SMattias Wallin 287bc628fd1SMattias Nilsson if (ab8500->write_masked == NULL) { 288bc628fd1SMattias Nilsson u8 data; 289bc628fd1SMattias Nilsson 29047c16975SMattias Wallin ret = ab8500->read(ab8500, addr); 29147c16975SMattias Wallin if (ret < 0) { 29247c16975SMattias Wallin dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 29347c16975SMattias Wallin addr, ret); 29447c16975SMattias Wallin goto out; 29547c16975SMattias Wallin } 29647c16975SMattias Wallin 29747c16975SMattias Wallin data = (u8)ret; 29847c16975SMattias Wallin data = (~bitmask & data) | (bitmask & bitvalues); 29947c16975SMattias Wallin 30062579266SRabin Vincent ret = ab8500->write(ab8500, addr, data); 30162579266SRabin Vincent if (ret < 0) 30262579266SRabin Vincent dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 30362579266SRabin Vincent addr, ret); 30462579266SRabin Vincent 305bc628fd1SMattias Nilsson dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, 306bc628fd1SMattias Nilsson data); 307bc628fd1SMattias Nilsson goto out; 308bc628fd1SMattias Nilsson } 309bc628fd1SMattias Nilsson ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues); 310bc628fd1SMattias Nilsson if (ret < 0) 311bc628fd1SMattias Nilsson dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr, 312bc628fd1SMattias Nilsson ret); 31362579266SRabin Vincent out: 31462579266SRabin Vincent mutex_unlock(&ab8500->lock); 31562579266SRabin Vincent return ret; 31662579266SRabin Vincent } 31747c16975SMattias Wallin 31847c16975SMattias Wallin static int ab8500_mask_and_set_register(struct device *dev, 31947c16975SMattias Wallin u8 bank, u8 reg, u8 bitmask, u8 bitvalues) 32047c16975SMattias Wallin { 321112a80d2SJonas Aaberg int ret; 32247c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 32347c16975SMattias Wallin 324112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 325112a80d2SJonas Aaberg ret = mask_and_set_register_interruptible(ab8500, bank, reg, 32647c16975SMattias Wallin bitmask, bitvalues); 327112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 328112a80d2SJonas Aaberg return ret; 32947c16975SMattias Wallin } 33047c16975SMattias Wallin 33147c16975SMattias Wallin static struct abx500_ops ab8500_ops = { 33247c16975SMattias Wallin .get_chip_id = ab8500_get_chip_id, 33347c16975SMattias Wallin .get_register = ab8500_get_register, 33447c16975SMattias Wallin .set_register = ab8500_set_register, 33547c16975SMattias Wallin .get_register_page = NULL, 33647c16975SMattias Wallin .set_register_page = NULL, 33747c16975SMattias Wallin .mask_and_set_register = ab8500_mask_and_set_register, 33847c16975SMattias Wallin .event_registers_startup_state_get = NULL, 33947c16975SMattias Wallin .startup_irq_enabled = NULL, 3401d843a6cSMian Yousaf Kaukab .dump_all_banks = ab8500_dump_all_banks, 34147c16975SMattias Wallin }; 34262579266SRabin Vincent 3439505a0a0SMark Brown static void ab8500_irq_lock(struct irq_data *data) 34462579266SRabin Vincent { 3459505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 34662579266SRabin Vincent 34762579266SRabin Vincent mutex_lock(&ab8500->irq_lock); 348112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 34962579266SRabin Vincent } 35062579266SRabin Vincent 3519505a0a0SMark Brown static void ab8500_irq_sync_unlock(struct irq_data *data) 35262579266SRabin Vincent { 3539505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 35462579266SRabin Vincent int i; 35562579266SRabin Vincent 3562ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 35762579266SRabin Vincent u8 old = ab8500->oldmask[i]; 35862579266SRabin Vincent u8 new = ab8500->mask[i]; 35962579266SRabin Vincent int reg; 36062579266SRabin Vincent 36162579266SRabin Vincent if (new == old) 36262579266SRabin Vincent continue; 36362579266SRabin Vincent 3640f620837SLinus Walleij /* 3650f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 3660f620837SLinus Walleij * 2.0 3670f620837SLinus Walleij */ 3680f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 3690f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 37092d50a41SMattias Wallin continue; 37192d50a41SMattias Wallin 3723e1a498fSLee Jones if (ab8500->irq_reg_offset[i] < 0) 3733e1a498fSLee Jones continue; 3743e1a498fSLee Jones 37562579266SRabin Vincent ab8500->oldmask[i] = new; 37662579266SRabin Vincent 3772ced445eSLinus Walleij reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i]; 37847c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new); 37962579266SRabin Vincent } 380112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 38162579266SRabin Vincent mutex_unlock(&ab8500->irq_lock); 38262579266SRabin Vincent } 38362579266SRabin Vincent 3849505a0a0SMark Brown static void ab8500_irq_mask(struct irq_data *data) 38562579266SRabin Vincent { 3869505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 38706e589efSLee Jones int offset = data->hwirq; 38862579266SRabin Vincent int index = offset / 8; 38962579266SRabin Vincent int mask = 1 << (offset % 8); 39062579266SRabin Vincent 39162579266SRabin Vincent ab8500->mask[index] |= mask; 3929c677b9bSLee Jones 3939c677b9bSLee Jones /* The AB8500 GPIOs have two interrupts each (rising & falling). */ 3949c677b9bSLee Jones if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R) 3959c677b9bSLee Jones ab8500->mask[index + 2] |= mask; 3969c677b9bSLee Jones if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R) 3979c677b9bSLee Jones ab8500->mask[index + 1] |= mask; 3989c677b9bSLee Jones if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R) 399e2ddf46aSLinus Walleij /* Here the falling IRQ is one bit lower */ 400e2ddf46aSLinus Walleij ab8500->mask[index] |= (mask << 1); 40162579266SRabin Vincent } 40262579266SRabin Vincent 4039505a0a0SMark Brown static void ab8500_irq_unmask(struct irq_data *data) 40462579266SRabin Vincent { 4059505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 4069c677b9bSLee Jones unsigned int type = irqd_get_trigger_type(data); 40706e589efSLee Jones int offset = data->hwirq; 40862579266SRabin Vincent int index = offset / 8; 40962579266SRabin Vincent int mask = 1 << (offset % 8); 41062579266SRabin Vincent 4119c677b9bSLee Jones if (type & IRQ_TYPE_EDGE_RISING) 41262579266SRabin Vincent ab8500->mask[index] &= ~mask; 4139c677b9bSLee Jones 4149c677b9bSLee Jones /* The AB8500 GPIOs have two interrupts each (rising & falling). */ 4159c677b9bSLee Jones if (type & IRQ_TYPE_EDGE_FALLING) { 4169c677b9bSLee Jones if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R) 4179c677b9bSLee Jones ab8500->mask[index + 2] &= ~mask; 4187ccf40b1SLee Jones else if (offset >= AB9540_INT_GPIO50R && 4197ccf40b1SLee Jones offset <= AB9540_INT_GPIO54R) 4209c677b9bSLee Jones ab8500->mask[index + 1] &= ~mask; 4217ccf40b1SLee Jones else if (offset == AB8540_INT_GPIO43R || 4227ccf40b1SLee Jones offset == AB8540_INT_GPIO44R) 423e2ddf46aSLinus Walleij /* Here the falling IRQ is one bit lower */ 424e2ddf46aSLinus Walleij ab8500->mask[index] &= ~(mask << 1); 4259c677b9bSLee Jones else 4269c677b9bSLee Jones ab8500->mask[index] &= ~mask; 427e2ddf46aSLinus Walleij } else { 4289c677b9bSLee Jones /* Satisfies the case where type is not set. */ 42962579266SRabin Vincent ab8500->mask[index] &= ~mask; 43062579266SRabin Vincent } 431e2ddf46aSLinus Walleij } 43262579266SRabin Vincent 43340f6e5a2SLee Jones static int ab8500_irq_set_type(struct irq_data *data, unsigned int type) 43440f6e5a2SLee Jones { 43540f6e5a2SLee Jones return 0; 43662579266SRabin Vincent } 43762579266SRabin Vincent 43862579266SRabin Vincent static struct irq_chip ab8500_irq_chip = { 43962579266SRabin Vincent .name = "ab8500", 4409505a0a0SMark Brown .irq_bus_lock = ab8500_irq_lock, 4419505a0a0SMark Brown .irq_bus_sync_unlock = ab8500_irq_sync_unlock, 4429505a0a0SMark Brown .irq_mask = ab8500_irq_mask, 443e6f9306eSVirupax Sadashivpetimath .irq_disable = ab8500_irq_mask, 4449505a0a0SMark Brown .irq_unmask = ab8500_irq_unmask, 44540f6e5a2SLee Jones .irq_set_type = ab8500_irq_set_type, 44662579266SRabin Vincent }; 44762579266SRabin Vincent 4483e1a498fSLee Jones static void update_latch_offset(u8 *offset, int i) 4493e1a498fSLee Jones { 4503e1a498fSLee Jones /* Fix inconsistent ITFromLatch25 bit mapping... */ 4513e1a498fSLee Jones if (unlikely(*offset == 17)) 4523e1a498fSLee Jones *offset = 24; 4533e1a498fSLee Jones /* Fix inconsistent ab8540 bit mapping... */ 4543e1a498fSLee Jones if (unlikely(*offset == 16)) 4553e1a498fSLee Jones *offset = 25; 4563e1a498fSLee Jones if ((i == 3) && (*offset >= 24)) 4573e1a498fSLee Jones *offset += 2; 4583e1a498fSLee Jones } 4593e1a498fSLee Jones 4607ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, 4617ccfe9b1SMichel JAOUEN int latch_offset, u8 latch_val) 4627ccfe9b1SMichel JAOUEN { 4637a93fb37SFabio Baltieri int int_bit, line, i; 4647ccfe9b1SMichel JAOUEN 4657ccfe9b1SMichel JAOUEN for (i = 0; i < ab8500->mask_size; i++) 4667ccfe9b1SMichel JAOUEN if (ab8500->irq_reg_offset[i] == latch_offset) 4677ccfe9b1SMichel JAOUEN break; 4687ccfe9b1SMichel JAOUEN 4697ccfe9b1SMichel JAOUEN if (i >= ab8500->mask_size) { 4707ccfe9b1SMichel JAOUEN dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", 4717ccfe9b1SMichel JAOUEN latch_offset); 4727ccfe9b1SMichel JAOUEN return -ENXIO; 4737ccfe9b1SMichel JAOUEN } 4747ccfe9b1SMichel JAOUEN 4757a93fb37SFabio Baltieri /* ignore masked out interrupts */ 4767a93fb37SFabio Baltieri latch_val &= ~ab8500->mask[i]; 4777a93fb37SFabio Baltieri 4787a93fb37SFabio Baltieri while (latch_val) { 4797a93fb37SFabio Baltieri int_bit = __ffs(latch_val); 4807ccfe9b1SMichel JAOUEN line = (i << 3) + int_bit; 4817ccfe9b1SMichel JAOUEN latch_val &= ~(1 << int_bit); 4827ccfe9b1SMichel JAOUEN 483e2ddf46aSLinus Walleij /* 484e2ddf46aSLinus Walleij * This handles the falling edge hwirqs from the GPIO 485e2ddf46aSLinus Walleij * lines. Route them back to the line registered for the 486e2ddf46aSLinus Walleij * rising IRQ, as this is merely a flag for the same IRQ 487e2ddf46aSLinus Walleij * in linux terms. 488e2ddf46aSLinus Walleij */ 489e2ddf46aSLinus Walleij if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F) 490e2ddf46aSLinus Walleij line -= 16; 491e2ddf46aSLinus Walleij if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F) 492e2ddf46aSLinus Walleij line -= 8; 493e2ddf46aSLinus Walleij if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F) 494e2ddf46aSLinus Walleij line += 1; 495e2ddf46aSLinus Walleij 496ed83d301SLinus Walleij handle_nested_irq(irq_create_mapping(ab8500->domain, line)); 4977a93fb37SFabio Baltieri } 4987ccfe9b1SMichel JAOUEN 4997ccfe9b1SMichel JAOUEN return 0; 5007ccfe9b1SMichel JAOUEN } 5017ccfe9b1SMichel JAOUEN 5027ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500, 5037ccfe9b1SMichel JAOUEN int hier_offset, u8 hier_val) 5047ccfe9b1SMichel JAOUEN { 5057ccfe9b1SMichel JAOUEN int latch_bit, status; 5067ccfe9b1SMichel JAOUEN u8 latch_offset, latch_val; 5077ccfe9b1SMichel JAOUEN 5087ccfe9b1SMichel JAOUEN do { 5097ccfe9b1SMichel JAOUEN latch_bit = __ffs(hier_val); 5107ccfe9b1SMichel JAOUEN latch_offset = (hier_offset << 3) + latch_bit; 5117ccfe9b1SMichel JAOUEN 5123e1a498fSLee Jones update_latch_offset(&latch_offset, hier_offset); 5137ccfe9b1SMichel JAOUEN 5147ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, 5157ccfe9b1SMichel JAOUEN AB8500_INTERRUPT, 5167ccfe9b1SMichel JAOUEN AB8500_IT_LATCH1_REG + latch_offset, 5177ccfe9b1SMichel JAOUEN &latch_val); 5187ccfe9b1SMichel JAOUEN if (status < 0 || latch_val == 0) 5197ccfe9b1SMichel JAOUEN goto discard; 5207ccfe9b1SMichel JAOUEN 5217ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_line(ab8500, 5227ccfe9b1SMichel JAOUEN latch_offset, latch_val); 5237ccfe9b1SMichel JAOUEN if (status < 0) 5247ccfe9b1SMichel JAOUEN return status; 5257ccfe9b1SMichel JAOUEN discard: 5267ccfe9b1SMichel JAOUEN hier_val &= ~(1 << latch_bit); 5277ccfe9b1SMichel JAOUEN } while (hier_val); 5287ccfe9b1SMichel JAOUEN 5297ccfe9b1SMichel JAOUEN return 0; 5307ccfe9b1SMichel JAOUEN } 5317ccfe9b1SMichel JAOUEN 5327ccfe9b1SMichel JAOUEN static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev) 5337ccfe9b1SMichel JAOUEN { 5347ccfe9b1SMichel JAOUEN struct ab8500 *ab8500 = dev; 5357ccfe9b1SMichel JAOUEN u8 i; 5367ccfe9b1SMichel JAOUEN 5377ccfe9b1SMichel JAOUEN dev_vdbg(ab8500->dev, "interrupt\n"); 5387ccfe9b1SMichel JAOUEN 5397ccfe9b1SMichel JAOUEN /* Hierarchical interrupt version */ 5403e1a498fSLee Jones for (i = 0; i < (ab8500->it_latchhier_num); i++) { 5417ccfe9b1SMichel JAOUEN int status; 5427ccfe9b1SMichel JAOUEN u8 hier_val; 5437ccfe9b1SMichel JAOUEN 5447ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, AB8500_INTERRUPT, 5457ccfe9b1SMichel JAOUEN AB8500_IT_LATCHHIER1_REG + i, &hier_val); 5467ccfe9b1SMichel JAOUEN if (status < 0 || hier_val == 0) 5477ccfe9b1SMichel JAOUEN continue; 5487ccfe9b1SMichel JAOUEN 5497ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val); 5507ccfe9b1SMichel JAOUEN if (status < 0) 5517ccfe9b1SMichel JAOUEN break; 5527ccfe9b1SMichel JAOUEN } 5537ccfe9b1SMichel JAOUEN return IRQ_HANDLED; 5547ccfe9b1SMichel JAOUEN } 5557ccfe9b1SMichel JAOUEN 55606e589efSLee Jones static int ab8500_irq_map(struct irq_domain *d, unsigned int virq, 55706e589efSLee Jones irq_hw_number_t hwirq) 55806e589efSLee Jones { 55906e589efSLee Jones struct ab8500 *ab8500 = d->host_data; 56006e589efSLee Jones 56106e589efSLee Jones if (!ab8500) 56206e589efSLee Jones return -EINVAL; 56306e589efSLee Jones 56406e589efSLee Jones irq_set_chip_data(virq, ab8500); 56506e589efSLee Jones irq_set_chip_and_handler(virq, &ab8500_irq_chip, 56606e589efSLee Jones handle_simple_irq); 56706e589efSLee Jones irq_set_nested_thread(virq, 1); 56806e589efSLee Jones irq_set_noprobe(virq); 56962579266SRabin Vincent 57062579266SRabin Vincent return 0; 57162579266SRabin Vincent } 57262579266SRabin Vincent 5737ce7b26fSKrzysztof Kozlowski static const struct irq_domain_ops ab8500_irq_ops = { 57406e589efSLee Jones .map = ab8500_irq_map, 57506e589efSLee Jones .xlate = irq_domain_xlate_twocell, 57606e589efSLee Jones }; 57706e589efSLee Jones 57806e589efSLee Jones static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np) 57962579266SRabin Vincent { 5802ced445eSLinus Walleij int num_irqs; 58162579266SRabin Vincent 5823e1a498fSLee Jones if (is_ab8540(ab8500)) 5833e1a498fSLee Jones num_irqs = AB8540_NR_IRQS; 5843e1a498fSLee Jones else if (is_ab9540(ab8500)) 585d6255529SLinus Walleij num_irqs = AB9540_NR_IRQS; 586a982362cSBengt Jonsson else if (is_ab8505(ab8500)) 587a982362cSBengt Jonsson num_irqs = AB8505_NR_IRQS; 588d6255529SLinus Walleij else 5892ced445eSLinus Walleij num_irqs = AB8500_NR_IRQS; 5902ced445eSLinus Walleij 591f1d11f39SLinus Walleij /* If ->irq_base is zero this will give a linear mapping */ 5927602e05dSGrygorii Strashko ab8500->domain = irq_domain_add_simple(ab8500->dev->of_node, 593f864c46aSLinus Walleij num_irqs, 0, 594f1d11f39SLinus Walleij &ab8500_irq_ops, ab8500); 59506e589efSLee Jones 59606e589efSLee Jones if (!ab8500->domain) { 59706e589efSLee Jones dev_err(ab8500->dev, "Failed to create irqdomain\n"); 598500e69a1SLee Jones return -ENODEV; 59906e589efSLee Jones } 60006e589efSLee Jones 60106e589efSLee Jones return 0; 60262579266SRabin Vincent } 60362579266SRabin Vincent 604112a80d2SJonas Aaberg int ab8500_suspend(struct ab8500 *ab8500) 605112a80d2SJonas Aaberg { 606112a80d2SJonas Aaberg if (atomic_read(&ab8500->transfer_ongoing)) 607112a80d2SJonas Aaberg return -EINVAL; 608f3556302SLee Jones 609112a80d2SJonas Aaberg return 0; 610112a80d2SJonas Aaberg } 611112a80d2SJonas Aaberg 6125ac98553SGeert Uytterhoeven static const struct mfd_cell ab8500_bm_devs[] = { 613f4d41ad8SLee Jones OF_MFD_CELL("ab8500-charger", NULL, &ab8500_bm_data, 614f4d41ad8SLee Jones sizeof(ab8500_bm_data), 0, "stericsson,ab8500-charger"), 615f4d41ad8SLee Jones OF_MFD_CELL("ab8500-btemp", NULL, &ab8500_bm_data, 616f4d41ad8SLee Jones sizeof(ab8500_bm_data), 0, "stericsson,ab8500-btemp"), 617f4d41ad8SLee Jones OF_MFD_CELL("ab8500-fg", NULL, &ab8500_bm_data, 618f4d41ad8SLee Jones sizeof(ab8500_bm_data), 0, "stericsson,ab8500-fg"), 619f4d41ad8SLee Jones OF_MFD_CELL("ab8500-chargalg", NULL, &ab8500_bm_data, 620f4d41ad8SLee Jones sizeof(ab8500_bm_data), 0, "stericsson,ab8500-chargalg"), 6216ef9418cSRickard Andersson }; 6226ef9418cSRickard Andersson 6235ac98553SGeert Uytterhoeven static const struct mfd_cell ab8500_devs[] = { 6244b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 625f4d41ad8SLee Jones OF_MFD_CELL("ab8500-debug", 626f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-debug"), 6274b106fb9SLee Jones #endif 628f4d41ad8SLee Jones OF_MFD_CELL("ab8500-sysctrl", 629f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-sysctrl"), 630f4d41ad8SLee Jones OF_MFD_CELL("ab8500-ext-regulator", 631f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-ext-regulator"), 632f4d41ad8SLee Jones OF_MFD_CELL("ab8500-regulator", 633f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-regulator"), 634f4d41ad8SLee Jones OF_MFD_CELL("abx500-clk", 635f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,abx500-clk"), 636f4d41ad8SLee Jones OF_MFD_CELL("ab8500-gpadc", 637f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-gpadc"), 638f4d41ad8SLee Jones OF_MFD_CELL("ab8500-rtc", 639f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-rtc"), 640f4d41ad8SLee Jones OF_MFD_CELL("ab8500-acc-det", 641f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-acc-det"), 642f4d41ad8SLee Jones OF_MFD_CELL("ab8500-poweron-key", 643f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-poweron-key"), 644f4d41ad8SLee Jones OF_MFD_CELL("ab8500-pwm", 645f4d41ad8SLee Jones NULL, NULL, 0, 1, "stericsson,ab8500-pwm"), 646f4d41ad8SLee Jones OF_MFD_CELL("ab8500-pwm", 647f4d41ad8SLee Jones NULL, NULL, 0, 2, "stericsson,ab8500-pwm"), 648f4d41ad8SLee Jones OF_MFD_CELL("ab8500-pwm", 649f4d41ad8SLee Jones NULL, NULL, 0, 3, "stericsson,ab8500-pwm"), 650f4d41ad8SLee Jones OF_MFD_CELL("ab8500-denc", 651f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-denc"), 652f4d41ad8SLee Jones OF_MFD_CELL("pinctrl-ab8500", 653f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-gpio"), 654f4d41ad8SLee Jones OF_MFD_CELL("abx500-temp", 655f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,abx500-temp"), 656f4d41ad8SLee Jones OF_MFD_CELL("ab8500-usb", 657f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-usb"), 658f4d41ad8SLee Jones OF_MFD_CELL("ab8500-codec", 659f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-codec"), 6604b106fb9SLee Jones }; 6614b106fb9SLee Jones 6625ac98553SGeert Uytterhoeven static const struct mfd_cell ab9540_devs[] = { 6634b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 6644b106fb9SLee Jones { 6654b106fb9SLee Jones .name = "ab8500-debug", 6664b106fb9SLee Jones }, 6674b106fb9SLee Jones #endif 6684b106fb9SLee Jones { 6694b106fb9SLee Jones .name = "ab8500-sysctrl", 6704b106fb9SLee Jones }, 6714b106fb9SLee Jones { 67253f325beSLee Jones .name = "ab8500-ext-regulator", 67353f325beSLee Jones }, 67453f325beSLee Jones { 6754b106fb9SLee Jones .name = "ab8500-regulator", 67644f72e53SVirupax Sadashivpetimath }, 677c0eda9aeSLee Jones { 6789ee17676SUlf Hansson .name = "abx500-clk", 6799ee17676SUlf Hansson .of_compatible = "stericsson,abx500-clk", 6809ee17676SUlf Hansson }, 6819ee17676SUlf Hansson { 682c0eda9aeSLee Jones .name = "ab8500-gpadc", 683c0eda9aeSLee Jones .of_compatible = "stericsson,ab8500-gpadc", 684c0eda9aeSLee Jones }, 6854b106fb9SLee Jones { 6864b106fb9SLee Jones .name = "ab8500-rtc", 6874b106fb9SLee Jones }, 6884b106fb9SLee Jones { 6894b106fb9SLee Jones .name = "ab8500-acc-det", 6904b106fb9SLee Jones }, 6914b106fb9SLee Jones { 6924b106fb9SLee Jones .name = "ab8500-poweron-key", 6934b106fb9SLee Jones }, 6944b106fb9SLee Jones { 6954b106fb9SLee Jones .name = "ab8500-pwm", 6964b106fb9SLee Jones .id = 1, 6974b106fb9SLee Jones }, 6984b106fb9SLee Jones { 6994b106fb9SLee Jones .name = "abx500-temp", 7004b106fb9SLee Jones }, 701d6255529SLinus Walleij { 702e64d905eSLee Jones .name = "pinctrl-ab9540", 703e64d905eSLee Jones .of_compatible = "stericsson,ab9540-gpio", 704d6255529SLinus Walleij }, 705d6255529SLinus Walleij { 706d6255529SLinus Walleij .name = "ab9540-usb", 707d6255529SLinus Walleij }, 70844f72e53SVirupax Sadashivpetimath { 70944f72e53SVirupax Sadashivpetimath .name = "ab9540-codec", 71044f72e53SVirupax Sadashivpetimath }, 711c0eda9aeSLee Jones { 712c0eda9aeSLee Jones .name = "ab-iddet", 713c0eda9aeSLee Jones }, 71444f72e53SVirupax Sadashivpetimath }; 71544f72e53SVirupax Sadashivpetimath 716c0eda9aeSLee Jones /* Device list for ab8505 */ 7175ac98553SGeert Uytterhoeven static const struct mfd_cell ab8505_devs[] = { 7184b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 7194b106fb9SLee Jones { 7204b106fb9SLee Jones .name = "ab8500-debug", 721*1c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-debug", 7224b106fb9SLee Jones }, 7234b106fb9SLee Jones #endif 7244b106fb9SLee Jones { 7254b106fb9SLee Jones .name = "ab8500-sysctrl", 726*1c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-sysctrl", 7274b106fb9SLee Jones }, 7284b106fb9SLee Jones { 7294b106fb9SLee Jones .name = "ab8500-regulator", 730*1c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8505-regulator", 7314b106fb9SLee Jones }, 7324b106fb9SLee Jones { 7339ee17676SUlf Hansson .name = "abx500-clk", 734*1c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-clk", 7359ee17676SUlf Hansson }, 7369ee17676SUlf Hansson { 7374b106fb9SLee Jones .name = "ab8500-gpadc", 738955de2eaSLee Jones .of_compatible = "stericsson,ab8500-gpadc", 7394b106fb9SLee Jones }, 7404b106fb9SLee Jones { 7414b106fb9SLee Jones .name = "ab8500-rtc", 742*1c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-rtc", 7434b106fb9SLee Jones }, 7444b106fb9SLee Jones { 7454b106fb9SLee Jones .name = "ab8500-acc-det", 746*1c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-acc-det", 7474b106fb9SLee Jones }, 7484b106fb9SLee Jones { 7494b106fb9SLee Jones .name = "ab8500-poweron-key", 750*1c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-poweron-key", 7514b106fb9SLee Jones }, 7524b106fb9SLee Jones { 7534b106fb9SLee Jones .name = "ab8500-pwm", 754*1c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-pwm", 7554b106fb9SLee Jones .id = 1, 7564b106fb9SLee Jones }, 7574b106fb9SLee Jones { 758eb696c31SLee Jones .name = "pinctrl-ab8505", 759*1c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8505-gpio", 7604b106fb9SLee Jones }, 7614b106fb9SLee Jones { 7624b106fb9SLee Jones .name = "ab8500-usb", 763*1c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-usb", 7644b106fb9SLee Jones }, 7654b106fb9SLee Jones { 7664b106fb9SLee Jones .name = "ab8500-codec", 767*1c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-codec", 7684b106fb9SLee Jones }, 769c0eda9aeSLee Jones { 770c0eda9aeSLee Jones .name = "ab-iddet", 771c0eda9aeSLee Jones }, 772c0eda9aeSLee Jones }; 773c0eda9aeSLee Jones 7745ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_devs[] = { 7754b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 7764b106fb9SLee Jones { 7774b106fb9SLee Jones .name = "ab8500-debug", 7784b106fb9SLee Jones }, 7794b106fb9SLee Jones #endif 7804b106fb9SLee Jones { 7814b106fb9SLee Jones .name = "ab8500-sysctrl", 7824b106fb9SLee Jones }, 7834b106fb9SLee Jones { 78453f325beSLee Jones .name = "ab8500-ext-regulator", 78553f325beSLee Jones }, 78653f325beSLee Jones { 7874b106fb9SLee Jones .name = "ab8500-regulator", 7884b106fb9SLee Jones }, 7894b106fb9SLee Jones { 7909ee17676SUlf Hansson .name = "abx500-clk", 7919ee17676SUlf Hansson .of_compatible = "stericsson,abx500-clk", 7929ee17676SUlf Hansson }, 7939ee17676SUlf Hansson { 7944b106fb9SLee Jones .name = "ab8500-gpadc", 795955de2eaSLee Jones .of_compatible = "stericsson,ab8500-gpadc", 7964b106fb9SLee Jones }, 7974b106fb9SLee Jones { 7984b106fb9SLee Jones .name = "ab8500-acc-det", 7994b106fb9SLee Jones }, 8004b106fb9SLee Jones { 8014b106fb9SLee Jones .name = "ab8500-poweron-key", 8024b106fb9SLee Jones }, 8034b106fb9SLee Jones { 8044b106fb9SLee Jones .name = "ab8500-pwm", 8054b106fb9SLee Jones .id = 1, 8064b106fb9SLee Jones }, 8074b106fb9SLee Jones { 8084b106fb9SLee Jones .name = "abx500-temp", 8094b106fb9SLee Jones }, 810c0eda9aeSLee Jones { 811eb696c31SLee Jones .name = "pinctrl-ab8540", 812c0eda9aeSLee Jones }, 813c0eda9aeSLee Jones { 814c0eda9aeSLee Jones .name = "ab8540-usb", 815c0eda9aeSLee Jones }, 816c0eda9aeSLee Jones { 817c0eda9aeSLee Jones .name = "ab8540-codec", 818c0eda9aeSLee Jones }, 819c0eda9aeSLee Jones { 82044f72e53SVirupax Sadashivpetimath .name = "ab-iddet", 82144f72e53SVirupax Sadashivpetimath }, 822d6255529SLinus Walleij }; 823d6255529SLinus Walleij 8245ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_cut1_devs[] = { 8259c717cf3SAlexandre Torgue { 8269c717cf3SAlexandre Torgue .name = "ab8500-rtc", 8279c717cf3SAlexandre Torgue .of_compatible = "stericsson,ab8500-rtc", 8289c717cf3SAlexandre Torgue }, 8299c717cf3SAlexandre Torgue }; 8309c717cf3SAlexandre Torgue 8315ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_cut2_devs[] = { 8329c717cf3SAlexandre Torgue { 8339c717cf3SAlexandre Torgue .name = "ab8540-rtc", 8349c717cf3SAlexandre Torgue .of_compatible = "stericsson,ab8540-rtc", 8359c717cf3SAlexandre Torgue }, 8369c717cf3SAlexandre Torgue }; 8379c717cf3SAlexandre Torgue 838cca69b67SMattias Wallin static ssize_t show_chip_id(struct device *dev, 839cca69b67SMattias Wallin struct device_attribute *attr, char *buf) 840cca69b67SMattias Wallin { 841cca69b67SMattias Wallin struct ab8500 *ab8500; 842cca69b67SMattias Wallin 843cca69b67SMattias Wallin ab8500 = dev_get_drvdata(dev); 844e436ddffSLee Jones 845cca69b67SMattias Wallin return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); 846cca69b67SMattias Wallin } 847cca69b67SMattias Wallin 848e5c238c3SMattias Wallin /* 849e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 850e5c238c3SMattias Wallin * 0x01 Swoff bit programming 851e5c238c3SMattias Wallin * 0x02 Thermal protection activation 852e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 853e5c238c3SMattias Wallin * 0x08 Watchdog expired 854e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 855e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 856e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 857e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 858e5c238c3SMattias Wallin */ 859e5c238c3SMattias Wallin static ssize_t show_switch_off_status(struct device *dev, 860e5c238c3SMattias Wallin struct device_attribute *attr, char *buf) 861e5c238c3SMattias Wallin { 862e5c238c3SMattias Wallin int ret; 863e5c238c3SMattias Wallin u8 value; 864e5c238c3SMattias Wallin struct ab8500 *ab8500; 865e5c238c3SMattias Wallin 866e5c238c3SMattias Wallin ab8500 = dev_get_drvdata(dev); 867e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 868e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 869e5c238c3SMattias Wallin if (ret < 0) 870e5c238c3SMattias Wallin return ret; 871e5c238c3SMattias Wallin return sprintf(buf, "%#x\n", value); 872e5c238c3SMattias Wallin } 873e5c238c3SMattias Wallin 874f04a9d8aSRajkumar Kasirajan /* use mask and set to override the register turn_on_stat value */ 875f04a9d8aSRajkumar Kasirajan void ab8500_override_turn_on_stat(u8 mask, u8 set) 876f04a9d8aSRajkumar Kasirajan { 877f04a9d8aSRajkumar Kasirajan spin_lock(&on_stat_lock); 878f04a9d8aSRajkumar Kasirajan turn_on_stat_mask = mask; 879f04a9d8aSRajkumar Kasirajan turn_on_stat_set = set; 880f04a9d8aSRajkumar Kasirajan spin_unlock(&on_stat_lock); 881f04a9d8aSRajkumar Kasirajan } 882f04a9d8aSRajkumar Kasirajan 883b4a31037SAndrew Lynn /* 884b4a31037SAndrew Lynn * ab8500 has turned on due to (TURN_ON_STATUS): 885b4a31037SAndrew Lynn * 0x01 PORnVbat 886b4a31037SAndrew Lynn * 0x02 PonKey1dbF 887b4a31037SAndrew Lynn * 0x04 PonKey2dbF 888b4a31037SAndrew Lynn * 0x08 RTCAlarm 889b4a31037SAndrew Lynn * 0x10 MainChDet 890b4a31037SAndrew Lynn * 0x20 VbusDet 891b4a31037SAndrew Lynn * 0x40 UsbIDDetect 892b4a31037SAndrew Lynn * 0x80 Reserved 893b4a31037SAndrew Lynn */ 894b4a31037SAndrew Lynn static ssize_t show_turn_on_status(struct device *dev, 895b4a31037SAndrew Lynn struct device_attribute *attr, char *buf) 896b4a31037SAndrew Lynn { 897b4a31037SAndrew Lynn int ret; 898b4a31037SAndrew Lynn u8 value; 899b4a31037SAndrew Lynn struct ab8500 *ab8500; 900b4a31037SAndrew Lynn 901b4a31037SAndrew Lynn ab8500 = dev_get_drvdata(dev); 902b4a31037SAndrew Lynn ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 903b4a31037SAndrew Lynn AB8500_TURN_ON_STATUS, &value); 904b4a31037SAndrew Lynn if (ret < 0) 905b4a31037SAndrew Lynn return ret; 906f04a9d8aSRajkumar Kasirajan 907f04a9d8aSRajkumar Kasirajan /* 908f04a9d8aSRajkumar Kasirajan * In L9540, turn_on_status register is not updated correctly if 909f04a9d8aSRajkumar Kasirajan * the device is rebooted with AC/USB charger connected. Due to 910f04a9d8aSRajkumar Kasirajan * this, the device boots android instead of entering into charge 911f04a9d8aSRajkumar Kasirajan * only mode. Read the AC/USB status register to detect the charger 912f04a9d8aSRajkumar Kasirajan * presence and update the turn on status manually. 913f04a9d8aSRajkumar Kasirajan */ 914f04a9d8aSRajkumar Kasirajan if (is_ab9540(ab8500)) { 915f04a9d8aSRajkumar Kasirajan spin_lock(&on_stat_lock); 916f04a9d8aSRajkumar Kasirajan value = (value & turn_on_stat_mask) | turn_on_stat_set; 917f04a9d8aSRajkumar Kasirajan spin_unlock(&on_stat_lock); 918f04a9d8aSRajkumar Kasirajan } 919f04a9d8aSRajkumar Kasirajan 920b4a31037SAndrew Lynn return sprintf(buf, "%#x\n", value); 921b4a31037SAndrew Lynn } 922b4a31037SAndrew Lynn 92393ff722eSLee Jones static ssize_t show_turn_on_status_2(struct device *dev, 92493ff722eSLee Jones struct device_attribute *attr, char *buf) 92593ff722eSLee Jones { 92693ff722eSLee Jones int ret; 92793ff722eSLee Jones u8 value; 92893ff722eSLee Jones struct ab8500 *ab8500; 92993ff722eSLee Jones 93093ff722eSLee Jones ab8500 = dev_get_drvdata(dev); 93193ff722eSLee Jones ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 93293ff722eSLee Jones AB8505_TURN_ON_STATUS_2, &value); 93393ff722eSLee Jones if (ret < 0) 93493ff722eSLee Jones return ret; 93593ff722eSLee Jones return sprintf(buf, "%#x\n", (value & 0x1)); 93693ff722eSLee Jones } 93793ff722eSLee Jones 938d6255529SLinus Walleij static ssize_t show_ab9540_dbbrstn(struct device *dev, 939d6255529SLinus Walleij struct device_attribute *attr, char *buf) 940d6255529SLinus Walleij { 941d6255529SLinus Walleij struct ab8500 *ab8500; 942d6255529SLinus Walleij int ret; 943d6255529SLinus Walleij u8 value; 944d6255529SLinus Walleij 945d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 946d6255529SLinus Walleij 947d6255529SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2, 948d6255529SLinus Walleij AB9540_MODEM_CTRL2_REG, &value); 949d6255529SLinus Walleij if (ret < 0) 950d6255529SLinus Walleij return ret; 951d6255529SLinus Walleij 952d6255529SLinus Walleij return sprintf(buf, "%d\n", 953d6255529SLinus Walleij (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0); 954d6255529SLinus Walleij } 955d6255529SLinus Walleij 956d6255529SLinus Walleij static ssize_t store_ab9540_dbbrstn(struct device *dev, 957d6255529SLinus Walleij struct device_attribute *attr, const char *buf, size_t count) 958d6255529SLinus Walleij { 959d6255529SLinus Walleij struct ab8500 *ab8500; 960d6255529SLinus Walleij int ret = count; 961d6255529SLinus Walleij int err; 962d6255529SLinus Walleij u8 bitvalues; 963d6255529SLinus Walleij 964d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 965d6255529SLinus Walleij 966d6255529SLinus Walleij if (count > 0) { 967d6255529SLinus Walleij switch (buf[0]) { 968d6255529SLinus Walleij case '0': 969d6255529SLinus Walleij bitvalues = 0; 970d6255529SLinus Walleij break; 971d6255529SLinus Walleij case '1': 972d6255529SLinus Walleij bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT; 973d6255529SLinus Walleij break; 974d6255529SLinus Walleij default: 975d6255529SLinus Walleij goto exit; 976d6255529SLinus Walleij } 977d6255529SLinus Walleij 978d6255529SLinus Walleij err = mask_and_set_register_interruptible(ab8500, 979d6255529SLinus Walleij AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG, 980d6255529SLinus Walleij AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues); 981d6255529SLinus Walleij if (err) 982d6255529SLinus Walleij dev_info(ab8500->dev, 983d6255529SLinus Walleij "Failed to set DBBRSTN %c, err %#x\n", 984d6255529SLinus Walleij buf[0], err); 985d6255529SLinus Walleij } 986d6255529SLinus Walleij 987d6255529SLinus Walleij exit: 988d6255529SLinus Walleij return ret; 989d6255529SLinus Walleij } 990d6255529SLinus Walleij 991cca69b67SMattias Wallin static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); 992e5c238c3SMattias Wallin static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL); 993b4a31037SAndrew Lynn static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL); 99493ff722eSLee Jones static DEVICE_ATTR(turn_on_status_2, S_IRUGO, show_turn_on_status_2, NULL); 995d6255529SLinus Walleij static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR, 996d6255529SLinus Walleij show_ab9540_dbbrstn, store_ab9540_dbbrstn); 997cca69b67SMattias Wallin 998cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = { 999cca69b67SMattias Wallin &dev_attr_chip_id.attr, 1000e5c238c3SMattias Wallin &dev_attr_switch_off_status.attr, 1001b4a31037SAndrew Lynn &dev_attr_turn_on_status.attr, 1002cca69b67SMattias Wallin NULL, 1003cca69b67SMattias Wallin }; 1004cca69b67SMattias Wallin 100593ff722eSLee Jones static struct attribute *ab8505_sysfs_entries[] = { 100693ff722eSLee Jones &dev_attr_turn_on_status_2.attr, 100793ff722eSLee Jones NULL, 100893ff722eSLee Jones }; 100993ff722eSLee Jones 1010d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = { 1011d6255529SLinus Walleij &dev_attr_chip_id.attr, 1012d6255529SLinus Walleij &dev_attr_switch_off_status.attr, 1013d6255529SLinus Walleij &dev_attr_turn_on_status.attr, 1014d6255529SLinus Walleij &dev_attr_dbbrstn.attr, 1015d6255529SLinus Walleij NULL, 1016d6255529SLinus Walleij }; 1017d6255529SLinus Walleij 101852557dc6SArvind Yadav static const struct attribute_group ab8500_attr_group = { 1019cca69b67SMattias Wallin .attrs = ab8500_sysfs_entries, 1020cca69b67SMattias Wallin }; 1021cca69b67SMattias Wallin 102252557dc6SArvind Yadav static const struct attribute_group ab8505_attr_group = { 102393ff722eSLee Jones .attrs = ab8505_sysfs_entries, 102493ff722eSLee Jones }; 102593ff722eSLee Jones 102652557dc6SArvind Yadav static const struct attribute_group ab9540_attr_group = { 1027d6255529SLinus Walleij .attrs = ab9540_sysfs_entries, 1028d6255529SLinus Walleij }; 1029d6255529SLinus Walleij 1030f791be49SBill Pemberton static int ab8500_probe(struct platform_device *pdev) 103162579266SRabin Vincent { 1032500e69a1SLee Jones static const char * const switch_off_status[] = { 1033b04c530cSJonas Aaberg "Swoff bit programming", 1034b04c530cSJonas Aaberg "Thermal protection activation", 1035b04c530cSJonas Aaberg "Vbat lower then BattOk falling threshold", 1036b04c530cSJonas Aaberg "Watchdog expired", 1037b04c530cSJonas Aaberg "Non presence of 32kHz clock", 1038b04c530cSJonas Aaberg "Battery level lower than power on reset threshold", 1039b04c530cSJonas Aaberg "Power on key 1 pressed longer than 10 seconds", 1040b04c530cSJonas Aaberg "DB8500 thermal shutdown"}; 1041500e69a1SLee Jones static const char * const turn_on_status[] = { 1042abee26cdSMattias Wallin "Battery rising (Vbat)", 1043abee26cdSMattias Wallin "Power On Key 1 dbF", 1044abee26cdSMattias Wallin "Power On Key 2 dbF", 1045abee26cdSMattias Wallin "RTC Alarm", 1046abee26cdSMattias Wallin "Main Charger Detect", 1047abee26cdSMattias Wallin "Vbus Detect (USB)", 1048abee26cdSMattias Wallin "USB ID Detect", 1049abee26cdSMattias Wallin "UART Factory Mode Detect"}; 1050d28f1db8SLee Jones const struct platform_device_id *platid = platform_get_device_id(pdev); 10516bc4a568SLee Jones enum ab8500_version version = AB8500_VERSION_UNDEFINED; 10526bc4a568SLee Jones struct device_node *np = pdev->dev.of_node; 1053d28f1db8SLee Jones struct ab8500 *ab8500; 1054d28f1db8SLee Jones struct resource *resource; 105562579266SRabin Vincent int ret; 105662579266SRabin Vincent int i; 105747c16975SMattias Wallin u8 value; 105862579266SRabin Vincent 10597ccf40b1SLee Jones ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL); 1060d28f1db8SLee Jones if (!ab8500) 1061d28f1db8SLee Jones return -ENOMEM; 1062d28f1db8SLee Jones 1063d28f1db8SLee Jones ab8500->dev = &pdev->dev; 1064d28f1db8SLee Jones 1065d28f1db8SLee Jones resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 1066f864c46aSLinus Walleij if (!resource) { 1067f864c46aSLinus Walleij dev_err(&pdev->dev, "no IRQ resource\n"); 10688c4203cbSLee Jones return -ENODEV; 1069f864c46aSLinus Walleij } 1070d28f1db8SLee Jones 1071d28f1db8SLee Jones ab8500->irq = resource->start; 1072d28f1db8SLee Jones 1073822672a7SLee Jones ab8500->read = ab8500_prcmu_read; 1074822672a7SLee Jones ab8500->write = ab8500_prcmu_write; 1075822672a7SLee Jones ab8500->write_masked = ab8500_prcmu_write_masked; 1076d28f1db8SLee Jones 107762579266SRabin Vincent mutex_init(&ab8500->lock); 107862579266SRabin Vincent mutex_init(&ab8500->irq_lock); 1079112a80d2SJonas Aaberg atomic_set(&ab8500->transfer_ongoing, 0); 108062579266SRabin Vincent 1081d28f1db8SLee Jones platform_set_drvdata(pdev, ab8500); 1082d28f1db8SLee Jones 10836bc4a568SLee Jones if (platid) 10846bc4a568SLee Jones version = platid->driver_data; 10856bc4a568SLee Jones 10860f620837SLinus Walleij if (version != AB8500_VERSION_UNDEFINED) 10870f620837SLinus Walleij ab8500->version = version; 10880f620837SLinus Walleij else { 10890f620837SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_MISC, 10900f620837SLinus Walleij AB8500_IC_NAME_REG, &value); 1091f864c46aSLinus Walleij if (ret < 0) { 1092f864c46aSLinus Walleij dev_err(&pdev->dev, "could not probe HW\n"); 10938c4203cbSLee Jones return ret; 1094f864c46aSLinus Walleij } 10950f620837SLinus Walleij 10960f620837SLinus Walleij ab8500->version = value; 10970f620837SLinus Walleij } 10980f620837SLinus Walleij 109947c16975SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_MISC, 110047c16975SMattias Wallin AB8500_REV_REG, &value); 110162579266SRabin Vincent if (ret < 0) 11028c4203cbSLee Jones return ret; 110362579266SRabin Vincent 110447c16975SMattias Wallin ab8500->chip_id = value; 110562579266SRabin Vincent 11060f620837SLinus Walleij dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n", 11070f620837SLinus Walleij ab8500_version_str[ab8500->version], 11080f620837SLinus Walleij ab8500->chip_id >> 4, 11090f620837SLinus Walleij ab8500->chip_id & 0x0F); 11100f620837SLinus Walleij 11113e1a498fSLee Jones /* Configure AB8540 */ 11123e1a498fSLee Jones if (is_ab8540(ab8500)) { 11133e1a498fSLee Jones ab8500->mask_size = AB8540_NUM_IRQ_REGS; 11143e1a498fSLee Jones ab8500->irq_reg_offset = ab8540_irq_regoffset; 11153e1a498fSLee Jones ab8500->it_latchhier_num = AB8540_IT_LATCHHIER_NUM; 11163e1a498fSLee Jones } /* Configure AB8500 or AB9540 IRQ */ 11173e1a498fSLee Jones else if (is_ab9540(ab8500) || is_ab8505(ab8500)) { 1118d6255529SLinus Walleij ab8500->mask_size = AB9540_NUM_IRQ_REGS; 1119d6255529SLinus Walleij ab8500->irq_reg_offset = ab9540_irq_regoffset; 11203e1a498fSLee Jones ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM; 1121d6255529SLinus Walleij } else { 11222ced445eSLinus Walleij ab8500->mask_size = AB8500_NUM_IRQ_REGS; 11232ced445eSLinus Walleij ab8500->irq_reg_offset = ab8500_irq_regoffset; 11243e1a498fSLee Jones ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM; 1125d6255529SLinus Walleij } 11267ccf40b1SLee Jones ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size, 11277ccf40b1SLee Jones GFP_KERNEL); 11282ced445eSLinus Walleij if (!ab8500->mask) 11292ced445eSLinus Walleij return -ENOMEM; 11307ccf40b1SLee Jones ab8500->oldmask = devm_kzalloc(&pdev->dev, ab8500->mask_size, 11317ccf40b1SLee Jones GFP_KERNEL); 11328c4203cbSLee Jones if (!ab8500->oldmask) 11338c4203cbSLee Jones return -ENOMEM; 11348c4203cbSLee Jones 1135e5c238c3SMattias Wallin /* 1136e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 1137e5c238c3SMattias Wallin * 0x01 Swoff bit programming 1138e5c238c3SMattias Wallin * 0x02 Thermal protection activation 1139e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 1140e5c238c3SMattias Wallin * 0x08 Watchdog expired 1141e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 1142e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 1143e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 1144e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 1145e5c238c3SMattias Wallin */ 1146e5c238c3SMattias Wallin 1147e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 1148e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 1149e5c238c3SMattias Wallin if (ret < 0) 1150e5c238c3SMattias Wallin return ret; 1151b04c530cSJonas Aaberg dev_info(ab8500->dev, "switch off cause(s) (%#x): ", value); 1152b04c530cSJonas Aaberg 1153b04c530cSJonas Aaberg if (value) { 1154b04c530cSJonas Aaberg for (i = 0; i < ARRAY_SIZE(switch_off_status); i++) { 1155b04c530cSJonas Aaberg if (value & 1) 11567ccf40b1SLee Jones pr_cont(" \"%s\"", switch_off_status[i]); 1157b04c530cSJonas Aaberg value = value >> 1; 1158b04c530cSJonas Aaberg 1159b04c530cSJonas Aaberg } 11607ccf40b1SLee Jones pr_cont("\n"); 1161b04c530cSJonas Aaberg } else { 11627ccf40b1SLee Jones pr_cont(" None\n"); 1163b04c530cSJonas Aaberg } 1164abee26cdSMattias Wallin ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 1165abee26cdSMattias Wallin AB8500_TURN_ON_STATUS, &value); 1166abee26cdSMattias Wallin if (ret < 0) 1167abee26cdSMattias Wallin return ret; 1168abee26cdSMattias Wallin dev_info(ab8500->dev, "turn on reason(s) (%#x): ", value); 1169abee26cdSMattias Wallin 1170abee26cdSMattias Wallin if (value) { 1171abee26cdSMattias Wallin for (i = 0; i < ARRAY_SIZE(turn_on_status); i++) { 1172abee26cdSMattias Wallin if (value & 1) 11737ccf40b1SLee Jones pr_cont("\"%s\" ", turn_on_status[i]); 1174abee26cdSMattias Wallin value = value >> 1; 1175abee26cdSMattias Wallin } 11767ccf40b1SLee Jones pr_cont("\n"); 1177abee26cdSMattias Wallin } else { 11787ccf40b1SLee Jones pr_cont("None\n"); 1179abee26cdSMattias Wallin } 1180e5c238c3SMattias Wallin 1181f04a9d8aSRajkumar Kasirajan if (is_ab9540(ab8500)) { 1182f04a9d8aSRajkumar Kasirajan ret = get_register_interruptible(ab8500, AB8500_CHARGER, 1183f04a9d8aSRajkumar Kasirajan AB8500_CH_USBCH_STAT1_REG, &value); 1184f04a9d8aSRajkumar Kasirajan if (ret < 0) 1185f04a9d8aSRajkumar Kasirajan return ret; 1186f04a9d8aSRajkumar Kasirajan if ((value & VBUS_DET_DBNC1) && (value & VBUS_DET_DBNC100)) 1187f04a9d8aSRajkumar Kasirajan ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON, 1188f04a9d8aSRajkumar Kasirajan AB8500_VBUS_DET); 1189f04a9d8aSRajkumar Kasirajan } 119062579266SRabin Vincent 119162579266SRabin Vincent /* Clear and mask all interrupts */ 11922ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 11930f620837SLinus Walleij /* 11940f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 11950f620837SLinus Walleij * 2.0 11960f620837SLinus Walleij */ 11970f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 11980f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 119992d50a41SMattias Wallin continue; 120062579266SRabin Vincent 12013e1a498fSLee Jones if (ab8500->irq_reg_offset[i] < 0) 12023e1a498fSLee Jones continue; 12033e1a498fSLee Jones 120447c16975SMattias Wallin get_register_interruptible(ab8500, AB8500_INTERRUPT, 12052ced445eSLinus Walleij AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i], 120692d50a41SMattias Wallin &value); 120747c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, 12082ced445eSLinus Walleij AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff); 120962579266SRabin Vincent } 121062579266SRabin Vincent 121147c16975SMattias Wallin ret = abx500_register_ops(ab8500->dev, &ab8500_ops); 121247c16975SMattias Wallin if (ret) 12138c4203cbSLee Jones return ret; 121447c16975SMattias Wallin 12152ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) 121662579266SRabin Vincent ab8500->mask[i] = ab8500->oldmask[i] = 0xff; 121762579266SRabin Vincent 121806e589efSLee Jones ret = ab8500_irq_init(ab8500, np); 121962579266SRabin Vincent if (ret) 12208c4203cbSLee Jones return ret; 122162579266SRabin Vincent 12228c4203cbSLee Jones ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL, 12237ccfe9b1SMichel JAOUEN ab8500_hierarchical_irq, 12247ccfe9b1SMichel JAOUEN IRQF_ONESHOT | IRQF_NO_SUSPEND, 12257ccfe9b1SMichel JAOUEN "ab8500", ab8500); 122662579266SRabin Vincent if (ret) 12278c4203cbSLee Jones return ret; 122862579266SRabin Vincent 1229d6255529SLinus Walleij if (is_ab9540(ab8500)) 1230d6255529SLinus Walleij ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, 1231d6255529SLinus Walleij ARRAY_SIZE(ab9540_devs), NULL, 1232f864c46aSLinus Walleij 0, ab8500->domain); 12339c717cf3SAlexandre Torgue else if (is_ab8540(ab8500)) { 1234c0eda9aeSLee Jones ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs, 1235c0eda9aeSLee Jones ARRAY_SIZE(ab8540_devs), NULL, 1236f864c46aSLinus Walleij 0, ab8500->domain); 12379c717cf3SAlexandre Torgue if (ret) 12389c717cf3SAlexandre Torgue return ret; 12399c717cf3SAlexandre Torgue 12409c717cf3SAlexandre Torgue if (is_ab8540_1p2_or_earlier(ab8500)) 12419c717cf3SAlexandre Torgue ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut1_devs, 12429c717cf3SAlexandre Torgue ARRAY_SIZE(ab8540_cut1_devs), NULL, 1243f864c46aSLinus Walleij 0, ab8500->domain); 12449c717cf3SAlexandre Torgue else /* ab8540 >= cut2 */ 12459c717cf3SAlexandre Torgue ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut2_devs, 12469c717cf3SAlexandre Torgue ARRAY_SIZE(ab8540_cut2_devs), NULL, 1247f864c46aSLinus Walleij 0, ab8500->domain); 12489c717cf3SAlexandre Torgue } else if (is_ab8505(ab8500)) 1249c0eda9aeSLee Jones ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs, 1250c0eda9aeSLee Jones ARRAY_SIZE(ab8505_devs), NULL, 1251f864c46aSLinus Walleij 0, ab8500->domain); 1252d6255529SLinus Walleij else 1253549931f9SSundar R Iyer ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, 125444f72e53SVirupax Sadashivpetimath ARRAY_SIZE(ab8500_devs), NULL, 1255f864c46aSLinus Walleij 0, ab8500->domain); 12566bc4a568SLee Jones if (ret) 12578c4203cbSLee Jones return ret; 125844f72e53SVirupax Sadashivpetimath 12596ef9418cSRickard Andersson if (!no_bm) { 12606ef9418cSRickard Andersson /* Add battery management devices */ 12616ef9418cSRickard Andersson ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, 12626ef9418cSRickard Andersson ARRAY_SIZE(ab8500_bm_devs), NULL, 1263f864c46aSLinus Walleij 0, ab8500->domain); 12646ef9418cSRickard Andersson if (ret) 12656ef9418cSRickard Andersson dev_err(ab8500->dev, "error adding bm devices\n"); 12666ef9418cSRickard Andersson } 12676ef9418cSRickard Andersson 1268e436ddffSLee Jones if (((is_ab8505(ab8500) || is_ab9540(ab8500)) && 1269e436ddffSLee Jones ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500)) 1270d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1271d6255529SLinus Walleij &ab9540_attr_group); 1272d6255529SLinus Walleij else 1273d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1274d6255529SLinus Walleij &ab8500_attr_group); 127593ff722eSLee Jones 127693ff722eSLee Jones if ((is_ab8505(ab8500) || is_ab9540(ab8500)) && 127793ff722eSLee Jones ab8500->chip_id >= AB8500_CUT2P0) 127893ff722eSLee Jones ret = sysfs_create_group(&ab8500->dev->kobj, 127993ff722eSLee Jones &ab8505_attr_group); 128093ff722eSLee Jones 1281cca69b67SMattias Wallin if (ret) 1282cca69b67SMattias Wallin dev_err(ab8500->dev, "error creating sysfs entries\n"); 128306e589efSLee Jones 128462579266SRabin Vincent return ret; 128562579266SRabin Vincent } 128662579266SRabin Vincent 1287d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = { 1288d28f1db8SLee Jones { "ab8500-core", AB8500_VERSION_AB8500 }, 1289*1c0769d2SStephan Gerhold { "ab8505-core", AB8500_VERSION_AB8505 }, 1290d28f1db8SLee Jones { "ab9540-i2c", AB8500_VERSION_AB9540 }, 1291d28f1db8SLee Jones { "ab8540-i2c", AB8500_VERSION_AB8540 }, 1292d28f1db8SLee Jones { } 1293d28f1db8SLee Jones }; 1294d28f1db8SLee Jones 1295d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = { 1296d28f1db8SLee Jones .driver = { 1297d28f1db8SLee Jones .name = "ab8500-core", 129831cbae22SPaul Gortmaker .suppress_bind_attrs = true, 1299d28f1db8SLee Jones }, 1300d28f1db8SLee Jones .probe = ab8500_probe, 1301d28f1db8SLee Jones .id_table = ab8500_id, 1302d28f1db8SLee Jones }; 1303d28f1db8SLee Jones 1304d28f1db8SLee Jones static int __init ab8500_core_init(void) 1305d28f1db8SLee Jones { 1306d28f1db8SLee Jones return platform_driver_register(&ab8500_core_driver); 1307d28f1db8SLee Jones } 1308ba7cbc3eSLee Jones core_initcall(ab8500_core_init); 1309