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> 22d28f1db8SLee Jones #include <linux/mfd/dbx500-prcmu.h> 236bc4a568SLee Jones #include <linux/of.h> 246bc4a568SLee Jones #include <linux/of_device.h> 2562579266SRabin Vincent 2662579266SRabin Vincent /* 2762579266SRabin Vincent * Interrupt register offsets 2862579266SRabin Vincent * Bank : 0x0E 2962579266SRabin Vincent */ 3047c16975SMattias Wallin #define AB8500_IT_SOURCE1_REG 0x00 3147c16975SMattias Wallin #define AB8500_IT_SOURCE2_REG 0x01 3247c16975SMattias Wallin #define AB8500_IT_SOURCE3_REG 0x02 3347c16975SMattias Wallin #define AB8500_IT_SOURCE4_REG 0x03 3447c16975SMattias Wallin #define AB8500_IT_SOURCE5_REG 0x04 3547c16975SMattias Wallin #define AB8500_IT_SOURCE6_REG 0x05 3647c16975SMattias Wallin #define AB8500_IT_SOURCE7_REG 0x06 3747c16975SMattias Wallin #define AB8500_IT_SOURCE8_REG 0x07 38d6255529SLinus Walleij #define AB9540_IT_SOURCE13_REG 0x0C 3947c16975SMattias Wallin #define AB8500_IT_SOURCE19_REG 0x12 4047c16975SMattias Wallin #define AB8500_IT_SOURCE20_REG 0x13 4147c16975SMattias Wallin #define AB8500_IT_SOURCE21_REG 0x14 4247c16975SMattias Wallin #define AB8500_IT_SOURCE22_REG 0x15 4347c16975SMattias Wallin #define AB8500_IT_SOURCE23_REG 0x16 4447c16975SMattias Wallin #define AB8500_IT_SOURCE24_REG 0x17 4562579266SRabin Vincent 4662579266SRabin Vincent /* 4762579266SRabin Vincent * latch registers 4862579266SRabin Vincent */ 4947c16975SMattias Wallin #define AB8500_IT_LATCH1_REG 0x20 5047c16975SMattias Wallin #define AB8500_IT_LATCH2_REG 0x21 5147c16975SMattias Wallin #define AB8500_IT_LATCH3_REG 0x22 5247c16975SMattias Wallin #define AB8500_IT_LATCH4_REG 0x23 5347c16975SMattias Wallin #define AB8500_IT_LATCH5_REG 0x24 5447c16975SMattias Wallin #define AB8500_IT_LATCH6_REG 0x25 5547c16975SMattias Wallin #define AB8500_IT_LATCH7_REG 0x26 5647c16975SMattias Wallin #define AB8500_IT_LATCH8_REG 0x27 5747c16975SMattias Wallin #define AB8500_IT_LATCH9_REG 0x28 5847c16975SMattias Wallin #define AB8500_IT_LATCH10_REG 0x29 5992d50a41SMattias Wallin #define AB8500_IT_LATCH12_REG 0x2B 60d6255529SLinus Walleij #define AB9540_IT_LATCH13_REG 0x2C 6147c16975SMattias Wallin #define AB8500_IT_LATCH19_REG 0x32 6247c16975SMattias Wallin #define AB8500_IT_LATCH20_REG 0x33 6347c16975SMattias Wallin #define AB8500_IT_LATCH21_REG 0x34 6447c16975SMattias Wallin #define AB8500_IT_LATCH22_REG 0x35 6547c16975SMattias Wallin #define AB8500_IT_LATCH23_REG 0x36 6647c16975SMattias Wallin #define AB8500_IT_LATCH24_REG 0x37 6762579266SRabin Vincent 6862579266SRabin Vincent /* 6962579266SRabin Vincent * mask registers 7062579266SRabin Vincent */ 7162579266SRabin Vincent 7247c16975SMattias Wallin #define AB8500_IT_MASK1_REG 0x40 7347c16975SMattias Wallin #define AB8500_IT_MASK2_REG 0x41 7447c16975SMattias Wallin #define AB8500_IT_MASK3_REG 0x42 7547c16975SMattias Wallin #define AB8500_IT_MASK4_REG 0x43 7647c16975SMattias Wallin #define AB8500_IT_MASK5_REG 0x44 7747c16975SMattias Wallin #define AB8500_IT_MASK6_REG 0x45 7847c16975SMattias Wallin #define AB8500_IT_MASK7_REG 0x46 7947c16975SMattias Wallin #define AB8500_IT_MASK8_REG 0x47 8047c16975SMattias Wallin #define AB8500_IT_MASK9_REG 0x48 8147c16975SMattias Wallin #define AB8500_IT_MASK10_REG 0x49 8247c16975SMattias Wallin #define AB8500_IT_MASK11_REG 0x4A 8347c16975SMattias Wallin #define AB8500_IT_MASK12_REG 0x4B 8447c16975SMattias Wallin #define AB8500_IT_MASK13_REG 0x4C 8547c16975SMattias Wallin #define AB8500_IT_MASK14_REG 0x4D 8647c16975SMattias Wallin #define AB8500_IT_MASK15_REG 0x4E 8747c16975SMattias Wallin #define AB8500_IT_MASK16_REG 0x4F 8847c16975SMattias Wallin #define AB8500_IT_MASK17_REG 0x50 8947c16975SMattias Wallin #define AB8500_IT_MASK18_REG 0x51 9047c16975SMattias Wallin #define AB8500_IT_MASK19_REG 0x52 9147c16975SMattias Wallin #define AB8500_IT_MASK20_REG 0x53 9247c16975SMattias Wallin #define AB8500_IT_MASK21_REG 0x54 9347c16975SMattias Wallin #define AB8500_IT_MASK22_REG 0x55 9447c16975SMattias Wallin #define AB8500_IT_MASK23_REG 0x56 9547c16975SMattias Wallin #define AB8500_IT_MASK24_REG 0x57 96a29264b6SLee Jones #define AB8500_IT_MASK25_REG 0x58 9762579266SRabin Vincent 987ccfe9b1SMichel JAOUEN /* 997ccfe9b1SMichel JAOUEN * latch hierarchy registers 1007ccfe9b1SMichel JAOUEN */ 1017ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER1_REG 0x60 1027ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER2_REG 0x61 1037ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER3_REG 0x62 1043e1a498fSLee Jones #define AB8540_IT_LATCHHIER4_REG 0x63 1057ccfe9b1SMichel JAOUEN 1067ccfe9b1SMichel JAOUEN #define AB8500_IT_LATCHHIER_NUM 3 1073e1a498fSLee Jones #define AB8540_IT_LATCHHIER_NUM 4 1087ccfe9b1SMichel JAOUEN 10947c16975SMattias Wallin #define AB8500_REV_REG 0x80 1100f620837SLinus Walleij #define AB8500_IC_NAME_REG 0x82 111e5c238c3SMattias Wallin #define AB8500_SWITCH_OFF_STATUS 0x00 11262579266SRabin Vincent 113b4a31037SAndrew Lynn #define AB8500_TURN_ON_STATUS 0x00 11493ff722eSLee Jones #define AB8505_TURN_ON_STATUS_2 0x04 115b4a31037SAndrew Lynn 116f04a9d8aSRajkumar Kasirajan #define AB8500_CH_USBCH_STAT1_REG 0x02 117f04a9d8aSRajkumar Kasirajan #define VBUS_DET_DBNC100 0x02 118f04a9d8aSRajkumar Kasirajan #define VBUS_DET_DBNC1 0x01 119f04a9d8aSRajkumar Kasirajan 120f04a9d8aSRajkumar Kasirajan static DEFINE_SPINLOCK(on_stat_lock); 121f04a9d8aSRajkumar Kasirajan static u8 turn_on_stat_mask = 0xFF; 122f04a9d8aSRajkumar Kasirajan static u8 turn_on_stat_set; 1236ef9418cSRickard Andersson static bool no_bm; /* No battery management */ 12431cbae22SPaul Gortmaker /* 12531cbae22SPaul Gortmaker * not really modular, but the easiest way to keep compat with existing 12631cbae22SPaul Gortmaker * bootargs behaviour is to continue using module_param here. 12731cbae22SPaul Gortmaker */ 1286ef9418cSRickard Andersson module_param(no_bm, bool, S_IRUGO); 1296ef9418cSRickard Andersson 130d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_REG 0x23 131d6255529SLinus Walleij #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2) 132d6255529SLinus Walleij 13362579266SRabin Vincent /* 13462579266SRabin Vincent * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt 1352ced445eSLinus Walleij * numbers are indexed into this array with (num / 8). The interupts are 1362ced445eSLinus Walleij * defined in linux/mfd/ab8500.h 13762579266SRabin Vincent * 13862579266SRabin Vincent * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at 13962579266SRabin Vincent * offset 0. 14062579266SRabin Vincent */ 1412ced445eSLinus Walleij /* AB8500 support */ 14262579266SRabin Vincent static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { 14392d50a41SMattias Wallin 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 14462579266SRabin Vincent }; 14562579266SRabin Vincent 146a29264b6SLee Jones /* AB9540 / AB8505 support */ 147d6255529SLinus Walleij static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = { 148a29264b6SLee Jones 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23 149d6255529SLinus Walleij }; 150d6255529SLinus Walleij 1513e1a498fSLee Jones /* AB8540 support */ 1523e1a498fSLee Jones static const int ab8540_irq_regoffset[AB8540_NUM_IRQ_REGS] = { 1537ccf40b1SLee Jones 0, 1, 2, 3, 4, -1, -1, -1, -1, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 1547ccf40b1SLee Jones 23, 25, 26, 27, 28, 29, 30, 31, 1553e1a498fSLee Jones }; 1563e1a498fSLee Jones 1570f620837SLinus Walleij static const char ab8500_version_str[][7] = { 1580f620837SLinus Walleij [AB8500_VERSION_AB8500] = "AB8500", 1590f620837SLinus Walleij [AB8500_VERSION_AB8505] = "AB8505", 1600f620837SLinus Walleij [AB8500_VERSION_AB9540] = "AB9540", 1610f620837SLinus Walleij [AB8500_VERSION_AB8540] = "AB8540", 1620f620837SLinus Walleij }; 1630f620837SLinus Walleij 164822672a7SLee Jones static int ab8500_prcmu_write(struct ab8500 *ab8500, u16 addr, u8 data) 165d28f1db8SLee Jones { 166d28f1db8SLee Jones int ret; 167d28f1db8SLee Jones 168d28f1db8SLee Jones ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 169d28f1db8SLee Jones if (ret < 0) 170d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 171d28f1db8SLee Jones return ret; 172d28f1db8SLee Jones } 173d28f1db8SLee Jones 174822672a7SLee Jones static int ab8500_prcmu_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask, 175d28f1db8SLee Jones u8 data) 176d28f1db8SLee Jones { 177d28f1db8SLee Jones int ret; 178d28f1db8SLee Jones 179d28f1db8SLee Jones ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 180d28f1db8SLee Jones &mask, 1); 181d28f1db8SLee Jones if (ret < 0) 182d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 183d28f1db8SLee Jones return ret; 184d28f1db8SLee Jones } 185d28f1db8SLee Jones 186822672a7SLee Jones static int ab8500_prcmu_read(struct ab8500 *ab8500, u16 addr) 187d28f1db8SLee Jones { 188d28f1db8SLee Jones int ret; 189d28f1db8SLee Jones u8 data; 190d28f1db8SLee Jones 191d28f1db8SLee Jones ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 192d28f1db8SLee Jones if (ret < 0) { 193d28f1db8SLee Jones dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 194d28f1db8SLee Jones return ret; 195d28f1db8SLee Jones } 196d28f1db8SLee Jones return (int)data; 197d28f1db8SLee Jones } 198d28f1db8SLee Jones 19947c16975SMattias Wallin static int ab8500_get_chip_id(struct device *dev) 20047c16975SMattias Wallin { 2016bce7bf1SMattias Wallin struct ab8500 *ab8500; 2026bce7bf1SMattias Wallin 2036bce7bf1SMattias Wallin if (!dev) 2046bce7bf1SMattias Wallin return -EINVAL; 2056bce7bf1SMattias Wallin ab8500 = dev_get_drvdata(dev->parent); 2066bce7bf1SMattias Wallin return ab8500 ? (int)ab8500->chip_id : -EINVAL; 20747c16975SMattias Wallin } 20847c16975SMattias Wallin 20947c16975SMattias Wallin static int set_register_interruptible(struct ab8500 *ab8500, u8 bank, 21047c16975SMattias Wallin u8 reg, u8 data) 21162579266SRabin Vincent { 21262579266SRabin Vincent int ret; 21347c16975SMattias Wallin /* 21447c16975SMattias Wallin * Put the u8 bank and u8 register together into a an u16. 21547c16975SMattias Wallin * The bank on higher 8 bits and register in lower 8 bits. 216500e69a1SLee Jones */ 21747c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 21862579266SRabin Vincent 21962579266SRabin Vincent dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data); 22062579266SRabin Vincent 221392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 22247c16975SMattias Wallin 22347c16975SMattias Wallin ret = ab8500->write(ab8500, addr, data); 22447c16975SMattias Wallin if (ret < 0) 22547c16975SMattias Wallin dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 22647c16975SMattias Wallin addr, ret); 22747c16975SMattias Wallin mutex_unlock(&ab8500->lock); 22847c16975SMattias Wallin 22947c16975SMattias Wallin return ret; 23047c16975SMattias Wallin } 23147c16975SMattias Wallin 23247c16975SMattias Wallin static int ab8500_set_register(struct device *dev, u8 bank, 23347c16975SMattias Wallin u8 reg, u8 value) 23447c16975SMattias Wallin { 235112a80d2SJonas Aaberg int ret; 23647c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 23747c16975SMattias Wallin 238112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 239112a80d2SJonas Aaberg ret = set_register_interruptible(ab8500, bank, reg, value); 240112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 241112a80d2SJonas Aaberg return ret; 24247c16975SMattias Wallin } 24347c16975SMattias Wallin 24447c16975SMattias Wallin static int get_register_interruptible(struct ab8500 *ab8500, u8 bank, 24547c16975SMattias Wallin u8 reg, u8 *value) 24647c16975SMattias Wallin { 24747c16975SMattias Wallin int ret; 24847c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 24947c16975SMattias Wallin 250392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 25147c16975SMattias Wallin 25247c16975SMattias Wallin ret = ab8500->read(ab8500, addr); 25347c16975SMattias Wallin if (ret < 0) 25447c16975SMattias Wallin dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 25547c16975SMattias Wallin addr, ret); 25647c16975SMattias Wallin else 25747c16975SMattias Wallin *value = ret; 25847c16975SMattias Wallin 25947c16975SMattias Wallin mutex_unlock(&ab8500->lock); 26047c16975SMattias Wallin dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret); 26147c16975SMattias Wallin 26210628e3eSDan Carpenter return (ret < 0) ? ret : 0; 26347c16975SMattias Wallin } 26447c16975SMattias Wallin 26547c16975SMattias Wallin static int ab8500_get_register(struct device *dev, u8 bank, 26647c16975SMattias Wallin u8 reg, u8 *value) 26747c16975SMattias Wallin { 268112a80d2SJonas Aaberg int ret; 26947c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 27047c16975SMattias Wallin 271112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 272112a80d2SJonas Aaberg ret = get_register_interruptible(ab8500, bank, reg, value); 273112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 274112a80d2SJonas Aaberg return ret; 27547c16975SMattias Wallin } 27647c16975SMattias Wallin 27747c16975SMattias Wallin static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank, 27847c16975SMattias Wallin u8 reg, u8 bitmask, u8 bitvalues) 27947c16975SMattias Wallin { 28047c16975SMattias Wallin int ret; 28147c16975SMattias Wallin u16 addr = ((u16)bank) << 8 | reg; 28247c16975SMattias Wallin 283392cbd1eSRabin Vincent mutex_lock(&ab8500->lock); 28447c16975SMattias Wallin 285bc628fd1SMattias Nilsson if (ab8500->write_masked == NULL) { 286bc628fd1SMattias Nilsson u8 data; 287bc628fd1SMattias Nilsson 28847c16975SMattias Wallin ret = ab8500->read(ab8500, addr); 28947c16975SMattias Wallin if (ret < 0) { 29047c16975SMattias Wallin dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 29147c16975SMattias Wallin addr, ret); 29247c16975SMattias Wallin goto out; 29347c16975SMattias Wallin } 29447c16975SMattias Wallin 29547c16975SMattias Wallin data = (u8)ret; 29647c16975SMattias Wallin data = (~bitmask & data) | (bitmask & bitvalues); 29747c16975SMattias Wallin 29862579266SRabin Vincent ret = ab8500->write(ab8500, addr, data); 29962579266SRabin Vincent if (ret < 0) 30062579266SRabin Vincent dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 30162579266SRabin Vincent addr, ret); 30262579266SRabin Vincent 303bc628fd1SMattias Nilsson dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, 304bc628fd1SMattias Nilsson data); 305bc628fd1SMattias Nilsson goto out; 306bc628fd1SMattias Nilsson } 307bc628fd1SMattias Nilsson ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues); 308bc628fd1SMattias Nilsson if (ret < 0) 309bc628fd1SMattias Nilsson dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr, 310bc628fd1SMattias Nilsson ret); 31162579266SRabin Vincent out: 31262579266SRabin Vincent mutex_unlock(&ab8500->lock); 31362579266SRabin Vincent return ret; 31462579266SRabin Vincent } 31547c16975SMattias Wallin 31647c16975SMattias Wallin static int ab8500_mask_and_set_register(struct device *dev, 31747c16975SMattias Wallin u8 bank, u8 reg, u8 bitmask, u8 bitvalues) 31847c16975SMattias Wallin { 319112a80d2SJonas Aaberg int ret; 32047c16975SMattias Wallin struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 32147c16975SMattias Wallin 322112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 323112a80d2SJonas Aaberg ret = mask_and_set_register_interruptible(ab8500, bank, reg, 32447c16975SMattias Wallin bitmask, bitvalues); 325112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 326112a80d2SJonas Aaberg return ret; 32747c16975SMattias Wallin } 32847c16975SMattias Wallin 32947c16975SMattias Wallin static struct abx500_ops ab8500_ops = { 33047c16975SMattias Wallin .get_chip_id = ab8500_get_chip_id, 33147c16975SMattias Wallin .get_register = ab8500_get_register, 33247c16975SMattias Wallin .set_register = ab8500_set_register, 33347c16975SMattias Wallin .get_register_page = NULL, 33447c16975SMattias Wallin .set_register_page = NULL, 33547c16975SMattias Wallin .mask_and_set_register = ab8500_mask_and_set_register, 33647c16975SMattias Wallin .event_registers_startup_state_get = NULL, 33747c16975SMattias Wallin .startup_irq_enabled = NULL, 3381d843a6cSMian Yousaf Kaukab .dump_all_banks = ab8500_dump_all_banks, 33947c16975SMattias Wallin }; 34062579266SRabin Vincent 3419505a0a0SMark Brown static void ab8500_irq_lock(struct irq_data *data) 34262579266SRabin Vincent { 3439505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 34462579266SRabin Vincent 34562579266SRabin Vincent mutex_lock(&ab8500->irq_lock); 346112a80d2SJonas Aaberg atomic_inc(&ab8500->transfer_ongoing); 34762579266SRabin Vincent } 34862579266SRabin Vincent 3499505a0a0SMark Brown static void ab8500_irq_sync_unlock(struct irq_data *data) 35062579266SRabin Vincent { 3519505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 35262579266SRabin Vincent int i; 35362579266SRabin Vincent 3542ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 35562579266SRabin Vincent u8 old = ab8500->oldmask[i]; 35662579266SRabin Vincent u8 new = ab8500->mask[i]; 35762579266SRabin Vincent int reg; 35862579266SRabin Vincent 35962579266SRabin Vincent if (new == old) 36062579266SRabin Vincent continue; 36162579266SRabin Vincent 3620f620837SLinus Walleij /* 3630f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 3640f620837SLinus Walleij * 2.0 3650f620837SLinus Walleij */ 3660f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 3670f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 36892d50a41SMattias Wallin continue; 36992d50a41SMattias Wallin 3703e1a498fSLee Jones if (ab8500->irq_reg_offset[i] < 0) 3713e1a498fSLee Jones continue; 3723e1a498fSLee Jones 37362579266SRabin Vincent ab8500->oldmask[i] = new; 37462579266SRabin Vincent 3752ced445eSLinus Walleij reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i]; 37647c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new); 37762579266SRabin Vincent } 378112a80d2SJonas Aaberg atomic_dec(&ab8500->transfer_ongoing); 37962579266SRabin Vincent mutex_unlock(&ab8500->irq_lock); 38062579266SRabin Vincent } 38162579266SRabin Vincent 3829505a0a0SMark Brown static void ab8500_irq_mask(struct irq_data *data) 38362579266SRabin Vincent { 3849505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 38506e589efSLee Jones int offset = data->hwirq; 38662579266SRabin Vincent int index = offset / 8; 38762579266SRabin Vincent int mask = 1 << (offset % 8); 38862579266SRabin Vincent 38962579266SRabin Vincent ab8500->mask[index] |= mask; 3909c677b9bSLee Jones 3919c677b9bSLee Jones /* The AB8500 GPIOs have two interrupts each (rising & falling). */ 3929c677b9bSLee Jones if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R) 3939c677b9bSLee Jones ab8500->mask[index + 2] |= mask; 3949c677b9bSLee Jones if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R) 3959c677b9bSLee Jones ab8500->mask[index + 1] |= mask; 3969c677b9bSLee Jones if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R) 397e2ddf46aSLinus Walleij /* Here the falling IRQ is one bit lower */ 398e2ddf46aSLinus Walleij ab8500->mask[index] |= (mask << 1); 39962579266SRabin Vincent } 40062579266SRabin Vincent 4019505a0a0SMark Brown static void ab8500_irq_unmask(struct irq_data *data) 40262579266SRabin Vincent { 4039505a0a0SMark Brown struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 4049c677b9bSLee Jones unsigned int type = irqd_get_trigger_type(data); 40506e589efSLee Jones int offset = data->hwirq; 40662579266SRabin Vincent int index = offset / 8; 40762579266SRabin Vincent int mask = 1 << (offset % 8); 40862579266SRabin Vincent 4099c677b9bSLee Jones if (type & IRQ_TYPE_EDGE_RISING) 41062579266SRabin Vincent ab8500->mask[index] &= ~mask; 4119c677b9bSLee Jones 4129c677b9bSLee Jones /* The AB8500 GPIOs have two interrupts each (rising & falling). */ 4139c677b9bSLee Jones if (type & IRQ_TYPE_EDGE_FALLING) { 4149c677b9bSLee Jones if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R) 4159c677b9bSLee Jones ab8500->mask[index + 2] &= ~mask; 4167ccf40b1SLee Jones else if (offset >= AB9540_INT_GPIO50R && 4177ccf40b1SLee Jones offset <= AB9540_INT_GPIO54R) 4189c677b9bSLee Jones ab8500->mask[index + 1] &= ~mask; 4197ccf40b1SLee Jones else if (offset == AB8540_INT_GPIO43R || 4207ccf40b1SLee Jones offset == AB8540_INT_GPIO44R) 421e2ddf46aSLinus Walleij /* Here the falling IRQ is one bit lower */ 422e2ddf46aSLinus Walleij ab8500->mask[index] &= ~(mask << 1); 4239c677b9bSLee Jones else 4249c677b9bSLee Jones ab8500->mask[index] &= ~mask; 425e2ddf46aSLinus Walleij } else { 4269c677b9bSLee Jones /* Satisfies the case where type is not set. */ 42762579266SRabin Vincent ab8500->mask[index] &= ~mask; 42862579266SRabin Vincent } 429e2ddf46aSLinus Walleij } 43062579266SRabin Vincent 43140f6e5a2SLee Jones static int ab8500_irq_set_type(struct irq_data *data, unsigned int type) 43240f6e5a2SLee Jones { 43340f6e5a2SLee Jones return 0; 43462579266SRabin Vincent } 43562579266SRabin Vincent 43662579266SRabin Vincent static struct irq_chip ab8500_irq_chip = { 43762579266SRabin Vincent .name = "ab8500", 4389505a0a0SMark Brown .irq_bus_lock = ab8500_irq_lock, 4399505a0a0SMark Brown .irq_bus_sync_unlock = ab8500_irq_sync_unlock, 4409505a0a0SMark Brown .irq_mask = ab8500_irq_mask, 441e6f9306eSVirupax Sadashivpetimath .irq_disable = ab8500_irq_mask, 4429505a0a0SMark Brown .irq_unmask = ab8500_irq_unmask, 44340f6e5a2SLee Jones .irq_set_type = ab8500_irq_set_type, 44462579266SRabin Vincent }; 44562579266SRabin Vincent 4463e1a498fSLee Jones static void update_latch_offset(u8 *offset, int i) 4473e1a498fSLee Jones { 4483e1a498fSLee Jones /* Fix inconsistent ITFromLatch25 bit mapping... */ 4493e1a498fSLee Jones if (unlikely(*offset == 17)) 4503e1a498fSLee Jones *offset = 24; 4513e1a498fSLee Jones /* Fix inconsistent ab8540 bit mapping... */ 4523e1a498fSLee Jones if (unlikely(*offset == 16)) 4533e1a498fSLee Jones *offset = 25; 4543e1a498fSLee Jones if ((i == 3) && (*offset >= 24)) 4553e1a498fSLee Jones *offset += 2; 4563e1a498fSLee Jones } 4573e1a498fSLee Jones 4587ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, 4597ccfe9b1SMichel JAOUEN int latch_offset, u8 latch_val) 4607ccfe9b1SMichel JAOUEN { 4617a93fb37SFabio Baltieri int int_bit, line, i; 4627ccfe9b1SMichel JAOUEN 4637ccfe9b1SMichel JAOUEN for (i = 0; i < ab8500->mask_size; i++) 4647ccfe9b1SMichel JAOUEN if (ab8500->irq_reg_offset[i] == latch_offset) 4657ccfe9b1SMichel JAOUEN break; 4667ccfe9b1SMichel JAOUEN 4677ccfe9b1SMichel JAOUEN if (i >= ab8500->mask_size) { 4687ccfe9b1SMichel JAOUEN dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", 4697ccfe9b1SMichel JAOUEN latch_offset); 4707ccfe9b1SMichel JAOUEN return -ENXIO; 4717ccfe9b1SMichel JAOUEN } 4727ccfe9b1SMichel JAOUEN 4737a93fb37SFabio Baltieri /* ignore masked out interrupts */ 4747a93fb37SFabio Baltieri latch_val &= ~ab8500->mask[i]; 4757a93fb37SFabio Baltieri 4767a93fb37SFabio Baltieri while (latch_val) { 4777a93fb37SFabio Baltieri int_bit = __ffs(latch_val); 4787ccfe9b1SMichel JAOUEN line = (i << 3) + int_bit; 4797ccfe9b1SMichel JAOUEN latch_val &= ~(1 << int_bit); 4807ccfe9b1SMichel JAOUEN 481e2ddf46aSLinus Walleij /* 482e2ddf46aSLinus Walleij * This handles the falling edge hwirqs from the GPIO 483e2ddf46aSLinus Walleij * lines. Route them back to the line registered for the 484e2ddf46aSLinus Walleij * rising IRQ, as this is merely a flag for the same IRQ 485e2ddf46aSLinus Walleij * in linux terms. 486e2ddf46aSLinus Walleij */ 487e2ddf46aSLinus Walleij if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F) 488e2ddf46aSLinus Walleij line -= 16; 489e2ddf46aSLinus Walleij if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F) 490e2ddf46aSLinus Walleij line -= 8; 491e2ddf46aSLinus Walleij if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F) 492e2ddf46aSLinus Walleij line += 1; 493e2ddf46aSLinus Walleij 494ed83d301SLinus Walleij handle_nested_irq(irq_create_mapping(ab8500->domain, line)); 4957a93fb37SFabio Baltieri } 4967ccfe9b1SMichel JAOUEN 4977ccfe9b1SMichel JAOUEN return 0; 4987ccfe9b1SMichel JAOUEN } 4997ccfe9b1SMichel JAOUEN 5007ccfe9b1SMichel JAOUEN static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500, 5017ccfe9b1SMichel JAOUEN int hier_offset, u8 hier_val) 5027ccfe9b1SMichel JAOUEN { 5037ccfe9b1SMichel JAOUEN int latch_bit, status; 5047ccfe9b1SMichel JAOUEN u8 latch_offset, latch_val; 5057ccfe9b1SMichel JAOUEN 5067ccfe9b1SMichel JAOUEN do { 5077ccfe9b1SMichel JAOUEN latch_bit = __ffs(hier_val); 5087ccfe9b1SMichel JAOUEN latch_offset = (hier_offset << 3) + latch_bit; 5097ccfe9b1SMichel JAOUEN 5103e1a498fSLee Jones update_latch_offset(&latch_offset, hier_offset); 5117ccfe9b1SMichel JAOUEN 5127ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, 5137ccfe9b1SMichel JAOUEN AB8500_INTERRUPT, 5147ccfe9b1SMichel JAOUEN AB8500_IT_LATCH1_REG + latch_offset, 5157ccfe9b1SMichel JAOUEN &latch_val); 5167ccfe9b1SMichel JAOUEN if (status < 0 || latch_val == 0) 5177ccfe9b1SMichel JAOUEN goto discard; 5187ccfe9b1SMichel JAOUEN 5197ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_line(ab8500, 5207ccfe9b1SMichel JAOUEN latch_offset, latch_val); 5217ccfe9b1SMichel JAOUEN if (status < 0) 5227ccfe9b1SMichel JAOUEN return status; 5237ccfe9b1SMichel JAOUEN discard: 5247ccfe9b1SMichel JAOUEN hier_val &= ~(1 << latch_bit); 5257ccfe9b1SMichel JAOUEN } while (hier_val); 5267ccfe9b1SMichel JAOUEN 5277ccfe9b1SMichel JAOUEN return 0; 5287ccfe9b1SMichel JAOUEN } 5297ccfe9b1SMichel JAOUEN 5307ccfe9b1SMichel JAOUEN static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev) 5317ccfe9b1SMichel JAOUEN { 5327ccfe9b1SMichel JAOUEN struct ab8500 *ab8500 = dev; 5337ccfe9b1SMichel JAOUEN u8 i; 5347ccfe9b1SMichel JAOUEN 5357ccfe9b1SMichel JAOUEN dev_vdbg(ab8500->dev, "interrupt\n"); 5367ccfe9b1SMichel JAOUEN 5377ccfe9b1SMichel JAOUEN /* Hierarchical interrupt version */ 5383e1a498fSLee Jones for (i = 0; i < (ab8500->it_latchhier_num); i++) { 5397ccfe9b1SMichel JAOUEN int status; 5407ccfe9b1SMichel JAOUEN u8 hier_val; 5417ccfe9b1SMichel JAOUEN 5427ccfe9b1SMichel JAOUEN status = get_register_interruptible(ab8500, AB8500_INTERRUPT, 5437ccfe9b1SMichel JAOUEN AB8500_IT_LATCHHIER1_REG + i, &hier_val); 5447ccfe9b1SMichel JAOUEN if (status < 0 || hier_val == 0) 5457ccfe9b1SMichel JAOUEN continue; 5467ccfe9b1SMichel JAOUEN 5477ccfe9b1SMichel JAOUEN status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val); 5487ccfe9b1SMichel JAOUEN if (status < 0) 5497ccfe9b1SMichel JAOUEN break; 5507ccfe9b1SMichel JAOUEN } 5517ccfe9b1SMichel JAOUEN return IRQ_HANDLED; 5527ccfe9b1SMichel JAOUEN } 5537ccfe9b1SMichel JAOUEN 55406e589efSLee Jones static int ab8500_irq_map(struct irq_domain *d, unsigned int virq, 55506e589efSLee Jones irq_hw_number_t hwirq) 55606e589efSLee Jones { 55706e589efSLee Jones struct ab8500 *ab8500 = d->host_data; 55806e589efSLee Jones 55906e589efSLee Jones if (!ab8500) 56006e589efSLee Jones return -EINVAL; 56106e589efSLee Jones 56206e589efSLee Jones irq_set_chip_data(virq, ab8500); 56306e589efSLee Jones irq_set_chip_and_handler(virq, &ab8500_irq_chip, 56406e589efSLee Jones handle_simple_irq); 56506e589efSLee Jones irq_set_nested_thread(virq, 1); 56606e589efSLee Jones irq_set_noprobe(virq); 56762579266SRabin Vincent 56862579266SRabin Vincent return 0; 56962579266SRabin Vincent } 57062579266SRabin Vincent 5717ce7b26fSKrzysztof Kozlowski static const struct irq_domain_ops ab8500_irq_ops = { 57206e589efSLee Jones .map = ab8500_irq_map, 57306e589efSLee Jones .xlate = irq_domain_xlate_twocell, 57406e589efSLee Jones }; 57506e589efSLee Jones 57606e589efSLee Jones static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np) 57762579266SRabin Vincent { 5782ced445eSLinus Walleij int num_irqs; 57962579266SRabin Vincent 5803e1a498fSLee Jones if (is_ab8540(ab8500)) 5813e1a498fSLee Jones num_irqs = AB8540_NR_IRQS; 5823e1a498fSLee Jones else if (is_ab9540(ab8500)) 583d6255529SLinus Walleij num_irqs = AB9540_NR_IRQS; 584a982362cSBengt Jonsson else if (is_ab8505(ab8500)) 585a982362cSBengt Jonsson num_irqs = AB8505_NR_IRQS; 586d6255529SLinus Walleij else 5872ced445eSLinus Walleij num_irqs = AB8500_NR_IRQS; 5882ced445eSLinus Walleij 589f1d11f39SLinus Walleij /* If ->irq_base is zero this will give a linear mapping */ 5907602e05dSGrygorii Strashko ab8500->domain = irq_domain_add_simple(ab8500->dev->of_node, 591f864c46aSLinus Walleij num_irqs, 0, 592f1d11f39SLinus Walleij &ab8500_irq_ops, ab8500); 59306e589efSLee Jones 59406e589efSLee Jones if (!ab8500->domain) { 59506e589efSLee Jones dev_err(ab8500->dev, "Failed to create irqdomain\n"); 596500e69a1SLee Jones return -ENODEV; 59706e589efSLee Jones } 59806e589efSLee Jones 59906e589efSLee Jones return 0; 60062579266SRabin Vincent } 60162579266SRabin Vincent 602112a80d2SJonas Aaberg int ab8500_suspend(struct ab8500 *ab8500) 603112a80d2SJonas Aaberg { 604112a80d2SJonas Aaberg if (atomic_read(&ab8500->transfer_ongoing)) 605112a80d2SJonas Aaberg return -EINVAL; 606f3556302SLee Jones 607112a80d2SJonas Aaberg return 0; 608112a80d2SJonas Aaberg } 609112a80d2SJonas Aaberg 6105ac98553SGeert Uytterhoeven static const struct mfd_cell ab8500_bm_devs[] = { 611*417c0fc2SLinus Walleij MFD_CELL_OF("ab8500-charger", NULL, NULL, 0, 0, 612*417c0fc2SLinus Walleij "stericsson,ab8500-charger"), 613*417c0fc2SLinus Walleij MFD_CELL_OF("ab8500-btemp", NULL, NULL, 0, 0, 614*417c0fc2SLinus Walleij "stericsson,ab8500-btemp"), 615*417c0fc2SLinus Walleij MFD_CELL_OF("ab8500-fg", NULL, NULL, 0, 0, 616*417c0fc2SLinus Walleij "stericsson,ab8500-fg"), 617*417c0fc2SLinus Walleij MFD_CELL_OF("ab8500-chargalg", NULL, NULL, 0, 0, 618*417c0fc2SLinus Walleij "stericsson,ab8500-chargalg"), 6196ef9418cSRickard Andersson }; 6206ef9418cSRickard Andersson 6215ac98553SGeert Uytterhoeven static const struct mfd_cell ab8500_devs[] = { 6224b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 623db783e76SLee Jones MFD_CELL_OF("ab8500-debug", 624f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-debug"), 6254b106fb9SLee Jones #endif 626db783e76SLee Jones MFD_CELL_OF("ab8500-sysctrl", 627f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-sysctrl"), 628db783e76SLee Jones MFD_CELL_OF("ab8500-ext-regulator", 629f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-ext-regulator"), 630db783e76SLee Jones MFD_CELL_OF("ab8500-regulator", 631f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-regulator"), 632db783e76SLee Jones MFD_CELL_OF("ab8500-clk", 633702204c2SLinus Walleij NULL, NULL, 0, 0, "stericsson,ab8500-clk"), 634db783e76SLee Jones MFD_CELL_OF("ab8500-gpadc", 635f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-gpadc"), 636db783e76SLee Jones MFD_CELL_OF("ab8500-rtc", 637f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-rtc"), 638db783e76SLee Jones MFD_CELL_OF("ab8500-acc-det", 639f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-acc-det"), 640db783e76SLee Jones MFD_CELL_OF("ab8500-poweron-key", 641f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-poweron-key"), 642db783e76SLee Jones MFD_CELL_OF("ab8500-pwm", 643f4d41ad8SLee Jones NULL, NULL, 0, 1, "stericsson,ab8500-pwm"), 644db783e76SLee Jones MFD_CELL_OF("ab8500-pwm", 645f4d41ad8SLee Jones NULL, NULL, 0, 2, "stericsson,ab8500-pwm"), 646db783e76SLee Jones MFD_CELL_OF("ab8500-pwm", 647f4d41ad8SLee Jones NULL, NULL, 0, 3, "stericsson,ab8500-pwm"), 648db783e76SLee Jones MFD_CELL_OF("ab8500-denc", 649f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-denc"), 650db783e76SLee Jones MFD_CELL_OF("pinctrl-ab8500", 651f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-gpio"), 652db783e76SLee Jones MFD_CELL_OF("abx500-temp", 653f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,abx500-temp"), 654db783e76SLee Jones MFD_CELL_OF("ab8500-usb", 655f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-usb"), 656db783e76SLee Jones MFD_CELL_OF("ab8500-codec", 657f4d41ad8SLee Jones NULL, NULL, 0, 0, "stericsson,ab8500-codec"), 6584b106fb9SLee Jones }; 6594b106fb9SLee Jones 6605ac98553SGeert Uytterhoeven static const struct mfd_cell ab9540_devs[] = { 6614b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 6624b106fb9SLee Jones { 6634b106fb9SLee Jones .name = "ab8500-debug", 6644b106fb9SLee Jones }, 6654b106fb9SLee Jones #endif 6664b106fb9SLee Jones { 6674b106fb9SLee Jones .name = "ab8500-sysctrl", 6684b106fb9SLee Jones }, 6694b106fb9SLee Jones { 67053f325beSLee Jones .name = "ab8500-ext-regulator", 67153f325beSLee Jones }, 67253f325beSLee Jones { 6734b106fb9SLee Jones .name = "ab8500-regulator", 67444f72e53SVirupax Sadashivpetimath }, 675c0eda9aeSLee Jones { 6769ee17676SUlf Hansson .name = "abx500-clk", 6779ee17676SUlf Hansson .of_compatible = "stericsson,abx500-clk", 6789ee17676SUlf Hansson }, 6799ee17676SUlf Hansson { 680c0eda9aeSLee Jones .name = "ab8500-gpadc", 681c0eda9aeSLee Jones .of_compatible = "stericsson,ab8500-gpadc", 682c0eda9aeSLee Jones }, 6834b106fb9SLee Jones { 6844b106fb9SLee Jones .name = "ab8500-rtc", 6854b106fb9SLee Jones }, 6864b106fb9SLee Jones { 6874b106fb9SLee Jones .name = "ab8500-acc-det", 6884b106fb9SLee Jones }, 6894b106fb9SLee Jones { 6904b106fb9SLee Jones .name = "ab8500-poweron-key", 6914b106fb9SLee Jones }, 6924b106fb9SLee Jones { 6934b106fb9SLee Jones .name = "ab8500-pwm", 6944b106fb9SLee Jones .id = 1, 6954b106fb9SLee Jones }, 6964b106fb9SLee Jones { 6974b106fb9SLee Jones .name = "abx500-temp", 6984b106fb9SLee Jones }, 699d6255529SLinus Walleij { 700e64d905eSLee Jones .name = "pinctrl-ab9540", 701e64d905eSLee Jones .of_compatible = "stericsson,ab9540-gpio", 702d6255529SLinus Walleij }, 703d6255529SLinus Walleij { 704d6255529SLinus Walleij .name = "ab9540-usb", 705d6255529SLinus Walleij }, 70644f72e53SVirupax Sadashivpetimath { 70744f72e53SVirupax Sadashivpetimath .name = "ab9540-codec", 70844f72e53SVirupax Sadashivpetimath }, 709c0eda9aeSLee Jones { 710c0eda9aeSLee Jones .name = "ab-iddet", 711c0eda9aeSLee Jones }, 71244f72e53SVirupax Sadashivpetimath }; 71344f72e53SVirupax Sadashivpetimath 714c0eda9aeSLee Jones /* Device list for ab8505 */ 7155ac98553SGeert Uytterhoeven static const struct mfd_cell ab8505_devs[] = { 7164b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 7174b106fb9SLee Jones { 7184b106fb9SLee Jones .name = "ab8500-debug", 7191c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-debug", 7204b106fb9SLee Jones }, 7214b106fb9SLee Jones #endif 7224b106fb9SLee Jones { 7234b106fb9SLee Jones .name = "ab8500-sysctrl", 7241c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-sysctrl", 7254b106fb9SLee Jones }, 7264b106fb9SLee Jones { 7274b106fb9SLee Jones .name = "ab8500-regulator", 7281c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8505-regulator", 7294b106fb9SLee Jones }, 7304b106fb9SLee Jones { 7319ee17676SUlf Hansson .name = "abx500-clk", 7321c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-clk", 7339ee17676SUlf Hansson }, 7349ee17676SUlf Hansson { 7354b106fb9SLee Jones .name = "ab8500-gpadc", 736955de2eaSLee Jones .of_compatible = "stericsson,ab8500-gpadc", 7374b106fb9SLee Jones }, 7384b106fb9SLee Jones { 7394b106fb9SLee Jones .name = "ab8500-rtc", 7401c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-rtc", 7414b106fb9SLee Jones }, 7424b106fb9SLee Jones { 7434b106fb9SLee Jones .name = "ab8500-acc-det", 7441c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-acc-det", 7454b106fb9SLee Jones }, 7464b106fb9SLee Jones { 7474b106fb9SLee Jones .name = "ab8500-poweron-key", 7481c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-poweron-key", 7494b106fb9SLee Jones }, 7504b106fb9SLee Jones { 7514b106fb9SLee Jones .name = "ab8500-pwm", 7521c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-pwm", 7534b106fb9SLee Jones .id = 1, 7544b106fb9SLee Jones }, 7554b106fb9SLee Jones { 756eb696c31SLee Jones .name = "pinctrl-ab8505", 7571c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8505-gpio", 7584b106fb9SLee Jones }, 7594b106fb9SLee Jones { 7604b106fb9SLee Jones .name = "ab8500-usb", 7611c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-usb", 7624b106fb9SLee Jones }, 7634b106fb9SLee Jones { 7644b106fb9SLee Jones .name = "ab8500-codec", 7651c0769d2SStephan Gerhold .of_compatible = "stericsson,ab8500-codec", 7664b106fb9SLee Jones }, 767c0eda9aeSLee Jones { 768c0eda9aeSLee Jones .name = "ab-iddet", 769c0eda9aeSLee Jones }, 770c0eda9aeSLee Jones }; 771c0eda9aeSLee Jones 7725ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_devs[] = { 7734b106fb9SLee Jones #ifdef CONFIG_DEBUG_FS 7744b106fb9SLee Jones { 7754b106fb9SLee Jones .name = "ab8500-debug", 7764b106fb9SLee Jones }, 7774b106fb9SLee Jones #endif 7784b106fb9SLee Jones { 7794b106fb9SLee Jones .name = "ab8500-sysctrl", 7804b106fb9SLee Jones }, 7814b106fb9SLee Jones { 78253f325beSLee Jones .name = "ab8500-ext-regulator", 78353f325beSLee Jones }, 78453f325beSLee Jones { 7854b106fb9SLee Jones .name = "ab8500-regulator", 7864b106fb9SLee Jones }, 7874b106fb9SLee Jones { 7889ee17676SUlf Hansson .name = "abx500-clk", 7899ee17676SUlf Hansson .of_compatible = "stericsson,abx500-clk", 7909ee17676SUlf Hansson }, 7919ee17676SUlf Hansson { 7924b106fb9SLee Jones .name = "ab8500-gpadc", 793955de2eaSLee Jones .of_compatible = "stericsson,ab8500-gpadc", 7944b106fb9SLee Jones }, 7954b106fb9SLee Jones { 7964b106fb9SLee Jones .name = "ab8500-acc-det", 7974b106fb9SLee Jones }, 7984b106fb9SLee Jones { 7994b106fb9SLee Jones .name = "ab8500-poweron-key", 8004b106fb9SLee Jones }, 8014b106fb9SLee Jones { 8024b106fb9SLee Jones .name = "ab8500-pwm", 8034b106fb9SLee Jones .id = 1, 8044b106fb9SLee Jones }, 8054b106fb9SLee Jones { 8064b106fb9SLee Jones .name = "abx500-temp", 8074b106fb9SLee Jones }, 808c0eda9aeSLee Jones { 809eb696c31SLee Jones .name = "pinctrl-ab8540", 810c0eda9aeSLee Jones }, 811c0eda9aeSLee Jones { 812c0eda9aeSLee Jones .name = "ab8540-usb", 813c0eda9aeSLee Jones }, 814c0eda9aeSLee Jones { 815c0eda9aeSLee Jones .name = "ab8540-codec", 816c0eda9aeSLee Jones }, 817c0eda9aeSLee Jones { 81844f72e53SVirupax Sadashivpetimath .name = "ab-iddet", 81944f72e53SVirupax Sadashivpetimath }, 820d6255529SLinus Walleij }; 821d6255529SLinus Walleij 8225ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_cut1_devs[] = { 8239c717cf3SAlexandre Torgue { 8249c717cf3SAlexandre Torgue .name = "ab8500-rtc", 8259c717cf3SAlexandre Torgue .of_compatible = "stericsson,ab8500-rtc", 8269c717cf3SAlexandre Torgue }, 8279c717cf3SAlexandre Torgue }; 8289c717cf3SAlexandre Torgue 8295ac98553SGeert Uytterhoeven static const struct mfd_cell ab8540_cut2_devs[] = { 8309c717cf3SAlexandre Torgue { 8319c717cf3SAlexandre Torgue .name = "ab8540-rtc", 8329c717cf3SAlexandre Torgue .of_compatible = "stericsson,ab8540-rtc", 8339c717cf3SAlexandre Torgue }, 8349c717cf3SAlexandre Torgue }; 8359c717cf3SAlexandre Torgue 836cca69b67SMattias Wallin static ssize_t show_chip_id(struct device *dev, 837cca69b67SMattias Wallin struct device_attribute *attr, char *buf) 838cca69b67SMattias Wallin { 839cca69b67SMattias Wallin struct ab8500 *ab8500; 840cca69b67SMattias Wallin 841cca69b67SMattias Wallin ab8500 = dev_get_drvdata(dev); 842e436ddffSLee Jones 843cca69b67SMattias Wallin return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); 844cca69b67SMattias Wallin } 845cca69b67SMattias Wallin 846e5c238c3SMattias Wallin /* 847e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 848e5c238c3SMattias Wallin * 0x01 Swoff bit programming 849e5c238c3SMattias Wallin * 0x02 Thermal protection activation 850e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 851e5c238c3SMattias Wallin * 0x08 Watchdog expired 852e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 853e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 854e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 855e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 856e5c238c3SMattias Wallin */ 857e5c238c3SMattias Wallin static ssize_t show_switch_off_status(struct device *dev, 858e5c238c3SMattias Wallin struct device_attribute *attr, char *buf) 859e5c238c3SMattias Wallin { 860e5c238c3SMattias Wallin int ret; 861e5c238c3SMattias Wallin u8 value; 862e5c238c3SMattias Wallin struct ab8500 *ab8500; 863e5c238c3SMattias Wallin 864e5c238c3SMattias Wallin ab8500 = dev_get_drvdata(dev); 865e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 866e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 867e5c238c3SMattias Wallin if (ret < 0) 868e5c238c3SMattias Wallin return ret; 869e5c238c3SMattias Wallin return sprintf(buf, "%#x\n", value); 870e5c238c3SMattias Wallin } 871e5c238c3SMattias Wallin 872f04a9d8aSRajkumar Kasirajan /* use mask and set to override the register turn_on_stat value */ 873f04a9d8aSRajkumar Kasirajan void ab8500_override_turn_on_stat(u8 mask, u8 set) 874f04a9d8aSRajkumar Kasirajan { 875f04a9d8aSRajkumar Kasirajan spin_lock(&on_stat_lock); 876f04a9d8aSRajkumar Kasirajan turn_on_stat_mask = mask; 877f04a9d8aSRajkumar Kasirajan turn_on_stat_set = set; 878f04a9d8aSRajkumar Kasirajan spin_unlock(&on_stat_lock); 879f04a9d8aSRajkumar Kasirajan } 880f04a9d8aSRajkumar Kasirajan 881b4a31037SAndrew Lynn /* 882b4a31037SAndrew Lynn * ab8500 has turned on due to (TURN_ON_STATUS): 883b4a31037SAndrew Lynn * 0x01 PORnVbat 884b4a31037SAndrew Lynn * 0x02 PonKey1dbF 885b4a31037SAndrew Lynn * 0x04 PonKey2dbF 886b4a31037SAndrew Lynn * 0x08 RTCAlarm 887b4a31037SAndrew Lynn * 0x10 MainChDet 888b4a31037SAndrew Lynn * 0x20 VbusDet 889b4a31037SAndrew Lynn * 0x40 UsbIDDetect 890b4a31037SAndrew Lynn * 0x80 Reserved 891b4a31037SAndrew Lynn */ 892b4a31037SAndrew Lynn static ssize_t show_turn_on_status(struct device *dev, 893b4a31037SAndrew Lynn struct device_attribute *attr, char *buf) 894b4a31037SAndrew Lynn { 895b4a31037SAndrew Lynn int ret; 896b4a31037SAndrew Lynn u8 value; 897b4a31037SAndrew Lynn struct ab8500 *ab8500; 898b4a31037SAndrew Lynn 899b4a31037SAndrew Lynn ab8500 = dev_get_drvdata(dev); 900b4a31037SAndrew Lynn ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 901b4a31037SAndrew Lynn AB8500_TURN_ON_STATUS, &value); 902b4a31037SAndrew Lynn if (ret < 0) 903b4a31037SAndrew Lynn return ret; 904f04a9d8aSRajkumar Kasirajan 905f04a9d8aSRajkumar Kasirajan /* 906f04a9d8aSRajkumar Kasirajan * In L9540, turn_on_status register is not updated correctly if 907f04a9d8aSRajkumar Kasirajan * the device is rebooted with AC/USB charger connected. Due to 908f04a9d8aSRajkumar Kasirajan * this, the device boots android instead of entering into charge 909f04a9d8aSRajkumar Kasirajan * only mode. Read the AC/USB status register to detect the charger 910f04a9d8aSRajkumar Kasirajan * presence and update the turn on status manually. 911f04a9d8aSRajkumar Kasirajan */ 912f04a9d8aSRajkumar Kasirajan if (is_ab9540(ab8500)) { 913f04a9d8aSRajkumar Kasirajan spin_lock(&on_stat_lock); 914f04a9d8aSRajkumar Kasirajan value = (value & turn_on_stat_mask) | turn_on_stat_set; 915f04a9d8aSRajkumar Kasirajan spin_unlock(&on_stat_lock); 916f04a9d8aSRajkumar Kasirajan } 917f04a9d8aSRajkumar Kasirajan 918b4a31037SAndrew Lynn return sprintf(buf, "%#x\n", value); 919b4a31037SAndrew Lynn } 920b4a31037SAndrew Lynn 92193ff722eSLee Jones static ssize_t show_turn_on_status_2(struct device *dev, 92293ff722eSLee Jones struct device_attribute *attr, char *buf) 92393ff722eSLee Jones { 92493ff722eSLee Jones int ret; 92593ff722eSLee Jones u8 value; 92693ff722eSLee Jones struct ab8500 *ab8500; 92793ff722eSLee Jones 92893ff722eSLee Jones ab8500 = dev_get_drvdata(dev); 92993ff722eSLee Jones ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 93093ff722eSLee Jones AB8505_TURN_ON_STATUS_2, &value); 93193ff722eSLee Jones if (ret < 0) 93293ff722eSLee Jones return ret; 93393ff722eSLee Jones return sprintf(buf, "%#x\n", (value & 0x1)); 93493ff722eSLee Jones } 93593ff722eSLee Jones 936d6255529SLinus Walleij static ssize_t show_ab9540_dbbrstn(struct device *dev, 937d6255529SLinus Walleij struct device_attribute *attr, char *buf) 938d6255529SLinus Walleij { 939d6255529SLinus Walleij struct ab8500 *ab8500; 940d6255529SLinus Walleij int ret; 941d6255529SLinus Walleij u8 value; 942d6255529SLinus Walleij 943d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 944d6255529SLinus Walleij 945d6255529SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2, 946d6255529SLinus Walleij AB9540_MODEM_CTRL2_REG, &value); 947d6255529SLinus Walleij if (ret < 0) 948d6255529SLinus Walleij return ret; 949d6255529SLinus Walleij 950d6255529SLinus Walleij return sprintf(buf, "%d\n", 951d6255529SLinus Walleij (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0); 952d6255529SLinus Walleij } 953d6255529SLinus Walleij 954d6255529SLinus Walleij static ssize_t store_ab9540_dbbrstn(struct device *dev, 955d6255529SLinus Walleij struct device_attribute *attr, const char *buf, size_t count) 956d6255529SLinus Walleij { 957d6255529SLinus Walleij struct ab8500 *ab8500; 958d6255529SLinus Walleij int ret = count; 959d6255529SLinus Walleij int err; 960d6255529SLinus Walleij u8 bitvalues; 961d6255529SLinus Walleij 962d6255529SLinus Walleij ab8500 = dev_get_drvdata(dev); 963d6255529SLinus Walleij 964d6255529SLinus Walleij if (count > 0) { 965d6255529SLinus Walleij switch (buf[0]) { 966d6255529SLinus Walleij case '0': 967d6255529SLinus Walleij bitvalues = 0; 968d6255529SLinus Walleij break; 969d6255529SLinus Walleij case '1': 970d6255529SLinus Walleij bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT; 971d6255529SLinus Walleij break; 972d6255529SLinus Walleij default: 973d6255529SLinus Walleij goto exit; 974d6255529SLinus Walleij } 975d6255529SLinus Walleij 976d6255529SLinus Walleij err = mask_and_set_register_interruptible(ab8500, 977d6255529SLinus Walleij AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG, 978d6255529SLinus Walleij AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues); 979d6255529SLinus Walleij if (err) 980d6255529SLinus Walleij dev_info(ab8500->dev, 981d6255529SLinus Walleij "Failed to set DBBRSTN %c, err %#x\n", 982d6255529SLinus Walleij buf[0], err); 983d6255529SLinus Walleij } 984d6255529SLinus Walleij 985d6255529SLinus Walleij exit: 986d6255529SLinus Walleij return ret; 987d6255529SLinus Walleij } 988d6255529SLinus Walleij 989cca69b67SMattias Wallin static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); 990e5c238c3SMattias Wallin static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL); 991b4a31037SAndrew Lynn static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL); 99293ff722eSLee Jones static DEVICE_ATTR(turn_on_status_2, S_IRUGO, show_turn_on_status_2, NULL); 993d6255529SLinus Walleij static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR, 994d6255529SLinus Walleij show_ab9540_dbbrstn, store_ab9540_dbbrstn); 995cca69b67SMattias Wallin 996cca69b67SMattias Wallin static struct attribute *ab8500_sysfs_entries[] = { 997cca69b67SMattias Wallin &dev_attr_chip_id.attr, 998e5c238c3SMattias Wallin &dev_attr_switch_off_status.attr, 999b4a31037SAndrew Lynn &dev_attr_turn_on_status.attr, 1000cca69b67SMattias Wallin NULL, 1001cca69b67SMattias Wallin }; 1002cca69b67SMattias Wallin 100393ff722eSLee Jones static struct attribute *ab8505_sysfs_entries[] = { 100493ff722eSLee Jones &dev_attr_turn_on_status_2.attr, 100593ff722eSLee Jones NULL, 100693ff722eSLee Jones }; 100793ff722eSLee Jones 1008d6255529SLinus Walleij static struct attribute *ab9540_sysfs_entries[] = { 1009d6255529SLinus Walleij &dev_attr_chip_id.attr, 1010d6255529SLinus Walleij &dev_attr_switch_off_status.attr, 1011d6255529SLinus Walleij &dev_attr_turn_on_status.attr, 1012d6255529SLinus Walleij &dev_attr_dbbrstn.attr, 1013d6255529SLinus Walleij NULL, 1014d6255529SLinus Walleij }; 1015d6255529SLinus Walleij 101652557dc6SArvind Yadav static const struct attribute_group ab8500_attr_group = { 1017cca69b67SMattias Wallin .attrs = ab8500_sysfs_entries, 1018cca69b67SMattias Wallin }; 1019cca69b67SMattias Wallin 102052557dc6SArvind Yadav static const struct attribute_group ab8505_attr_group = { 102193ff722eSLee Jones .attrs = ab8505_sysfs_entries, 102293ff722eSLee Jones }; 102393ff722eSLee Jones 102452557dc6SArvind Yadav static const struct attribute_group ab9540_attr_group = { 1025d6255529SLinus Walleij .attrs = ab9540_sysfs_entries, 1026d6255529SLinus Walleij }; 1027d6255529SLinus Walleij 1028f791be49SBill Pemberton static int ab8500_probe(struct platform_device *pdev) 102962579266SRabin Vincent { 1030500e69a1SLee Jones static const char * const switch_off_status[] = { 1031b04c530cSJonas Aaberg "Swoff bit programming", 1032b04c530cSJonas Aaberg "Thermal protection activation", 1033b04c530cSJonas Aaberg "Vbat lower then BattOk falling threshold", 1034b04c530cSJonas Aaberg "Watchdog expired", 1035b04c530cSJonas Aaberg "Non presence of 32kHz clock", 1036b04c530cSJonas Aaberg "Battery level lower than power on reset threshold", 1037b04c530cSJonas Aaberg "Power on key 1 pressed longer than 10 seconds", 1038b04c530cSJonas Aaberg "DB8500 thermal shutdown"}; 1039500e69a1SLee Jones static const char * const turn_on_status[] = { 1040abee26cdSMattias Wallin "Battery rising (Vbat)", 1041abee26cdSMattias Wallin "Power On Key 1 dbF", 1042abee26cdSMattias Wallin "Power On Key 2 dbF", 1043abee26cdSMattias Wallin "RTC Alarm", 1044abee26cdSMattias Wallin "Main Charger Detect", 1045abee26cdSMattias Wallin "Vbus Detect (USB)", 1046abee26cdSMattias Wallin "USB ID Detect", 1047abee26cdSMattias Wallin "UART Factory Mode Detect"}; 1048d28f1db8SLee Jones const struct platform_device_id *platid = platform_get_device_id(pdev); 10496bc4a568SLee Jones enum ab8500_version version = AB8500_VERSION_UNDEFINED; 10506bc4a568SLee Jones struct device_node *np = pdev->dev.of_node; 1051d28f1db8SLee Jones struct ab8500 *ab8500; 1052d28f1db8SLee Jones struct resource *resource; 105362579266SRabin Vincent int ret; 105462579266SRabin Vincent int i; 105547c16975SMattias Wallin u8 value; 105662579266SRabin Vincent 10577ccf40b1SLee Jones ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL); 1058d28f1db8SLee Jones if (!ab8500) 1059d28f1db8SLee Jones return -ENOMEM; 1060d28f1db8SLee Jones 1061d28f1db8SLee Jones ab8500->dev = &pdev->dev; 1062d28f1db8SLee Jones 1063d28f1db8SLee Jones resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 1064f864c46aSLinus Walleij if (!resource) { 1065f864c46aSLinus Walleij dev_err(&pdev->dev, "no IRQ resource\n"); 10668c4203cbSLee Jones return -ENODEV; 1067f864c46aSLinus Walleij } 1068d28f1db8SLee Jones 1069d28f1db8SLee Jones ab8500->irq = resource->start; 1070d28f1db8SLee Jones 1071822672a7SLee Jones ab8500->read = ab8500_prcmu_read; 1072822672a7SLee Jones ab8500->write = ab8500_prcmu_write; 1073822672a7SLee Jones ab8500->write_masked = ab8500_prcmu_write_masked; 1074d28f1db8SLee Jones 107562579266SRabin Vincent mutex_init(&ab8500->lock); 107662579266SRabin Vincent mutex_init(&ab8500->irq_lock); 1077112a80d2SJonas Aaberg atomic_set(&ab8500->transfer_ongoing, 0); 107862579266SRabin Vincent 1079d28f1db8SLee Jones platform_set_drvdata(pdev, ab8500); 1080d28f1db8SLee Jones 10816bc4a568SLee Jones if (platid) 10826bc4a568SLee Jones version = platid->driver_data; 10836bc4a568SLee Jones 10840f620837SLinus Walleij if (version != AB8500_VERSION_UNDEFINED) 10850f620837SLinus Walleij ab8500->version = version; 10860f620837SLinus Walleij else { 10870f620837SLinus Walleij ret = get_register_interruptible(ab8500, AB8500_MISC, 10880f620837SLinus Walleij AB8500_IC_NAME_REG, &value); 1089f864c46aSLinus Walleij if (ret < 0) { 1090f864c46aSLinus Walleij dev_err(&pdev->dev, "could not probe HW\n"); 10918c4203cbSLee Jones return ret; 1092f864c46aSLinus Walleij } 10930f620837SLinus Walleij 10940f620837SLinus Walleij ab8500->version = value; 10950f620837SLinus Walleij } 10960f620837SLinus Walleij 109747c16975SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_MISC, 109847c16975SMattias Wallin AB8500_REV_REG, &value); 109962579266SRabin Vincent if (ret < 0) 11008c4203cbSLee Jones return ret; 110162579266SRabin Vincent 110247c16975SMattias Wallin ab8500->chip_id = value; 110362579266SRabin Vincent 11040f620837SLinus Walleij dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n", 11050f620837SLinus Walleij ab8500_version_str[ab8500->version], 11060f620837SLinus Walleij ab8500->chip_id >> 4, 11070f620837SLinus Walleij ab8500->chip_id & 0x0F); 11080f620837SLinus Walleij 11093e1a498fSLee Jones /* Configure AB8540 */ 11103e1a498fSLee Jones if (is_ab8540(ab8500)) { 11113e1a498fSLee Jones ab8500->mask_size = AB8540_NUM_IRQ_REGS; 11123e1a498fSLee Jones ab8500->irq_reg_offset = ab8540_irq_regoffset; 11133e1a498fSLee Jones ab8500->it_latchhier_num = AB8540_IT_LATCHHIER_NUM; 11143e1a498fSLee Jones } /* Configure AB8500 or AB9540 IRQ */ 11153e1a498fSLee Jones else if (is_ab9540(ab8500) || is_ab8505(ab8500)) { 1116d6255529SLinus Walleij ab8500->mask_size = AB9540_NUM_IRQ_REGS; 1117d6255529SLinus Walleij ab8500->irq_reg_offset = ab9540_irq_regoffset; 11183e1a498fSLee Jones ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM; 1119d6255529SLinus Walleij } else { 11202ced445eSLinus Walleij ab8500->mask_size = AB8500_NUM_IRQ_REGS; 11212ced445eSLinus Walleij ab8500->irq_reg_offset = ab8500_irq_regoffset; 11223e1a498fSLee Jones ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM; 1123d6255529SLinus Walleij } 11247ccf40b1SLee Jones ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size, 11257ccf40b1SLee Jones GFP_KERNEL); 11262ced445eSLinus Walleij if (!ab8500->mask) 11272ced445eSLinus Walleij return -ENOMEM; 11287ccf40b1SLee Jones ab8500->oldmask = devm_kzalloc(&pdev->dev, ab8500->mask_size, 11297ccf40b1SLee Jones GFP_KERNEL); 11308c4203cbSLee Jones if (!ab8500->oldmask) 11318c4203cbSLee Jones return -ENOMEM; 11328c4203cbSLee Jones 1133e5c238c3SMattias Wallin /* 1134e5c238c3SMattias Wallin * ab8500 has switched off due to (SWITCH_OFF_STATUS): 1135e5c238c3SMattias Wallin * 0x01 Swoff bit programming 1136e5c238c3SMattias Wallin * 0x02 Thermal protection activation 1137e5c238c3SMattias Wallin * 0x04 Vbat lower then BattOk falling threshold 1138e5c238c3SMattias Wallin * 0x08 Watchdog expired 1139e5c238c3SMattias Wallin * 0x10 Non presence of 32kHz clock 1140e5c238c3SMattias Wallin * 0x20 Battery level lower than power on reset threshold 1141e5c238c3SMattias Wallin * 0x40 Power on key 1 pressed longer than 10 seconds 1142e5c238c3SMattias Wallin * 0x80 DB8500 thermal shutdown 1143e5c238c3SMattias Wallin */ 1144e5c238c3SMattias Wallin 1145e5c238c3SMattias Wallin ret = get_register_interruptible(ab8500, AB8500_RTC, 1146e5c238c3SMattias Wallin AB8500_SWITCH_OFF_STATUS, &value); 1147e5c238c3SMattias Wallin if (ret < 0) 1148e5c238c3SMattias Wallin return ret; 1149b04c530cSJonas Aaberg dev_info(ab8500->dev, "switch off cause(s) (%#x): ", value); 1150b04c530cSJonas Aaberg 1151b04c530cSJonas Aaberg if (value) { 1152b04c530cSJonas Aaberg for (i = 0; i < ARRAY_SIZE(switch_off_status); i++) { 1153b04c530cSJonas Aaberg if (value & 1) 11547ccf40b1SLee Jones pr_cont(" \"%s\"", switch_off_status[i]); 1155b04c530cSJonas Aaberg value = value >> 1; 1156b04c530cSJonas Aaberg 1157b04c530cSJonas Aaberg } 11587ccf40b1SLee Jones pr_cont("\n"); 1159b04c530cSJonas Aaberg } else { 11607ccf40b1SLee Jones pr_cont(" None\n"); 1161b04c530cSJonas Aaberg } 1162abee26cdSMattias Wallin ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 1163abee26cdSMattias Wallin AB8500_TURN_ON_STATUS, &value); 1164abee26cdSMattias Wallin if (ret < 0) 1165abee26cdSMattias Wallin return ret; 1166abee26cdSMattias Wallin dev_info(ab8500->dev, "turn on reason(s) (%#x): ", value); 1167abee26cdSMattias Wallin 1168abee26cdSMattias Wallin if (value) { 1169abee26cdSMattias Wallin for (i = 0; i < ARRAY_SIZE(turn_on_status); i++) { 1170abee26cdSMattias Wallin if (value & 1) 11717ccf40b1SLee Jones pr_cont("\"%s\" ", turn_on_status[i]); 1172abee26cdSMattias Wallin value = value >> 1; 1173abee26cdSMattias Wallin } 11747ccf40b1SLee Jones pr_cont("\n"); 1175abee26cdSMattias Wallin } else { 11767ccf40b1SLee Jones pr_cont("None\n"); 1177abee26cdSMattias Wallin } 1178e5c238c3SMattias Wallin 1179f04a9d8aSRajkumar Kasirajan if (is_ab9540(ab8500)) { 1180f04a9d8aSRajkumar Kasirajan ret = get_register_interruptible(ab8500, AB8500_CHARGER, 1181f04a9d8aSRajkumar Kasirajan AB8500_CH_USBCH_STAT1_REG, &value); 1182f04a9d8aSRajkumar Kasirajan if (ret < 0) 1183f04a9d8aSRajkumar Kasirajan return ret; 1184f04a9d8aSRajkumar Kasirajan if ((value & VBUS_DET_DBNC1) && (value & VBUS_DET_DBNC100)) 1185f04a9d8aSRajkumar Kasirajan ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON, 1186f04a9d8aSRajkumar Kasirajan AB8500_VBUS_DET); 1187f04a9d8aSRajkumar Kasirajan } 118862579266SRabin Vincent 118962579266SRabin Vincent /* Clear and mask all interrupts */ 11902ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) { 11910f620837SLinus Walleij /* 11920f620837SLinus Walleij * Interrupt register 12 doesn't exist prior to AB8500 version 11930f620837SLinus Walleij * 2.0 11940f620837SLinus Walleij */ 11950f620837SLinus Walleij if (ab8500->irq_reg_offset[i] == 11 && 11960f620837SLinus Walleij is_ab8500_1p1_or_earlier(ab8500)) 119792d50a41SMattias Wallin continue; 119862579266SRabin Vincent 11993e1a498fSLee Jones if (ab8500->irq_reg_offset[i] < 0) 12003e1a498fSLee Jones continue; 12013e1a498fSLee Jones 120247c16975SMattias Wallin get_register_interruptible(ab8500, AB8500_INTERRUPT, 12032ced445eSLinus Walleij AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i], 120492d50a41SMattias Wallin &value); 120547c16975SMattias Wallin set_register_interruptible(ab8500, AB8500_INTERRUPT, 12062ced445eSLinus Walleij AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff); 120762579266SRabin Vincent } 120862579266SRabin Vincent 120947c16975SMattias Wallin ret = abx500_register_ops(ab8500->dev, &ab8500_ops); 121047c16975SMattias Wallin if (ret) 12118c4203cbSLee Jones return ret; 121247c16975SMattias Wallin 12132ced445eSLinus Walleij for (i = 0; i < ab8500->mask_size; i++) 121462579266SRabin Vincent ab8500->mask[i] = ab8500->oldmask[i] = 0xff; 121562579266SRabin Vincent 121606e589efSLee Jones ret = ab8500_irq_init(ab8500, np); 121762579266SRabin Vincent if (ret) 12188c4203cbSLee Jones return ret; 121962579266SRabin Vincent 12208c4203cbSLee Jones ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL, 12217ccfe9b1SMichel JAOUEN ab8500_hierarchical_irq, 12227ccfe9b1SMichel JAOUEN IRQF_ONESHOT | IRQF_NO_SUSPEND, 12237ccfe9b1SMichel JAOUEN "ab8500", ab8500); 122462579266SRabin Vincent if (ret) 12258c4203cbSLee Jones return ret; 122662579266SRabin Vincent 1227d6255529SLinus Walleij if (is_ab9540(ab8500)) 1228d6255529SLinus Walleij ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, 1229d6255529SLinus Walleij ARRAY_SIZE(ab9540_devs), NULL, 1230f864c46aSLinus Walleij 0, ab8500->domain); 12319c717cf3SAlexandre Torgue else if (is_ab8540(ab8500)) { 1232c0eda9aeSLee Jones ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs, 1233c0eda9aeSLee Jones ARRAY_SIZE(ab8540_devs), NULL, 1234f864c46aSLinus Walleij 0, ab8500->domain); 12359c717cf3SAlexandre Torgue if (ret) 12369c717cf3SAlexandre Torgue return ret; 12379c717cf3SAlexandre Torgue 12389c717cf3SAlexandre Torgue if (is_ab8540_1p2_or_earlier(ab8500)) 12399c717cf3SAlexandre Torgue ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut1_devs, 12409c717cf3SAlexandre Torgue ARRAY_SIZE(ab8540_cut1_devs), NULL, 1241f864c46aSLinus Walleij 0, ab8500->domain); 12429c717cf3SAlexandre Torgue else /* ab8540 >= cut2 */ 12439c717cf3SAlexandre Torgue ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut2_devs, 12449c717cf3SAlexandre Torgue ARRAY_SIZE(ab8540_cut2_devs), NULL, 1245f864c46aSLinus Walleij 0, ab8500->domain); 12469c717cf3SAlexandre Torgue } else if (is_ab8505(ab8500)) 1247c0eda9aeSLee Jones ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs, 1248c0eda9aeSLee Jones ARRAY_SIZE(ab8505_devs), NULL, 1249f864c46aSLinus Walleij 0, ab8500->domain); 1250d6255529SLinus Walleij else 1251549931f9SSundar R Iyer ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, 125244f72e53SVirupax Sadashivpetimath ARRAY_SIZE(ab8500_devs), NULL, 1253f864c46aSLinus Walleij 0, ab8500->domain); 12546bc4a568SLee Jones if (ret) 12558c4203cbSLee Jones return ret; 125644f72e53SVirupax Sadashivpetimath 12576ef9418cSRickard Andersson if (!no_bm) { 12586ef9418cSRickard Andersson /* Add battery management devices */ 12596ef9418cSRickard Andersson ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, 12606ef9418cSRickard Andersson ARRAY_SIZE(ab8500_bm_devs), NULL, 1261f864c46aSLinus Walleij 0, ab8500->domain); 12626ef9418cSRickard Andersson if (ret) 12636ef9418cSRickard Andersson dev_err(ab8500->dev, "error adding bm devices\n"); 12646ef9418cSRickard Andersson } 12656ef9418cSRickard Andersson 1266e436ddffSLee Jones if (((is_ab8505(ab8500) || is_ab9540(ab8500)) && 1267e436ddffSLee Jones ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500)) 1268d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1269d6255529SLinus Walleij &ab9540_attr_group); 1270d6255529SLinus Walleij else 1271d6255529SLinus Walleij ret = sysfs_create_group(&ab8500->dev->kobj, 1272d6255529SLinus Walleij &ab8500_attr_group); 127393ff722eSLee Jones 127493ff722eSLee Jones if ((is_ab8505(ab8500) || is_ab9540(ab8500)) && 127593ff722eSLee Jones ab8500->chip_id >= AB8500_CUT2P0) 127693ff722eSLee Jones ret = sysfs_create_group(&ab8500->dev->kobj, 127793ff722eSLee Jones &ab8505_attr_group); 127893ff722eSLee Jones 1279cca69b67SMattias Wallin if (ret) 1280cca69b67SMattias Wallin dev_err(ab8500->dev, "error creating sysfs entries\n"); 128106e589efSLee Jones 128262579266SRabin Vincent return ret; 128362579266SRabin Vincent } 128462579266SRabin Vincent 1285d28f1db8SLee Jones static const struct platform_device_id ab8500_id[] = { 1286d28f1db8SLee Jones { "ab8500-core", AB8500_VERSION_AB8500 }, 12871c0769d2SStephan Gerhold { "ab8505-core", AB8500_VERSION_AB8505 }, 1288d28f1db8SLee Jones { "ab9540-i2c", AB8500_VERSION_AB9540 }, 1289d28f1db8SLee Jones { "ab8540-i2c", AB8500_VERSION_AB8540 }, 1290d28f1db8SLee Jones { } 1291d28f1db8SLee Jones }; 1292d28f1db8SLee Jones 1293d28f1db8SLee Jones static struct platform_driver ab8500_core_driver = { 1294d28f1db8SLee Jones .driver = { 1295d28f1db8SLee Jones .name = "ab8500-core", 129631cbae22SPaul Gortmaker .suppress_bind_attrs = true, 1297d28f1db8SLee Jones }, 1298d28f1db8SLee Jones .probe = ab8500_probe, 1299d28f1db8SLee Jones .id_table = ab8500_id, 1300d28f1db8SLee Jones }; 1301d28f1db8SLee Jones 1302d28f1db8SLee Jones static int __init ab8500_core_init(void) 1303d28f1db8SLee Jones { 1304d28f1db8SLee Jones return platform_driver_register(&ab8500_core_driver); 1305d28f1db8SLee Jones } 1306ba7cbc3eSLee Jones core_initcall(ab8500_core_init); 1307