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[] = { 613*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-charger", NULL, &ab8500_bm_data, 614*f4d41ad8SLee Jones sizeof(ab8500_bm_data), 0, "stericsson,ab8500-charger"), 615*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-btemp", NULL, &ab8500_bm_data, 616*f4d41ad8SLee Jones sizeof(ab8500_bm_data), 0, "stericsson,ab8500-btemp"), 617*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-fg", NULL, &ab8500_bm_data, 618*f4d41ad8SLee Jones sizeof(ab8500_bm_data), 0, "stericsson,ab8500-fg"), 619*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-chargalg", NULL, &ab8500_bm_data, 620*f4d41ad8SLee 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 625*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-debug", 626*f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-debug"), 6274b106fb9SLee Jones #endif 628*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-sysctrl", 629*f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-sysctrl"), 630*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-ext-regulator", 631*f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-ext-regulator"), 632*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-regulator", 633*f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-regulator"), 634*f4d41ad8SLee Jones OF_MFD_CELL("abx500-clk", 635*f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,abx500-clk"), 636*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-gpadc", 637*f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-gpadc"), 638*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-rtc", 639*f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-rtc"), 640*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-acc-det", 641*f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-acc-det"), 642*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-poweron-key", 643*f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-poweron-key"), 644*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-pwm", 645*f4d41ad8SLee Jones NULL, NULL, 0, 1, "stericsson,ab8500-pwm"), 646*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-pwm", 647*f4d41ad8SLee Jones NULL, NULL, 0, 2, "stericsson,ab8500-pwm"), 648*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-pwm", 649*f4d41ad8SLee Jones NULL, NULL, 0, 3, "stericsson,ab8500-pwm"), 650*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-denc", 651*f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-denc"), 652*f4d41ad8SLee Jones OF_MFD_CELL("pinctrl-ab8500", 653*f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-gpio"), 654*f4d41ad8SLee Jones OF_MFD_CELL("abx500-temp", 655*f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,abx500-temp"), 656*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-usb", 657*f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-usb"), 658*f4d41ad8SLee Jones OF_MFD_CELL("ab8500-codec", 659*f4d41ad8SLee 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", 7214b106fb9SLee Jones }, 7224b106fb9SLee Jones #endif 7234b106fb9SLee Jones { 7244b106fb9SLee Jones .name = "ab8500-sysctrl", 7254b106fb9SLee Jones }, 7264b106fb9SLee Jones { 7274b106fb9SLee Jones .name = "ab8500-regulator", 7284b106fb9SLee Jones }, 7294b106fb9SLee Jones { 7309ee17676SUlf Hansson .name = "abx500-clk", 7319ee17676SUlf Hansson .of_compatible = "stericsson,abx500-clk", 7329ee17676SUlf Hansson }, 7339ee17676SUlf Hansson { 7344b106fb9SLee Jones .name = "ab8500-gpadc", 735955de2eaSLee Jones .of_compatible = "stericsson,ab8500-gpadc", 7364b106fb9SLee Jones }, 7374b106fb9SLee Jones { 7384b106fb9SLee Jones .name = "ab8500-rtc", 7394b106fb9SLee Jones }, 7404b106fb9SLee Jones { 7414b106fb9SLee Jones .name = "ab8500-acc-det", 7424b106fb9SLee Jones }, 7434b106fb9SLee Jones { 7444b106fb9SLee Jones .name = "ab8500-poweron-key", 7454b106fb9SLee Jones }, 7464b106fb9SLee Jones { 7474b106fb9SLee Jones .name = "ab8500-pwm", 7484b106fb9SLee Jones .id = 1, 7494b106fb9SLee Jones }, 7504b106fb9SLee Jones { 751eb696c31SLee Jones .name = "pinctrl-ab8505", 7524b106fb9SLee Jones }, 7534b106fb9SLee Jones { 7544b106fb9SLee Jones .name = "ab8500-usb", 7554b106fb9SLee Jones }, 7564b106fb9SLee Jones { 7574b106fb9SLee Jones .name = "ab8500-codec", 7584b106fb9SLee Jones }, 759c0eda9aeSLee Jones { 760c0eda9aeSLee Jones .name = "ab-iddet", 761c0eda9aeSLee Jones }, 762c0eda9aeSLee Jones }; 763c0eda9aeSLee Jones 7645ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_devs[] = { 7654b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 7664b106fb9SLee Jones { 7674b106fb9SLee Jones .name = "ab8500-debug", 7684b106fb9SLee Jones }, 7694b106fb9SLee Jones #endif 7704b106fb9SLee Jones { 7714b106fb9SLee Jones .name = "ab8500-sysctrl", 7724b106fb9SLee Jones }, 7734b106fb9SLee Jones { 77453f325beSLee Jones .name = "ab8500-ext-regulator", 77553f325beSLee Jones }, 77653f325beSLee Jones { 7774b106fb9SLee Jones .name = "ab8500-regulator", 7784b106fb9SLee Jones }, 7794b106fb9SLee Jones { 7809ee17676SUlf Hansson .name = "abx500-clk", 7819ee17676SUlf Hansson .of_compatible = "stericsson,abx500-clk", 7829ee17676SUlf Hansson }, 7839ee17676SUlf Hansson { 7844b106fb9SLee Jones .name = "ab8500-gpadc", 785955de2eaSLee Jones .of_compatible = "stericsson,ab8500-gpadc", 7864b106fb9SLee Jones }, 7874b106fb9SLee Jones { 7884b106fb9SLee Jones .name = "ab8500-acc-det", 7894b106fb9SLee Jones }, 7904b106fb9SLee Jones { 7914b106fb9SLee Jones .name = "ab8500-poweron-key", 7924b106fb9SLee Jones }, 7934b106fb9SLee Jones { 7944b106fb9SLee Jones .name = "ab8500-pwm", 7954b106fb9SLee Jones .id = 1, 7964b106fb9SLee Jones }, 7974b106fb9SLee Jones { 7984b106fb9SLee Jones .name = "abx500-temp", 7994b106fb9SLee Jones }, 800c0eda9aeSLee Jones { 801eb696c31SLee Jones .name = "pinctrl-ab8540", 802c0eda9aeSLee Jones }, 803c0eda9aeSLee Jones { 804c0eda9aeSLee Jones .name = "ab8540-usb", 805c0eda9aeSLee Jones }, 806c0eda9aeSLee Jones { 807c0eda9aeSLee Jones .name = "ab8540-codec", 808c0eda9aeSLee Jones }, 809c0eda9aeSLee Jones { 81044f72e53SVirupax Sadashivpetimath .name = "ab-iddet", 81144f72e53SVirupax Sadashivpetimath }, 812d6255529SLinus Walleij }; 813d6255529SLinus Walleij 8145ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_cut1_devs[] = { 8159c717cf3SAlexandre Torgue { 8169c717cf3SAlexandre Torgue .name = "ab8500-rtc", 8179c717cf3SAlexandre Torgue .of_compatible = "stericsson,ab8500-rtc", 8189c717cf3SAlexandre Torgue }, 8199c717cf3SAlexandre Torgue }; 8209c717cf3SAlexandre Torgue 8215ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_cut2_devs[] = { 8229c717cf3SAlexandre Torgue { 8239c717cf3SAlexandre Torgue .name = "ab8540-rtc", 8249c717cf3SAlexandre Torgue .of_compatible = "stericsson,ab8540-rtc", 8259c717cf3SAlexandre Torgue }, 8269c717cf3SAlexandre Torgue }; 8279c717cf3SAlexandre Torgue 828cca69b67SMattias Wallin static ssize_t show_chip_id(struct device *dev, 829cca69b67SMattias Wallin struct device_attribute *attr, char *buf) 830cca69b67SMattias Wallin { 831cca69b67SMattias Wallin struct ab8500 *ab8500; 832cca69b67SMattias Wallin 833cca69b67SMattias Wallin ab8500 = dev_get_drvdata(dev); 834e436ddffSLee Jones 835cca69b67SMattias Wallin return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); 836cca69b67SMattias Wallin } 837cca69b67SMattias Wallin 838e5c238c3SMattias Wallin /* 839e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 840e5c238c3SMattias Wallin * 0x01 Swoff bit programming 841e5c238c3SMattias Wallin * 0x02 Thermal protection activation 842e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 843e5c238c3SMattias Wallin * 0x08 Watchdog expired 844e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 845e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 846e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 847e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 848e5c238c3SMattias Wallin */ 849e5c238c3SMattias Wallin static ssize_t show_switch_off_status(struct device *dev, 850e5c238c3SMattias Wallin struct device_attribute *attr, char *buf) 851e5c238c3SMattias Wallin { 852e5c238c3SMattias Wallin int ret; 853e5c238c3SMattias Wallin u8 value; 854e5c238c3SMattias Wallin struct ab8500 *ab8500; 855e5c238c3SMattias Wallin 856e5c238c3SMattias Wallin ab8500 = dev_get_drvdata(dev); 857e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 858e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 859e5c238c3SMattias Wallin if (ret < 0) 860e5c238c3SMattias Wallin return ret; 861e5c238c3SMattias Wallin return sprintf(buf, "%#x\n", value); 862e5c238c3SMattias Wallin } 863e5c238c3SMattias Wallin 864f04a9d8aSRajkumar Kasirajan /* use mask and set to override the register turn_on_stat value */ 865f04a9d8aSRajkumar Kasirajan void ab8500_override_turn_on_stat(u8 mask, u8 set) 866f04a9d8aSRajkumar Kasirajan { 867f04a9d8aSRajkumar Kasirajan spin_lock(&on_stat_lock); 868f04a9d8aSRajkumar Kasirajan turn_on_stat_mask = mask; 869f04a9d8aSRajkumar Kasirajan turn_on_stat_set = set; 870f04a9d8aSRajkumar Kasirajan spin_unlock(&on_stat_lock); 871f04a9d8aSRajkumar Kasirajan } 872f04a9d8aSRajkumar Kasirajan 873b4a31037SAndrew Lynn /* 874b4a31037SAndrew Lynn * ab8500 has turned on due to (TURN_ON_STATUS): 875b4a31037SAndrew Lynn * 0x01 PORnVbat 876b4a31037SAndrew Lynn * 0x02 PonKey1dbF 877b4a31037SAndrew Lynn * 0x04 PonKey2dbF 878b4a31037SAndrew Lynn * 0x08 RTCAlarm 879b4a31037SAndrew Lynn * 0x10 MainChDet 880b4a31037SAndrew Lynn * 0x20 VbusDet 881b4a31037SAndrew Lynn * 0x40 UsbIDDetect 882b4a31037SAndrew Lynn * 0x80 Reserved 883b4a31037SAndrew Lynn */ 884b4a31037SAndrew Lynn static ssize_t show_turn_on_status(struct device *dev, 885b4a31037SAndrew Lynn struct device_attribute *attr, char *buf) 886b4a31037SAndrew Lynn { 887b4a31037SAndrew Lynn int ret; 888b4a31037SAndrew Lynn u8 value; 889b4a31037SAndrew Lynn struct ab8500 *ab8500; 890b4a31037SAndrew Lynn 891b4a31037SAndrew Lynn ab8500 = dev_get_drvdata(dev); 892b4a31037SAndrew Lynn ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 893b4a31037SAndrew Lynn AB8500_TURN_ON_STATUS, &value); 894b4a31037SAndrew Lynn if (ret < 0) 895b4a31037SAndrew Lynn return ret; 896f04a9d8aSRajkumar Kasirajan 897f04a9d8aSRajkumar Kasirajan /* 898f04a9d8aSRajkumar Kasirajan * In L9540, turn_on_status register is not updated correctly if 899f04a9d8aSRajkumar Kasirajan * the device is rebooted with AC/USB charger connected. Due to 900f04a9d8aSRajkumar Kasirajan * this, the device boots android instead of entering into charge 901f04a9d8aSRajkumar Kasirajan * only mode. Read the AC/USB status register to detect the charger 902f04a9d8aSRajkumar Kasirajan * presence and update the turn on status manually. 903f04a9d8aSRajkumar Kasirajan */ 904f04a9d8aSRajkumar Kasirajan if (is_ab9540(ab8500)) { 905f04a9d8aSRajkumar Kasirajan spin_lock(&on_stat_lock); 906f04a9d8aSRajkumar Kasirajan value = (value & turn_on_stat_mask) | turn_on_stat_set; 907f04a9d8aSRajkumar Kasirajan spin_unlock(&on_stat_lock); 908f04a9d8aSRajkumar Kasirajan } 909f04a9d8aSRajkumar Kasirajan 910b4a31037SAndrew Lynn return sprintf(buf, "%#x\n", value); 911b4a31037SAndrew Lynn } 912b4a31037SAndrew Lynn 91393ff722eSLee Jones static ssize_t show_turn_on_status_2(struct device *dev, 91493ff722eSLee Jones struct device_attribute *attr, char *buf) 91593ff722eSLee Jones { 91693ff722eSLee Jones int ret; 91793ff722eSLee Jones u8 value; 91893ff722eSLee Jones struct ab8500 *ab8500; 91993ff722eSLee Jones 92093ff722eSLee Jones ab8500 = dev_get_drvdata(dev); 92193ff722eSLee Jones ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 92293ff722eSLee Jones AB8505_TURN_ON_STATUS_2, &value); 92393ff722eSLee Jones if (ret < 0) 92493ff722eSLee Jones return ret; 92593ff722eSLee Jones return sprintf(buf, "%#x\n", (value & 0x1)); 92693ff722eSLee Jones } 92793ff722eSLee Jones 928d6255529SLinus Walleij static ssize_t show_ab9540_dbbrstn(struct device *dev, 929d6255529SLinus Walleij struct device_attribute *attr, char *buf) 930d6255529SLinus Walleij { 931d6255529SLinus Walleij struct ab8500 *ab8500; 932d6255529SLinus Walleij int ret; 933d6255529SLinus Walleij u8 value; 934d6255529SLinus Walleij 935d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 936d6255529SLinus Walleij 937d6255529SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2, 938d6255529SLinus Walleij AB9540_MODEM_CTRL2_REG, &value); 939d6255529SLinus Walleij if (ret < 0) 940d6255529SLinus Walleij return ret; 941d6255529SLinus Walleij 942d6255529SLinus Walleij return sprintf(buf, "%d\n", 943d6255529SLinus Walleij (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0); 944d6255529SLinus Walleij } 945d6255529SLinus Walleij 946d6255529SLinus Walleij static ssize_t store_ab9540_dbbrstn(struct device *dev, 947d6255529SLinus Walleij struct device_attribute *attr, const char *buf, size_t count) 948d6255529SLinus Walleij { 949d6255529SLinus Walleij struct ab8500 *ab8500; 950d6255529SLinus Walleij int ret = count; 951d6255529SLinus Walleij int err; 952d6255529SLinus Walleij u8 bitvalues; 953d6255529SLinus Walleij 954d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 955d6255529SLinus Walleij 956d6255529SLinus Walleij if (count > 0) { 957d6255529SLinus Walleij switch (buf[0]) { 958d6255529SLinus Walleij case '0': 959d6255529SLinus Walleij bitvalues = 0; 960d6255529SLinus Walleij break; 961d6255529SLinus Walleij case '1': 962d6255529SLinus Walleij bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT; 963d6255529SLinus Walleij break; 964d6255529SLinus Walleij default: 965d6255529SLinus Walleij goto exit; 966d6255529SLinus Walleij } 967d6255529SLinus Walleij 968d6255529SLinus Walleij err = mask_and_set_register_interruptible(ab8500, 969d6255529SLinus Walleij AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG, 970d6255529SLinus Walleij AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues); 971d6255529SLinus Walleij if (err) 972d6255529SLinus Walleij dev_info(ab8500->dev, 973d6255529SLinus Walleij "Failed to set DBBRSTN %c, err %#x\n", 974d6255529SLinus Walleij buf[0], err); 975d6255529SLinus Walleij } 976d6255529SLinus Walleij 977d6255529SLinus Walleij exit: 978d6255529SLinus Walleij return ret; 979d6255529SLinus Walleij } 980d6255529SLinus Walleij 981cca69b67SMattias Wallin static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); 982e5c238c3SMattias Wallin static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL); 983b4a31037SAndrew Lynn static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL); 98493ff722eSLee Jones static DEVICE_ATTR(turn_on_status_2, S_IRUGO, show_turn_on_status_2, NULL); 985d6255529SLinus Walleij static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR, 986d6255529SLinus Walleij show_ab9540_dbbrstn, store_ab9540_dbbrstn); 987cca69b67SMattias Wallin 988cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = { 989cca69b67SMattias Wallin &dev_attr_chip_id.attr, 990e5c238c3SMattias Wallin &dev_attr_switch_off_status.attr, 991b4a31037SAndrew Lynn &dev_attr_turn_on_status.attr, 992cca69b67SMattias Wallin NULL, 993cca69b67SMattias Wallin }; 994cca69b67SMattias Wallin 99593ff722eSLee Jones static struct attribute *ab8505_sysfs_entries[] = { 99693ff722eSLee Jones &dev_attr_turn_on_status_2.attr, 99793ff722eSLee Jones NULL, 99893ff722eSLee Jones }; 99993ff722eSLee Jones 1000d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = { 1001d6255529SLinus Walleij &dev_attr_chip_id.attr, 1002d6255529SLinus Walleij &dev_attr_switch_off_status.attr, 1003d6255529SLinus Walleij &dev_attr_turn_on_status.attr, 1004d6255529SLinus Walleij &dev_attr_dbbrstn.attr, 1005d6255529SLinus Walleij NULL, 1006d6255529SLinus Walleij }; 1007d6255529SLinus Walleij 100852557dc6SArvind Yadav static const struct attribute_group ab8500_attr_group = { 1009cca69b67SMattias Wallin .attrs = ab8500_sysfs_entries, 1010cca69b67SMattias Wallin }; 1011cca69b67SMattias Wallin 101252557dc6SArvind Yadav static const struct attribute_group ab8505_attr_group = { 101393ff722eSLee Jones .attrs = ab8505_sysfs_entries, 101493ff722eSLee Jones }; 101593ff722eSLee Jones 101652557dc6SArvind Yadav static const struct attribute_group ab9540_attr_group = { 1017d6255529SLinus Walleij .attrs = ab9540_sysfs_entries, 1018d6255529SLinus Walleij }; 1019d6255529SLinus Walleij 1020f791be49SBill Pemberton static int ab8500_probe(struct platform_device *pdev) 102162579266SRabin Vincent { 1022500e69a1SLee Jones static const char * const switch_off_status[] = { 1023b04c530cSJonas Aaberg "Swoff bit programming", 1024b04c530cSJonas Aaberg "Thermal protection activation", 1025b04c530cSJonas Aaberg "Vbat lower then BattOk falling threshold", 1026b04c530cSJonas Aaberg "Watchdog expired", 1027b04c530cSJonas Aaberg "Non presence of 32kHz clock", 1028b04c530cSJonas Aaberg "Battery level lower than power on reset threshold", 1029b04c530cSJonas Aaberg "Power on key 1 pressed longer than 10 seconds", 1030b04c530cSJonas Aaberg "DB8500 thermal shutdown"}; 1031500e69a1SLee Jones static const char * const turn_on_status[] = { 1032abee26cdSMattias Wallin "Battery rising (Vbat)", 1033abee26cdSMattias Wallin "Power On Key 1 dbF", 1034abee26cdSMattias Wallin "Power On Key 2 dbF", 1035abee26cdSMattias Wallin "RTC Alarm", 1036abee26cdSMattias Wallin "Main Charger Detect", 1037abee26cdSMattias Wallin "Vbus Detect (USB)", 1038abee26cdSMattias Wallin "USB ID Detect", 1039abee26cdSMattias Wallin "UART Factory Mode Detect"}; 1040d28f1db8SLee Jones const struct platform_device_id *platid = platform_get_device_id(pdev); 10416bc4a568SLee Jones enum ab8500_version version = AB8500_VERSION_UNDEFINED; 10426bc4a568SLee Jones struct device_node *np = pdev->dev.of_node; 1043d28f1db8SLee Jones struct ab8500 *ab8500; 1044d28f1db8SLee Jones struct resource *resource; 104562579266SRabin Vincent int ret; 104662579266SRabin Vincent int i; 104747c16975SMattias Wallin u8 value; 104862579266SRabin Vincent 10497ccf40b1SLee Jones ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL); 1050d28f1db8SLee Jones if (!ab8500) 1051d28f1db8SLee Jones return -ENOMEM; 1052d28f1db8SLee Jones 1053d28f1db8SLee Jones ab8500->dev = &pdev->dev; 1054d28f1db8SLee Jones 1055d28f1db8SLee Jones resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 1056f864c46aSLinus Walleij if (!resource) { 1057f864c46aSLinus Walleij dev_err(&pdev->dev, "no IRQ resource\n"); 10588c4203cbSLee Jones return -ENODEV; 1059f864c46aSLinus Walleij } 1060d28f1db8SLee Jones 1061d28f1db8SLee Jones ab8500->irq = resource->start; 1062d28f1db8SLee Jones 1063822672a7SLee Jones ab8500->read = ab8500_prcmu_read; 1064822672a7SLee Jones ab8500->write = ab8500_prcmu_write; 1065822672a7SLee Jones ab8500->write_masked = ab8500_prcmu_write_masked; 1066d28f1db8SLee Jones 106762579266SRabin Vincent mutex_init(&ab8500->lock); 106862579266SRabin Vincent mutex_init(&ab8500->irq_lock); 1069112a80d2SJonas Aaberg atomic_set(&ab8500->transfer_ongoing, 0); 107062579266SRabin Vincent 1071d28f1db8SLee Jones platform_set_drvdata(pdev, ab8500); 1072d28f1db8SLee Jones 10736bc4a568SLee Jones if (platid) 10746bc4a568SLee Jones version = platid->driver_data; 10756bc4a568SLee Jones 10760f620837SLinus Walleij if (version != AB8500_VERSION_UNDEFINED) 10770f620837SLinus Walleij ab8500->version = version; 10780f620837SLinus Walleij else { 10790f620837SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_MISC, 10800f620837SLinus Walleij AB8500_IC_NAME_REG, &value); 1081f864c46aSLinus Walleij if (ret < 0) { 1082f864c46aSLinus Walleij dev_err(&pdev->dev, "could not probe HW\n"); 10838c4203cbSLee Jones return ret; 1084f864c46aSLinus Walleij } 10850f620837SLinus Walleij 10860f620837SLinus Walleij ab8500->version = value; 10870f620837SLinus Walleij } 10880f620837SLinus Walleij 108947c16975SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_MISC, 109047c16975SMattias Wallin AB8500_REV_REG, &value); 109162579266SRabin Vincent if (ret < 0) 10928c4203cbSLee Jones return ret; 109362579266SRabin Vincent 109447c16975SMattias Wallin ab8500->chip_id = value; 109562579266SRabin Vincent 10960f620837SLinus Walleij dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n", 10970f620837SLinus Walleij ab8500_version_str[ab8500->version], 10980f620837SLinus Walleij ab8500->chip_id >> 4, 10990f620837SLinus Walleij ab8500->chip_id & 0x0F); 11000f620837SLinus Walleij 11013e1a498fSLee Jones /* Configure AB8540 */ 11023e1a498fSLee Jones if (is_ab8540(ab8500)) { 11033e1a498fSLee Jones ab8500->mask_size = AB8540_NUM_IRQ_REGS; 11043e1a498fSLee Jones ab8500->irq_reg_offset = ab8540_irq_regoffset; 11053e1a498fSLee Jones ab8500->it_latchhier_num = AB8540_IT_LATCHHIER_NUM; 11063e1a498fSLee Jones } /* Configure AB8500 or AB9540 IRQ */ 11073e1a498fSLee Jones else if (is_ab9540(ab8500) || is_ab8505(ab8500)) { 1108d6255529SLinus Walleij ab8500->mask_size = AB9540_NUM_IRQ_REGS; 1109d6255529SLinus Walleij ab8500->irq_reg_offset = ab9540_irq_regoffset; 11103e1a498fSLee Jones ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM; 1111d6255529SLinus Walleij } else { 11122ced445eSLinus Walleij ab8500->mask_size = AB8500_NUM_IRQ_REGS; 11132ced445eSLinus Walleij ab8500->irq_reg_offset = ab8500_irq_regoffset; 11143e1a498fSLee Jones ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM; 1115d6255529SLinus Walleij } 11167ccf40b1SLee Jones ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size, 11177ccf40b1SLee Jones GFP_KERNEL); 11182ced445eSLinus Walleij if (!ab8500->mask) 11192ced445eSLinus Walleij return -ENOMEM; 11207ccf40b1SLee Jones ab8500->oldmask = devm_kzalloc(&pdev->dev, ab8500->mask_size, 11217ccf40b1SLee Jones GFP_KERNEL); 11228c4203cbSLee Jones if (!ab8500->oldmask) 11238c4203cbSLee Jones return -ENOMEM; 11248c4203cbSLee Jones 1125e5c238c3SMattias Wallin /* 1126e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 1127e5c238c3SMattias Wallin * 0x01 Swoff bit programming 1128e5c238c3SMattias Wallin * 0x02 Thermal protection activation 1129e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 1130e5c238c3SMattias Wallin * 0x08 Watchdog expired 1131e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 1132e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 1133e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 1134e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 1135e5c238c3SMattias Wallin */ 1136e5c238c3SMattias Wallin 1137e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 1138e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 1139e5c238c3SMattias Wallin if (ret < 0) 1140e5c238c3SMattias Wallin return ret; 1141b04c530cSJonas Aaberg dev_info(ab8500->dev, "switch off cause(s) (%#x): ", value); 1142b04c530cSJonas Aaberg 1143b04c530cSJonas Aaberg if (value) { 1144b04c530cSJonas Aaberg for (i = 0; i < ARRAY_SIZE(switch_off_status); i++) { 1145b04c530cSJonas Aaberg if (value & 1) 11467ccf40b1SLee Jones pr_cont(" \"%s\"", switch_off_status[i]); 1147b04c530cSJonas Aaberg value = value >> 1; 1148b04c530cSJonas Aaberg 1149b04c530cSJonas Aaberg } 11507ccf40b1SLee Jones pr_cont("\n"); 1151b04c530cSJonas Aaberg } else { 11527ccf40b1SLee Jones pr_cont(" None\n"); 1153b04c530cSJonas Aaberg } 1154abee26cdSMattias Wallin ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 1155abee26cdSMattias Wallin AB8500_TURN_ON_STATUS, &value); 1156abee26cdSMattias Wallin if (ret < 0) 1157abee26cdSMattias Wallin return ret; 1158abee26cdSMattias Wallin dev_info(ab8500->dev, "turn on reason(s) (%#x): ", value); 1159abee26cdSMattias Wallin 1160abee26cdSMattias Wallin if (value) { 1161abee26cdSMattias Wallin for (i = 0; i < ARRAY_SIZE(turn_on_status); i++) { 1162abee26cdSMattias Wallin if (value & 1) 11637ccf40b1SLee Jones pr_cont("\"%s\" ", turn_on_status[i]); 1164abee26cdSMattias Wallin value = value >> 1; 1165abee26cdSMattias Wallin } 11667ccf40b1SLee Jones pr_cont("\n"); 1167abee26cdSMattias Wallin } else { 11687ccf40b1SLee Jones pr_cont("None\n"); 1169abee26cdSMattias Wallin } 1170e5c238c3SMattias Wallin 1171f04a9d8aSRajkumar Kasirajan if (is_ab9540(ab8500)) { 1172f04a9d8aSRajkumar Kasirajan ret = get_register_interruptible(ab8500, AB8500_CHARGER, 1173f04a9d8aSRajkumar Kasirajan AB8500_CH_USBCH_STAT1_REG, &value); 1174f04a9d8aSRajkumar Kasirajan if (ret < 0) 1175f04a9d8aSRajkumar Kasirajan return ret; 1176f04a9d8aSRajkumar Kasirajan if ((value & VBUS_DET_DBNC1) && (value & VBUS_DET_DBNC100)) 1177f04a9d8aSRajkumar Kasirajan ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON, 1178f04a9d8aSRajkumar Kasirajan AB8500_VBUS_DET); 1179f04a9d8aSRajkumar Kasirajan } 118062579266SRabin Vincent 118162579266SRabin Vincent /* Clear and mask all interrupts */ 11822ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 11830f620837SLinus Walleij /* 11840f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 11850f620837SLinus Walleij * 2.0 11860f620837SLinus Walleij */ 11870f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 11880f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 118992d50a41SMattias Wallin continue; 119062579266SRabin Vincent 11913e1a498fSLee Jones if (ab8500->irq_reg_offset[i] < 0) 11923e1a498fSLee Jones continue; 11933e1a498fSLee Jones 119447c16975SMattias Wallin get_register_interruptible(ab8500, AB8500_INTERRUPT, 11952ced445eSLinus Walleij AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i], 119692d50a41SMattias Wallin &value); 119747c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, 11982ced445eSLinus Walleij AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff); 119962579266SRabin Vincent } 120062579266SRabin Vincent 120147c16975SMattias Wallin ret = abx500_register_ops(ab8500->dev, &ab8500_ops); 120247c16975SMattias Wallin if (ret) 12038c4203cbSLee Jones return ret; 120447c16975SMattias Wallin 12052ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) 120662579266SRabin Vincent ab8500->mask[i] = ab8500->oldmask[i] = 0xff; 120762579266SRabin Vincent 120806e589efSLee Jones ret = ab8500_irq_init(ab8500, np); 120962579266SRabin Vincent if (ret) 12108c4203cbSLee Jones return ret; 121162579266SRabin Vincent 12128c4203cbSLee Jones ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL, 12137ccfe9b1SMichel JAOUEN ab8500_hierarchical_irq, 12147ccfe9b1SMichel JAOUEN IRQF_ONESHOT | IRQF_NO_SUSPEND, 12157ccfe9b1SMichel JAOUEN "ab8500", ab8500); 121662579266SRabin Vincent if (ret) 12178c4203cbSLee Jones return ret; 121862579266SRabin Vincent 1219d6255529SLinus Walleij if (is_ab9540(ab8500)) 1220d6255529SLinus Walleij ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, 1221d6255529SLinus Walleij ARRAY_SIZE(ab9540_devs), NULL, 1222f864c46aSLinus Walleij 0, ab8500->domain); 12239c717cf3SAlexandre Torgue else if (is_ab8540(ab8500)) { 1224c0eda9aeSLee Jones ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs, 1225c0eda9aeSLee Jones ARRAY_SIZE(ab8540_devs), NULL, 1226f864c46aSLinus Walleij 0, ab8500->domain); 12279c717cf3SAlexandre Torgue if (ret) 12289c717cf3SAlexandre Torgue return ret; 12299c717cf3SAlexandre Torgue 12309c717cf3SAlexandre Torgue if (is_ab8540_1p2_or_earlier(ab8500)) 12319c717cf3SAlexandre Torgue ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut1_devs, 12329c717cf3SAlexandre Torgue ARRAY_SIZE(ab8540_cut1_devs), NULL, 1233f864c46aSLinus Walleij 0, ab8500->domain); 12349c717cf3SAlexandre Torgue else /* ab8540 >= cut2 */ 12359c717cf3SAlexandre Torgue ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut2_devs, 12369c717cf3SAlexandre Torgue ARRAY_SIZE(ab8540_cut2_devs), NULL, 1237f864c46aSLinus Walleij 0, ab8500->domain); 12389c717cf3SAlexandre Torgue } else if (is_ab8505(ab8500)) 1239c0eda9aeSLee Jones ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs, 1240c0eda9aeSLee Jones ARRAY_SIZE(ab8505_devs), NULL, 1241f864c46aSLinus Walleij 0, ab8500->domain); 1242d6255529SLinus Walleij else 1243549931f9SSundar R Iyer ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, 124444f72e53SVirupax Sadashivpetimath ARRAY_SIZE(ab8500_devs), NULL, 1245f864c46aSLinus Walleij 0, ab8500->domain); 12466bc4a568SLee Jones if (ret) 12478c4203cbSLee Jones return ret; 124844f72e53SVirupax Sadashivpetimath 12496ef9418cSRickard Andersson if (!no_bm) { 12506ef9418cSRickard Andersson /* Add battery management devices */ 12516ef9418cSRickard Andersson ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, 12526ef9418cSRickard Andersson ARRAY_SIZE(ab8500_bm_devs), NULL, 1253f864c46aSLinus Walleij 0, ab8500->domain); 12546ef9418cSRickard Andersson if (ret) 12556ef9418cSRickard Andersson dev_err(ab8500->dev, "error adding bm devices\n"); 12566ef9418cSRickard Andersson } 12576ef9418cSRickard Andersson 1258e436ddffSLee Jones if (((is_ab8505(ab8500) || is_ab9540(ab8500)) && 1259e436ddffSLee Jones ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500)) 1260d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1261d6255529SLinus Walleij &ab9540_attr_group); 1262d6255529SLinus Walleij else 1263d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1264d6255529SLinus Walleij &ab8500_attr_group); 126593ff722eSLee Jones 126693ff722eSLee Jones if ((is_ab8505(ab8500) || is_ab9540(ab8500)) && 126793ff722eSLee Jones ab8500->chip_id >= AB8500_CUT2P0) 126893ff722eSLee Jones ret = sysfs_create_group(&ab8500->dev->kobj, 126993ff722eSLee Jones &ab8505_attr_group); 127093ff722eSLee Jones 1271cca69b67SMattias Wallin if (ret) 1272cca69b67SMattias Wallin dev_err(ab8500->dev, "error creating sysfs entries\n"); 127306e589efSLee Jones 127462579266SRabin Vincent return ret; 127562579266SRabin Vincent } 127662579266SRabin Vincent 1277d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = { 1278d28f1db8SLee Jones { "ab8500-core", AB8500_VERSION_AB8500 }, 1279d28f1db8SLee Jones { "ab8505-i2c", AB8500_VERSION_AB8505 }, 1280d28f1db8SLee Jones { "ab9540-i2c", AB8500_VERSION_AB9540 }, 1281d28f1db8SLee Jones { "ab8540-i2c", AB8500_VERSION_AB8540 }, 1282d28f1db8SLee Jones { } 1283d28f1db8SLee Jones }; 1284d28f1db8SLee Jones 1285d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = { 1286d28f1db8SLee Jones .driver = { 1287d28f1db8SLee Jones .name = "ab8500-core", 128831cbae22SPaul Gortmaker .suppress_bind_attrs = true, 1289d28f1db8SLee Jones }, 1290d28f1db8SLee Jones .probe = ab8500_probe, 1291d28f1db8SLee Jones .id_table = ab8500_id, 1292d28f1db8SLee Jones }; 1293d28f1db8SLee Jones 1294d28f1db8SLee Jones static int __init ab8500_core_init(void) 1295d28f1db8SLee Jones { 1296d28f1db8SLee Jones return platform_driver_register(&ab8500_core_driver); 1297d28f1db8SLee Jones } 1298ba7cbc3eSLee Jones core_initcall(ab8500_core_init); 1299