18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * DA9150 Core MFD Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2014 Dialog Semiconductor 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 138c2ecf20Sopenharmony_ci#include <linux/i2c.h> 148c2ecf20Sopenharmony_ci#include <linux/regmap.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/irq.h> 178c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 188c2ecf20Sopenharmony_ci#include <linux/mfd/core.h> 198c2ecf20Sopenharmony_ci#include <linux/mfd/da9150/core.h> 208c2ecf20Sopenharmony_ci#include <linux/mfd/da9150/registers.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* Raw device access, used for QIF */ 238c2ecf20Sopenharmony_cistatic int da9150_i2c_read_device(struct i2c_client *client, u8 addr, int count, 248c2ecf20Sopenharmony_ci u8 *buf) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct i2c_msg xfer; 278c2ecf20Sopenharmony_ci int ret; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci /* 308c2ecf20Sopenharmony_ci * Read is split into two transfers as device expects STOP/START rather 318c2ecf20Sopenharmony_ci * than repeated start to carry out this kind of access. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci /* Write address */ 358c2ecf20Sopenharmony_ci xfer.addr = client->addr; 368c2ecf20Sopenharmony_ci xfer.flags = 0; 378c2ecf20Sopenharmony_ci xfer.len = 1; 388c2ecf20Sopenharmony_ci xfer.buf = &addr; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, &xfer, 1); 418c2ecf20Sopenharmony_ci if (ret != 1) { 428c2ecf20Sopenharmony_ci if (ret < 0) 438c2ecf20Sopenharmony_ci return ret; 448c2ecf20Sopenharmony_ci else 458c2ecf20Sopenharmony_ci return -EIO; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* Read data */ 498c2ecf20Sopenharmony_ci xfer.addr = client->addr; 508c2ecf20Sopenharmony_ci xfer.flags = I2C_M_RD; 518c2ecf20Sopenharmony_ci xfer.len = count; 528c2ecf20Sopenharmony_ci xfer.buf = buf; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, &xfer, 1); 558c2ecf20Sopenharmony_ci if (ret == 1) 568c2ecf20Sopenharmony_ci return 0; 578c2ecf20Sopenharmony_ci else if (ret < 0) 588c2ecf20Sopenharmony_ci return ret; 598c2ecf20Sopenharmony_ci else 608c2ecf20Sopenharmony_ci return -EIO; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int da9150_i2c_write_device(struct i2c_client *client, u8 addr, 648c2ecf20Sopenharmony_ci int count, const u8 *buf) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct i2c_msg xfer; 678c2ecf20Sopenharmony_ci u8 *reg_data; 688c2ecf20Sopenharmony_ci int ret; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci reg_data = kzalloc(1 + count, GFP_KERNEL); 718c2ecf20Sopenharmony_ci if (!reg_data) 728c2ecf20Sopenharmony_ci return -ENOMEM; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci reg_data[0] = addr; 758c2ecf20Sopenharmony_ci memcpy(®_data[1], buf, count); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* Write address & data */ 788c2ecf20Sopenharmony_ci xfer.addr = client->addr; 798c2ecf20Sopenharmony_ci xfer.flags = 0; 808c2ecf20Sopenharmony_ci xfer.len = 1 + count; 818c2ecf20Sopenharmony_ci xfer.buf = reg_data; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, &xfer, 1); 848c2ecf20Sopenharmony_ci kfree(reg_data); 858c2ecf20Sopenharmony_ci if (ret == 1) 868c2ecf20Sopenharmony_ci return 0; 878c2ecf20Sopenharmony_ci else if (ret < 0) 888c2ecf20Sopenharmony_ci return ret; 898c2ecf20Sopenharmony_ci else 908c2ecf20Sopenharmony_ci return -EIO; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic bool da9150_volatile_reg(struct device *dev, unsigned int reg) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci switch (reg) { 968c2ecf20Sopenharmony_ci case DA9150_PAGE_CON: 978c2ecf20Sopenharmony_ci case DA9150_STATUS_A: 988c2ecf20Sopenharmony_ci case DA9150_STATUS_B: 998c2ecf20Sopenharmony_ci case DA9150_STATUS_C: 1008c2ecf20Sopenharmony_ci case DA9150_STATUS_D: 1018c2ecf20Sopenharmony_ci case DA9150_STATUS_E: 1028c2ecf20Sopenharmony_ci case DA9150_STATUS_F: 1038c2ecf20Sopenharmony_ci case DA9150_STATUS_G: 1048c2ecf20Sopenharmony_ci case DA9150_STATUS_H: 1058c2ecf20Sopenharmony_ci case DA9150_STATUS_I: 1068c2ecf20Sopenharmony_ci case DA9150_STATUS_J: 1078c2ecf20Sopenharmony_ci case DA9150_STATUS_K: 1088c2ecf20Sopenharmony_ci case DA9150_STATUS_L: 1098c2ecf20Sopenharmony_ci case DA9150_STATUS_N: 1108c2ecf20Sopenharmony_ci case DA9150_FAULT_LOG_A: 1118c2ecf20Sopenharmony_ci case DA9150_FAULT_LOG_B: 1128c2ecf20Sopenharmony_ci case DA9150_EVENT_E: 1138c2ecf20Sopenharmony_ci case DA9150_EVENT_F: 1148c2ecf20Sopenharmony_ci case DA9150_EVENT_G: 1158c2ecf20Sopenharmony_ci case DA9150_EVENT_H: 1168c2ecf20Sopenharmony_ci case DA9150_CONTROL_B: 1178c2ecf20Sopenharmony_ci case DA9150_CONTROL_C: 1188c2ecf20Sopenharmony_ci case DA9150_GPADC_MAN: 1198c2ecf20Sopenharmony_ci case DA9150_GPADC_RES_A: 1208c2ecf20Sopenharmony_ci case DA9150_GPADC_RES_B: 1218c2ecf20Sopenharmony_ci case DA9150_ADETVB_CFG_C: 1228c2ecf20Sopenharmony_ci case DA9150_ADETD_STAT: 1238c2ecf20Sopenharmony_ci case DA9150_ADET_CMPSTAT: 1248c2ecf20Sopenharmony_ci case DA9150_ADET_CTRL_A: 1258c2ecf20Sopenharmony_ci case DA9150_PPR_TCTR_B: 1268c2ecf20Sopenharmony_ci case DA9150_COREBTLD_STAT_A: 1278c2ecf20Sopenharmony_ci case DA9150_CORE_DATA_A: 1288c2ecf20Sopenharmony_ci case DA9150_CORE_DATA_B: 1298c2ecf20Sopenharmony_ci case DA9150_CORE_DATA_C: 1308c2ecf20Sopenharmony_ci case DA9150_CORE_DATA_D: 1318c2ecf20Sopenharmony_ci case DA9150_CORE2WIRE_STAT_A: 1328c2ecf20Sopenharmony_ci case DA9150_FW_CTRL_C: 1338c2ecf20Sopenharmony_ci case DA9150_FG_CTRL_B: 1348c2ecf20Sopenharmony_ci case DA9150_FW_CTRL_B: 1358c2ecf20Sopenharmony_ci case DA9150_GPADC_CMAN: 1368c2ecf20Sopenharmony_ci case DA9150_GPADC_CRES_A: 1378c2ecf20Sopenharmony_ci case DA9150_GPADC_CRES_B: 1388c2ecf20Sopenharmony_ci case DA9150_CC_ICHG_RES_A: 1398c2ecf20Sopenharmony_ci case DA9150_CC_ICHG_RES_B: 1408c2ecf20Sopenharmony_ci case DA9150_CC_IAVG_RES_A: 1418c2ecf20Sopenharmony_ci case DA9150_CC_IAVG_RES_B: 1428c2ecf20Sopenharmony_ci case DA9150_TAUX_CTRL_A: 1438c2ecf20Sopenharmony_ci case DA9150_TAUX_VALUE_H: 1448c2ecf20Sopenharmony_ci case DA9150_TAUX_VALUE_L: 1458c2ecf20Sopenharmony_ci case DA9150_TBAT_RES_A: 1468c2ecf20Sopenharmony_ci case DA9150_TBAT_RES_B: 1478c2ecf20Sopenharmony_ci return true; 1488c2ecf20Sopenharmony_ci default: 1498c2ecf20Sopenharmony_ci return false; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic const struct regmap_range_cfg da9150_range_cfg[] = { 1548c2ecf20Sopenharmony_ci { 1558c2ecf20Sopenharmony_ci .range_min = DA9150_PAGE_CON, 1568c2ecf20Sopenharmony_ci .range_max = DA9150_TBAT_RES_B, 1578c2ecf20Sopenharmony_ci .selector_reg = DA9150_PAGE_CON, 1588c2ecf20Sopenharmony_ci .selector_mask = DA9150_I2C_PAGE_MASK, 1598c2ecf20Sopenharmony_ci .selector_shift = DA9150_I2C_PAGE_SHIFT, 1608c2ecf20Sopenharmony_ci .window_start = 0, 1618c2ecf20Sopenharmony_ci .window_len = 256, 1628c2ecf20Sopenharmony_ci }, 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic const struct regmap_config da9150_regmap_config = { 1668c2ecf20Sopenharmony_ci .reg_bits = 8, 1678c2ecf20Sopenharmony_ci .val_bits = 8, 1688c2ecf20Sopenharmony_ci .ranges = da9150_range_cfg, 1698c2ecf20Sopenharmony_ci .num_ranges = ARRAY_SIZE(da9150_range_cfg), 1708c2ecf20Sopenharmony_ci .max_register = DA9150_TBAT_RES_B, 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci .volatile_reg = da9150_volatile_reg, 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_civoid da9150_read_qif(struct da9150 *da9150, u8 addr, int count, u8 *buf) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci int ret; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci ret = da9150_i2c_read_device(da9150->core_qif, addr, count, buf); 1828c2ecf20Sopenharmony_ci if (ret < 0) 1838c2ecf20Sopenharmony_ci dev_err(da9150->dev, "Failed to read from QIF 0x%x: %d\n", 1848c2ecf20Sopenharmony_ci addr, ret); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(da9150_read_qif); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_civoid da9150_write_qif(struct da9150 *da9150, u8 addr, int count, const u8 *buf) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci int ret; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci ret = da9150_i2c_write_device(da9150->core_qif, addr, count, buf); 1938c2ecf20Sopenharmony_ci if (ret < 0) 1948c2ecf20Sopenharmony_ci dev_err(da9150->dev, "Failed to write to QIF 0x%x: %d\n", 1958c2ecf20Sopenharmony_ci addr, ret); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(da9150_write_qif); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ciu8 da9150_reg_read(struct da9150 *da9150, u16 reg) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci int val, ret; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci ret = regmap_read(da9150->regmap, reg, &val); 2048c2ecf20Sopenharmony_ci if (ret) 2058c2ecf20Sopenharmony_ci dev_err(da9150->dev, "Failed to read from reg 0x%x: %d\n", 2068c2ecf20Sopenharmony_ci reg, ret); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return (u8) val; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(da9150_reg_read); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_civoid da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci int ret; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci ret = regmap_write(da9150->regmap, reg, val); 2178c2ecf20Sopenharmony_ci if (ret) 2188c2ecf20Sopenharmony_ci dev_err(da9150->dev, "Failed to write to reg 0x%x: %d\n", 2198c2ecf20Sopenharmony_ci reg, ret); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(da9150_reg_write); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_civoid da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci int ret; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci ret = regmap_update_bits(da9150->regmap, reg, mask, val); 2288c2ecf20Sopenharmony_ci if (ret) 2298c2ecf20Sopenharmony_ci dev_err(da9150->dev, "Failed to set bits in reg 0x%x: %d\n", 2308c2ecf20Sopenharmony_ci reg, ret); 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(da9150_set_bits); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_civoid da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci int ret; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci ret = regmap_bulk_read(da9150->regmap, reg, buf, count); 2398c2ecf20Sopenharmony_ci if (ret) 2408c2ecf20Sopenharmony_ci dev_err(da9150->dev, "Failed to bulk read from reg 0x%x: %d\n", 2418c2ecf20Sopenharmony_ci reg, ret); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(da9150_bulk_read); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_civoid da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci int ret; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci ret = regmap_raw_write(da9150->regmap, reg, buf, count); 2508c2ecf20Sopenharmony_ci if (ret) 2518c2ecf20Sopenharmony_ci dev_err(da9150->dev, "Failed to bulk write to reg 0x%x %d\n", 2528c2ecf20Sopenharmony_ci reg, ret); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(da9150_bulk_write); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic const struct regmap_irq da9150_irqs[] = { 2578c2ecf20Sopenharmony_ci [DA9150_IRQ_VBUS] = { 2588c2ecf20Sopenharmony_ci .reg_offset = 0, 2598c2ecf20Sopenharmony_ci .mask = DA9150_E_VBUS_MASK, 2608c2ecf20Sopenharmony_ci }, 2618c2ecf20Sopenharmony_ci [DA9150_IRQ_CHG] = { 2628c2ecf20Sopenharmony_ci .reg_offset = 0, 2638c2ecf20Sopenharmony_ci .mask = DA9150_E_CHG_MASK, 2648c2ecf20Sopenharmony_ci }, 2658c2ecf20Sopenharmony_ci [DA9150_IRQ_TCLASS] = { 2668c2ecf20Sopenharmony_ci .reg_offset = 0, 2678c2ecf20Sopenharmony_ci .mask = DA9150_E_TCLASS_MASK, 2688c2ecf20Sopenharmony_ci }, 2698c2ecf20Sopenharmony_ci [DA9150_IRQ_TJUNC] = { 2708c2ecf20Sopenharmony_ci .reg_offset = 0, 2718c2ecf20Sopenharmony_ci .mask = DA9150_E_TJUNC_MASK, 2728c2ecf20Sopenharmony_ci }, 2738c2ecf20Sopenharmony_ci [DA9150_IRQ_VFAULT] = { 2748c2ecf20Sopenharmony_ci .reg_offset = 0, 2758c2ecf20Sopenharmony_ci .mask = DA9150_E_VFAULT_MASK, 2768c2ecf20Sopenharmony_ci }, 2778c2ecf20Sopenharmony_ci [DA9150_IRQ_CONF] = { 2788c2ecf20Sopenharmony_ci .reg_offset = 1, 2798c2ecf20Sopenharmony_ci .mask = DA9150_E_CONF_MASK, 2808c2ecf20Sopenharmony_ci }, 2818c2ecf20Sopenharmony_ci [DA9150_IRQ_DAT] = { 2828c2ecf20Sopenharmony_ci .reg_offset = 1, 2838c2ecf20Sopenharmony_ci .mask = DA9150_E_DAT_MASK, 2848c2ecf20Sopenharmony_ci }, 2858c2ecf20Sopenharmony_ci [DA9150_IRQ_DTYPE] = { 2868c2ecf20Sopenharmony_ci .reg_offset = 1, 2878c2ecf20Sopenharmony_ci .mask = DA9150_E_DTYPE_MASK, 2888c2ecf20Sopenharmony_ci }, 2898c2ecf20Sopenharmony_ci [DA9150_IRQ_ID] = { 2908c2ecf20Sopenharmony_ci .reg_offset = 1, 2918c2ecf20Sopenharmony_ci .mask = DA9150_E_ID_MASK, 2928c2ecf20Sopenharmony_ci }, 2938c2ecf20Sopenharmony_ci [DA9150_IRQ_ADP] = { 2948c2ecf20Sopenharmony_ci .reg_offset = 1, 2958c2ecf20Sopenharmony_ci .mask = DA9150_E_ADP_MASK, 2968c2ecf20Sopenharmony_ci }, 2978c2ecf20Sopenharmony_ci [DA9150_IRQ_SESS_END] = { 2988c2ecf20Sopenharmony_ci .reg_offset = 1, 2998c2ecf20Sopenharmony_ci .mask = DA9150_E_SESS_END_MASK, 3008c2ecf20Sopenharmony_ci }, 3018c2ecf20Sopenharmony_ci [DA9150_IRQ_SESS_VLD] = { 3028c2ecf20Sopenharmony_ci .reg_offset = 1, 3038c2ecf20Sopenharmony_ci .mask = DA9150_E_SESS_VLD_MASK, 3048c2ecf20Sopenharmony_ci }, 3058c2ecf20Sopenharmony_ci [DA9150_IRQ_FG] = { 3068c2ecf20Sopenharmony_ci .reg_offset = 2, 3078c2ecf20Sopenharmony_ci .mask = DA9150_E_FG_MASK, 3088c2ecf20Sopenharmony_ci }, 3098c2ecf20Sopenharmony_ci [DA9150_IRQ_GP] = { 3108c2ecf20Sopenharmony_ci .reg_offset = 2, 3118c2ecf20Sopenharmony_ci .mask = DA9150_E_GP_MASK, 3128c2ecf20Sopenharmony_ci }, 3138c2ecf20Sopenharmony_ci [DA9150_IRQ_TBAT] = { 3148c2ecf20Sopenharmony_ci .reg_offset = 2, 3158c2ecf20Sopenharmony_ci .mask = DA9150_E_TBAT_MASK, 3168c2ecf20Sopenharmony_ci }, 3178c2ecf20Sopenharmony_ci [DA9150_IRQ_GPIOA] = { 3188c2ecf20Sopenharmony_ci .reg_offset = 2, 3198c2ecf20Sopenharmony_ci .mask = DA9150_E_GPIOA_MASK, 3208c2ecf20Sopenharmony_ci }, 3218c2ecf20Sopenharmony_ci [DA9150_IRQ_GPIOB] = { 3228c2ecf20Sopenharmony_ci .reg_offset = 2, 3238c2ecf20Sopenharmony_ci .mask = DA9150_E_GPIOB_MASK, 3248c2ecf20Sopenharmony_ci }, 3258c2ecf20Sopenharmony_ci [DA9150_IRQ_GPIOC] = { 3268c2ecf20Sopenharmony_ci .reg_offset = 2, 3278c2ecf20Sopenharmony_ci .mask = DA9150_E_GPIOC_MASK, 3288c2ecf20Sopenharmony_ci }, 3298c2ecf20Sopenharmony_ci [DA9150_IRQ_GPIOD] = { 3308c2ecf20Sopenharmony_ci .reg_offset = 2, 3318c2ecf20Sopenharmony_ci .mask = DA9150_E_GPIOD_MASK, 3328c2ecf20Sopenharmony_ci }, 3338c2ecf20Sopenharmony_ci [DA9150_IRQ_GPADC] = { 3348c2ecf20Sopenharmony_ci .reg_offset = 2, 3358c2ecf20Sopenharmony_ci .mask = DA9150_E_GPADC_MASK, 3368c2ecf20Sopenharmony_ci }, 3378c2ecf20Sopenharmony_ci [DA9150_IRQ_WKUP] = { 3388c2ecf20Sopenharmony_ci .reg_offset = 3, 3398c2ecf20Sopenharmony_ci .mask = DA9150_E_WKUP_MASK, 3408c2ecf20Sopenharmony_ci }, 3418c2ecf20Sopenharmony_ci}; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic const struct regmap_irq_chip da9150_regmap_irq_chip = { 3448c2ecf20Sopenharmony_ci .name = "da9150_irq", 3458c2ecf20Sopenharmony_ci .status_base = DA9150_EVENT_E, 3468c2ecf20Sopenharmony_ci .mask_base = DA9150_IRQ_MASK_E, 3478c2ecf20Sopenharmony_ci .ack_base = DA9150_EVENT_E, 3488c2ecf20Sopenharmony_ci .num_regs = DA9150_NUM_IRQ_REGS, 3498c2ecf20Sopenharmony_ci .irqs = da9150_irqs, 3508c2ecf20Sopenharmony_ci .num_irqs = ARRAY_SIZE(da9150_irqs), 3518c2ecf20Sopenharmony_ci}; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic struct resource da9150_gpadc_resources[] = { 3548c2ecf20Sopenharmony_ci DEFINE_RES_IRQ_NAMED(DA9150_IRQ_GPADC, "GPADC"), 3558c2ecf20Sopenharmony_ci}; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic struct resource da9150_charger_resources[] = { 3588c2ecf20Sopenharmony_ci DEFINE_RES_IRQ_NAMED(DA9150_IRQ_CHG, "CHG_STATUS"), 3598c2ecf20Sopenharmony_ci DEFINE_RES_IRQ_NAMED(DA9150_IRQ_TJUNC, "CHG_TJUNC"), 3608c2ecf20Sopenharmony_ci DEFINE_RES_IRQ_NAMED(DA9150_IRQ_VFAULT, "CHG_VFAULT"), 3618c2ecf20Sopenharmony_ci DEFINE_RES_IRQ_NAMED(DA9150_IRQ_VBUS, "CHG_VBUS"), 3628c2ecf20Sopenharmony_ci}; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic struct resource da9150_fg_resources[] = { 3658c2ecf20Sopenharmony_ci DEFINE_RES_IRQ_NAMED(DA9150_IRQ_FG, "FG"), 3668c2ecf20Sopenharmony_ci}; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cienum da9150_dev_idx { 3698c2ecf20Sopenharmony_ci DA9150_GPADC_IDX = 0, 3708c2ecf20Sopenharmony_ci DA9150_CHARGER_IDX, 3718c2ecf20Sopenharmony_ci DA9150_FG_IDX, 3728c2ecf20Sopenharmony_ci}; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic struct mfd_cell da9150_devs[] = { 3758c2ecf20Sopenharmony_ci [DA9150_GPADC_IDX] = { 3768c2ecf20Sopenharmony_ci .name = "da9150-gpadc", 3778c2ecf20Sopenharmony_ci .of_compatible = "dlg,da9150-gpadc", 3788c2ecf20Sopenharmony_ci .resources = da9150_gpadc_resources, 3798c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(da9150_gpadc_resources), 3808c2ecf20Sopenharmony_ci }, 3818c2ecf20Sopenharmony_ci [DA9150_CHARGER_IDX] = { 3828c2ecf20Sopenharmony_ci .name = "da9150-charger", 3838c2ecf20Sopenharmony_ci .of_compatible = "dlg,da9150-charger", 3848c2ecf20Sopenharmony_ci .resources = da9150_charger_resources, 3858c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(da9150_charger_resources), 3868c2ecf20Sopenharmony_ci }, 3878c2ecf20Sopenharmony_ci [DA9150_FG_IDX] = { 3888c2ecf20Sopenharmony_ci .name = "da9150-fuel-gauge", 3898c2ecf20Sopenharmony_ci .of_compatible = "dlg,da9150-fuel-gauge", 3908c2ecf20Sopenharmony_ci .resources = da9150_fg_resources, 3918c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(da9150_fg_resources), 3928c2ecf20Sopenharmony_ci }, 3938c2ecf20Sopenharmony_ci}; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic int da9150_probe(struct i2c_client *client, 3968c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci struct da9150 *da9150; 3998c2ecf20Sopenharmony_ci struct da9150_pdata *pdata = dev_get_platdata(&client->dev); 4008c2ecf20Sopenharmony_ci int qif_addr; 4018c2ecf20Sopenharmony_ci int ret; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci da9150 = devm_kzalloc(&client->dev, sizeof(*da9150), GFP_KERNEL); 4048c2ecf20Sopenharmony_ci if (!da9150) 4058c2ecf20Sopenharmony_ci return -ENOMEM; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci da9150->dev = &client->dev; 4088c2ecf20Sopenharmony_ci da9150->irq = client->irq; 4098c2ecf20Sopenharmony_ci i2c_set_clientdata(client, da9150); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci da9150->regmap = devm_regmap_init_i2c(client, &da9150_regmap_config); 4128c2ecf20Sopenharmony_ci if (IS_ERR(da9150->regmap)) { 4138c2ecf20Sopenharmony_ci ret = PTR_ERR(da9150->regmap); 4148c2ecf20Sopenharmony_ci dev_err(da9150->dev, "Failed to allocate register map: %d\n", 4158c2ecf20Sopenharmony_ci ret); 4168c2ecf20Sopenharmony_ci return ret; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* Setup secondary I2C interface for QIF access */ 4208c2ecf20Sopenharmony_ci qif_addr = da9150_reg_read(da9150, DA9150_CORE2WIRE_CTRL_A); 4218c2ecf20Sopenharmony_ci qif_addr = (qif_addr & DA9150_CORE_BASE_ADDR_MASK) >> 1; 4228c2ecf20Sopenharmony_ci qif_addr |= DA9150_QIF_I2C_ADDR_LSB; 4238c2ecf20Sopenharmony_ci da9150->core_qif = i2c_new_dummy_device(client->adapter, qif_addr); 4248c2ecf20Sopenharmony_ci if (IS_ERR(da9150->core_qif)) { 4258c2ecf20Sopenharmony_ci dev_err(da9150->dev, "Failed to attach QIF client\n"); 4268c2ecf20Sopenharmony_ci return PTR_ERR(da9150->core_qif); 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci i2c_set_clientdata(da9150->core_qif, da9150); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (pdata) { 4328c2ecf20Sopenharmony_ci da9150->irq_base = pdata->irq_base; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci da9150_devs[DA9150_FG_IDX].platform_data = pdata->fg_pdata; 4358c2ecf20Sopenharmony_ci da9150_devs[DA9150_FG_IDX].pdata_size = 4368c2ecf20Sopenharmony_ci sizeof(struct da9150_fg_pdata); 4378c2ecf20Sopenharmony_ci } else { 4388c2ecf20Sopenharmony_ci da9150->irq_base = -1; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci ret = regmap_add_irq_chip(da9150->regmap, da9150->irq, 4428c2ecf20Sopenharmony_ci IRQF_TRIGGER_LOW | IRQF_ONESHOT, 4438c2ecf20Sopenharmony_ci da9150->irq_base, &da9150_regmap_irq_chip, 4448c2ecf20Sopenharmony_ci &da9150->regmap_irq_data); 4458c2ecf20Sopenharmony_ci if (ret) { 4468c2ecf20Sopenharmony_ci dev_err(da9150->dev, "Failed to add regmap irq chip: %d\n", 4478c2ecf20Sopenharmony_ci ret); 4488c2ecf20Sopenharmony_ci goto regmap_irq_fail; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci enable_irq_wake(da9150->irq); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci ret = mfd_add_devices(da9150->dev, -1, da9150_devs, 4578c2ecf20Sopenharmony_ci ARRAY_SIZE(da9150_devs), NULL, 4588c2ecf20Sopenharmony_ci da9150->irq_base, NULL); 4598c2ecf20Sopenharmony_ci if (ret) { 4608c2ecf20Sopenharmony_ci dev_err(da9150->dev, "Failed to add child devices: %d\n", ret); 4618c2ecf20Sopenharmony_ci goto mfd_fail; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci return 0; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cimfd_fail: 4678c2ecf20Sopenharmony_ci regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data); 4688c2ecf20Sopenharmony_ciregmap_irq_fail: 4698c2ecf20Sopenharmony_ci i2c_unregister_device(da9150->core_qif); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return ret; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic int da9150_remove(struct i2c_client *client) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci struct da9150 *da9150 = i2c_get_clientdata(client); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data); 4798c2ecf20Sopenharmony_ci mfd_remove_devices(da9150->dev); 4808c2ecf20Sopenharmony_ci i2c_unregister_device(da9150->core_qif); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci return 0; 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic void da9150_shutdown(struct i2c_client *client) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci struct da9150 *da9150 = i2c_get_clientdata(client); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* Make sure we have a wakup source for the device */ 4908c2ecf20Sopenharmony_ci da9150_set_bits(da9150, DA9150_CONFIG_D, 4918c2ecf20Sopenharmony_ci DA9150_WKUP_PM_EN_MASK, 4928c2ecf20Sopenharmony_ci DA9150_WKUP_PM_EN_MASK); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci /* Set device to DISABLED mode */ 4958c2ecf20Sopenharmony_ci da9150_set_bits(da9150, DA9150_CONTROL_C, 4968c2ecf20Sopenharmony_ci DA9150_DISABLE_MASK, DA9150_DISABLE_MASK); 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic const struct i2c_device_id da9150_i2c_id[] = { 5008c2ecf20Sopenharmony_ci { "da9150", }, 5018c2ecf20Sopenharmony_ci { } 5028c2ecf20Sopenharmony_ci}; 5038c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, da9150_i2c_id); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic const struct of_device_id da9150_of_match[] = { 5068c2ecf20Sopenharmony_ci { .compatible = "dlg,da9150", }, 5078c2ecf20Sopenharmony_ci { } 5088c2ecf20Sopenharmony_ci}; 5098c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, da9150_of_match); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic struct i2c_driver da9150_driver = { 5128c2ecf20Sopenharmony_ci .driver = { 5138c2ecf20Sopenharmony_ci .name = "da9150", 5148c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(da9150_of_match), 5158c2ecf20Sopenharmony_ci }, 5168c2ecf20Sopenharmony_ci .probe = da9150_probe, 5178c2ecf20Sopenharmony_ci .remove = da9150_remove, 5188c2ecf20Sopenharmony_ci .shutdown = da9150_shutdown, 5198c2ecf20Sopenharmony_ci .id_table = da9150_i2c_id, 5208c2ecf20Sopenharmony_ci}; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cimodule_i2c_driver(da9150_driver); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MFD Core Driver for DA9150"); 5258c2ecf20Sopenharmony_ciMODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>"); 5268c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 527