18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// pv88080-regulator.c - Regulator device driver for PV88080 48c2ecf20Sopenharmony_ci// Copyright (C) 2016 Powerventure Semiconductor Ltd. 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/err.h> 78c2ecf20Sopenharmony_ci#include <linux/i2c.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/of.h> 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 138c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h> 148c2ecf20Sopenharmony_ci#include <linux/regmap.h> 158c2ecf20Sopenharmony_ci#include <linux/irq.h> 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h> 188c2ecf20Sopenharmony_ci#include "pv88080-regulator.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define PV88080_MAX_REGULATORS 4 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* PV88080 REGULATOR IDs */ 238c2ecf20Sopenharmony_cienum { 248c2ecf20Sopenharmony_ci /* BUCKs */ 258c2ecf20Sopenharmony_ci PV88080_ID_BUCK1, 268c2ecf20Sopenharmony_ci PV88080_ID_BUCK2, 278c2ecf20Sopenharmony_ci PV88080_ID_BUCK3, 288c2ecf20Sopenharmony_ci PV88080_ID_HVBUCK, 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cienum pv88080_types { 328c2ecf20Sopenharmony_ci TYPE_PV88080_AA, 338c2ecf20Sopenharmony_ci TYPE_PV88080_BA, 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct pv88080_regulator { 378c2ecf20Sopenharmony_ci struct regulator_desc desc; 388c2ecf20Sopenharmony_ci unsigned int mode_reg; 398c2ecf20Sopenharmony_ci unsigned int conf2; 408c2ecf20Sopenharmony_ci unsigned int conf5; 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct pv88080 { 448c2ecf20Sopenharmony_ci struct device *dev; 458c2ecf20Sopenharmony_ci struct regmap *regmap; 468c2ecf20Sopenharmony_ci struct regulator_dev *rdev[PV88080_MAX_REGULATORS]; 478c2ecf20Sopenharmony_ci unsigned long type; 488c2ecf20Sopenharmony_ci const struct pv88080_compatible_regmap *regmap_config; 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct pv88080_buck_voltage { 528c2ecf20Sopenharmony_ci int min_uV; 538c2ecf20Sopenharmony_ci int max_uV; 548c2ecf20Sopenharmony_ci int uV_step; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistruct pv88080_buck_regmap { 588c2ecf20Sopenharmony_ci /* REGS */ 598c2ecf20Sopenharmony_ci int buck_enable_reg; 608c2ecf20Sopenharmony_ci int buck_vsel_reg; 618c2ecf20Sopenharmony_ci int buck_mode_reg; 628c2ecf20Sopenharmony_ci int buck_limit_reg; 638c2ecf20Sopenharmony_ci int buck_vdac_range_reg; 648c2ecf20Sopenharmony_ci int buck_vrange_gain_reg; 658c2ecf20Sopenharmony_ci /* MASKS */ 668c2ecf20Sopenharmony_ci int buck_enable_mask; 678c2ecf20Sopenharmony_ci int buck_vsel_mask; 688c2ecf20Sopenharmony_ci int buck_limit_mask; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistruct pv88080_compatible_regmap { 728c2ecf20Sopenharmony_ci /* BUCK1, 2, 3 */ 738c2ecf20Sopenharmony_ci struct pv88080_buck_regmap buck_regmap[PV88080_MAX_REGULATORS-1]; 748c2ecf20Sopenharmony_ci /* HVBUCK */ 758c2ecf20Sopenharmony_ci int hvbuck_enable_reg; 768c2ecf20Sopenharmony_ci int hvbuck_vsel_reg; 778c2ecf20Sopenharmony_ci int hvbuck_enable_mask; 788c2ecf20Sopenharmony_ci int hvbuck_vsel_mask; 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic const struct regmap_config pv88080_regmap_config = { 828c2ecf20Sopenharmony_ci .reg_bits = 8, 838c2ecf20Sopenharmony_ci .val_bits = 8, 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* Current limits array (in uA) for BUCK1, BUCK2, BUCK3. 878c2ecf20Sopenharmony_ci * Entry indexes corresponds to register values. 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic const unsigned int pv88080_buck1_limits[] = { 918c2ecf20Sopenharmony_ci 3230000, 5130000, 6960000, 8790000 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic const unsigned int pv88080_buck23_limits[] = { 958c2ecf20Sopenharmony_ci 1496000, 2393000, 3291000, 4189000 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic const struct pv88080_buck_voltage pv88080_buck_vol[2] = { 998c2ecf20Sopenharmony_ci { 1008c2ecf20Sopenharmony_ci .min_uV = 600000, 1018c2ecf20Sopenharmony_ci .max_uV = 1393750, 1028c2ecf20Sopenharmony_ci .uV_step = 6250, 1038c2ecf20Sopenharmony_ci }, 1048c2ecf20Sopenharmony_ci { 1058c2ecf20Sopenharmony_ci .min_uV = 1400000, 1068c2ecf20Sopenharmony_ci .max_uV = 2193750, 1078c2ecf20Sopenharmony_ci .uV_step = 6250, 1088c2ecf20Sopenharmony_ci }, 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic const struct pv88080_compatible_regmap pv88080_aa_regs = { 1128c2ecf20Sopenharmony_ci /* BUCK1 */ 1138c2ecf20Sopenharmony_ci .buck_regmap[0] = { 1148c2ecf20Sopenharmony_ci .buck_enable_reg = PV88080AA_REG_BUCK1_CONF0, 1158c2ecf20Sopenharmony_ci .buck_vsel_reg = PV88080AA_REG_BUCK1_CONF0, 1168c2ecf20Sopenharmony_ci .buck_mode_reg = PV88080AA_REG_BUCK1_CONF1, 1178c2ecf20Sopenharmony_ci .buck_limit_reg = PV88080AA_REG_BUCK1_CONF1, 1188c2ecf20Sopenharmony_ci .buck_vdac_range_reg = PV88080AA_REG_BUCK1_CONF2, 1198c2ecf20Sopenharmony_ci .buck_vrange_gain_reg = PV88080AA_REG_BUCK1_CONF5, 1208c2ecf20Sopenharmony_ci .buck_enable_mask = PV88080_BUCK1_EN, 1218c2ecf20Sopenharmony_ci .buck_vsel_mask = PV88080_VBUCK1_MASK, 1228c2ecf20Sopenharmony_ci .buck_limit_mask = PV88080_BUCK1_ILIM_MASK, 1238c2ecf20Sopenharmony_ci }, 1248c2ecf20Sopenharmony_ci /* BUCK2 */ 1258c2ecf20Sopenharmony_ci .buck_regmap[1] = { 1268c2ecf20Sopenharmony_ci .buck_enable_reg = PV88080AA_REG_BUCK2_CONF0, 1278c2ecf20Sopenharmony_ci .buck_vsel_reg = PV88080AA_REG_BUCK2_CONF0, 1288c2ecf20Sopenharmony_ci .buck_mode_reg = PV88080AA_REG_BUCK2_CONF1, 1298c2ecf20Sopenharmony_ci .buck_limit_reg = PV88080AA_REG_BUCK2_CONF1, 1308c2ecf20Sopenharmony_ci .buck_vdac_range_reg = PV88080AA_REG_BUCK2_CONF2, 1318c2ecf20Sopenharmony_ci .buck_vrange_gain_reg = PV88080AA_REG_BUCK2_CONF5, 1328c2ecf20Sopenharmony_ci .buck_enable_mask = PV88080_BUCK2_EN, 1338c2ecf20Sopenharmony_ci .buck_vsel_mask = PV88080_VBUCK2_MASK, 1348c2ecf20Sopenharmony_ci .buck_limit_mask = PV88080_BUCK2_ILIM_MASK, 1358c2ecf20Sopenharmony_ci }, 1368c2ecf20Sopenharmony_ci /* BUCK3 */ 1378c2ecf20Sopenharmony_ci .buck_regmap[2] = { 1388c2ecf20Sopenharmony_ci .buck_enable_reg = PV88080AA_REG_BUCK3_CONF0, 1398c2ecf20Sopenharmony_ci .buck_vsel_reg = PV88080AA_REG_BUCK3_CONF0, 1408c2ecf20Sopenharmony_ci .buck_mode_reg = PV88080AA_REG_BUCK3_CONF1, 1418c2ecf20Sopenharmony_ci .buck_limit_reg = PV88080AA_REG_BUCK3_CONF1, 1428c2ecf20Sopenharmony_ci .buck_vdac_range_reg = PV88080AA_REG_BUCK3_CONF2, 1438c2ecf20Sopenharmony_ci .buck_vrange_gain_reg = PV88080AA_REG_BUCK3_CONF5, 1448c2ecf20Sopenharmony_ci .buck_enable_mask = PV88080_BUCK3_EN, 1458c2ecf20Sopenharmony_ci .buck_vsel_mask = PV88080_VBUCK3_MASK, 1468c2ecf20Sopenharmony_ci .buck_limit_mask = PV88080_BUCK3_ILIM_MASK, 1478c2ecf20Sopenharmony_ci }, 1488c2ecf20Sopenharmony_ci /* HVBUCK */ 1498c2ecf20Sopenharmony_ci .hvbuck_enable_reg = PV88080AA_REG_HVBUCK_CONF2, 1508c2ecf20Sopenharmony_ci .hvbuck_vsel_reg = PV88080AA_REG_HVBUCK_CONF1, 1518c2ecf20Sopenharmony_ci .hvbuck_enable_mask = PV88080_HVBUCK_EN, 1528c2ecf20Sopenharmony_ci .hvbuck_vsel_mask = PV88080_VHVBUCK_MASK, 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic const struct pv88080_compatible_regmap pv88080_ba_regs = { 1568c2ecf20Sopenharmony_ci /* BUCK1 */ 1578c2ecf20Sopenharmony_ci .buck_regmap[0] = { 1588c2ecf20Sopenharmony_ci .buck_enable_reg = PV88080BA_REG_BUCK1_CONF0, 1598c2ecf20Sopenharmony_ci .buck_vsel_reg = PV88080BA_REG_BUCK1_CONF0, 1608c2ecf20Sopenharmony_ci .buck_mode_reg = PV88080BA_REG_BUCK1_CONF1, 1618c2ecf20Sopenharmony_ci .buck_limit_reg = PV88080BA_REG_BUCK1_CONF1, 1628c2ecf20Sopenharmony_ci .buck_vdac_range_reg = PV88080BA_REG_BUCK1_CONF2, 1638c2ecf20Sopenharmony_ci .buck_vrange_gain_reg = PV88080BA_REG_BUCK1_CONF5, 1648c2ecf20Sopenharmony_ci .buck_enable_mask = PV88080_BUCK1_EN, 1658c2ecf20Sopenharmony_ci .buck_vsel_mask = PV88080_VBUCK1_MASK, 1668c2ecf20Sopenharmony_ci .buck_limit_mask = PV88080_BUCK1_ILIM_MASK, 1678c2ecf20Sopenharmony_ci }, 1688c2ecf20Sopenharmony_ci /* BUCK2 */ 1698c2ecf20Sopenharmony_ci .buck_regmap[1] = { 1708c2ecf20Sopenharmony_ci .buck_enable_reg = PV88080BA_REG_BUCK2_CONF0, 1718c2ecf20Sopenharmony_ci .buck_vsel_reg = PV88080BA_REG_BUCK2_CONF0, 1728c2ecf20Sopenharmony_ci .buck_mode_reg = PV88080BA_REG_BUCK2_CONF1, 1738c2ecf20Sopenharmony_ci .buck_limit_reg = PV88080BA_REG_BUCK2_CONF1, 1748c2ecf20Sopenharmony_ci .buck_vdac_range_reg = PV88080BA_REG_BUCK2_CONF2, 1758c2ecf20Sopenharmony_ci .buck_vrange_gain_reg = PV88080BA_REG_BUCK2_CONF5, 1768c2ecf20Sopenharmony_ci .buck_enable_mask = PV88080_BUCK2_EN, 1778c2ecf20Sopenharmony_ci .buck_vsel_mask = PV88080_VBUCK2_MASK, 1788c2ecf20Sopenharmony_ci .buck_limit_mask = PV88080_BUCK2_ILIM_MASK, 1798c2ecf20Sopenharmony_ci }, 1808c2ecf20Sopenharmony_ci /* BUCK3 */ 1818c2ecf20Sopenharmony_ci .buck_regmap[2] = { 1828c2ecf20Sopenharmony_ci .buck_enable_reg = PV88080BA_REG_BUCK3_CONF0, 1838c2ecf20Sopenharmony_ci .buck_vsel_reg = PV88080BA_REG_BUCK3_CONF0, 1848c2ecf20Sopenharmony_ci .buck_mode_reg = PV88080BA_REG_BUCK3_CONF1, 1858c2ecf20Sopenharmony_ci .buck_limit_reg = PV88080BA_REG_BUCK3_CONF1, 1868c2ecf20Sopenharmony_ci .buck_vdac_range_reg = PV88080BA_REG_BUCK3_CONF2, 1878c2ecf20Sopenharmony_ci .buck_vrange_gain_reg = PV88080BA_REG_BUCK3_CONF5, 1888c2ecf20Sopenharmony_ci .buck_enable_mask = PV88080_BUCK3_EN, 1898c2ecf20Sopenharmony_ci .buck_vsel_mask = PV88080_VBUCK3_MASK, 1908c2ecf20Sopenharmony_ci .buck_limit_mask = PV88080_BUCK3_ILIM_MASK, 1918c2ecf20Sopenharmony_ci }, 1928c2ecf20Sopenharmony_ci /* HVBUCK */ 1938c2ecf20Sopenharmony_ci .hvbuck_enable_reg = PV88080BA_REG_HVBUCK_CONF2, 1948c2ecf20Sopenharmony_ci .hvbuck_vsel_reg = PV88080BA_REG_HVBUCK_CONF1, 1958c2ecf20Sopenharmony_ci .hvbuck_enable_mask = PV88080_HVBUCK_EN, 1968c2ecf20Sopenharmony_ci .hvbuck_vsel_mask = PV88080_VHVBUCK_MASK, 1978c2ecf20Sopenharmony_ci}; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 2008c2ecf20Sopenharmony_cistatic const struct of_device_id pv88080_dt_ids[] = { 2018c2ecf20Sopenharmony_ci { .compatible = "pvs,pv88080", .data = (void *)TYPE_PV88080_AA }, 2028c2ecf20Sopenharmony_ci { .compatible = "pvs,pv88080-aa", .data = (void *)TYPE_PV88080_AA }, 2038c2ecf20Sopenharmony_ci { .compatible = "pvs,pv88080-ba", .data = (void *)TYPE_PV88080_BA }, 2048c2ecf20Sopenharmony_ci {}, 2058c2ecf20Sopenharmony_ci}; 2068c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, pv88080_dt_ids); 2078c2ecf20Sopenharmony_ci#endif 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic unsigned int pv88080_buck_get_mode(struct regulator_dev *rdev) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct pv88080_regulator *info = rdev_get_drvdata(rdev); 2128c2ecf20Sopenharmony_ci unsigned int data; 2138c2ecf20Sopenharmony_ci int ret, mode = 0; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci ret = regmap_read(rdev->regmap, info->mode_reg, &data); 2168c2ecf20Sopenharmony_ci if (ret < 0) 2178c2ecf20Sopenharmony_ci return ret; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci switch (data & PV88080_BUCK1_MODE_MASK) { 2208c2ecf20Sopenharmony_ci case PV88080_BUCK_MODE_SYNC: 2218c2ecf20Sopenharmony_ci mode = REGULATOR_MODE_FAST; 2228c2ecf20Sopenharmony_ci break; 2238c2ecf20Sopenharmony_ci case PV88080_BUCK_MODE_AUTO: 2248c2ecf20Sopenharmony_ci mode = REGULATOR_MODE_NORMAL; 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci case PV88080_BUCK_MODE_SLEEP: 2278c2ecf20Sopenharmony_ci mode = REGULATOR_MODE_STANDBY; 2288c2ecf20Sopenharmony_ci break; 2298c2ecf20Sopenharmony_ci default: 2308c2ecf20Sopenharmony_ci return -EINVAL; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return mode; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int pv88080_buck_set_mode(struct regulator_dev *rdev, 2378c2ecf20Sopenharmony_ci unsigned int mode) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct pv88080_regulator *info = rdev_get_drvdata(rdev); 2408c2ecf20Sopenharmony_ci int val = 0; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci switch (mode) { 2438c2ecf20Sopenharmony_ci case REGULATOR_MODE_FAST: 2448c2ecf20Sopenharmony_ci val = PV88080_BUCK_MODE_SYNC; 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci case REGULATOR_MODE_NORMAL: 2478c2ecf20Sopenharmony_ci val = PV88080_BUCK_MODE_AUTO; 2488c2ecf20Sopenharmony_ci break; 2498c2ecf20Sopenharmony_ci case REGULATOR_MODE_STANDBY: 2508c2ecf20Sopenharmony_ci val = PV88080_BUCK_MODE_SLEEP; 2518c2ecf20Sopenharmony_ci break; 2528c2ecf20Sopenharmony_ci default: 2538c2ecf20Sopenharmony_ci return -EINVAL; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return regmap_update_bits(rdev->regmap, info->mode_reg, 2578c2ecf20Sopenharmony_ci PV88080_BUCK1_MODE_MASK, val); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic const struct regulator_ops pv88080_buck_ops = { 2618c2ecf20Sopenharmony_ci .get_mode = pv88080_buck_get_mode, 2628c2ecf20Sopenharmony_ci .set_mode = pv88080_buck_set_mode, 2638c2ecf20Sopenharmony_ci .enable = regulator_enable_regmap, 2648c2ecf20Sopenharmony_ci .disable = regulator_disable_regmap, 2658c2ecf20Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 2668c2ecf20Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 2678c2ecf20Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 2688c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 2698c2ecf20Sopenharmony_ci .set_current_limit = regulator_set_current_limit_regmap, 2708c2ecf20Sopenharmony_ci .get_current_limit = regulator_get_current_limit_regmap, 2718c2ecf20Sopenharmony_ci}; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic const struct regulator_ops pv88080_hvbuck_ops = { 2748c2ecf20Sopenharmony_ci .enable = regulator_enable_regmap, 2758c2ecf20Sopenharmony_ci .disable = regulator_disable_regmap, 2768c2ecf20Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 2778c2ecf20Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 2788c2ecf20Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 2798c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 2808c2ecf20Sopenharmony_ci}; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci#define PV88080_BUCK(chip, regl_name, min, step, max, limits_array) \ 2838c2ecf20Sopenharmony_ci{\ 2848c2ecf20Sopenharmony_ci .desc = {\ 2858c2ecf20Sopenharmony_ci .id = chip##_ID_##regl_name,\ 2868c2ecf20Sopenharmony_ci .name = __stringify(chip##_##regl_name),\ 2878c2ecf20Sopenharmony_ci .of_match = of_match_ptr(#regl_name),\ 2888c2ecf20Sopenharmony_ci .regulators_node = of_match_ptr("regulators"),\ 2898c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE,\ 2908c2ecf20Sopenharmony_ci .owner = THIS_MODULE,\ 2918c2ecf20Sopenharmony_ci .ops = &pv88080_buck_ops,\ 2928c2ecf20Sopenharmony_ci .min_uV = min, \ 2938c2ecf20Sopenharmony_ci .uV_step = step, \ 2948c2ecf20Sopenharmony_ci .n_voltages = ((max) - (min))/(step) + 1, \ 2958c2ecf20Sopenharmony_ci .curr_table = limits_array, \ 2968c2ecf20Sopenharmony_ci .n_current_limits = ARRAY_SIZE(limits_array), \ 2978c2ecf20Sopenharmony_ci },\ 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci#define PV88080_HVBUCK(chip, regl_name, min, step, max) \ 3018c2ecf20Sopenharmony_ci{\ 3028c2ecf20Sopenharmony_ci .desc = {\ 3038c2ecf20Sopenharmony_ci .id = chip##_ID_##regl_name,\ 3048c2ecf20Sopenharmony_ci .name = __stringify(chip##_##regl_name),\ 3058c2ecf20Sopenharmony_ci .of_match = of_match_ptr(#regl_name),\ 3068c2ecf20Sopenharmony_ci .regulators_node = of_match_ptr("regulators"),\ 3078c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE,\ 3088c2ecf20Sopenharmony_ci .owner = THIS_MODULE,\ 3098c2ecf20Sopenharmony_ci .ops = &pv88080_hvbuck_ops,\ 3108c2ecf20Sopenharmony_ci .min_uV = min, \ 3118c2ecf20Sopenharmony_ci .uV_step = step, \ 3128c2ecf20Sopenharmony_ci .n_voltages = ((max) - (min))/(step) + 1, \ 3138c2ecf20Sopenharmony_ci },\ 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic struct pv88080_regulator pv88080_regulator_info[] = { 3178c2ecf20Sopenharmony_ci PV88080_BUCK(PV88080, BUCK1, 600000, 6250, 1393750, 3188c2ecf20Sopenharmony_ci pv88080_buck1_limits), 3198c2ecf20Sopenharmony_ci PV88080_BUCK(PV88080, BUCK2, 600000, 6250, 1393750, 3208c2ecf20Sopenharmony_ci pv88080_buck23_limits), 3218c2ecf20Sopenharmony_ci PV88080_BUCK(PV88080, BUCK3, 600000, 6250, 1393750, 3228c2ecf20Sopenharmony_ci pv88080_buck23_limits), 3238c2ecf20Sopenharmony_ci PV88080_HVBUCK(PV88080, HVBUCK, 0, 5000, 1275000), 3248c2ecf20Sopenharmony_ci}; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic irqreturn_t pv88080_irq_handler(int irq, void *data) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct pv88080 *chip = data; 3298c2ecf20Sopenharmony_ci int i, reg_val, err, ret = IRQ_NONE; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci err = regmap_read(chip->regmap, PV88080_REG_EVENT_A, ®_val); 3328c2ecf20Sopenharmony_ci if (err < 0) 3338c2ecf20Sopenharmony_ci goto error_i2c; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (reg_val & PV88080_E_VDD_FLT) { 3368c2ecf20Sopenharmony_ci for (i = 0; i < PV88080_MAX_REGULATORS; i++) { 3378c2ecf20Sopenharmony_ci if (chip->rdev[i] != NULL) 3388c2ecf20Sopenharmony_ci regulator_notifier_call_chain(chip->rdev[i], 3398c2ecf20Sopenharmony_ci REGULATOR_EVENT_UNDER_VOLTAGE, 3408c2ecf20Sopenharmony_ci NULL); 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci err = regmap_write(chip->regmap, PV88080_REG_EVENT_A, 3448c2ecf20Sopenharmony_ci PV88080_E_VDD_FLT); 3458c2ecf20Sopenharmony_ci if (err < 0) 3468c2ecf20Sopenharmony_ci goto error_i2c; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (reg_val & PV88080_E_OVER_TEMP) { 3528c2ecf20Sopenharmony_ci for (i = 0; i < PV88080_MAX_REGULATORS; i++) { 3538c2ecf20Sopenharmony_ci if (chip->rdev[i] != NULL) 3548c2ecf20Sopenharmony_ci regulator_notifier_call_chain(chip->rdev[i], 3558c2ecf20Sopenharmony_ci REGULATOR_EVENT_OVER_TEMP, 3568c2ecf20Sopenharmony_ci NULL); 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci err = regmap_write(chip->regmap, PV88080_REG_EVENT_A, 3608c2ecf20Sopenharmony_ci PV88080_E_OVER_TEMP); 3618c2ecf20Sopenharmony_ci if (err < 0) 3628c2ecf20Sopenharmony_ci goto error_i2c; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return ret; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cierror_i2c: 3708c2ecf20Sopenharmony_ci dev_err(chip->dev, "I2C error : %d\n", err); 3718c2ecf20Sopenharmony_ci return IRQ_NONE; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci/* 3758c2ecf20Sopenharmony_ci * I2C driver interface functions 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_cistatic int pv88080_i2c_probe(struct i2c_client *i2c, 3788c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev); 3818c2ecf20Sopenharmony_ci struct pv88080 *chip; 3828c2ecf20Sopenharmony_ci const struct pv88080_compatible_regmap *regmap_config; 3838c2ecf20Sopenharmony_ci const struct of_device_id *match; 3848c2ecf20Sopenharmony_ci struct regulator_config config = { }; 3858c2ecf20Sopenharmony_ci int i, error, ret; 3868c2ecf20Sopenharmony_ci unsigned int conf2, conf5; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci chip = devm_kzalloc(&i2c->dev, sizeof(struct pv88080), GFP_KERNEL); 3898c2ecf20Sopenharmony_ci if (!chip) 3908c2ecf20Sopenharmony_ci return -ENOMEM; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci chip->dev = &i2c->dev; 3938c2ecf20Sopenharmony_ci chip->regmap = devm_regmap_init_i2c(i2c, &pv88080_regmap_config); 3948c2ecf20Sopenharmony_ci if (IS_ERR(chip->regmap)) { 3958c2ecf20Sopenharmony_ci error = PTR_ERR(chip->regmap); 3968c2ecf20Sopenharmony_ci dev_err(chip->dev, "Failed to allocate register map: %d\n", 3978c2ecf20Sopenharmony_ci error); 3988c2ecf20Sopenharmony_ci return error; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (i2c->dev.of_node) { 4028c2ecf20Sopenharmony_ci match = of_match_node(pv88080_dt_ids, i2c->dev.of_node); 4038c2ecf20Sopenharmony_ci if (!match) { 4048c2ecf20Sopenharmony_ci dev_err(chip->dev, "Failed to get of_match_node\n"); 4058c2ecf20Sopenharmony_ci return -EINVAL; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci chip->type = (unsigned long)match->data; 4088c2ecf20Sopenharmony_ci } else { 4098c2ecf20Sopenharmony_ci chip->type = id->driver_data; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci i2c_set_clientdata(i2c, chip); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (i2c->irq != 0) { 4158c2ecf20Sopenharmony_ci ret = regmap_write(chip->regmap, PV88080_REG_MASK_A, 0xFF); 4168c2ecf20Sopenharmony_ci if (ret < 0) { 4178c2ecf20Sopenharmony_ci dev_err(chip->dev, 4188c2ecf20Sopenharmony_ci "Failed to mask A reg: %d\n", ret); 4198c2ecf20Sopenharmony_ci return ret; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci ret = regmap_write(chip->regmap, PV88080_REG_MASK_B, 0xFF); 4228c2ecf20Sopenharmony_ci if (ret < 0) { 4238c2ecf20Sopenharmony_ci dev_err(chip->dev, 4248c2ecf20Sopenharmony_ci "Failed to mask B reg: %d\n", ret); 4258c2ecf20Sopenharmony_ci return ret; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci ret = regmap_write(chip->regmap, PV88080_REG_MASK_C, 0xFF); 4288c2ecf20Sopenharmony_ci if (ret < 0) { 4298c2ecf20Sopenharmony_ci dev_err(chip->dev, 4308c2ecf20Sopenharmony_ci "Failed to mask C reg: %d\n", ret); 4318c2ecf20Sopenharmony_ci return ret; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, 4358c2ecf20Sopenharmony_ci pv88080_irq_handler, 4368c2ecf20Sopenharmony_ci IRQF_TRIGGER_LOW|IRQF_ONESHOT, 4378c2ecf20Sopenharmony_ci "pv88080", chip); 4388c2ecf20Sopenharmony_ci if (ret != 0) { 4398c2ecf20Sopenharmony_ci dev_err(chip->dev, "Failed to request IRQ: %d\n", 4408c2ecf20Sopenharmony_ci i2c->irq); 4418c2ecf20Sopenharmony_ci return ret; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci ret = regmap_update_bits(chip->regmap, PV88080_REG_MASK_A, 4458c2ecf20Sopenharmony_ci PV88080_M_VDD_FLT | PV88080_M_OVER_TEMP, 0); 4468c2ecf20Sopenharmony_ci if (ret < 0) { 4478c2ecf20Sopenharmony_ci dev_err(chip->dev, 4488c2ecf20Sopenharmony_ci "Failed to update mask reg: %d\n", ret); 4498c2ecf20Sopenharmony_ci return ret; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci } else { 4528c2ecf20Sopenharmony_ci dev_warn(chip->dev, "No IRQ configured\n"); 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci switch (chip->type) { 4568c2ecf20Sopenharmony_ci case TYPE_PV88080_AA: 4578c2ecf20Sopenharmony_ci chip->regmap_config = &pv88080_aa_regs; 4588c2ecf20Sopenharmony_ci break; 4598c2ecf20Sopenharmony_ci case TYPE_PV88080_BA: 4608c2ecf20Sopenharmony_ci chip->regmap_config = &pv88080_ba_regs; 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci regmap_config = chip->regmap_config; 4658c2ecf20Sopenharmony_ci config.dev = chip->dev; 4668c2ecf20Sopenharmony_ci config.regmap = chip->regmap; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci /* Registeration for BUCK1, 2, 3 */ 4698c2ecf20Sopenharmony_ci for (i = 0; i < PV88080_MAX_REGULATORS-1; i++) { 4708c2ecf20Sopenharmony_ci if (init_data) 4718c2ecf20Sopenharmony_ci config.init_data = &init_data[i]; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci pv88080_regulator_info[i].desc.csel_reg 4748c2ecf20Sopenharmony_ci = regmap_config->buck_regmap[i].buck_limit_reg; 4758c2ecf20Sopenharmony_ci pv88080_regulator_info[i].desc.csel_mask 4768c2ecf20Sopenharmony_ci = regmap_config->buck_regmap[i].buck_limit_mask; 4778c2ecf20Sopenharmony_ci pv88080_regulator_info[i].mode_reg 4788c2ecf20Sopenharmony_ci = regmap_config->buck_regmap[i].buck_mode_reg; 4798c2ecf20Sopenharmony_ci pv88080_regulator_info[i].conf2 4808c2ecf20Sopenharmony_ci = regmap_config->buck_regmap[i].buck_vdac_range_reg; 4818c2ecf20Sopenharmony_ci pv88080_regulator_info[i].conf5 4828c2ecf20Sopenharmony_ci = regmap_config->buck_regmap[i].buck_vrange_gain_reg; 4838c2ecf20Sopenharmony_ci pv88080_regulator_info[i].desc.enable_reg 4848c2ecf20Sopenharmony_ci = regmap_config->buck_regmap[i].buck_enable_reg; 4858c2ecf20Sopenharmony_ci pv88080_regulator_info[i].desc.enable_mask 4868c2ecf20Sopenharmony_ci = regmap_config->buck_regmap[i].buck_enable_mask; 4878c2ecf20Sopenharmony_ci pv88080_regulator_info[i].desc.vsel_reg 4888c2ecf20Sopenharmony_ci = regmap_config->buck_regmap[i].buck_vsel_reg; 4898c2ecf20Sopenharmony_ci pv88080_regulator_info[i].desc.vsel_mask 4908c2ecf20Sopenharmony_ci = regmap_config->buck_regmap[i].buck_vsel_mask; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci ret = regmap_read(chip->regmap, 4938c2ecf20Sopenharmony_ci pv88080_regulator_info[i].conf2, &conf2); 4948c2ecf20Sopenharmony_ci if (ret < 0) 4958c2ecf20Sopenharmony_ci return ret; 4968c2ecf20Sopenharmony_ci conf2 = ((conf2 >> PV88080_BUCK_VDAC_RANGE_SHIFT) & 4978c2ecf20Sopenharmony_ci PV88080_BUCK_VDAC_RANGE_MASK); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci ret = regmap_read(chip->regmap, 5008c2ecf20Sopenharmony_ci pv88080_regulator_info[i].conf5, &conf5); 5018c2ecf20Sopenharmony_ci if (ret < 0) 5028c2ecf20Sopenharmony_ci return ret; 5038c2ecf20Sopenharmony_ci conf5 = ((conf5 >> PV88080_BUCK_VRANGE_GAIN_SHIFT) & 5048c2ecf20Sopenharmony_ci PV88080_BUCK_VRANGE_GAIN_MASK); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci pv88080_regulator_info[i].desc.min_uV = 5078c2ecf20Sopenharmony_ci pv88080_buck_vol[conf2].min_uV * (conf5+1); 5088c2ecf20Sopenharmony_ci pv88080_regulator_info[i].desc.uV_step = 5098c2ecf20Sopenharmony_ci pv88080_buck_vol[conf2].uV_step * (conf5+1); 5108c2ecf20Sopenharmony_ci pv88080_regulator_info[i].desc.n_voltages = 5118c2ecf20Sopenharmony_ci ((pv88080_buck_vol[conf2].max_uV * (conf5+1)) 5128c2ecf20Sopenharmony_ci - (pv88080_regulator_info[i].desc.min_uV)) 5138c2ecf20Sopenharmony_ci /(pv88080_regulator_info[i].desc.uV_step) + 1; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci config.driver_data = (void *)&pv88080_regulator_info[i]; 5168c2ecf20Sopenharmony_ci chip->rdev[i] = devm_regulator_register(chip->dev, 5178c2ecf20Sopenharmony_ci &pv88080_regulator_info[i].desc, &config); 5188c2ecf20Sopenharmony_ci if (IS_ERR(chip->rdev[i])) { 5198c2ecf20Sopenharmony_ci dev_err(chip->dev, 5208c2ecf20Sopenharmony_ci "Failed to register PV88080 regulator\n"); 5218c2ecf20Sopenharmony_ci return PTR_ERR(chip->rdev[i]); 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci pv88080_regulator_info[PV88080_ID_HVBUCK].desc.enable_reg 5268c2ecf20Sopenharmony_ci = regmap_config->hvbuck_enable_reg; 5278c2ecf20Sopenharmony_ci pv88080_regulator_info[PV88080_ID_HVBUCK].desc.enable_mask 5288c2ecf20Sopenharmony_ci = regmap_config->hvbuck_enable_mask; 5298c2ecf20Sopenharmony_ci pv88080_regulator_info[PV88080_ID_HVBUCK].desc.vsel_reg 5308c2ecf20Sopenharmony_ci = regmap_config->hvbuck_vsel_reg; 5318c2ecf20Sopenharmony_ci pv88080_regulator_info[PV88080_ID_HVBUCK].desc.vsel_mask 5328c2ecf20Sopenharmony_ci = regmap_config->hvbuck_vsel_mask; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* Registeration for HVBUCK */ 5358c2ecf20Sopenharmony_ci if (init_data) 5368c2ecf20Sopenharmony_ci config.init_data = &init_data[PV88080_ID_HVBUCK]; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci config.driver_data = (void *)&pv88080_regulator_info[PV88080_ID_HVBUCK]; 5398c2ecf20Sopenharmony_ci chip->rdev[PV88080_ID_HVBUCK] = devm_regulator_register(chip->dev, 5408c2ecf20Sopenharmony_ci &pv88080_regulator_info[PV88080_ID_HVBUCK].desc, &config); 5418c2ecf20Sopenharmony_ci if (IS_ERR(chip->rdev[PV88080_ID_HVBUCK])) { 5428c2ecf20Sopenharmony_ci dev_err(chip->dev, "Failed to register PV88080 regulator\n"); 5438c2ecf20Sopenharmony_ci return PTR_ERR(chip->rdev[PV88080_ID_HVBUCK]); 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci return 0; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_cistatic const struct i2c_device_id pv88080_i2c_id[] = { 5508c2ecf20Sopenharmony_ci { "pv88080", TYPE_PV88080_AA }, 5518c2ecf20Sopenharmony_ci { "pv88080-aa", TYPE_PV88080_AA }, 5528c2ecf20Sopenharmony_ci { "pv88080-ba", TYPE_PV88080_BA }, 5538c2ecf20Sopenharmony_ci {}, 5548c2ecf20Sopenharmony_ci}; 5558c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, pv88080_i2c_id); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic struct i2c_driver pv88080_regulator_driver = { 5588c2ecf20Sopenharmony_ci .driver = { 5598c2ecf20Sopenharmony_ci .name = "pv88080", 5608c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(pv88080_dt_ids), 5618c2ecf20Sopenharmony_ci }, 5628c2ecf20Sopenharmony_ci .probe = pv88080_i2c_probe, 5638c2ecf20Sopenharmony_ci .id_table = pv88080_i2c_id, 5648c2ecf20Sopenharmony_ci}; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cimodule_i2c_driver(pv88080_regulator_driver); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ciMODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>"); 5698c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Regulator device driver for Powerventure PV88080"); 5708c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 571