162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// pv88080-regulator.c - Regulator device driver for PV88080 462306a36Sopenharmony_ci// Copyright (C) 2016 Powerventure Semiconductor Ltd. 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/err.h> 762306a36Sopenharmony_ci#include <linux/i2c.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/of.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/regulator/driver.h> 1362306a36Sopenharmony_ci#include <linux/regulator/machine.h> 1462306a36Sopenharmony_ci#include <linux/regmap.h> 1562306a36Sopenharmony_ci#include <linux/irq.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h> 1862306a36Sopenharmony_ci#include "pv88080-regulator.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define PV88080_MAX_REGULATORS 4 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* PV88080 REGULATOR IDs */ 2362306a36Sopenharmony_cienum { 2462306a36Sopenharmony_ci /* BUCKs */ 2562306a36Sopenharmony_ci PV88080_ID_BUCK1, 2662306a36Sopenharmony_ci PV88080_ID_BUCK2, 2762306a36Sopenharmony_ci PV88080_ID_BUCK3, 2862306a36Sopenharmony_ci PV88080_ID_HVBUCK, 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cienum pv88080_types { 3262306a36Sopenharmony_ci TYPE_PV88080_AA, 3362306a36Sopenharmony_ci TYPE_PV88080_BA, 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistruct pv88080_regulator { 3762306a36Sopenharmony_ci struct regulator_desc desc; 3862306a36Sopenharmony_ci unsigned int mode_reg; 3962306a36Sopenharmony_ci unsigned int conf2; 4062306a36Sopenharmony_ci unsigned int conf5; 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistruct pv88080 { 4462306a36Sopenharmony_ci struct device *dev; 4562306a36Sopenharmony_ci struct regmap *regmap; 4662306a36Sopenharmony_ci struct regulator_dev *rdev[PV88080_MAX_REGULATORS]; 4762306a36Sopenharmony_ci unsigned long type; 4862306a36Sopenharmony_ci const struct pv88080_compatible_regmap *regmap_config; 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistruct pv88080_buck_voltage { 5262306a36Sopenharmony_ci int min_uV; 5362306a36Sopenharmony_ci int max_uV; 5462306a36Sopenharmony_ci int uV_step; 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistruct pv88080_buck_regmap { 5862306a36Sopenharmony_ci /* REGS */ 5962306a36Sopenharmony_ci int buck_enable_reg; 6062306a36Sopenharmony_ci int buck_vsel_reg; 6162306a36Sopenharmony_ci int buck_mode_reg; 6262306a36Sopenharmony_ci int buck_limit_reg; 6362306a36Sopenharmony_ci int buck_vdac_range_reg; 6462306a36Sopenharmony_ci int buck_vrange_gain_reg; 6562306a36Sopenharmony_ci /* MASKS */ 6662306a36Sopenharmony_ci int buck_enable_mask; 6762306a36Sopenharmony_ci int buck_vsel_mask; 6862306a36Sopenharmony_ci int buck_limit_mask; 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistruct pv88080_compatible_regmap { 7262306a36Sopenharmony_ci /* BUCK1, 2, 3 */ 7362306a36Sopenharmony_ci struct pv88080_buck_regmap buck_regmap[PV88080_MAX_REGULATORS-1]; 7462306a36Sopenharmony_ci /* HVBUCK */ 7562306a36Sopenharmony_ci int hvbuck_enable_reg; 7662306a36Sopenharmony_ci int hvbuck_vsel_reg; 7762306a36Sopenharmony_ci int hvbuck_enable_mask; 7862306a36Sopenharmony_ci int hvbuck_vsel_mask; 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic const struct regmap_config pv88080_regmap_config = { 8262306a36Sopenharmony_ci .reg_bits = 8, 8362306a36Sopenharmony_ci .val_bits = 8, 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* Current limits array (in uA) for BUCK1, BUCK2, BUCK3. 8762306a36Sopenharmony_ci * Entry indexes corresponds to register values. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic const unsigned int pv88080_buck1_limits[] = { 9162306a36Sopenharmony_ci 3230000, 5130000, 6960000, 8790000 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic const unsigned int pv88080_buck23_limits[] = { 9562306a36Sopenharmony_ci 1496000, 2393000, 3291000, 4189000 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic const struct pv88080_buck_voltage pv88080_buck_vol[2] = { 9962306a36Sopenharmony_ci { 10062306a36Sopenharmony_ci .min_uV = 600000, 10162306a36Sopenharmony_ci .max_uV = 1393750, 10262306a36Sopenharmony_ci .uV_step = 6250, 10362306a36Sopenharmony_ci }, 10462306a36Sopenharmony_ci { 10562306a36Sopenharmony_ci .min_uV = 1400000, 10662306a36Sopenharmony_ci .max_uV = 2193750, 10762306a36Sopenharmony_ci .uV_step = 6250, 10862306a36Sopenharmony_ci }, 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic const struct pv88080_compatible_regmap pv88080_aa_regs = { 11262306a36Sopenharmony_ci /* BUCK1 */ 11362306a36Sopenharmony_ci .buck_regmap[0] = { 11462306a36Sopenharmony_ci .buck_enable_reg = PV88080AA_REG_BUCK1_CONF0, 11562306a36Sopenharmony_ci .buck_vsel_reg = PV88080AA_REG_BUCK1_CONF0, 11662306a36Sopenharmony_ci .buck_mode_reg = PV88080AA_REG_BUCK1_CONF1, 11762306a36Sopenharmony_ci .buck_limit_reg = PV88080AA_REG_BUCK1_CONF1, 11862306a36Sopenharmony_ci .buck_vdac_range_reg = PV88080AA_REG_BUCK1_CONF2, 11962306a36Sopenharmony_ci .buck_vrange_gain_reg = PV88080AA_REG_BUCK1_CONF5, 12062306a36Sopenharmony_ci .buck_enable_mask = PV88080_BUCK1_EN, 12162306a36Sopenharmony_ci .buck_vsel_mask = PV88080_VBUCK1_MASK, 12262306a36Sopenharmony_ci .buck_limit_mask = PV88080_BUCK1_ILIM_MASK, 12362306a36Sopenharmony_ci }, 12462306a36Sopenharmony_ci /* BUCK2 */ 12562306a36Sopenharmony_ci .buck_regmap[1] = { 12662306a36Sopenharmony_ci .buck_enable_reg = PV88080AA_REG_BUCK2_CONF0, 12762306a36Sopenharmony_ci .buck_vsel_reg = PV88080AA_REG_BUCK2_CONF0, 12862306a36Sopenharmony_ci .buck_mode_reg = PV88080AA_REG_BUCK2_CONF1, 12962306a36Sopenharmony_ci .buck_limit_reg = PV88080AA_REG_BUCK2_CONF1, 13062306a36Sopenharmony_ci .buck_vdac_range_reg = PV88080AA_REG_BUCK2_CONF2, 13162306a36Sopenharmony_ci .buck_vrange_gain_reg = PV88080AA_REG_BUCK2_CONF5, 13262306a36Sopenharmony_ci .buck_enable_mask = PV88080_BUCK2_EN, 13362306a36Sopenharmony_ci .buck_vsel_mask = PV88080_VBUCK2_MASK, 13462306a36Sopenharmony_ci .buck_limit_mask = PV88080_BUCK2_ILIM_MASK, 13562306a36Sopenharmony_ci }, 13662306a36Sopenharmony_ci /* BUCK3 */ 13762306a36Sopenharmony_ci .buck_regmap[2] = { 13862306a36Sopenharmony_ci .buck_enable_reg = PV88080AA_REG_BUCK3_CONF0, 13962306a36Sopenharmony_ci .buck_vsel_reg = PV88080AA_REG_BUCK3_CONF0, 14062306a36Sopenharmony_ci .buck_mode_reg = PV88080AA_REG_BUCK3_CONF1, 14162306a36Sopenharmony_ci .buck_limit_reg = PV88080AA_REG_BUCK3_CONF1, 14262306a36Sopenharmony_ci .buck_vdac_range_reg = PV88080AA_REG_BUCK3_CONF2, 14362306a36Sopenharmony_ci .buck_vrange_gain_reg = PV88080AA_REG_BUCK3_CONF5, 14462306a36Sopenharmony_ci .buck_enable_mask = PV88080_BUCK3_EN, 14562306a36Sopenharmony_ci .buck_vsel_mask = PV88080_VBUCK3_MASK, 14662306a36Sopenharmony_ci .buck_limit_mask = PV88080_BUCK3_ILIM_MASK, 14762306a36Sopenharmony_ci }, 14862306a36Sopenharmony_ci /* HVBUCK */ 14962306a36Sopenharmony_ci .hvbuck_enable_reg = PV88080AA_REG_HVBUCK_CONF2, 15062306a36Sopenharmony_ci .hvbuck_vsel_reg = PV88080AA_REG_HVBUCK_CONF1, 15162306a36Sopenharmony_ci .hvbuck_enable_mask = PV88080_HVBUCK_EN, 15262306a36Sopenharmony_ci .hvbuck_vsel_mask = PV88080_VHVBUCK_MASK, 15362306a36Sopenharmony_ci}; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic const struct pv88080_compatible_regmap pv88080_ba_regs = { 15662306a36Sopenharmony_ci /* BUCK1 */ 15762306a36Sopenharmony_ci .buck_regmap[0] = { 15862306a36Sopenharmony_ci .buck_enable_reg = PV88080BA_REG_BUCK1_CONF0, 15962306a36Sopenharmony_ci .buck_vsel_reg = PV88080BA_REG_BUCK1_CONF0, 16062306a36Sopenharmony_ci .buck_mode_reg = PV88080BA_REG_BUCK1_CONF1, 16162306a36Sopenharmony_ci .buck_limit_reg = PV88080BA_REG_BUCK1_CONF1, 16262306a36Sopenharmony_ci .buck_vdac_range_reg = PV88080BA_REG_BUCK1_CONF2, 16362306a36Sopenharmony_ci .buck_vrange_gain_reg = PV88080BA_REG_BUCK1_CONF5, 16462306a36Sopenharmony_ci .buck_enable_mask = PV88080_BUCK1_EN, 16562306a36Sopenharmony_ci .buck_vsel_mask = PV88080_VBUCK1_MASK, 16662306a36Sopenharmony_ci .buck_limit_mask = PV88080_BUCK1_ILIM_MASK, 16762306a36Sopenharmony_ci }, 16862306a36Sopenharmony_ci /* BUCK2 */ 16962306a36Sopenharmony_ci .buck_regmap[1] = { 17062306a36Sopenharmony_ci .buck_enable_reg = PV88080BA_REG_BUCK2_CONF0, 17162306a36Sopenharmony_ci .buck_vsel_reg = PV88080BA_REG_BUCK2_CONF0, 17262306a36Sopenharmony_ci .buck_mode_reg = PV88080BA_REG_BUCK2_CONF1, 17362306a36Sopenharmony_ci .buck_limit_reg = PV88080BA_REG_BUCK2_CONF1, 17462306a36Sopenharmony_ci .buck_vdac_range_reg = PV88080BA_REG_BUCK2_CONF2, 17562306a36Sopenharmony_ci .buck_vrange_gain_reg = PV88080BA_REG_BUCK2_CONF5, 17662306a36Sopenharmony_ci .buck_enable_mask = PV88080_BUCK2_EN, 17762306a36Sopenharmony_ci .buck_vsel_mask = PV88080_VBUCK2_MASK, 17862306a36Sopenharmony_ci .buck_limit_mask = PV88080_BUCK2_ILIM_MASK, 17962306a36Sopenharmony_ci }, 18062306a36Sopenharmony_ci /* BUCK3 */ 18162306a36Sopenharmony_ci .buck_regmap[2] = { 18262306a36Sopenharmony_ci .buck_enable_reg = PV88080BA_REG_BUCK3_CONF0, 18362306a36Sopenharmony_ci .buck_vsel_reg = PV88080BA_REG_BUCK3_CONF0, 18462306a36Sopenharmony_ci .buck_mode_reg = PV88080BA_REG_BUCK3_CONF1, 18562306a36Sopenharmony_ci .buck_limit_reg = PV88080BA_REG_BUCK3_CONF1, 18662306a36Sopenharmony_ci .buck_vdac_range_reg = PV88080BA_REG_BUCK3_CONF2, 18762306a36Sopenharmony_ci .buck_vrange_gain_reg = PV88080BA_REG_BUCK3_CONF5, 18862306a36Sopenharmony_ci .buck_enable_mask = PV88080_BUCK3_EN, 18962306a36Sopenharmony_ci .buck_vsel_mask = PV88080_VBUCK3_MASK, 19062306a36Sopenharmony_ci .buck_limit_mask = PV88080_BUCK3_ILIM_MASK, 19162306a36Sopenharmony_ci }, 19262306a36Sopenharmony_ci /* HVBUCK */ 19362306a36Sopenharmony_ci .hvbuck_enable_reg = PV88080BA_REG_HVBUCK_CONF2, 19462306a36Sopenharmony_ci .hvbuck_vsel_reg = PV88080BA_REG_HVBUCK_CONF1, 19562306a36Sopenharmony_ci .hvbuck_enable_mask = PV88080_HVBUCK_EN, 19662306a36Sopenharmony_ci .hvbuck_vsel_mask = PV88080_VHVBUCK_MASK, 19762306a36Sopenharmony_ci}; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci#ifdef CONFIG_OF 20062306a36Sopenharmony_cistatic const struct of_device_id pv88080_dt_ids[] = { 20162306a36Sopenharmony_ci { .compatible = "pvs,pv88080", .data = (void *)TYPE_PV88080_AA }, 20262306a36Sopenharmony_ci { .compatible = "pvs,pv88080-aa", .data = (void *)TYPE_PV88080_AA }, 20362306a36Sopenharmony_ci { .compatible = "pvs,pv88080-ba", .data = (void *)TYPE_PV88080_BA }, 20462306a36Sopenharmony_ci {}, 20562306a36Sopenharmony_ci}; 20662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, pv88080_dt_ids); 20762306a36Sopenharmony_ci#endif 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic unsigned int pv88080_buck_get_mode(struct regulator_dev *rdev) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct pv88080_regulator *info = rdev_get_drvdata(rdev); 21262306a36Sopenharmony_ci unsigned int data; 21362306a36Sopenharmony_ci int ret, mode = 0; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci ret = regmap_read(rdev->regmap, info->mode_reg, &data); 21662306a36Sopenharmony_ci if (ret < 0) 21762306a36Sopenharmony_ci return ret; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci switch (data & PV88080_BUCK1_MODE_MASK) { 22062306a36Sopenharmony_ci case PV88080_BUCK_MODE_SYNC: 22162306a36Sopenharmony_ci mode = REGULATOR_MODE_FAST; 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci case PV88080_BUCK_MODE_AUTO: 22462306a36Sopenharmony_ci mode = REGULATOR_MODE_NORMAL; 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci case PV88080_BUCK_MODE_SLEEP: 22762306a36Sopenharmony_ci mode = REGULATOR_MODE_STANDBY; 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci default: 23062306a36Sopenharmony_ci return -EINVAL; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci return mode; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int pv88080_buck_set_mode(struct regulator_dev *rdev, 23762306a36Sopenharmony_ci unsigned int mode) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct pv88080_regulator *info = rdev_get_drvdata(rdev); 24062306a36Sopenharmony_ci int val = 0; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci switch (mode) { 24362306a36Sopenharmony_ci case REGULATOR_MODE_FAST: 24462306a36Sopenharmony_ci val = PV88080_BUCK_MODE_SYNC; 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci case REGULATOR_MODE_NORMAL: 24762306a36Sopenharmony_ci val = PV88080_BUCK_MODE_AUTO; 24862306a36Sopenharmony_ci break; 24962306a36Sopenharmony_ci case REGULATOR_MODE_STANDBY: 25062306a36Sopenharmony_ci val = PV88080_BUCK_MODE_SLEEP; 25162306a36Sopenharmony_ci break; 25262306a36Sopenharmony_ci default: 25362306a36Sopenharmony_ci return -EINVAL; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return regmap_update_bits(rdev->regmap, info->mode_reg, 25762306a36Sopenharmony_ci PV88080_BUCK1_MODE_MASK, val); 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic const struct regulator_ops pv88080_buck_ops = { 26162306a36Sopenharmony_ci .get_mode = pv88080_buck_get_mode, 26262306a36Sopenharmony_ci .set_mode = pv88080_buck_set_mode, 26362306a36Sopenharmony_ci .enable = regulator_enable_regmap, 26462306a36Sopenharmony_ci .disable = regulator_disable_regmap, 26562306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 26662306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 26762306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 26862306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 26962306a36Sopenharmony_ci .set_current_limit = regulator_set_current_limit_regmap, 27062306a36Sopenharmony_ci .get_current_limit = regulator_get_current_limit_regmap, 27162306a36Sopenharmony_ci}; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic const struct regulator_ops pv88080_hvbuck_ops = { 27462306a36Sopenharmony_ci .enable = regulator_enable_regmap, 27562306a36Sopenharmony_ci .disable = regulator_disable_regmap, 27662306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 27762306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 27862306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 27962306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 28062306a36Sopenharmony_ci}; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci#define PV88080_BUCK(chip, regl_name, min, step, max, limits_array) \ 28362306a36Sopenharmony_ci{\ 28462306a36Sopenharmony_ci .desc = {\ 28562306a36Sopenharmony_ci .id = chip##_ID_##regl_name,\ 28662306a36Sopenharmony_ci .name = __stringify(chip##_##regl_name),\ 28762306a36Sopenharmony_ci .of_match = of_match_ptr(#regl_name),\ 28862306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"),\ 28962306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE,\ 29062306a36Sopenharmony_ci .owner = THIS_MODULE,\ 29162306a36Sopenharmony_ci .ops = &pv88080_buck_ops,\ 29262306a36Sopenharmony_ci .min_uV = min, \ 29362306a36Sopenharmony_ci .uV_step = step, \ 29462306a36Sopenharmony_ci .n_voltages = ((max) - (min))/(step) + 1, \ 29562306a36Sopenharmony_ci .curr_table = limits_array, \ 29662306a36Sopenharmony_ci .n_current_limits = ARRAY_SIZE(limits_array), \ 29762306a36Sopenharmony_ci },\ 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci#define PV88080_HVBUCK(chip, regl_name, min, step, max) \ 30162306a36Sopenharmony_ci{\ 30262306a36Sopenharmony_ci .desc = {\ 30362306a36Sopenharmony_ci .id = chip##_ID_##regl_name,\ 30462306a36Sopenharmony_ci .name = __stringify(chip##_##regl_name),\ 30562306a36Sopenharmony_ci .of_match = of_match_ptr(#regl_name),\ 30662306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"),\ 30762306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE,\ 30862306a36Sopenharmony_ci .owner = THIS_MODULE,\ 30962306a36Sopenharmony_ci .ops = &pv88080_hvbuck_ops,\ 31062306a36Sopenharmony_ci .min_uV = min, \ 31162306a36Sopenharmony_ci .uV_step = step, \ 31262306a36Sopenharmony_ci .n_voltages = ((max) - (min))/(step) + 1, \ 31362306a36Sopenharmony_ci },\ 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic struct pv88080_regulator pv88080_regulator_info[] = { 31762306a36Sopenharmony_ci PV88080_BUCK(PV88080, BUCK1, 600000, 6250, 1393750, 31862306a36Sopenharmony_ci pv88080_buck1_limits), 31962306a36Sopenharmony_ci PV88080_BUCK(PV88080, BUCK2, 600000, 6250, 1393750, 32062306a36Sopenharmony_ci pv88080_buck23_limits), 32162306a36Sopenharmony_ci PV88080_BUCK(PV88080, BUCK3, 600000, 6250, 1393750, 32262306a36Sopenharmony_ci pv88080_buck23_limits), 32362306a36Sopenharmony_ci PV88080_HVBUCK(PV88080, HVBUCK, 0, 5000, 1275000), 32462306a36Sopenharmony_ci}; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic irqreturn_t pv88080_irq_handler(int irq, void *data) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct pv88080 *chip = data; 32962306a36Sopenharmony_ci int i, reg_val, err, ret = IRQ_NONE; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci err = regmap_read(chip->regmap, PV88080_REG_EVENT_A, ®_val); 33262306a36Sopenharmony_ci if (err < 0) 33362306a36Sopenharmony_ci goto error_i2c; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (reg_val & PV88080_E_VDD_FLT) { 33662306a36Sopenharmony_ci for (i = 0; i < PV88080_MAX_REGULATORS; i++) { 33762306a36Sopenharmony_ci if (chip->rdev[i] != NULL) 33862306a36Sopenharmony_ci regulator_notifier_call_chain(chip->rdev[i], 33962306a36Sopenharmony_ci REGULATOR_EVENT_UNDER_VOLTAGE, 34062306a36Sopenharmony_ci NULL); 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci err = regmap_write(chip->regmap, PV88080_REG_EVENT_A, 34462306a36Sopenharmony_ci PV88080_E_VDD_FLT); 34562306a36Sopenharmony_ci if (err < 0) 34662306a36Sopenharmony_ci goto error_i2c; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci ret = IRQ_HANDLED; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (reg_val & PV88080_E_OVER_TEMP) { 35262306a36Sopenharmony_ci for (i = 0; i < PV88080_MAX_REGULATORS; i++) { 35362306a36Sopenharmony_ci if (chip->rdev[i] != NULL) 35462306a36Sopenharmony_ci regulator_notifier_call_chain(chip->rdev[i], 35562306a36Sopenharmony_ci REGULATOR_EVENT_OVER_TEMP, 35662306a36Sopenharmony_ci NULL); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci err = regmap_write(chip->regmap, PV88080_REG_EVENT_A, 36062306a36Sopenharmony_ci PV88080_E_OVER_TEMP); 36162306a36Sopenharmony_ci if (err < 0) 36262306a36Sopenharmony_ci goto error_i2c; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci ret = IRQ_HANDLED; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci return ret; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cierror_i2c: 37062306a36Sopenharmony_ci dev_err(chip->dev, "I2C error : %d\n", err); 37162306a36Sopenharmony_ci return IRQ_NONE; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci/* 37562306a36Sopenharmony_ci * I2C driver interface functions 37662306a36Sopenharmony_ci */ 37762306a36Sopenharmony_cistatic int pv88080_i2c_probe(struct i2c_client *i2c) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci const struct i2c_device_id *id = i2c_client_get_device_id(i2c); 38062306a36Sopenharmony_ci struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev); 38162306a36Sopenharmony_ci struct pv88080 *chip; 38262306a36Sopenharmony_ci const struct pv88080_compatible_regmap *regmap_config; 38362306a36Sopenharmony_ci const struct of_device_id *match; 38462306a36Sopenharmony_ci struct regulator_config config = { }; 38562306a36Sopenharmony_ci int i, error, ret; 38662306a36Sopenharmony_ci unsigned int conf2, conf5; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci chip = devm_kzalloc(&i2c->dev, sizeof(struct pv88080), GFP_KERNEL); 38962306a36Sopenharmony_ci if (!chip) 39062306a36Sopenharmony_ci return -ENOMEM; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci chip->dev = &i2c->dev; 39362306a36Sopenharmony_ci chip->regmap = devm_regmap_init_i2c(i2c, &pv88080_regmap_config); 39462306a36Sopenharmony_ci if (IS_ERR(chip->regmap)) { 39562306a36Sopenharmony_ci error = PTR_ERR(chip->regmap); 39662306a36Sopenharmony_ci dev_err(chip->dev, "Failed to allocate register map: %d\n", 39762306a36Sopenharmony_ci error); 39862306a36Sopenharmony_ci return error; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (i2c->dev.of_node) { 40262306a36Sopenharmony_ci match = of_match_node(pv88080_dt_ids, i2c->dev.of_node); 40362306a36Sopenharmony_ci if (!match) { 40462306a36Sopenharmony_ci dev_err(chip->dev, "Failed to get of_match_node\n"); 40562306a36Sopenharmony_ci return -EINVAL; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci chip->type = (unsigned long)match->data; 40862306a36Sopenharmony_ci } else { 40962306a36Sopenharmony_ci chip->type = id->driver_data; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci i2c_set_clientdata(i2c, chip); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (i2c->irq != 0) { 41562306a36Sopenharmony_ci ret = regmap_write(chip->regmap, PV88080_REG_MASK_A, 0xFF); 41662306a36Sopenharmony_ci if (ret < 0) { 41762306a36Sopenharmony_ci dev_err(chip->dev, 41862306a36Sopenharmony_ci "Failed to mask A reg: %d\n", ret); 41962306a36Sopenharmony_ci return ret; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci ret = regmap_write(chip->regmap, PV88080_REG_MASK_B, 0xFF); 42262306a36Sopenharmony_ci if (ret < 0) { 42362306a36Sopenharmony_ci dev_err(chip->dev, 42462306a36Sopenharmony_ci "Failed to mask B reg: %d\n", ret); 42562306a36Sopenharmony_ci return ret; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci ret = regmap_write(chip->regmap, PV88080_REG_MASK_C, 0xFF); 42862306a36Sopenharmony_ci if (ret < 0) { 42962306a36Sopenharmony_ci dev_err(chip->dev, 43062306a36Sopenharmony_ci "Failed to mask C reg: %d\n", ret); 43162306a36Sopenharmony_ci return ret; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, 43562306a36Sopenharmony_ci pv88080_irq_handler, 43662306a36Sopenharmony_ci IRQF_TRIGGER_LOW|IRQF_ONESHOT, 43762306a36Sopenharmony_ci "pv88080", chip); 43862306a36Sopenharmony_ci if (ret != 0) { 43962306a36Sopenharmony_ci dev_err(chip->dev, "Failed to request IRQ: %d\n", 44062306a36Sopenharmony_ci i2c->irq); 44162306a36Sopenharmony_ci return ret; 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci ret = regmap_update_bits(chip->regmap, PV88080_REG_MASK_A, 44562306a36Sopenharmony_ci PV88080_M_VDD_FLT | PV88080_M_OVER_TEMP, 0); 44662306a36Sopenharmony_ci if (ret < 0) { 44762306a36Sopenharmony_ci dev_err(chip->dev, 44862306a36Sopenharmony_ci "Failed to update mask reg: %d\n", ret); 44962306a36Sopenharmony_ci return ret; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci } else { 45262306a36Sopenharmony_ci dev_warn(chip->dev, "No IRQ configured\n"); 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci switch (chip->type) { 45662306a36Sopenharmony_ci case TYPE_PV88080_AA: 45762306a36Sopenharmony_ci chip->regmap_config = &pv88080_aa_regs; 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci case TYPE_PV88080_BA: 46062306a36Sopenharmony_ci chip->regmap_config = &pv88080_ba_regs; 46162306a36Sopenharmony_ci break; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci regmap_config = chip->regmap_config; 46562306a36Sopenharmony_ci config.dev = chip->dev; 46662306a36Sopenharmony_ci config.regmap = chip->regmap; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* Registeration for BUCK1, 2, 3 */ 46962306a36Sopenharmony_ci for (i = 0; i < PV88080_MAX_REGULATORS-1; i++) { 47062306a36Sopenharmony_ci if (init_data) 47162306a36Sopenharmony_ci config.init_data = &init_data[i]; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci pv88080_regulator_info[i].desc.csel_reg 47462306a36Sopenharmony_ci = regmap_config->buck_regmap[i].buck_limit_reg; 47562306a36Sopenharmony_ci pv88080_regulator_info[i].desc.csel_mask 47662306a36Sopenharmony_ci = regmap_config->buck_regmap[i].buck_limit_mask; 47762306a36Sopenharmony_ci pv88080_regulator_info[i].mode_reg 47862306a36Sopenharmony_ci = regmap_config->buck_regmap[i].buck_mode_reg; 47962306a36Sopenharmony_ci pv88080_regulator_info[i].conf2 48062306a36Sopenharmony_ci = regmap_config->buck_regmap[i].buck_vdac_range_reg; 48162306a36Sopenharmony_ci pv88080_regulator_info[i].conf5 48262306a36Sopenharmony_ci = regmap_config->buck_regmap[i].buck_vrange_gain_reg; 48362306a36Sopenharmony_ci pv88080_regulator_info[i].desc.enable_reg 48462306a36Sopenharmony_ci = regmap_config->buck_regmap[i].buck_enable_reg; 48562306a36Sopenharmony_ci pv88080_regulator_info[i].desc.enable_mask 48662306a36Sopenharmony_ci = regmap_config->buck_regmap[i].buck_enable_mask; 48762306a36Sopenharmony_ci pv88080_regulator_info[i].desc.vsel_reg 48862306a36Sopenharmony_ci = regmap_config->buck_regmap[i].buck_vsel_reg; 48962306a36Sopenharmony_ci pv88080_regulator_info[i].desc.vsel_mask 49062306a36Sopenharmony_ci = regmap_config->buck_regmap[i].buck_vsel_mask; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci ret = regmap_read(chip->regmap, 49362306a36Sopenharmony_ci pv88080_regulator_info[i].conf2, &conf2); 49462306a36Sopenharmony_ci if (ret < 0) 49562306a36Sopenharmony_ci return ret; 49662306a36Sopenharmony_ci conf2 = ((conf2 >> PV88080_BUCK_VDAC_RANGE_SHIFT) & 49762306a36Sopenharmony_ci PV88080_BUCK_VDAC_RANGE_MASK); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci ret = regmap_read(chip->regmap, 50062306a36Sopenharmony_ci pv88080_regulator_info[i].conf5, &conf5); 50162306a36Sopenharmony_ci if (ret < 0) 50262306a36Sopenharmony_ci return ret; 50362306a36Sopenharmony_ci conf5 = ((conf5 >> PV88080_BUCK_VRANGE_GAIN_SHIFT) & 50462306a36Sopenharmony_ci PV88080_BUCK_VRANGE_GAIN_MASK); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci pv88080_regulator_info[i].desc.min_uV = 50762306a36Sopenharmony_ci pv88080_buck_vol[conf2].min_uV * (conf5+1); 50862306a36Sopenharmony_ci pv88080_regulator_info[i].desc.uV_step = 50962306a36Sopenharmony_ci pv88080_buck_vol[conf2].uV_step * (conf5+1); 51062306a36Sopenharmony_ci pv88080_regulator_info[i].desc.n_voltages = 51162306a36Sopenharmony_ci ((pv88080_buck_vol[conf2].max_uV * (conf5+1)) 51262306a36Sopenharmony_ci - (pv88080_regulator_info[i].desc.min_uV)) 51362306a36Sopenharmony_ci /(pv88080_regulator_info[i].desc.uV_step) + 1; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci config.driver_data = (void *)&pv88080_regulator_info[i]; 51662306a36Sopenharmony_ci chip->rdev[i] = devm_regulator_register(chip->dev, 51762306a36Sopenharmony_ci &pv88080_regulator_info[i].desc, &config); 51862306a36Sopenharmony_ci if (IS_ERR(chip->rdev[i])) { 51962306a36Sopenharmony_ci dev_err(chip->dev, 52062306a36Sopenharmony_ci "Failed to register PV88080 regulator\n"); 52162306a36Sopenharmony_ci return PTR_ERR(chip->rdev[i]); 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci pv88080_regulator_info[PV88080_ID_HVBUCK].desc.enable_reg 52662306a36Sopenharmony_ci = regmap_config->hvbuck_enable_reg; 52762306a36Sopenharmony_ci pv88080_regulator_info[PV88080_ID_HVBUCK].desc.enable_mask 52862306a36Sopenharmony_ci = regmap_config->hvbuck_enable_mask; 52962306a36Sopenharmony_ci pv88080_regulator_info[PV88080_ID_HVBUCK].desc.vsel_reg 53062306a36Sopenharmony_ci = regmap_config->hvbuck_vsel_reg; 53162306a36Sopenharmony_ci pv88080_regulator_info[PV88080_ID_HVBUCK].desc.vsel_mask 53262306a36Sopenharmony_ci = regmap_config->hvbuck_vsel_mask; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* Registeration for HVBUCK */ 53562306a36Sopenharmony_ci if (init_data) 53662306a36Sopenharmony_ci config.init_data = &init_data[PV88080_ID_HVBUCK]; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci config.driver_data = (void *)&pv88080_regulator_info[PV88080_ID_HVBUCK]; 53962306a36Sopenharmony_ci chip->rdev[PV88080_ID_HVBUCK] = devm_regulator_register(chip->dev, 54062306a36Sopenharmony_ci &pv88080_regulator_info[PV88080_ID_HVBUCK].desc, &config); 54162306a36Sopenharmony_ci if (IS_ERR(chip->rdev[PV88080_ID_HVBUCK])) { 54262306a36Sopenharmony_ci dev_err(chip->dev, "Failed to register PV88080 regulator\n"); 54362306a36Sopenharmony_ci return PTR_ERR(chip->rdev[PV88080_ID_HVBUCK]); 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci return 0; 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic const struct i2c_device_id pv88080_i2c_id[] = { 55062306a36Sopenharmony_ci { "pv88080", TYPE_PV88080_AA }, 55162306a36Sopenharmony_ci { "pv88080-aa", TYPE_PV88080_AA }, 55262306a36Sopenharmony_ci { "pv88080-ba", TYPE_PV88080_BA }, 55362306a36Sopenharmony_ci {}, 55462306a36Sopenharmony_ci}; 55562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, pv88080_i2c_id); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic struct i2c_driver pv88080_regulator_driver = { 55862306a36Sopenharmony_ci .driver = { 55962306a36Sopenharmony_ci .name = "pv88080", 56062306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 56162306a36Sopenharmony_ci .of_match_table = of_match_ptr(pv88080_dt_ids), 56262306a36Sopenharmony_ci }, 56362306a36Sopenharmony_ci .probe = pv88080_i2c_probe, 56462306a36Sopenharmony_ci .id_table = pv88080_i2c_id, 56562306a36Sopenharmony_ci}; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cimodule_i2c_driver(pv88080_regulator_driver); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ciMODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>"); 57062306a36Sopenharmony_ciMODULE_DESCRIPTION("Regulator device driver for Powerventure PV88080"); 57162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 572