18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) ST-Ericsson SA 2010 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> 68c2ecf20Sopenharmony_ci * Author: Rabin Vincent <rabin.vincent@stericsson.com> 78c2ecf20Sopenharmony_ci * Author: Mattias Wallin <mattias.wallin@stericsson.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/irq.h> 148c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 188c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 198c2ecf20Sopenharmony_ci#include <linux/mfd/core.h> 208c2ecf20Sopenharmony_ci#include <linux/mfd/abx500.h> 218c2ecf20Sopenharmony_ci#include <linux/mfd/abx500/ab8500.h> 228c2ecf20Sopenharmony_ci#include <linux/mfd/abx500/ab8500-bm.h> 238c2ecf20Sopenharmony_ci#include <linux/mfd/dbx500-prcmu.h> 248c2ecf20Sopenharmony_ci#include <linux/regulator/ab8500.h> 258c2ecf20Sopenharmony_ci#include <linux/of.h> 268c2ecf20Sopenharmony_ci#include <linux/of_device.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * Interrupt register offsets 308c2ecf20Sopenharmony_ci * Bank : 0x0E 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci#define AB8500_IT_SOURCE1_REG 0x00 338c2ecf20Sopenharmony_ci#define AB8500_IT_SOURCE2_REG 0x01 348c2ecf20Sopenharmony_ci#define AB8500_IT_SOURCE3_REG 0x02 358c2ecf20Sopenharmony_ci#define AB8500_IT_SOURCE4_REG 0x03 368c2ecf20Sopenharmony_ci#define AB8500_IT_SOURCE5_REG 0x04 378c2ecf20Sopenharmony_ci#define AB8500_IT_SOURCE6_REG 0x05 388c2ecf20Sopenharmony_ci#define AB8500_IT_SOURCE7_REG 0x06 398c2ecf20Sopenharmony_ci#define AB8500_IT_SOURCE8_REG 0x07 408c2ecf20Sopenharmony_ci#define AB9540_IT_SOURCE13_REG 0x0C 418c2ecf20Sopenharmony_ci#define AB8500_IT_SOURCE19_REG 0x12 428c2ecf20Sopenharmony_ci#define AB8500_IT_SOURCE20_REG 0x13 438c2ecf20Sopenharmony_ci#define AB8500_IT_SOURCE21_REG 0x14 448c2ecf20Sopenharmony_ci#define AB8500_IT_SOURCE22_REG 0x15 458c2ecf20Sopenharmony_ci#define AB8500_IT_SOURCE23_REG 0x16 468c2ecf20Sopenharmony_ci#define AB8500_IT_SOURCE24_REG 0x17 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 498c2ecf20Sopenharmony_ci * latch registers 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH1_REG 0x20 528c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH2_REG 0x21 538c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH3_REG 0x22 548c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH4_REG 0x23 558c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH5_REG 0x24 568c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH6_REG 0x25 578c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH7_REG 0x26 588c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH8_REG 0x27 598c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH9_REG 0x28 608c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH10_REG 0x29 618c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH12_REG 0x2B 628c2ecf20Sopenharmony_ci#define AB9540_IT_LATCH13_REG 0x2C 638c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH19_REG 0x32 648c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH20_REG 0x33 658c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH21_REG 0x34 668c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH22_REG 0x35 678c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH23_REG 0x36 688c2ecf20Sopenharmony_ci#define AB8500_IT_LATCH24_REG 0x37 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* 718c2ecf20Sopenharmony_ci * mask registers 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define AB8500_IT_MASK1_REG 0x40 758c2ecf20Sopenharmony_ci#define AB8500_IT_MASK2_REG 0x41 768c2ecf20Sopenharmony_ci#define AB8500_IT_MASK3_REG 0x42 778c2ecf20Sopenharmony_ci#define AB8500_IT_MASK4_REG 0x43 788c2ecf20Sopenharmony_ci#define AB8500_IT_MASK5_REG 0x44 798c2ecf20Sopenharmony_ci#define AB8500_IT_MASK6_REG 0x45 808c2ecf20Sopenharmony_ci#define AB8500_IT_MASK7_REG 0x46 818c2ecf20Sopenharmony_ci#define AB8500_IT_MASK8_REG 0x47 828c2ecf20Sopenharmony_ci#define AB8500_IT_MASK9_REG 0x48 838c2ecf20Sopenharmony_ci#define AB8500_IT_MASK10_REG 0x49 848c2ecf20Sopenharmony_ci#define AB8500_IT_MASK11_REG 0x4A 858c2ecf20Sopenharmony_ci#define AB8500_IT_MASK12_REG 0x4B 868c2ecf20Sopenharmony_ci#define AB8500_IT_MASK13_REG 0x4C 878c2ecf20Sopenharmony_ci#define AB8500_IT_MASK14_REG 0x4D 888c2ecf20Sopenharmony_ci#define AB8500_IT_MASK15_REG 0x4E 898c2ecf20Sopenharmony_ci#define AB8500_IT_MASK16_REG 0x4F 908c2ecf20Sopenharmony_ci#define AB8500_IT_MASK17_REG 0x50 918c2ecf20Sopenharmony_ci#define AB8500_IT_MASK18_REG 0x51 928c2ecf20Sopenharmony_ci#define AB8500_IT_MASK19_REG 0x52 938c2ecf20Sopenharmony_ci#define AB8500_IT_MASK20_REG 0x53 948c2ecf20Sopenharmony_ci#define AB8500_IT_MASK21_REG 0x54 958c2ecf20Sopenharmony_ci#define AB8500_IT_MASK22_REG 0x55 968c2ecf20Sopenharmony_ci#define AB8500_IT_MASK23_REG 0x56 978c2ecf20Sopenharmony_ci#define AB8500_IT_MASK24_REG 0x57 988c2ecf20Sopenharmony_ci#define AB8500_IT_MASK25_REG 0x58 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* 1018c2ecf20Sopenharmony_ci * latch hierarchy registers 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_ci#define AB8500_IT_LATCHHIER1_REG 0x60 1048c2ecf20Sopenharmony_ci#define AB8500_IT_LATCHHIER2_REG 0x61 1058c2ecf20Sopenharmony_ci#define AB8500_IT_LATCHHIER3_REG 0x62 1068c2ecf20Sopenharmony_ci#define AB8540_IT_LATCHHIER4_REG 0x63 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#define AB8500_IT_LATCHHIER_NUM 3 1098c2ecf20Sopenharmony_ci#define AB8540_IT_LATCHHIER_NUM 4 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci#define AB8500_REV_REG 0x80 1128c2ecf20Sopenharmony_ci#define AB8500_IC_NAME_REG 0x82 1138c2ecf20Sopenharmony_ci#define AB8500_SWITCH_OFF_STATUS 0x00 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#define AB8500_TURN_ON_STATUS 0x00 1168c2ecf20Sopenharmony_ci#define AB8505_TURN_ON_STATUS_2 0x04 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#define AB8500_CH_USBCH_STAT1_REG 0x02 1198c2ecf20Sopenharmony_ci#define VBUS_DET_DBNC100 0x02 1208c2ecf20Sopenharmony_ci#define VBUS_DET_DBNC1 0x01 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(on_stat_lock); 1238c2ecf20Sopenharmony_cistatic u8 turn_on_stat_mask = 0xFF; 1248c2ecf20Sopenharmony_cistatic u8 turn_on_stat_set; 1258c2ecf20Sopenharmony_cistatic bool no_bm; /* No battery management */ 1268c2ecf20Sopenharmony_ci/* 1278c2ecf20Sopenharmony_ci * not really modular, but the easiest way to keep compat with existing 1288c2ecf20Sopenharmony_ci * bootargs behaviour is to continue using module_param here. 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_cimodule_param(no_bm, bool, S_IRUGO); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci#define AB9540_MODEM_CTRL2_REG 0x23 1338c2ecf20Sopenharmony_ci#define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2) 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/* 1368c2ecf20Sopenharmony_ci * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt 1378c2ecf20Sopenharmony_ci * numbers are indexed into this array with (num / 8). The interupts are 1388c2ecf20Sopenharmony_ci * defined in linux/mfd/ab8500.h 1398c2ecf20Sopenharmony_ci * 1408c2ecf20Sopenharmony_ci * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at 1418c2ecf20Sopenharmony_ci * offset 0. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ci/* AB8500 support */ 1448c2ecf20Sopenharmony_cistatic const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { 1458c2ecf20Sopenharmony_ci 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 1468c2ecf20Sopenharmony_ci}; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci/* AB9540 / AB8505 support */ 1498c2ecf20Sopenharmony_cistatic const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = { 1508c2ecf20Sopenharmony_ci 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23 1518c2ecf20Sopenharmony_ci}; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci/* AB8540 support */ 1548c2ecf20Sopenharmony_cistatic const int ab8540_irq_regoffset[AB8540_NUM_IRQ_REGS] = { 1558c2ecf20Sopenharmony_ci 0, 1, 2, 3, 4, -1, -1, -1, -1, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 1568c2ecf20Sopenharmony_ci 23, 25, 26, 27, 28, 29, 30, 31, 1578c2ecf20Sopenharmony_ci}; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic const char ab8500_version_str[][7] = { 1608c2ecf20Sopenharmony_ci [AB8500_VERSION_AB8500] = "AB8500", 1618c2ecf20Sopenharmony_ci [AB8500_VERSION_AB8505] = "AB8505", 1628c2ecf20Sopenharmony_ci [AB8500_VERSION_AB9540] = "AB9540", 1638c2ecf20Sopenharmony_ci [AB8500_VERSION_AB8540] = "AB8540", 1648c2ecf20Sopenharmony_ci}; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int ab8500_prcmu_write(struct ab8500 *ab8500, u16 addr, u8 data) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci int ret; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 1718c2ecf20Sopenharmony_ci if (ret < 0) 1728c2ecf20Sopenharmony_ci dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 1738c2ecf20Sopenharmony_ci return ret; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic int ab8500_prcmu_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask, 1778c2ecf20Sopenharmony_ci u8 data) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci int ret; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1828c2ecf20Sopenharmony_ci &mask, 1); 1838c2ecf20Sopenharmony_ci if (ret < 0) 1848c2ecf20Sopenharmony_ci dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 1858c2ecf20Sopenharmony_ci return ret; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int ab8500_prcmu_read(struct ab8500 *ab8500, u16 addr) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci int ret; 1918c2ecf20Sopenharmony_ci u8 data; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); 1948c2ecf20Sopenharmony_ci if (ret < 0) { 1958c2ecf20Sopenharmony_ci dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); 1968c2ecf20Sopenharmony_ci return ret; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci return (int)data; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic int ab8500_get_chip_id(struct device *dev) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct ab8500 *ab8500; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (!dev) 2068c2ecf20Sopenharmony_ci return -EINVAL; 2078c2ecf20Sopenharmony_ci ab8500 = dev_get_drvdata(dev->parent); 2088c2ecf20Sopenharmony_ci return ab8500 ? (int)ab8500->chip_id : -EINVAL; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic int set_register_interruptible(struct ab8500 *ab8500, u8 bank, 2128c2ecf20Sopenharmony_ci u8 reg, u8 data) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci int ret; 2158c2ecf20Sopenharmony_ci /* 2168c2ecf20Sopenharmony_ci * Put the u8 bank and u8 register together into a an u16. 2178c2ecf20Sopenharmony_ci * The bank on higher 8 bits and register in lower 8 bits. 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_ci u16 addr = ((u16)bank) << 8 | reg; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci mutex_lock(&ab8500->lock); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci ret = ab8500->write(ab8500, addr, data); 2268c2ecf20Sopenharmony_ci if (ret < 0) 2278c2ecf20Sopenharmony_ci dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 2288c2ecf20Sopenharmony_ci addr, ret); 2298c2ecf20Sopenharmony_ci mutex_unlock(&ab8500->lock); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return ret; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic int ab8500_set_register(struct device *dev, u8 bank, 2358c2ecf20Sopenharmony_ci u8 reg, u8 value) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci int ret; 2388c2ecf20Sopenharmony_ci struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci atomic_inc(&ab8500->transfer_ongoing); 2418c2ecf20Sopenharmony_ci ret = set_register_interruptible(ab8500, bank, reg, value); 2428c2ecf20Sopenharmony_ci atomic_dec(&ab8500->transfer_ongoing); 2438c2ecf20Sopenharmony_ci return ret; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic int get_register_interruptible(struct ab8500 *ab8500, u8 bank, 2478c2ecf20Sopenharmony_ci u8 reg, u8 *value) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci int ret; 2508c2ecf20Sopenharmony_ci u16 addr = ((u16)bank) << 8 | reg; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci mutex_lock(&ab8500->lock); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci ret = ab8500->read(ab8500, addr); 2558c2ecf20Sopenharmony_ci if (ret < 0) 2568c2ecf20Sopenharmony_ci dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 2578c2ecf20Sopenharmony_ci addr, ret); 2588c2ecf20Sopenharmony_ci else 2598c2ecf20Sopenharmony_ci *value = ret; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci mutex_unlock(&ab8500->lock); 2628c2ecf20Sopenharmony_ci dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci return (ret < 0) ? ret : 0; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic int ab8500_get_register(struct device *dev, u8 bank, 2688c2ecf20Sopenharmony_ci u8 reg, u8 *value) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci int ret; 2718c2ecf20Sopenharmony_ci struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci atomic_inc(&ab8500->transfer_ongoing); 2748c2ecf20Sopenharmony_ci ret = get_register_interruptible(ab8500, bank, reg, value); 2758c2ecf20Sopenharmony_ci atomic_dec(&ab8500->transfer_ongoing); 2768c2ecf20Sopenharmony_ci return ret; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank, 2808c2ecf20Sopenharmony_ci u8 reg, u8 bitmask, u8 bitvalues) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci int ret; 2838c2ecf20Sopenharmony_ci u16 addr = ((u16)bank) << 8 | reg; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci mutex_lock(&ab8500->lock); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (ab8500->write_masked == NULL) { 2888c2ecf20Sopenharmony_ci u8 data; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci ret = ab8500->read(ab8500, addr); 2918c2ecf20Sopenharmony_ci if (ret < 0) { 2928c2ecf20Sopenharmony_ci dev_err(ab8500->dev, "failed to read reg %#x: %d\n", 2938c2ecf20Sopenharmony_ci addr, ret); 2948c2ecf20Sopenharmony_ci goto out; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci data = (u8)ret; 2988c2ecf20Sopenharmony_ci data = (~bitmask & data) | (bitmask & bitvalues); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci ret = ab8500->write(ab8500, addr, data); 3018c2ecf20Sopenharmony_ci if (ret < 0) 3028c2ecf20Sopenharmony_ci dev_err(ab8500->dev, "failed to write reg %#x: %d\n", 3038c2ecf20Sopenharmony_ci addr, ret); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, 3068c2ecf20Sopenharmony_ci data); 3078c2ecf20Sopenharmony_ci goto out; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues); 3108c2ecf20Sopenharmony_ci if (ret < 0) 3118c2ecf20Sopenharmony_ci dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr, 3128c2ecf20Sopenharmony_ci ret); 3138c2ecf20Sopenharmony_ciout: 3148c2ecf20Sopenharmony_ci mutex_unlock(&ab8500->lock); 3158c2ecf20Sopenharmony_ci return ret; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic int ab8500_mask_and_set_register(struct device *dev, 3198c2ecf20Sopenharmony_ci u8 bank, u8 reg, u8 bitmask, u8 bitvalues) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci int ret; 3228c2ecf20Sopenharmony_ci struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci atomic_inc(&ab8500->transfer_ongoing); 3258c2ecf20Sopenharmony_ci ret = mask_and_set_register_interruptible(ab8500, bank, reg, 3268c2ecf20Sopenharmony_ci bitmask, bitvalues); 3278c2ecf20Sopenharmony_ci atomic_dec(&ab8500->transfer_ongoing); 3288c2ecf20Sopenharmony_ci return ret; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic struct abx500_ops ab8500_ops = { 3328c2ecf20Sopenharmony_ci .get_chip_id = ab8500_get_chip_id, 3338c2ecf20Sopenharmony_ci .get_register = ab8500_get_register, 3348c2ecf20Sopenharmony_ci .set_register = ab8500_set_register, 3358c2ecf20Sopenharmony_ci .get_register_page = NULL, 3368c2ecf20Sopenharmony_ci .set_register_page = NULL, 3378c2ecf20Sopenharmony_ci .mask_and_set_register = ab8500_mask_and_set_register, 3388c2ecf20Sopenharmony_ci .event_registers_startup_state_get = NULL, 3398c2ecf20Sopenharmony_ci .startup_irq_enabled = NULL, 3408c2ecf20Sopenharmony_ci .dump_all_banks = ab8500_dump_all_banks, 3418c2ecf20Sopenharmony_ci}; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic void ab8500_irq_lock(struct irq_data *data) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci mutex_lock(&ab8500->irq_lock); 3488c2ecf20Sopenharmony_ci atomic_inc(&ab8500->transfer_ongoing); 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic void ab8500_irq_sync_unlock(struct irq_data *data) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 3548c2ecf20Sopenharmony_ci int i; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci for (i = 0; i < ab8500->mask_size; i++) { 3578c2ecf20Sopenharmony_ci u8 old = ab8500->oldmask[i]; 3588c2ecf20Sopenharmony_ci u8 new = ab8500->mask[i]; 3598c2ecf20Sopenharmony_ci int reg; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (new == old) 3628c2ecf20Sopenharmony_ci continue; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci /* 3658c2ecf20Sopenharmony_ci * Interrupt register 12 doesn't exist prior to AB8500 version 3668c2ecf20Sopenharmony_ci * 2.0 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci if (ab8500->irq_reg_offset[i] == 11 && 3698c2ecf20Sopenharmony_ci is_ab8500_1p1_or_earlier(ab8500)) 3708c2ecf20Sopenharmony_ci continue; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (ab8500->irq_reg_offset[i] < 0) 3738c2ecf20Sopenharmony_ci continue; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ab8500->oldmask[i] = new; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i]; 3788c2ecf20Sopenharmony_ci set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new); 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci atomic_dec(&ab8500->transfer_ongoing); 3818c2ecf20Sopenharmony_ci mutex_unlock(&ab8500->irq_lock); 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic void ab8500_irq_mask(struct irq_data *data) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 3878c2ecf20Sopenharmony_ci int offset = data->hwirq; 3888c2ecf20Sopenharmony_ci int index = offset / 8; 3898c2ecf20Sopenharmony_ci int mask = 1 << (offset % 8); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci ab8500->mask[index] |= mask; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* The AB8500 GPIOs have two interrupts each (rising & falling). */ 3948c2ecf20Sopenharmony_ci if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R) 3958c2ecf20Sopenharmony_ci ab8500->mask[index + 2] |= mask; 3968c2ecf20Sopenharmony_ci if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R) 3978c2ecf20Sopenharmony_ci ab8500->mask[index + 1] |= mask; 3988c2ecf20Sopenharmony_ci if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R) 3998c2ecf20Sopenharmony_ci /* Here the falling IRQ is one bit lower */ 4008c2ecf20Sopenharmony_ci ab8500->mask[index] |= (mask << 1); 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic void ab8500_irq_unmask(struct irq_data *data) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 4068c2ecf20Sopenharmony_ci unsigned int type = irqd_get_trigger_type(data); 4078c2ecf20Sopenharmony_ci int offset = data->hwirq; 4088c2ecf20Sopenharmony_ci int index = offset / 8; 4098c2ecf20Sopenharmony_ci int mask = 1 << (offset % 8); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (type & IRQ_TYPE_EDGE_RISING) 4128c2ecf20Sopenharmony_ci ab8500->mask[index] &= ~mask; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci /* The AB8500 GPIOs have two interrupts each (rising & falling). */ 4158c2ecf20Sopenharmony_ci if (type & IRQ_TYPE_EDGE_FALLING) { 4168c2ecf20Sopenharmony_ci if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R) 4178c2ecf20Sopenharmony_ci ab8500->mask[index + 2] &= ~mask; 4188c2ecf20Sopenharmony_ci else if (offset >= AB9540_INT_GPIO50R && 4198c2ecf20Sopenharmony_ci offset <= AB9540_INT_GPIO54R) 4208c2ecf20Sopenharmony_ci ab8500->mask[index + 1] &= ~mask; 4218c2ecf20Sopenharmony_ci else if (offset == AB8540_INT_GPIO43R || 4228c2ecf20Sopenharmony_ci offset == AB8540_INT_GPIO44R) 4238c2ecf20Sopenharmony_ci /* Here the falling IRQ is one bit lower */ 4248c2ecf20Sopenharmony_ci ab8500->mask[index] &= ~(mask << 1); 4258c2ecf20Sopenharmony_ci else 4268c2ecf20Sopenharmony_ci ab8500->mask[index] &= ~mask; 4278c2ecf20Sopenharmony_ci } else { 4288c2ecf20Sopenharmony_ci /* Satisfies the case where type is not set. */ 4298c2ecf20Sopenharmony_ci ab8500->mask[index] &= ~mask; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic int ab8500_irq_set_type(struct irq_data *data, unsigned int type) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci return 0; 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic struct irq_chip ab8500_irq_chip = { 4398c2ecf20Sopenharmony_ci .name = "ab8500", 4408c2ecf20Sopenharmony_ci .irq_bus_lock = ab8500_irq_lock, 4418c2ecf20Sopenharmony_ci .irq_bus_sync_unlock = ab8500_irq_sync_unlock, 4428c2ecf20Sopenharmony_ci .irq_mask = ab8500_irq_mask, 4438c2ecf20Sopenharmony_ci .irq_disable = ab8500_irq_mask, 4448c2ecf20Sopenharmony_ci .irq_unmask = ab8500_irq_unmask, 4458c2ecf20Sopenharmony_ci .irq_set_type = ab8500_irq_set_type, 4468c2ecf20Sopenharmony_ci}; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic void update_latch_offset(u8 *offset, int i) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci /* Fix inconsistent ITFromLatch25 bit mapping... */ 4518c2ecf20Sopenharmony_ci if (unlikely(*offset == 17)) 4528c2ecf20Sopenharmony_ci *offset = 24; 4538c2ecf20Sopenharmony_ci /* Fix inconsistent ab8540 bit mapping... */ 4548c2ecf20Sopenharmony_ci if (unlikely(*offset == 16)) 4558c2ecf20Sopenharmony_ci *offset = 25; 4568c2ecf20Sopenharmony_ci if ((i == 3) && (*offset >= 24)) 4578c2ecf20Sopenharmony_ci *offset += 2; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, 4618c2ecf20Sopenharmony_ci int latch_offset, u8 latch_val) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci int int_bit, line, i; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci for (i = 0; i < ab8500->mask_size; i++) 4668c2ecf20Sopenharmony_ci if (ab8500->irq_reg_offset[i] == latch_offset) 4678c2ecf20Sopenharmony_ci break; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (i >= ab8500->mask_size) { 4708c2ecf20Sopenharmony_ci dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", 4718c2ecf20Sopenharmony_ci latch_offset); 4728c2ecf20Sopenharmony_ci return -ENXIO; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* ignore masked out interrupts */ 4768c2ecf20Sopenharmony_ci latch_val &= ~ab8500->mask[i]; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci while (latch_val) { 4798c2ecf20Sopenharmony_ci int_bit = __ffs(latch_val); 4808c2ecf20Sopenharmony_ci line = (i << 3) + int_bit; 4818c2ecf20Sopenharmony_ci latch_val &= ~(1 << int_bit); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* 4848c2ecf20Sopenharmony_ci * This handles the falling edge hwirqs from the GPIO 4858c2ecf20Sopenharmony_ci * lines. Route them back to the line registered for the 4868c2ecf20Sopenharmony_ci * rising IRQ, as this is merely a flag for the same IRQ 4878c2ecf20Sopenharmony_ci * in linux terms. 4888c2ecf20Sopenharmony_ci */ 4898c2ecf20Sopenharmony_ci if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F) 4908c2ecf20Sopenharmony_ci line -= 16; 4918c2ecf20Sopenharmony_ci if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F) 4928c2ecf20Sopenharmony_ci line -= 8; 4938c2ecf20Sopenharmony_ci if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F) 4948c2ecf20Sopenharmony_ci line += 1; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci handle_nested_irq(irq_find_mapping(ab8500->domain, line)); 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci return 0; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500, 5038c2ecf20Sopenharmony_ci int hier_offset, u8 hier_val) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci int latch_bit, status; 5068c2ecf20Sopenharmony_ci u8 latch_offset, latch_val; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci do { 5098c2ecf20Sopenharmony_ci latch_bit = __ffs(hier_val); 5108c2ecf20Sopenharmony_ci latch_offset = (hier_offset << 3) + latch_bit; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci update_latch_offset(&latch_offset, hier_offset); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci status = get_register_interruptible(ab8500, 5158c2ecf20Sopenharmony_ci AB8500_INTERRUPT, 5168c2ecf20Sopenharmony_ci AB8500_IT_LATCH1_REG + latch_offset, 5178c2ecf20Sopenharmony_ci &latch_val); 5188c2ecf20Sopenharmony_ci if (status < 0 || latch_val == 0) 5198c2ecf20Sopenharmony_ci goto discard; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci status = ab8500_handle_hierarchical_line(ab8500, 5228c2ecf20Sopenharmony_ci latch_offset, latch_val); 5238c2ecf20Sopenharmony_ci if (status < 0) 5248c2ecf20Sopenharmony_ci return status; 5258c2ecf20Sopenharmony_cidiscard: 5268c2ecf20Sopenharmony_ci hier_val &= ~(1 << latch_bit); 5278c2ecf20Sopenharmony_ci } while (hier_val); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci return 0; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic irqreturn_t ab8500_hierarchical_irq(int irq, void *dev) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci struct ab8500 *ab8500 = dev; 5358c2ecf20Sopenharmony_ci u8 i; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci dev_vdbg(ab8500->dev, "interrupt\n"); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* Hierarchical interrupt version */ 5408c2ecf20Sopenharmony_ci for (i = 0; i < (ab8500->it_latchhier_num); i++) { 5418c2ecf20Sopenharmony_ci int status; 5428c2ecf20Sopenharmony_ci u8 hier_val; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci status = get_register_interruptible(ab8500, AB8500_INTERRUPT, 5458c2ecf20Sopenharmony_ci AB8500_IT_LATCHHIER1_REG + i, &hier_val); 5468c2ecf20Sopenharmony_ci if (status < 0 || hier_val == 0) 5478c2ecf20Sopenharmony_ci continue; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val); 5508c2ecf20Sopenharmony_ci if (status < 0) 5518c2ecf20Sopenharmony_ci break; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic int ab8500_irq_map(struct irq_domain *d, unsigned int virq, 5578c2ecf20Sopenharmony_ci irq_hw_number_t hwirq) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct ab8500 *ab8500 = d->host_data; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (!ab8500) 5628c2ecf20Sopenharmony_ci return -EINVAL; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci irq_set_chip_data(virq, ab8500); 5658c2ecf20Sopenharmony_ci irq_set_chip_and_handler(virq, &ab8500_irq_chip, 5668c2ecf20Sopenharmony_ci handle_simple_irq); 5678c2ecf20Sopenharmony_ci irq_set_nested_thread(virq, 1); 5688c2ecf20Sopenharmony_ci irq_set_noprobe(virq); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci return 0; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic const struct irq_domain_ops ab8500_irq_ops = { 5748c2ecf20Sopenharmony_ci .map = ab8500_irq_map, 5758c2ecf20Sopenharmony_ci .xlate = irq_domain_xlate_twocell, 5768c2ecf20Sopenharmony_ci}; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci int num_irqs; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (is_ab8540(ab8500)) 5838c2ecf20Sopenharmony_ci num_irqs = AB8540_NR_IRQS; 5848c2ecf20Sopenharmony_ci else if (is_ab9540(ab8500)) 5858c2ecf20Sopenharmony_ci num_irqs = AB9540_NR_IRQS; 5868c2ecf20Sopenharmony_ci else if (is_ab8505(ab8500)) 5878c2ecf20Sopenharmony_ci num_irqs = AB8505_NR_IRQS; 5888c2ecf20Sopenharmony_ci else 5898c2ecf20Sopenharmony_ci num_irqs = AB8500_NR_IRQS; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci /* If ->irq_base is zero this will give a linear mapping */ 5928c2ecf20Sopenharmony_ci ab8500->domain = irq_domain_add_simple(ab8500->dev->of_node, 5938c2ecf20Sopenharmony_ci num_irqs, 0, 5948c2ecf20Sopenharmony_ci &ab8500_irq_ops, ab8500); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (!ab8500->domain) { 5978c2ecf20Sopenharmony_ci dev_err(ab8500->dev, "Failed to create irqdomain\n"); 5988c2ecf20Sopenharmony_ci return -ENODEV; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci return 0; 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ciint ab8500_suspend(struct ab8500 *ab8500) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci if (atomic_read(&ab8500->transfer_ongoing)) 6078c2ecf20Sopenharmony_ci return -EINVAL; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci return 0; 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic const struct mfd_cell ab8500_bm_devs[] = { 6138c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-charger", NULL, &ab8500_bm_data, 6148c2ecf20Sopenharmony_ci sizeof(ab8500_bm_data), 0, "stericsson,ab8500-charger"), 6158c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-btemp", NULL, &ab8500_bm_data, 6168c2ecf20Sopenharmony_ci sizeof(ab8500_bm_data), 0, "stericsson,ab8500-btemp"), 6178c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-fg", NULL, &ab8500_bm_data, 6188c2ecf20Sopenharmony_ci sizeof(ab8500_bm_data), 0, "stericsson,ab8500-fg"), 6198c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-chargalg", NULL, &ab8500_bm_data, 6208c2ecf20Sopenharmony_ci sizeof(ab8500_bm_data), 0, "stericsson,ab8500-chargalg"), 6218c2ecf20Sopenharmony_ci}; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic const struct mfd_cell ab8500_devs[] = { 6248c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 6258c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-debug", 6268c2ecf20Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-debug"), 6278c2ecf20Sopenharmony_ci#endif 6288c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-sysctrl", 6298c2ecf20Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-sysctrl"), 6308c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-ext-regulator", 6318c2ecf20Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-ext-regulator"), 6328c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-regulator", 6338c2ecf20Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-regulator"), 6348c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-clk", 6358c2ecf20Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-clk"), 6368c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-gpadc", 6378c2ecf20Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-gpadc"), 6388c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-rtc", 6398c2ecf20Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-rtc"), 6408c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-acc-det", 6418c2ecf20Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-acc-det"), 6428c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-poweron-key", 6438c2ecf20Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-poweron-key"), 6448c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-pwm", 6458c2ecf20Sopenharmony_ci NULL, NULL, 0, 1, "stericsson,ab8500-pwm"), 6468c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-pwm", 6478c2ecf20Sopenharmony_ci NULL, NULL, 0, 2, "stericsson,ab8500-pwm"), 6488c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-pwm", 6498c2ecf20Sopenharmony_ci NULL, NULL, 0, 3, "stericsson,ab8500-pwm"), 6508c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-denc", 6518c2ecf20Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-denc"), 6528c2ecf20Sopenharmony_ci OF_MFD_CELL("pinctrl-ab8500", 6538c2ecf20Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-gpio"), 6548c2ecf20Sopenharmony_ci OF_MFD_CELL("abx500-temp", 6558c2ecf20Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,abx500-temp"), 6568c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-usb", 6578c2ecf20Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-usb"), 6588c2ecf20Sopenharmony_ci OF_MFD_CELL("ab8500-codec", 6598c2ecf20Sopenharmony_ci NULL, NULL, 0, 0, "stericsson,ab8500-codec"), 6608c2ecf20Sopenharmony_ci}; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic const struct mfd_cell ab9540_devs[] = { 6638c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 6648c2ecf20Sopenharmony_ci { 6658c2ecf20Sopenharmony_ci .name = "ab8500-debug", 6668c2ecf20Sopenharmony_ci }, 6678c2ecf20Sopenharmony_ci#endif 6688c2ecf20Sopenharmony_ci { 6698c2ecf20Sopenharmony_ci .name = "ab8500-sysctrl", 6708c2ecf20Sopenharmony_ci }, 6718c2ecf20Sopenharmony_ci { 6728c2ecf20Sopenharmony_ci .name = "ab8500-ext-regulator", 6738c2ecf20Sopenharmony_ci }, 6748c2ecf20Sopenharmony_ci { 6758c2ecf20Sopenharmony_ci .name = "ab8500-regulator", 6768c2ecf20Sopenharmony_ci }, 6778c2ecf20Sopenharmony_ci { 6788c2ecf20Sopenharmony_ci .name = "abx500-clk", 6798c2ecf20Sopenharmony_ci .of_compatible = "stericsson,abx500-clk", 6808c2ecf20Sopenharmony_ci }, 6818c2ecf20Sopenharmony_ci { 6828c2ecf20Sopenharmony_ci .name = "ab8500-gpadc", 6838c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab8500-gpadc", 6848c2ecf20Sopenharmony_ci }, 6858c2ecf20Sopenharmony_ci { 6868c2ecf20Sopenharmony_ci .name = "ab8500-rtc", 6878c2ecf20Sopenharmony_ci }, 6888c2ecf20Sopenharmony_ci { 6898c2ecf20Sopenharmony_ci .name = "ab8500-acc-det", 6908c2ecf20Sopenharmony_ci }, 6918c2ecf20Sopenharmony_ci { 6928c2ecf20Sopenharmony_ci .name = "ab8500-poweron-key", 6938c2ecf20Sopenharmony_ci }, 6948c2ecf20Sopenharmony_ci { 6958c2ecf20Sopenharmony_ci .name = "ab8500-pwm", 6968c2ecf20Sopenharmony_ci .id = 1, 6978c2ecf20Sopenharmony_ci }, 6988c2ecf20Sopenharmony_ci { 6998c2ecf20Sopenharmony_ci .name = "abx500-temp", 7008c2ecf20Sopenharmony_ci }, 7018c2ecf20Sopenharmony_ci { 7028c2ecf20Sopenharmony_ci .name = "pinctrl-ab9540", 7038c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab9540-gpio", 7048c2ecf20Sopenharmony_ci }, 7058c2ecf20Sopenharmony_ci { 7068c2ecf20Sopenharmony_ci .name = "ab9540-usb", 7078c2ecf20Sopenharmony_ci }, 7088c2ecf20Sopenharmony_ci { 7098c2ecf20Sopenharmony_ci .name = "ab9540-codec", 7108c2ecf20Sopenharmony_ci }, 7118c2ecf20Sopenharmony_ci { 7128c2ecf20Sopenharmony_ci .name = "ab-iddet", 7138c2ecf20Sopenharmony_ci }, 7148c2ecf20Sopenharmony_ci}; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci/* Device list for ab8505 */ 7178c2ecf20Sopenharmony_cistatic const struct mfd_cell ab8505_devs[] = { 7188c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 7198c2ecf20Sopenharmony_ci { 7208c2ecf20Sopenharmony_ci .name = "ab8500-debug", 7218c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab8500-debug", 7228c2ecf20Sopenharmony_ci }, 7238c2ecf20Sopenharmony_ci#endif 7248c2ecf20Sopenharmony_ci { 7258c2ecf20Sopenharmony_ci .name = "ab8500-sysctrl", 7268c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab8500-sysctrl", 7278c2ecf20Sopenharmony_ci }, 7288c2ecf20Sopenharmony_ci { 7298c2ecf20Sopenharmony_ci .name = "ab8500-regulator", 7308c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab8505-regulator", 7318c2ecf20Sopenharmony_ci }, 7328c2ecf20Sopenharmony_ci { 7338c2ecf20Sopenharmony_ci .name = "abx500-clk", 7348c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab8500-clk", 7358c2ecf20Sopenharmony_ci }, 7368c2ecf20Sopenharmony_ci { 7378c2ecf20Sopenharmony_ci .name = "ab8500-gpadc", 7388c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab8500-gpadc", 7398c2ecf20Sopenharmony_ci }, 7408c2ecf20Sopenharmony_ci { 7418c2ecf20Sopenharmony_ci .name = "ab8500-rtc", 7428c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab8500-rtc", 7438c2ecf20Sopenharmony_ci }, 7448c2ecf20Sopenharmony_ci { 7458c2ecf20Sopenharmony_ci .name = "ab8500-acc-det", 7468c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab8500-acc-det", 7478c2ecf20Sopenharmony_ci }, 7488c2ecf20Sopenharmony_ci { 7498c2ecf20Sopenharmony_ci .name = "ab8500-poweron-key", 7508c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab8500-poweron-key", 7518c2ecf20Sopenharmony_ci }, 7528c2ecf20Sopenharmony_ci { 7538c2ecf20Sopenharmony_ci .name = "ab8500-pwm", 7548c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab8500-pwm", 7558c2ecf20Sopenharmony_ci .id = 1, 7568c2ecf20Sopenharmony_ci }, 7578c2ecf20Sopenharmony_ci { 7588c2ecf20Sopenharmony_ci .name = "pinctrl-ab8505", 7598c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab8505-gpio", 7608c2ecf20Sopenharmony_ci }, 7618c2ecf20Sopenharmony_ci { 7628c2ecf20Sopenharmony_ci .name = "ab8500-usb", 7638c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab8500-usb", 7648c2ecf20Sopenharmony_ci }, 7658c2ecf20Sopenharmony_ci { 7668c2ecf20Sopenharmony_ci .name = "ab8500-codec", 7678c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab8500-codec", 7688c2ecf20Sopenharmony_ci }, 7698c2ecf20Sopenharmony_ci { 7708c2ecf20Sopenharmony_ci .name = "ab-iddet", 7718c2ecf20Sopenharmony_ci }, 7728c2ecf20Sopenharmony_ci}; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic const struct mfd_cell ab8540_devs[] = { 7758c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 7768c2ecf20Sopenharmony_ci { 7778c2ecf20Sopenharmony_ci .name = "ab8500-debug", 7788c2ecf20Sopenharmony_ci }, 7798c2ecf20Sopenharmony_ci#endif 7808c2ecf20Sopenharmony_ci { 7818c2ecf20Sopenharmony_ci .name = "ab8500-sysctrl", 7828c2ecf20Sopenharmony_ci }, 7838c2ecf20Sopenharmony_ci { 7848c2ecf20Sopenharmony_ci .name = "ab8500-ext-regulator", 7858c2ecf20Sopenharmony_ci }, 7868c2ecf20Sopenharmony_ci { 7878c2ecf20Sopenharmony_ci .name = "ab8500-regulator", 7888c2ecf20Sopenharmony_ci }, 7898c2ecf20Sopenharmony_ci { 7908c2ecf20Sopenharmony_ci .name = "abx500-clk", 7918c2ecf20Sopenharmony_ci .of_compatible = "stericsson,abx500-clk", 7928c2ecf20Sopenharmony_ci }, 7938c2ecf20Sopenharmony_ci { 7948c2ecf20Sopenharmony_ci .name = "ab8500-gpadc", 7958c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab8500-gpadc", 7968c2ecf20Sopenharmony_ci }, 7978c2ecf20Sopenharmony_ci { 7988c2ecf20Sopenharmony_ci .name = "ab8500-acc-det", 7998c2ecf20Sopenharmony_ci }, 8008c2ecf20Sopenharmony_ci { 8018c2ecf20Sopenharmony_ci .name = "ab8500-poweron-key", 8028c2ecf20Sopenharmony_ci }, 8038c2ecf20Sopenharmony_ci { 8048c2ecf20Sopenharmony_ci .name = "ab8500-pwm", 8058c2ecf20Sopenharmony_ci .id = 1, 8068c2ecf20Sopenharmony_ci }, 8078c2ecf20Sopenharmony_ci { 8088c2ecf20Sopenharmony_ci .name = "abx500-temp", 8098c2ecf20Sopenharmony_ci }, 8108c2ecf20Sopenharmony_ci { 8118c2ecf20Sopenharmony_ci .name = "pinctrl-ab8540", 8128c2ecf20Sopenharmony_ci }, 8138c2ecf20Sopenharmony_ci { 8148c2ecf20Sopenharmony_ci .name = "ab8540-usb", 8158c2ecf20Sopenharmony_ci }, 8168c2ecf20Sopenharmony_ci { 8178c2ecf20Sopenharmony_ci .name = "ab8540-codec", 8188c2ecf20Sopenharmony_ci }, 8198c2ecf20Sopenharmony_ci { 8208c2ecf20Sopenharmony_ci .name = "ab-iddet", 8218c2ecf20Sopenharmony_ci }, 8228c2ecf20Sopenharmony_ci}; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic const struct mfd_cell ab8540_cut1_devs[] = { 8258c2ecf20Sopenharmony_ci { 8268c2ecf20Sopenharmony_ci .name = "ab8500-rtc", 8278c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab8500-rtc", 8288c2ecf20Sopenharmony_ci }, 8298c2ecf20Sopenharmony_ci}; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic const struct mfd_cell ab8540_cut2_devs[] = { 8328c2ecf20Sopenharmony_ci { 8338c2ecf20Sopenharmony_ci .name = "ab8540-rtc", 8348c2ecf20Sopenharmony_ci .of_compatible = "stericsson,ab8540-rtc", 8358c2ecf20Sopenharmony_ci }, 8368c2ecf20Sopenharmony_ci}; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cistatic ssize_t show_chip_id(struct device *dev, 8398c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 8408c2ecf20Sopenharmony_ci{ 8418c2ecf20Sopenharmony_ci struct ab8500 *ab8500; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci ab8500 = dev_get_drvdata(dev); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); 8468c2ecf20Sopenharmony_ci} 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci/* 8498c2ecf20Sopenharmony_ci * ab8500 has switched off due to (SWITCH_OFF_STATUS): 8508c2ecf20Sopenharmony_ci * 0x01 Swoff bit programming 8518c2ecf20Sopenharmony_ci * 0x02 Thermal protection activation 8528c2ecf20Sopenharmony_ci * 0x04 Vbat lower then BattOk falling threshold 8538c2ecf20Sopenharmony_ci * 0x08 Watchdog expired 8548c2ecf20Sopenharmony_ci * 0x10 Non presence of 32kHz clock 8558c2ecf20Sopenharmony_ci * 0x20 Battery level lower than power on reset threshold 8568c2ecf20Sopenharmony_ci * 0x40 Power on key 1 pressed longer than 10 seconds 8578c2ecf20Sopenharmony_ci * 0x80 DB8500 thermal shutdown 8588c2ecf20Sopenharmony_ci */ 8598c2ecf20Sopenharmony_cistatic ssize_t show_switch_off_status(struct device *dev, 8608c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci int ret; 8638c2ecf20Sopenharmony_ci u8 value; 8648c2ecf20Sopenharmony_ci struct ab8500 *ab8500; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci ab8500 = dev_get_drvdata(dev); 8678c2ecf20Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_RTC, 8688c2ecf20Sopenharmony_ci AB8500_SWITCH_OFF_STATUS, &value); 8698c2ecf20Sopenharmony_ci if (ret < 0) 8708c2ecf20Sopenharmony_ci return ret; 8718c2ecf20Sopenharmony_ci return sprintf(buf, "%#x\n", value); 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci/* use mask and set to override the register turn_on_stat value */ 8758c2ecf20Sopenharmony_civoid ab8500_override_turn_on_stat(u8 mask, u8 set) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci spin_lock(&on_stat_lock); 8788c2ecf20Sopenharmony_ci turn_on_stat_mask = mask; 8798c2ecf20Sopenharmony_ci turn_on_stat_set = set; 8808c2ecf20Sopenharmony_ci spin_unlock(&on_stat_lock); 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci/* 8848c2ecf20Sopenharmony_ci * ab8500 has turned on due to (TURN_ON_STATUS): 8858c2ecf20Sopenharmony_ci * 0x01 PORnVbat 8868c2ecf20Sopenharmony_ci * 0x02 PonKey1dbF 8878c2ecf20Sopenharmony_ci * 0x04 PonKey2dbF 8888c2ecf20Sopenharmony_ci * 0x08 RTCAlarm 8898c2ecf20Sopenharmony_ci * 0x10 MainChDet 8908c2ecf20Sopenharmony_ci * 0x20 VbusDet 8918c2ecf20Sopenharmony_ci * 0x40 UsbIDDetect 8928c2ecf20Sopenharmony_ci * 0x80 Reserved 8938c2ecf20Sopenharmony_ci */ 8948c2ecf20Sopenharmony_cistatic ssize_t show_turn_on_status(struct device *dev, 8958c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci int ret; 8988c2ecf20Sopenharmony_ci u8 value; 8998c2ecf20Sopenharmony_ci struct ab8500 *ab8500; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci ab8500 = dev_get_drvdata(dev); 9028c2ecf20Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 9038c2ecf20Sopenharmony_ci AB8500_TURN_ON_STATUS, &value); 9048c2ecf20Sopenharmony_ci if (ret < 0) 9058c2ecf20Sopenharmony_ci return ret; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci /* 9088c2ecf20Sopenharmony_ci * In L9540, turn_on_status register is not updated correctly if 9098c2ecf20Sopenharmony_ci * the device is rebooted with AC/USB charger connected. Due to 9108c2ecf20Sopenharmony_ci * this, the device boots android instead of entering into charge 9118c2ecf20Sopenharmony_ci * only mode. Read the AC/USB status register to detect the charger 9128c2ecf20Sopenharmony_ci * presence and update the turn on status manually. 9138c2ecf20Sopenharmony_ci */ 9148c2ecf20Sopenharmony_ci if (is_ab9540(ab8500)) { 9158c2ecf20Sopenharmony_ci spin_lock(&on_stat_lock); 9168c2ecf20Sopenharmony_ci value = (value & turn_on_stat_mask) | turn_on_stat_set; 9178c2ecf20Sopenharmony_ci spin_unlock(&on_stat_lock); 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci return sprintf(buf, "%#x\n", value); 9218c2ecf20Sopenharmony_ci} 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_cistatic ssize_t show_turn_on_status_2(struct device *dev, 9248c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci int ret; 9278c2ecf20Sopenharmony_ci u8 value; 9288c2ecf20Sopenharmony_ci struct ab8500 *ab8500; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci ab8500 = dev_get_drvdata(dev); 9318c2ecf20Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 9328c2ecf20Sopenharmony_ci AB8505_TURN_ON_STATUS_2, &value); 9338c2ecf20Sopenharmony_ci if (ret < 0) 9348c2ecf20Sopenharmony_ci return ret; 9358c2ecf20Sopenharmony_ci return sprintf(buf, "%#x\n", (value & 0x1)); 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic ssize_t show_ab9540_dbbrstn(struct device *dev, 9398c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci struct ab8500 *ab8500; 9428c2ecf20Sopenharmony_ci int ret; 9438c2ecf20Sopenharmony_ci u8 value; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci ab8500 = dev_get_drvdata(dev); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2, 9488c2ecf20Sopenharmony_ci AB9540_MODEM_CTRL2_REG, &value); 9498c2ecf20Sopenharmony_ci if (ret < 0) 9508c2ecf20Sopenharmony_ci return ret; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", 9538c2ecf20Sopenharmony_ci (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0); 9548c2ecf20Sopenharmony_ci} 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_cistatic ssize_t store_ab9540_dbbrstn(struct device *dev, 9578c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 9588c2ecf20Sopenharmony_ci{ 9598c2ecf20Sopenharmony_ci struct ab8500 *ab8500; 9608c2ecf20Sopenharmony_ci int ret = count; 9618c2ecf20Sopenharmony_ci int err; 9628c2ecf20Sopenharmony_ci u8 bitvalues; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci ab8500 = dev_get_drvdata(dev); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci if (count > 0) { 9678c2ecf20Sopenharmony_ci switch (buf[0]) { 9688c2ecf20Sopenharmony_ci case '0': 9698c2ecf20Sopenharmony_ci bitvalues = 0; 9708c2ecf20Sopenharmony_ci break; 9718c2ecf20Sopenharmony_ci case '1': 9728c2ecf20Sopenharmony_ci bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT; 9738c2ecf20Sopenharmony_ci break; 9748c2ecf20Sopenharmony_ci default: 9758c2ecf20Sopenharmony_ci goto exit; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci err = mask_and_set_register_interruptible(ab8500, 9798c2ecf20Sopenharmony_ci AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG, 9808c2ecf20Sopenharmony_ci AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues); 9818c2ecf20Sopenharmony_ci if (err) 9828c2ecf20Sopenharmony_ci dev_info(ab8500->dev, 9838c2ecf20Sopenharmony_ci "Failed to set DBBRSTN %c, err %#x\n", 9848c2ecf20Sopenharmony_ci buf[0], err); 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ciexit: 9888c2ecf20Sopenharmony_ci return ret; 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); 9928c2ecf20Sopenharmony_cistatic DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL); 9938c2ecf20Sopenharmony_cistatic DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL); 9948c2ecf20Sopenharmony_cistatic DEVICE_ATTR(turn_on_status_2, S_IRUGO, show_turn_on_status_2, NULL); 9958c2ecf20Sopenharmony_cistatic DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR, 9968c2ecf20Sopenharmony_ci show_ab9540_dbbrstn, store_ab9540_dbbrstn); 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic struct attribute *ab8500_sysfs_entries[] = { 9998c2ecf20Sopenharmony_ci &dev_attr_chip_id.attr, 10008c2ecf20Sopenharmony_ci &dev_attr_switch_off_status.attr, 10018c2ecf20Sopenharmony_ci &dev_attr_turn_on_status.attr, 10028c2ecf20Sopenharmony_ci NULL, 10038c2ecf20Sopenharmony_ci}; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cistatic struct attribute *ab8505_sysfs_entries[] = { 10068c2ecf20Sopenharmony_ci &dev_attr_turn_on_status_2.attr, 10078c2ecf20Sopenharmony_ci NULL, 10088c2ecf20Sopenharmony_ci}; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_cistatic struct attribute *ab9540_sysfs_entries[] = { 10118c2ecf20Sopenharmony_ci &dev_attr_chip_id.attr, 10128c2ecf20Sopenharmony_ci &dev_attr_switch_off_status.attr, 10138c2ecf20Sopenharmony_ci &dev_attr_turn_on_status.attr, 10148c2ecf20Sopenharmony_ci &dev_attr_dbbrstn.attr, 10158c2ecf20Sopenharmony_ci NULL, 10168c2ecf20Sopenharmony_ci}; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic const struct attribute_group ab8500_attr_group = { 10198c2ecf20Sopenharmony_ci .attrs = ab8500_sysfs_entries, 10208c2ecf20Sopenharmony_ci}; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic const struct attribute_group ab8505_attr_group = { 10238c2ecf20Sopenharmony_ci .attrs = ab8505_sysfs_entries, 10248c2ecf20Sopenharmony_ci}; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_cistatic const struct attribute_group ab9540_attr_group = { 10278c2ecf20Sopenharmony_ci .attrs = ab9540_sysfs_entries, 10288c2ecf20Sopenharmony_ci}; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_cistatic int ab8500_probe(struct platform_device *pdev) 10318c2ecf20Sopenharmony_ci{ 10328c2ecf20Sopenharmony_ci static const char * const switch_off_status[] = { 10338c2ecf20Sopenharmony_ci "Swoff bit programming", 10348c2ecf20Sopenharmony_ci "Thermal protection activation", 10358c2ecf20Sopenharmony_ci "Vbat lower then BattOk falling threshold", 10368c2ecf20Sopenharmony_ci "Watchdog expired", 10378c2ecf20Sopenharmony_ci "Non presence of 32kHz clock", 10388c2ecf20Sopenharmony_ci "Battery level lower than power on reset threshold", 10398c2ecf20Sopenharmony_ci "Power on key 1 pressed longer than 10 seconds", 10408c2ecf20Sopenharmony_ci "DB8500 thermal shutdown"}; 10418c2ecf20Sopenharmony_ci static const char * const turn_on_status[] = { 10428c2ecf20Sopenharmony_ci "Battery rising (Vbat)", 10438c2ecf20Sopenharmony_ci "Power On Key 1 dbF", 10448c2ecf20Sopenharmony_ci "Power On Key 2 dbF", 10458c2ecf20Sopenharmony_ci "RTC Alarm", 10468c2ecf20Sopenharmony_ci "Main Charger Detect", 10478c2ecf20Sopenharmony_ci "Vbus Detect (USB)", 10488c2ecf20Sopenharmony_ci "USB ID Detect", 10498c2ecf20Sopenharmony_ci "UART Factory Mode Detect"}; 10508c2ecf20Sopenharmony_ci const struct platform_device_id *platid = platform_get_device_id(pdev); 10518c2ecf20Sopenharmony_ci enum ab8500_version version = AB8500_VERSION_UNDEFINED; 10528c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 10538c2ecf20Sopenharmony_ci struct ab8500 *ab8500; 10548c2ecf20Sopenharmony_ci struct resource *resource; 10558c2ecf20Sopenharmony_ci int ret; 10568c2ecf20Sopenharmony_ci int i; 10578c2ecf20Sopenharmony_ci u8 value; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL); 10608c2ecf20Sopenharmony_ci if (!ab8500) 10618c2ecf20Sopenharmony_ci return -ENOMEM; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci ab8500->dev = &pdev->dev; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 10668c2ecf20Sopenharmony_ci if (!resource) { 10678c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no IRQ resource\n"); 10688c2ecf20Sopenharmony_ci return -ENODEV; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci ab8500->irq = resource->start; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci ab8500->read = ab8500_prcmu_read; 10748c2ecf20Sopenharmony_ci ab8500->write = ab8500_prcmu_write; 10758c2ecf20Sopenharmony_ci ab8500->write_masked = ab8500_prcmu_write_masked; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci mutex_init(&ab8500->lock); 10788c2ecf20Sopenharmony_ci mutex_init(&ab8500->irq_lock); 10798c2ecf20Sopenharmony_ci atomic_set(&ab8500->transfer_ongoing, 0); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, ab8500); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci if (platid) 10848c2ecf20Sopenharmony_ci version = platid->driver_data; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci if (version != AB8500_VERSION_UNDEFINED) 10878c2ecf20Sopenharmony_ci ab8500->version = version; 10888c2ecf20Sopenharmony_ci else { 10898c2ecf20Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_MISC, 10908c2ecf20Sopenharmony_ci AB8500_IC_NAME_REG, &value); 10918c2ecf20Sopenharmony_ci if (ret < 0) { 10928c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "could not probe HW\n"); 10938c2ecf20Sopenharmony_ci return ret; 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci ab8500->version = value; 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_MISC, 11008c2ecf20Sopenharmony_ci AB8500_REV_REG, &value); 11018c2ecf20Sopenharmony_ci if (ret < 0) 11028c2ecf20Sopenharmony_ci return ret; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci ab8500->chip_id = value; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n", 11078c2ecf20Sopenharmony_ci ab8500_version_str[ab8500->version], 11088c2ecf20Sopenharmony_ci ab8500->chip_id >> 4, 11098c2ecf20Sopenharmony_ci ab8500->chip_id & 0x0F); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci /* Configure AB8540 */ 11128c2ecf20Sopenharmony_ci if (is_ab8540(ab8500)) { 11138c2ecf20Sopenharmony_ci ab8500->mask_size = AB8540_NUM_IRQ_REGS; 11148c2ecf20Sopenharmony_ci ab8500->irq_reg_offset = ab8540_irq_regoffset; 11158c2ecf20Sopenharmony_ci ab8500->it_latchhier_num = AB8540_IT_LATCHHIER_NUM; 11168c2ecf20Sopenharmony_ci } /* Configure AB8500 or AB9540 IRQ */ 11178c2ecf20Sopenharmony_ci else if (is_ab9540(ab8500) || is_ab8505(ab8500)) { 11188c2ecf20Sopenharmony_ci ab8500->mask_size = AB9540_NUM_IRQ_REGS; 11198c2ecf20Sopenharmony_ci ab8500->irq_reg_offset = ab9540_irq_regoffset; 11208c2ecf20Sopenharmony_ci ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM; 11218c2ecf20Sopenharmony_ci } else { 11228c2ecf20Sopenharmony_ci ab8500->mask_size = AB8500_NUM_IRQ_REGS; 11238c2ecf20Sopenharmony_ci ab8500->irq_reg_offset = ab8500_irq_regoffset; 11248c2ecf20Sopenharmony_ci ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM; 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size, 11278c2ecf20Sopenharmony_ci GFP_KERNEL); 11288c2ecf20Sopenharmony_ci if (!ab8500->mask) 11298c2ecf20Sopenharmony_ci return -ENOMEM; 11308c2ecf20Sopenharmony_ci ab8500->oldmask = devm_kzalloc(&pdev->dev, ab8500->mask_size, 11318c2ecf20Sopenharmony_ci GFP_KERNEL); 11328c2ecf20Sopenharmony_ci if (!ab8500->oldmask) 11338c2ecf20Sopenharmony_ci return -ENOMEM; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci /* 11368c2ecf20Sopenharmony_ci * ab8500 has switched off due to (SWITCH_OFF_STATUS): 11378c2ecf20Sopenharmony_ci * 0x01 Swoff bit programming 11388c2ecf20Sopenharmony_ci * 0x02 Thermal protection activation 11398c2ecf20Sopenharmony_ci * 0x04 Vbat lower then BattOk falling threshold 11408c2ecf20Sopenharmony_ci * 0x08 Watchdog expired 11418c2ecf20Sopenharmony_ci * 0x10 Non presence of 32kHz clock 11428c2ecf20Sopenharmony_ci * 0x20 Battery level lower than power on reset threshold 11438c2ecf20Sopenharmony_ci * 0x40 Power on key 1 pressed longer than 10 seconds 11448c2ecf20Sopenharmony_ci * 0x80 DB8500 thermal shutdown 11458c2ecf20Sopenharmony_ci */ 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_RTC, 11488c2ecf20Sopenharmony_ci AB8500_SWITCH_OFF_STATUS, &value); 11498c2ecf20Sopenharmony_ci if (ret < 0) 11508c2ecf20Sopenharmony_ci return ret; 11518c2ecf20Sopenharmony_ci dev_info(ab8500->dev, "switch off cause(s) (%#x): ", value); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci if (value) { 11548c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(switch_off_status); i++) { 11558c2ecf20Sopenharmony_ci if (value & 1) 11568c2ecf20Sopenharmony_ci pr_cont(" \"%s\"", switch_off_status[i]); 11578c2ecf20Sopenharmony_ci value = value >> 1; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci pr_cont("\n"); 11618c2ecf20Sopenharmony_ci } else { 11628c2ecf20Sopenharmony_ci pr_cont(" None\n"); 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK, 11658c2ecf20Sopenharmony_ci AB8500_TURN_ON_STATUS, &value); 11668c2ecf20Sopenharmony_ci if (ret < 0) 11678c2ecf20Sopenharmony_ci return ret; 11688c2ecf20Sopenharmony_ci dev_info(ab8500->dev, "turn on reason(s) (%#x): ", value); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci if (value) { 11718c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(turn_on_status); i++) { 11728c2ecf20Sopenharmony_ci if (value & 1) 11738c2ecf20Sopenharmony_ci pr_cont("\"%s\" ", turn_on_status[i]); 11748c2ecf20Sopenharmony_ci value = value >> 1; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci pr_cont("\n"); 11778c2ecf20Sopenharmony_ci } else { 11788c2ecf20Sopenharmony_ci pr_cont("None\n"); 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci if (is_ab9540(ab8500)) { 11828c2ecf20Sopenharmony_ci ret = get_register_interruptible(ab8500, AB8500_CHARGER, 11838c2ecf20Sopenharmony_ci AB8500_CH_USBCH_STAT1_REG, &value); 11848c2ecf20Sopenharmony_ci if (ret < 0) 11858c2ecf20Sopenharmony_ci return ret; 11868c2ecf20Sopenharmony_ci if ((value & VBUS_DET_DBNC1) && (value & VBUS_DET_DBNC100)) 11878c2ecf20Sopenharmony_ci ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON, 11888c2ecf20Sopenharmony_ci AB8500_VBUS_DET); 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci /* Clear and mask all interrupts */ 11928c2ecf20Sopenharmony_ci for (i = 0; i < ab8500->mask_size; i++) { 11938c2ecf20Sopenharmony_ci /* 11948c2ecf20Sopenharmony_ci * Interrupt register 12 doesn't exist prior to AB8500 version 11958c2ecf20Sopenharmony_ci * 2.0 11968c2ecf20Sopenharmony_ci */ 11978c2ecf20Sopenharmony_ci if (ab8500->irq_reg_offset[i] == 11 && 11988c2ecf20Sopenharmony_ci is_ab8500_1p1_or_earlier(ab8500)) 11998c2ecf20Sopenharmony_ci continue; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci if (ab8500->irq_reg_offset[i] < 0) 12028c2ecf20Sopenharmony_ci continue; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci get_register_interruptible(ab8500, AB8500_INTERRUPT, 12058c2ecf20Sopenharmony_ci AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i], 12068c2ecf20Sopenharmony_ci &value); 12078c2ecf20Sopenharmony_ci set_register_interruptible(ab8500, AB8500_INTERRUPT, 12088c2ecf20Sopenharmony_ci AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff); 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci ret = abx500_register_ops(ab8500->dev, &ab8500_ops); 12128c2ecf20Sopenharmony_ci if (ret) 12138c2ecf20Sopenharmony_ci return ret; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci for (i = 0; i < ab8500->mask_size; i++) 12168c2ecf20Sopenharmony_ci ab8500->mask[i] = ab8500->oldmask[i] = 0xff; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci ret = ab8500_irq_init(ab8500, np); 12198c2ecf20Sopenharmony_ci if (ret) 12208c2ecf20Sopenharmony_ci return ret; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL, 12238c2ecf20Sopenharmony_ci ab8500_hierarchical_irq, 12248c2ecf20Sopenharmony_ci IRQF_ONESHOT | IRQF_NO_SUSPEND, 12258c2ecf20Sopenharmony_ci "ab8500", ab8500); 12268c2ecf20Sopenharmony_ci if (ret) 12278c2ecf20Sopenharmony_ci return ret; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci if (is_ab9540(ab8500)) 12308c2ecf20Sopenharmony_ci ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, 12318c2ecf20Sopenharmony_ci ARRAY_SIZE(ab9540_devs), NULL, 12328c2ecf20Sopenharmony_ci 0, ab8500->domain); 12338c2ecf20Sopenharmony_ci else if (is_ab8540(ab8500)) { 12348c2ecf20Sopenharmony_ci ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs, 12358c2ecf20Sopenharmony_ci ARRAY_SIZE(ab8540_devs), NULL, 12368c2ecf20Sopenharmony_ci 0, ab8500->domain); 12378c2ecf20Sopenharmony_ci if (ret) 12388c2ecf20Sopenharmony_ci return ret; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci if (is_ab8540_1p2_or_earlier(ab8500)) 12418c2ecf20Sopenharmony_ci ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut1_devs, 12428c2ecf20Sopenharmony_ci ARRAY_SIZE(ab8540_cut1_devs), NULL, 12438c2ecf20Sopenharmony_ci 0, ab8500->domain); 12448c2ecf20Sopenharmony_ci else /* ab8540 >= cut2 */ 12458c2ecf20Sopenharmony_ci ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut2_devs, 12468c2ecf20Sopenharmony_ci ARRAY_SIZE(ab8540_cut2_devs), NULL, 12478c2ecf20Sopenharmony_ci 0, ab8500->domain); 12488c2ecf20Sopenharmony_ci } else if (is_ab8505(ab8500)) 12498c2ecf20Sopenharmony_ci ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs, 12508c2ecf20Sopenharmony_ci ARRAY_SIZE(ab8505_devs), NULL, 12518c2ecf20Sopenharmony_ci 0, ab8500->domain); 12528c2ecf20Sopenharmony_ci else 12538c2ecf20Sopenharmony_ci ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, 12548c2ecf20Sopenharmony_ci ARRAY_SIZE(ab8500_devs), NULL, 12558c2ecf20Sopenharmony_ci 0, ab8500->domain); 12568c2ecf20Sopenharmony_ci if (ret) 12578c2ecf20Sopenharmony_ci return ret; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci if (!no_bm) { 12608c2ecf20Sopenharmony_ci /* Add battery management devices */ 12618c2ecf20Sopenharmony_ci ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, 12628c2ecf20Sopenharmony_ci ARRAY_SIZE(ab8500_bm_devs), NULL, 12638c2ecf20Sopenharmony_ci 0, ab8500->domain); 12648c2ecf20Sopenharmony_ci if (ret) 12658c2ecf20Sopenharmony_ci dev_err(ab8500->dev, "error adding bm devices\n"); 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci if (((is_ab8505(ab8500) || is_ab9540(ab8500)) && 12698c2ecf20Sopenharmony_ci ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500)) 12708c2ecf20Sopenharmony_ci ret = sysfs_create_group(&ab8500->dev->kobj, 12718c2ecf20Sopenharmony_ci &ab9540_attr_group); 12728c2ecf20Sopenharmony_ci else 12738c2ecf20Sopenharmony_ci ret = sysfs_create_group(&ab8500->dev->kobj, 12748c2ecf20Sopenharmony_ci &ab8500_attr_group); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci if ((is_ab8505(ab8500) || is_ab9540(ab8500)) && 12778c2ecf20Sopenharmony_ci ab8500->chip_id >= AB8500_CUT2P0) 12788c2ecf20Sopenharmony_ci ret = sysfs_create_group(&ab8500->dev->kobj, 12798c2ecf20Sopenharmony_ci &ab8505_attr_group); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if (ret) 12828c2ecf20Sopenharmony_ci dev_err(ab8500->dev, "error creating sysfs entries\n"); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci return ret; 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_cistatic const struct platform_device_id ab8500_id[] = { 12888c2ecf20Sopenharmony_ci { "ab8500-core", AB8500_VERSION_AB8500 }, 12898c2ecf20Sopenharmony_ci { "ab8505-core", AB8500_VERSION_AB8505 }, 12908c2ecf20Sopenharmony_ci { "ab9540-i2c", AB8500_VERSION_AB9540 }, 12918c2ecf20Sopenharmony_ci { "ab8540-i2c", AB8500_VERSION_AB8540 }, 12928c2ecf20Sopenharmony_ci { } 12938c2ecf20Sopenharmony_ci}; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_cistatic struct platform_driver ab8500_core_driver = { 12968c2ecf20Sopenharmony_ci .driver = { 12978c2ecf20Sopenharmony_ci .name = "ab8500-core", 12988c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 12998c2ecf20Sopenharmony_ci }, 13008c2ecf20Sopenharmony_ci .probe = ab8500_probe, 13018c2ecf20Sopenharmony_ci .id_table = ab8500_id, 13028c2ecf20Sopenharmony_ci}; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_cistatic int __init ab8500_core_init(void) 13058c2ecf20Sopenharmony_ci{ 13068c2ecf20Sopenharmony_ci return platform_driver_register(&ab8500_core_driver); 13078c2ecf20Sopenharmony_ci} 13088c2ecf20Sopenharmony_cicore_initcall(ab8500_core_init); 1309