18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * LP8755 High Performance Power Management Unit : System Interface Driver 48c2ecf20Sopenharmony_ci * (based on rev. 0.26) 58c2ecf20Sopenharmony_ci * Copyright 2012 Texas Instruments 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Daniel(Geon Si) Jeong <daniel.jeong@ti.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/i2c.h> 138c2ecf20Sopenharmony_ci#include <linux/err.h> 148c2ecf20Sopenharmony_ci#include <linux/irq.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/gpio.h> 178c2ecf20Sopenharmony_ci#include <linux/regmap.h> 188c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 198c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 208c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h> 218c2ecf20Sopenharmony_ci#include <linux/platform_data/lp8755.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define LP8755_REG_BUCK0 0x00 248c2ecf20Sopenharmony_ci#define LP8755_REG_BUCK1 0x03 258c2ecf20Sopenharmony_ci#define LP8755_REG_BUCK2 0x04 268c2ecf20Sopenharmony_ci#define LP8755_REG_BUCK3 0x01 278c2ecf20Sopenharmony_ci#define LP8755_REG_BUCK4 0x05 288c2ecf20Sopenharmony_ci#define LP8755_REG_BUCK5 0x02 298c2ecf20Sopenharmony_ci#define LP8755_REG_MAX 0xFF 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define LP8755_BUCK_EN_M BIT(7) 328c2ecf20Sopenharmony_ci#define LP8755_BUCK_LINEAR_OUT_MAX 0x76 338c2ecf20Sopenharmony_ci#define LP8755_BUCK_VOUT_M 0x7F 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistruct lp8755_mphase { 368c2ecf20Sopenharmony_ci int nreg; 378c2ecf20Sopenharmony_ci int buck_num[LP8755_BUCK_MAX]; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistruct lp8755_chip { 418c2ecf20Sopenharmony_ci struct device *dev; 428c2ecf20Sopenharmony_ci struct regmap *regmap; 438c2ecf20Sopenharmony_ci struct lp8755_platform_data *pdata; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci int irq; 468c2ecf20Sopenharmony_ci unsigned int irqmask; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci int mphase; 498c2ecf20Sopenharmony_ci struct regulator_dev *rdev[LP8755_BUCK_MAX]; 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int lp8755_buck_enable_time(struct regulator_dev *rdev) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci int ret; 558c2ecf20Sopenharmony_ci unsigned int regval; 568c2ecf20Sopenharmony_ci enum lp8755_bucks id = rdev_get_id(rdev); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci ret = regmap_read(rdev->regmap, 0x12 + id, ®val); 598c2ecf20Sopenharmony_ci if (ret < 0) { 608c2ecf20Sopenharmony_ci dev_err(&rdev->dev, "i2c access error %s\n", __func__); 618c2ecf20Sopenharmony_ci return ret; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci return (regval & 0xff) * 100; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int lp8755_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci int ret; 698c2ecf20Sopenharmony_ci unsigned int regbval = 0x0; 708c2ecf20Sopenharmony_ci enum lp8755_bucks id = rdev_get_id(rdev); 718c2ecf20Sopenharmony_ci struct lp8755_chip *pchip = rdev_get_drvdata(rdev); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci switch (mode) { 748c2ecf20Sopenharmony_ci case REGULATOR_MODE_FAST: 758c2ecf20Sopenharmony_ci /* forced pwm mode */ 768c2ecf20Sopenharmony_ci regbval = (0x01 << id); 778c2ecf20Sopenharmony_ci break; 788c2ecf20Sopenharmony_ci case REGULATOR_MODE_NORMAL: 798c2ecf20Sopenharmony_ci /* enable automatic pwm/pfm mode */ 808c2ecf20Sopenharmony_ci ret = regmap_update_bits(rdev->regmap, 0x08 + id, 0x20, 0x00); 818c2ecf20Sopenharmony_ci if (ret < 0) 828c2ecf20Sopenharmony_ci goto err_i2c; 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci case REGULATOR_MODE_IDLE: 858c2ecf20Sopenharmony_ci /* enable automatic pwm/pfm/lppfm mode */ 868c2ecf20Sopenharmony_ci ret = regmap_update_bits(rdev->regmap, 0x08 + id, 0x20, 0x20); 878c2ecf20Sopenharmony_ci if (ret < 0) 888c2ecf20Sopenharmony_ci goto err_i2c; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci ret = regmap_update_bits(rdev->regmap, 0x10, 0x01, 0x01); 918c2ecf20Sopenharmony_ci if (ret < 0) 928c2ecf20Sopenharmony_ci goto err_i2c; 938c2ecf20Sopenharmony_ci break; 948c2ecf20Sopenharmony_ci default: 958c2ecf20Sopenharmony_ci dev_err(pchip->dev, "Not supported buck mode %s\n", __func__); 968c2ecf20Sopenharmony_ci /* forced pwm mode */ 978c2ecf20Sopenharmony_ci regbval = (0x01 << id); 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci ret = regmap_update_bits(rdev->regmap, 0x06, 0x01 << id, regbval); 1018c2ecf20Sopenharmony_ci if (ret < 0) 1028c2ecf20Sopenharmony_ci goto err_i2c; 1038c2ecf20Sopenharmony_ci return ret; 1048c2ecf20Sopenharmony_cierr_i2c: 1058c2ecf20Sopenharmony_ci dev_err(&rdev->dev, "i2c access error %s\n", __func__); 1068c2ecf20Sopenharmony_ci return ret; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic unsigned int lp8755_buck_get_mode(struct regulator_dev *rdev) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci int ret; 1128c2ecf20Sopenharmony_ci unsigned int regval; 1138c2ecf20Sopenharmony_ci enum lp8755_bucks id = rdev_get_id(rdev); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci ret = regmap_read(rdev->regmap, 0x06, ®val); 1168c2ecf20Sopenharmony_ci if (ret < 0) 1178c2ecf20Sopenharmony_ci goto err_i2c; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* mode fast means forced pwm mode */ 1208c2ecf20Sopenharmony_ci if (regval & (0x01 << id)) 1218c2ecf20Sopenharmony_ci return REGULATOR_MODE_FAST; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci ret = regmap_read(rdev->regmap, 0x08 + id, ®val); 1248c2ecf20Sopenharmony_ci if (ret < 0) 1258c2ecf20Sopenharmony_ci goto err_i2c; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* mode idle means automatic pwm/pfm/lppfm mode */ 1288c2ecf20Sopenharmony_ci if (regval & 0x20) 1298c2ecf20Sopenharmony_ci return REGULATOR_MODE_IDLE; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* mode normal means automatic pwm/pfm mode */ 1328c2ecf20Sopenharmony_ci return REGULATOR_MODE_NORMAL; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cierr_i2c: 1358c2ecf20Sopenharmony_ci dev_err(&rdev->dev, "i2c access error %s\n", __func__); 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int lp8755_buck_set_ramp(struct regulator_dev *rdev, int ramp) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci int ret; 1428c2ecf20Sopenharmony_ci unsigned int regval = 0x00; 1438c2ecf20Sopenharmony_ci enum lp8755_bucks id = rdev_get_id(rdev); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* uV/us */ 1468c2ecf20Sopenharmony_ci switch (ramp) { 1478c2ecf20Sopenharmony_ci case 0 ... 230: 1488c2ecf20Sopenharmony_ci regval = 0x07; 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci case 231 ... 470: 1518c2ecf20Sopenharmony_ci regval = 0x06; 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci case 471 ... 940: 1548c2ecf20Sopenharmony_ci regval = 0x05; 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci case 941 ... 1900: 1578c2ecf20Sopenharmony_ci regval = 0x04; 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci case 1901 ... 3800: 1608c2ecf20Sopenharmony_ci regval = 0x03; 1618c2ecf20Sopenharmony_ci break; 1628c2ecf20Sopenharmony_ci case 3801 ... 7500: 1638c2ecf20Sopenharmony_ci regval = 0x02; 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci case 7501 ... 15000: 1668c2ecf20Sopenharmony_ci regval = 0x01; 1678c2ecf20Sopenharmony_ci break; 1688c2ecf20Sopenharmony_ci case 15001 ... 30000: 1698c2ecf20Sopenharmony_ci regval = 0x00; 1708c2ecf20Sopenharmony_ci break; 1718c2ecf20Sopenharmony_ci default: 1728c2ecf20Sopenharmony_ci dev_err(&rdev->dev, 1738c2ecf20Sopenharmony_ci "Not supported ramp value %d %s\n", ramp, __func__); 1748c2ecf20Sopenharmony_ci return -EINVAL; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci ret = regmap_update_bits(rdev->regmap, 0x07 + id, 0x07, regval); 1788c2ecf20Sopenharmony_ci if (ret < 0) 1798c2ecf20Sopenharmony_ci goto err_i2c; 1808c2ecf20Sopenharmony_ci return ret; 1818c2ecf20Sopenharmony_cierr_i2c: 1828c2ecf20Sopenharmony_ci dev_err(&rdev->dev, "i2c access error %s\n", __func__); 1838c2ecf20Sopenharmony_ci return ret; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic const struct regulator_ops lp8755_buck_ops = { 1878c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 1888c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 1898c2ecf20Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 1908c2ecf20Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 1918c2ecf20Sopenharmony_ci .enable = regulator_enable_regmap, 1928c2ecf20Sopenharmony_ci .disable = regulator_disable_regmap, 1938c2ecf20Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 1948c2ecf20Sopenharmony_ci .enable_time = lp8755_buck_enable_time, 1958c2ecf20Sopenharmony_ci .set_mode = lp8755_buck_set_mode, 1968c2ecf20Sopenharmony_ci .get_mode = lp8755_buck_get_mode, 1978c2ecf20Sopenharmony_ci .set_ramp_delay = lp8755_buck_set_ramp, 1988c2ecf20Sopenharmony_ci}; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci#define lp8755_rail(_id) "lp8755_buck"#_id 2018c2ecf20Sopenharmony_ci#define lp8755_buck_init(_id)\ 2028c2ecf20Sopenharmony_ci{\ 2038c2ecf20Sopenharmony_ci .constraints = {\ 2048c2ecf20Sopenharmony_ci .name = lp8755_rail(_id),\ 2058c2ecf20Sopenharmony_ci .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,\ 2068c2ecf20Sopenharmony_ci .min_uV = 500000,\ 2078c2ecf20Sopenharmony_ci .max_uV = 1675000,\ 2088c2ecf20Sopenharmony_ci },\ 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic struct regulator_init_data lp8755_reg_default[LP8755_BUCK_MAX] = { 2128c2ecf20Sopenharmony_ci [LP8755_BUCK0] = lp8755_buck_init(0), 2138c2ecf20Sopenharmony_ci [LP8755_BUCK1] = lp8755_buck_init(1), 2148c2ecf20Sopenharmony_ci [LP8755_BUCK2] = lp8755_buck_init(2), 2158c2ecf20Sopenharmony_ci [LP8755_BUCK3] = lp8755_buck_init(3), 2168c2ecf20Sopenharmony_ci [LP8755_BUCK4] = lp8755_buck_init(4), 2178c2ecf20Sopenharmony_ci [LP8755_BUCK5] = lp8755_buck_init(5), 2188c2ecf20Sopenharmony_ci}; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic const struct lp8755_mphase mphase_buck[MPHASE_CONF_MAX] = { 2218c2ecf20Sopenharmony_ci { 3, { LP8755_BUCK0, LP8755_BUCK3, LP8755_BUCK5 } }, 2228c2ecf20Sopenharmony_ci { 6, { LP8755_BUCK0, LP8755_BUCK1, LP8755_BUCK2, LP8755_BUCK3, 2238c2ecf20Sopenharmony_ci LP8755_BUCK4, LP8755_BUCK5 } }, 2248c2ecf20Sopenharmony_ci { 5, { LP8755_BUCK0, LP8755_BUCK2, LP8755_BUCK3, LP8755_BUCK4, 2258c2ecf20Sopenharmony_ci LP8755_BUCK5} }, 2268c2ecf20Sopenharmony_ci { 4, { LP8755_BUCK0, LP8755_BUCK3, LP8755_BUCK4, LP8755_BUCK5} }, 2278c2ecf20Sopenharmony_ci { 3, { LP8755_BUCK0, LP8755_BUCK4, LP8755_BUCK5} }, 2288c2ecf20Sopenharmony_ci { 2, { LP8755_BUCK0, LP8755_BUCK5} }, 2298c2ecf20Sopenharmony_ci { 1, { LP8755_BUCK0} }, 2308c2ecf20Sopenharmony_ci { 2, { LP8755_BUCK0, LP8755_BUCK3} }, 2318c2ecf20Sopenharmony_ci { 4, { LP8755_BUCK0, LP8755_BUCK2, LP8755_BUCK3, LP8755_BUCK5} }, 2328c2ecf20Sopenharmony_ci}; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic int lp8755_init_data(struct lp8755_chip *pchip) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci unsigned int regval; 2378c2ecf20Sopenharmony_ci int ret, icnt, buck_num; 2388c2ecf20Sopenharmony_ci struct lp8755_platform_data *pdata = pchip->pdata; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* read back muti-phase configuration */ 2418c2ecf20Sopenharmony_ci ret = regmap_read(pchip->regmap, 0x3D, ®val); 2428c2ecf20Sopenharmony_ci if (ret < 0) 2438c2ecf20Sopenharmony_ci goto out_i2c_error; 2448c2ecf20Sopenharmony_ci pchip->mphase = regval & 0x0F; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* set default data based on multi-phase config */ 2478c2ecf20Sopenharmony_ci for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) { 2488c2ecf20Sopenharmony_ci buck_num = mphase_buck[pchip->mphase].buck_num[icnt]; 2498c2ecf20Sopenharmony_ci pdata->buck_data[buck_num] = &lp8755_reg_default[buck_num]; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci return ret; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ciout_i2c_error: 2548c2ecf20Sopenharmony_ci dev_err(pchip->dev, "i2c access error %s\n", __func__); 2558c2ecf20Sopenharmony_ci return ret; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci#define lp8755_buck_desc(_id)\ 2598c2ecf20Sopenharmony_ci{\ 2608c2ecf20Sopenharmony_ci .name = lp8755_rail(_id),\ 2618c2ecf20Sopenharmony_ci .id = LP8755_BUCK##_id,\ 2628c2ecf20Sopenharmony_ci .ops = &lp8755_buck_ops,\ 2638c2ecf20Sopenharmony_ci .n_voltages = LP8755_BUCK_LINEAR_OUT_MAX+1,\ 2648c2ecf20Sopenharmony_ci .uV_step = 10000,\ 2658c2ecf20Sopenharmony_ci .min_uV = 500000,\ 2668c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE,\ 2678c2ecf20Sopenharmony_ci .owner = THIS_MODULE,\ 2688c2ecf20Sopenharmony_ci .enable_reg = LP8755_REG_BUCK##_id,\ 2698c2ecf20Sopenharmony_ci .enable_mask = LP8755_BUCK_EN_M,\ 2708c2ecf20Sopenharmony_ci .vsel_reg = LP8755_REG_BUCK##_id,\ 2718c2ecf20Sopenharmony_ci .vsel_mask = LP8755_BUCK_VOUT_M,\ 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic const struct regulator_desc lp8755_regulators[] = { 2758c2ecf20Sopenharmony_ci lp8755_buck_desc(0), 2768c2ecf20Sopenharmony_ci lp8755_buck_desc(1), 2778c2ecf20Sopenharmony_ci lp8755_buck_desc(2), 2788c2ecf20Sopenharmony_ci lp8755_buck_desc(3), 2798c2ecf20Sopenharmony_ci lp8755_buck_desc(4), 2808c2ecf20Sopenharmony_ci lp8755_buck_desc(5), 2818c2ecf20Sopenharmony_ci}; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic int lp8755_regulator_init(struct lp8755_chip *pchip) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci int ret, icnt, buck_num; 2868c2ecf20Sopenharmony_ci struct lp8755_platform_data *pdata = pchip->pdata; 2878c2ecf20Sopenharmony_ci struct regulator_config rconfig = { }; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci rconfig.regmap = pchip->regmap; 2908c2ecf20Sopenharmony_ci rconfig.dev = pchip->dev; 2918c2ecf20Sopenharmony_ci rconfig.driver_data = pchip; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) { 2948c2ecf20Sopenharmony_ci buck_num = mphase_buck[pchip->mphase].buck_num[icnt]; 2958c2ecf20Sopenharmony_ci rconfig.init_data = pdata->buck_data[buck_num]; 2968c2ecf20Sopenharmony_ci rconfig.of_node = pchip->dev->of_node; 2978c2ecf20Sopenharmony_ci pchip->rdev[buck_num] = 2988c2ecf20Sopenharmony_ci devm_regulator_register(pchip->dev, 2998c2ecf20Sopenharmony_ci &lp8755_regulators[buck_num], &rconfig); 3008c2ecf20Sopenharmony_ci if (IS_ERR(pchip->rdev[buck_num])) { 3018c2ecf20Sopenharmony_ci ret = PTR_ERR(pchip->rdev[buck_num]); 3028c2ecf20Sopenharmony_ci pchip->rdev[buck_num] = NULL; 3038c2ecf20Sopenharmony_ci dev_err(pchip->dev, "regulator init failed: buck %d\n", 3048c2ecf20Sopenharmony_ci buck_num); 3058c2ecf20Sopenharmony_ci return ret; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci return 0; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic irqreturn_t lp8755_irq_handler(int irq, void *data) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci int ret, icnt; 3158c2ecf20Sopenharmony_ci unsigned int flag0, flag1; 3168c2ecf20Sopenharmony_ci struct lp8755_chip *pchip = data; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* read flag0 register */ 3198c2ecf20Sopenharmony_ci ret = regmap_read(pchip->regmap, 0x0D, &flag0); 3208c2ecf20Sopenharmony_ci if (ret < 0) 3218c2ecf20Sopenharmony_ci goto err_i2c; 3228c2ecf20Sopenharmony_ci /* clear flag register to pull up int. pin */ 3238c2ecf20Sopenharmony_ci ret = regmap_write(pchip->regmap, 0x0D, 0x00); 3248c2ecf20Sopenharmony_ci if (ret < 0) 3258c2ecf20Sopenharmony_ci goto err_i2c; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* sent power fault detection event to specific regulator */ 3288c2ecf20Sopenharmony_ci for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) 3298c2ecf20Sopenharmony_ci if ((flag0 & (0x4 << icnt)) 3308c2ecf20Sopenharmony_ci && (pchip->irqmask & (0x04 << icnt)) 3318c2ecf20Sopenharmony_ci && (pchip->rdev[icnt] != NULL)) { 3328c2ecf20Sopenharmony_ci regulator_notifier_call_chain(pchip->rdev[icnt], 3338c2ecf20Sopenharmony_ci LP8755_EVENT_PWR_FAULT, 3348c2ecf20Sopenharmony_ci NULL); 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* read flag1 register */ 3388c2ecf20Sopenharmony_ci ret = regmap_read(pchip->regmap, 0x0E, &flag1); 3398c2ecf20Sopenharmony_ci if (ret < 0) 3408c2ecf20Sopenharmony_ci goto err_i2c; 3418c2ecf20Sopenharmony_ci /* clear flag register to pull up int. pin */ 3428c2ecf20Sopenharmony_ci ret = regmap_write(pchip->regmap, 0x0E, 0x00); 3438c2ecf20Sopenharmony_ci if (ret < 0) 3448c2ecf20Sopenharmony_ci goto err_i2c; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* send OCP event to all regulator devices */ 3478c2ecf20Sopenharmony_ci if ((flag1 & 0x01) && (pchip->irqmask & 0x01)) 3488c2ecf20Sopenharmony_ci for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) 3498c2ecf20Sopenharmony_ci if (pchip->rdev[icnt] != NULL) { 3508c2ecf20Sopenharmony_ci regulator_notifier_call_chain(pchip->rdev[icnt], 3518c2ecf20Sopenharmony_ci LP8755_EVENT_OCP, 3528c2ecf20Sopenharmony_ci NULL); 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* send OVP event to all regulator devices */ 3568c2ecf20Sopenharmony_ci if ((flag1 & 0x02) && (pchip->irqmask & 0x02)) 3578c2ecf20Sopenharmony_ci for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) 3588c2ecf20Sopenharmony_ci if (pchip->rdev[icnt] != NULL) { 3598c2ecf20Sopenharmony_ci regulator_notifier_call_chain(pchip->rdev[icnt], 3608c2ecf20Sopenharmony_ci LP8755_EVENT_OVP, 3618c2ecf20Sopenharmony_ci NULL); 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cierr_i2c: 3668c2ecf20Sopenharmony_ci dev_err(pchip->dev, "i2c access error %s\n", __func__); 3678c2ecf20Sopenharmony_ci return IRQ_NONE; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int lp8755_int_config(struct lp8755_chip *pchip) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci int ret; 3738c2ecf20Sopenharmony_ci unsigned int regval; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (pchip->irq == 0) { 3768c2ecf20Sopenharmony_ci dev_warn(pchip->dev, "not use interrupt : %s\n", __func__); 3778c2ecf20Sopenharmony_ci return 0; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci ret = regmap_read(pchip->regmap, 0x0F, ®val); 3818c2ecf20Sopenharmony_ci if (ret < 0) { 3828c2ecf20Sopenharmony_ci dev_err(pchip->dev, "i2c access error %s\n", __func__); 3838c2ecf20Sopenharmony_ci return ret; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci pchip->irqmask = regval; 3878c2ecf20Sopenharmony_ci return devm_request_threaded_irq(pchip->dev, pchip->irq, NULL, 3888c2ecf20Sopenharmony_ci lp8755_irq_handler, 3898c2ecf20Sopenharmony_ci IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 3908c2ecf20Sopenharmony_ci "lp8755-irq", pchip); 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic const struct regmap_config lp8755_regmap = { 3948c2ecf20Sopenharmony_ci .reg_bits = 8, 3958c2ecf20Sopenharmony_ci .val_bits = 8, 3968c2ecf20Sopenharmony_ci .max_register = LP8755_REG_MAX, 3978c2ecf20Sopenharmony_ci}; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic int lp8755_probe(struct i2c_client *client, 4008c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci int ret, icnt; 4038c2ecf20Sopenharmony_ci struct lp8755_chip *pchip; 4048c2ecf20Sopenharmony_ci struct lp8755_platform_data *pdata = dev_get_platdata(&client->dev); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 4078c2ecf20Sopenharmony_ci dev_err(&client->dev, "i2c functionality check fail.\n"); 4088c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci pchip = devm_kzalloc(&client->dev, 4128c2ecf20Sopenharmony_ci sizeof(struct lp8755_chip), GFP_KERNEL); 4138c2ecf20Sopenharmony_ci if (!pchip) 4148c2ecf20Sopenharmony_ci return -ENOMEM; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci pchip->dev = &client->dev; 4178c2ecf20Sopenharmony_ci pchip->regmap = devm_regmap_init_i2c(client, &lp8755_regmap); 4188c2ecf20Sopenharmony_ci if (IS_ERR(pchip->regmap)) { 4198c2ecf20Sopenharmony_ci ret = PTR_ERR(pchip->regmap); 4208c2ecf20Sopenharmony_ci dev_err(&client->dev, "fail to allocate regmap %d\n", ret); 4218c2ecf20Sopenharmony_ci return ret; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci i2c_set_clientdata(client, pchip); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (pdata != NULL) { 4268c2ecf20Sopenharmony_ci pchip->pdata = pdata; 4278c2ecf20Sopenharmony_ci pchip->mphase = pdata->mphase; 4288c2ecf20Sopenharmony_ci } else { 4298c2ecf20Sopenharmony_ci pchip->pdata = devm_kzalloc(pchip->dev, 4308c2ecf20Sopenharmony_ci sizeof(struct lp8755_platform_data), 4318c2ecf20Sopenharmony_ci GFP_KERNEL); 4328c2ecf20Sopenharmony_ci if (!pchip->pdata) 4338c2ecf20Sopenharmony_ci return -ENOMEM; 4348c2ecf20Sopenharmony_ci ret = lp8755_init_data(pchip); 4358c2ecf20Sopenharmony_ci if (ret < 0) { 4368c2ecf20Sopenharmony_ci dev_err(&client->dev, "fail to initialize chip\n"); 4378c2ecf20Sopenharmony_ci return ret; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci ret = lp8755_regulator_init(pchip); 4428c2ecf20Sopenharmony_ci if (ret < 0) { 4438c2ecf20Sopenharmony_ci dev_err(&client->dev, "fail to initialize regulators\n"); 4448c2ecf20Sopenharmony_ci goto err; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci pchip->irq = client->irq; 4488c2ecf20Sopenharmony_ci ret = lp8755_int_config(pchip); 4498c2ecf20Sopenharmony_ci if (ret < 0) { 4508c2ecf20Sopenharmony_ci dev_err(&client->dev, "fail to irq config\n"); 4518c2ecf20Sopenharmony_ci goto err; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci return ret; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cierr: 4578c2ecf20Sopenharmony_ci /* output disable */ 4588c2ecf20Sopenharmony_ci for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) 4598c2ecf20Sopenharmony_ci regmap_write(pchip->regmap, icnt, 0x00); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci return ret; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic int lp8755_remove(struct i2c_client *client) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci int icnt; 4678c2ecf20Sopenharmony_ci struct lp8755_chip *pchip = i2c_get_clientdata(client); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) 4708c2ecf20Sopenharmony_ci regmap_write(pchip->regmap, icnt, 0x00); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return 0; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic const struct i2c_device_id lp8755_id[] = { 4768c2ecf20Sopenharmony_ci {LP8755_NAME, 0}, 4778c2ecf20Sopenharmony_ci {} 4788c2ecf20Sopenharmony_ci}; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, lp8755_id); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic struct i2c_driver lp8755_i2c_driver = { 4838c2ecf20Sopenharmony_ci .driver = { 4848c2ecf20Sopenharmony_ci .name = LP8755_NAME, 4858c2ecf20Sopenharmony_ci }, 4868c2ecf20Sopenharmony_ci .probe = lp8755_probe, 4878c2ecf20Sopenharmony_ci .remove = lp8755_remove, 4888c2ecf20Sopenharmony_ci .id_table = lp8755_id, 4898c2ecf20Sopenharmony_ci}; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_cistatic int __init lp8755_init(void) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci return i2c_add_driver(&lp8755_i2c_driver); 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cisubsys_initcall(lp8755_init); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic void __exit lp8755_exit(void) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci i2c_del_driver(&lp8755_i2c_driver); 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cimodule_exit(lp8755_exit); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Texas Instruments lp8755 driver"); 5068c2ecf20Sopenharmony_ciMODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>"); 5078c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 508