162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Maxim MAX77620 Regulator driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Mallikarjun Kasoju <mkasoju@nvidia.com> 862306a36Sopenharmony_ci * Laxman Dewangan <ldewangan@nvidia.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/mfd/max77620.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/of.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/regmap.h> 1762306a36Sopenharmony_ci#include <linux/regulator/driver.h> 1862306a36Sopenharmony_ci#include <linux/regulator/machine.h> 1962306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define max77620_rails(_name) "max77620-"#_name 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* Power Mode */ 2462306a36Sopenharmony_ci#define MAX77620_POWER_MODE_NORMAL 3 2562306a36Sopenharmony_ci#define MAX77620_POWER_MODE_LPM 2 2662306a36Sopenharmony_ci#define MAX77620_POWER_MODE_GLPM 1 2762306a36Sopenharmony_ci#define MAX77620_POWER_MODE_DISABLE 0 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* SD Slew Rate */ 3062306a36Sopenharmony_ci#define MAX77620_SD_SR_13_75 0 3162306a36Sopenharmony_ci#define MAX77620_SD_SR_27_5 1 3262306a36Sopenharmony_ci#define MAX77620_SD_SR_55 2 3362306a36Sopenharmony_ci#define MAX77620_SD_SR_100 3 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cienum max77620_regulators { 3662306a36Sopenharmony_ci MAX77620_REGULATOR_ID_SD0, 3762306a36Sopenharmony_ci MAX77620_REGULATOR_ID_SD1, 3862306a36Sopenharmony_ci MAX77620_REGULATOR_ID_SD2, 3962306a36Sopenharmony_ci MAX77620_REGULATOR_ID_SD3, 4062306a36Sopenharmony_ci MAX77620_REGULATOR_ID_SD4, 4162306a36Sopenharmony_ci MAX77620_REGULATOR_ID_LDO0, 4262306a36Sopenharmony_ci MAX77620_REGULATOR_ID_LDO1, 4362306a36Sopenharmony_ci MAX77620_REGULATOR_ID_LDO2, 4462306a36Sopenharmony_ci MAX77620_REGULATOR_ID_LDO3, 4562306a36Sopenharmony_ci MAX77620_REGULATOR_ID_LDO4, 4662306a36Sopenharmony_ci MAX77620_REGULATOR_ID_LDO5, 4762306a36Sopenharmony_ci MAX77620_REGULATOR_ID_LDO6, 4862306a36Sopenharmony_ci MAX77620_REGULATOR_ID_LDO7, 4962306a36Sopenharmony_ci MAX77620_REGULATOR_ID_LDO8, 5062306a36Sopenharmony_ci MAX77620_NUM_REGS, 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* Regulator types */ 5462306a36Sopenharmony_cienum max77620_regulator_type { 5562306a36Sopenharmony_ci MAX77620_REGULATOR_TYPE_SD, 5662306a36Sopenharmony_ci MAX77620_REGULATOR_TYPE_LDO_N, 5762306a36Sopenharmony_ci MAX77620_REGULATOR_TYPE_LDO_P, 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistruct max77620_regulator_info { 6162306a36Sopenharmony_ci u8 type; 6262306a36Sopenharmony_ci u8 fps_addr; 6362306a36Sopenharmony_ci u8 volt_addr; 6462306a36Sopenharmony_ci u8 cfg_addr; 6562306a36Sopenharmony_ci u8 power_mode_mask; 6662306a36Sopenharmony_ci u8 power_mode_shift; 6762306a36Sopenharmony_ci u8 remote_sense_addr; 6862306a36Sopenharmony_ci u8 remote_sense_mask; 6962306a36Sopenharmony_ci struct regulator_desc desc; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistruct max77620_regulator_pdata { 7362306a36Sopenharmony_ci int active_fps_src; 7462306a36Sopenharmony_ci int active_fps_pd_slot; 7562306a36Sopenharmony_ci int active_fps_pu_slot; 7662306a36Sopenharmony_ci int suspend_fps_src; 7762306a36Sopenharmony_ci int suspend_fps_pd_slot; 7862306a36Sopenharmony_ci int suspend_fps_pu_slot; 7962306a36Sopenharmony_ci int current_mode; 8062306a36Sopenharmony_ci int power_ok; 8162306a36Sopenharmony_ci int ramp_rate_setting; 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistruct max77620_regulator { 8562306a36Sopenharmony_ci struct device *dev; 8662306a36Sopenharmony_ci struct regmap *rmap; 8762306a36Sopenharmony_ci struct max77620_regulator_info *rinfo[MAX77620_NUM_REGS]; 8862306a36Sopenharmony_ci struct max77620_regulator_pdata reg_pdata[MAX77620_NUM_REGS]; 8962306a36Sopenharmony_ci int enable_power_mode[MAX77620_NUM_REGS]; 9062306a36Sopenharmony_ci int current_power_mode[MAX77620_NUM_REGS]; 9162306a36Sopenharmony_ci int active_fps_src[MAX77620_NUM_REGS]; 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define fps_src_name(fps_src) \ 9562306a36Sopenharmony_ci (fps_src == MAX77620_FPS_SRC_0 ? "FPS_SRC_0" : \ 9662306a36Sopenharmony_ci fps_src == MAX77620_FPS_SRC_1 ? "FPS_SRC_1" : \ 9762306a36Sopenharmony_ci fps_src == MAX77620_FPS_SRC_2 ? "FPS_SRC_2" : "FPS_SRC_NONE") 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic int max77620_regulator_get_fps_src(struct max77620_regulator *pmic, 10062306a36Sopenharmony_ci int id) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 10362306a36Sopenharmony_ci unsigned int val; 10462306a36Sopenharmony_ci int ret; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci ret = regmap_read(pmic->rmap, rinfo->fps_addr, &val); 10762306a36Sopenharmony_ci if (ret < 0) { 10862306a36Sopenharmony_ci dev_err(pmic->dev, "Reg 0x%02x read failed %d\n", 10962306a36Sopenharmony_ci rinfo->fps_addr, ret); 11062306a36Sopenharmony_ci return ret; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int max77620_regulator_set_fps_src(struct max77620_regulator *pmic, 11762306a36Sopenharmony_ci int fps_src, int id) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 12062306a36Sopenharmony_ci unsigned int val; 12162306a36Sopenharmony_ci int ret; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (!rinfo) 12462306a36Sopenharmony_ci return 0; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci switch (fps_src) { 12762306a36Sopenharmony_ci case MAX77620_FPS_SRC_0: 12862306a36Sopenharmony_ci case MAX77620_FPS_SRC_1: 12962306a36Sopenharmony_ci case MAX77620_FPS_SRC_2: 13062306a36Sopenharmony_ci case MAX77620_FPS_SRC_NONE: 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci case MAX77620_FPS_SRC_DEF: 13462306a36Sopenharmony_ci ret = regmap_read(pmic->rmap, rinfo->fps_addr, &val); 13562306a36Sopenharmony_ci if (ret < 0) { 13662306a36Sopenharmony_ci dev_err(pmic->dev, "Reg 0x%02x read failed %d\n", 13762306a36Sopenharmony_ci rinfo->fps_addr, ret); 13862306a36Sopenharmony_ci return ret; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci ret = (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT; 14162306a36Sopenharmony_ci pmic->active_fps_src[id] = ret; 14262306a36Sopenharmony_ci return 0; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci default: 14562306a36Sopenharmony_ci dev_err(pmic->dev, "Invalid FPS %d for regulator %d\n", 14662306a36Sopenharmony_ci fps_src, id); 14762306a36Sopenharmony_ci return -EINVAL; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci ret = regmap_update_bits(pmic->rmap, rinfo->fps_addr, 15162306a36Sopenharmony_ci MAX77620_FPS_SRC_MASK, 15262306a36Sopenharmony_ci fps_src << MAX77620_FPS_SRC_SHIFT); 15362306a36Sopenharmony_ci if (ret < 0) { 15462306a36Sopenharmony_ci dev_err(pmic->dev, "Reg 0x%02x update failed %d\n", 15562306a36Sopenharmony_ci rinfo->fps_addr, ret); 15662306a36Sopenharmony_ci return ret; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci pmic->active_fps_src[id] = fps_src; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci return 0; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic int max77620_regulator_set_fps_slots(struct max77620_regulator *pmic, 16462306a36Sopenharmony_ci int id, bool is_suspend) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id]; 16762306a36Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 16862306a36Sopenharmony_ci unsigned int val = 0; 16962306a36Sopenharmony_ci unsigned int mask = 0; 17062306a36Sopenharmony_ci int pu = rpdata->active_fps_pu_slot; 17162306a36Sopenharmony_ci int pd = rpdata->active_fps_pd_slot; 17262306a36Sopenharmony_ci int ret = 0; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (!rinfo) 17562306a36Sopenharmony_ci return 0; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (is_suspend) { 17862306a36Sopenharmony_ci pu = rpdata->suspend_fps_pu_slot; 17962306a36Sopenharmony_ci pd = rpdata->suspend_fps_pd_slot; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* FPS power up period setting */ 18362306a36Sopenharmony_ci if (pu >= 0) { 18462306a36Sopenharmony_ci val |= (pu << MAX77620_FPS_PU_PERIOD_SHIFT); 18562306a36Sopenharmony_ci mask |= MAX77620_FPS_PU_PERIOD_MASK; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* FPS power down period setting */ 18962306a36Sopenharmony_ci if (pd >= 0) { 19062306a36Sopenharmony_ci val |= (pd << MAX77620_FPS_PD_PERIOD_SHIFT); 19162306a36Sopenharmony_ci mask |= MAX77620_FPS_PD_PERIOD_MASK; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (mask) { 19562306a36Sopenharmony_ci ret = regmap_update_bits(pmic->rmap, rinfo->fps_addr, 19662306a36Sopenharmony_ci mask, val); 19762306a36Sopenharmony_ci if (ret < 0) { 19862306a36Sopenharmony_ci dev_err(pmic->dev, "Reg 0x%02x update failed: %d\n", 19962306a36Sopenharmony_ci rinfo->fps_addr, ret); 20062306a36Sopenharmony_ci return ret; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci return ret; 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic int max77620_regulator_set_power_mode(struct max77620_regulator *pmic, 20862306a36Sopenharmony_ci int power_mode, int id) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 21162306a36Sopenharmony_ci u8 mask = rinfo->power_mode_mask; 21262306a36Sopenharmony_ci u8 shift = rinfo->power_mode_shift; 21362306a36Sopenharmony_ci u8 addr; 21462306a36Sopenharmony_ci int ret; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci switch (rinfo->type) { 21762306a36Sopenharmony_ci case MAX77620_REGULATOR_TYPE_SD: 21862306a36Sopenharmony_ci addr = rinfo->cfg_addr; 21962306a36Sopenharmony_ci break; 22062306a36Sopenharmony_ci default: 22162306a36Sopenharmony_ci addr = rinfo->volt_addr; 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci ret = regmap_update_bits(pmic->rmap, addr, mask, power_mode << shift); 22662306a36Sopenharmony_ci if (ret < 0) { 22762306a36Sopenharmony_ci dev_err(pmic->dev, "Regulator %d mode set failed: %d\n", 22862306a36Sopenharmony_ci id, ret); 22962306a36Sopenharmony_ci return ret; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci pmic->current_power_mode[id] = power_mode; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci return ret; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int max77620_regulator_get_power_mode(struct max77620_regulator *pmic, 23762306a36Sopenharmony_ci int id) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 24062306a36Sopenharmony_ci unsigned int val, addr; 24162306a36Sopenharmony_ci u8 mask = rinfo->power_mode_mask; 24262306a36Sopenharmony_ci u8 shift = rinfo->power_mode_shift; 24362306a36Sopenharmony_ci int ret; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci switch (rinfo->type) { 24662306a36Sopenharmony_ci case MAX77620_REGULATOR_TYPE_SD: 24762306a36Sopenharmony_ci addr = rinfo->cfg_addr; 24862306a36Sopenharmony_ci break; 24962306a36Sopenharmony_ci default: 25062306a36Sopenharmony_ci addr = rinfo->volt_addr; 25162306a36Sopenharmony_ci break; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci ret = regmap_read(pmic->rmap, addr, &val); 25562306a36Sopenharmony_ci if (ret < 0) { 25662306a36Sopenharmony_ci dev_err(pmic->dev, "Regulator %d: Reg 0x%02x read failed: %d\n", 25762306a36Sopenharmony_ci id, addr, ret); 25862306a36Sopenharmony_ci return ret; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return (val & mask) >> shift; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic int max77620_read_slew_rate(struct max77620_regulator *pmic, int id) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 26762306a36Sopenharmony_ci unsigned int rval; 26862306a36Sopenharmony_ci int slew_rate; 26962306a36Sopenharmony_ci int ret; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci ret = regmap_read(pmic->rmap, rinfo->cfg_addr, &rval); 27262306a36Sopenharmony_ci if (ret < 0) { 27362306a36Sopenharmony_ci dev_err(pmic->dev, "Register 0x%02x read failed: %d\n", 27462306a36Sopenharmony_ci rinfo->cfg_addr, ret); 27562306a36Sopenharmony_ci return ret; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci switch (rinfo->type) { 27962306a36Sopenharmony_ci case MAX77620_REGULATOR_TYPE_SD: 28062306a36Sopenharmony_ci slew_rate = (rval >> MAX77620_SD_SR_SHIFT) & 0x3; 28162306a36Sopenharmony_ci switch (slew_rate) { 28262306a36Sopenharmony_ci case 0: 28362306a36Sopenharmony_ci slew_rate = 13750; 28462306a36Sopenharmony_ci break; 28562306a36Sopenharmony_ci case 1: 28662306a36Sopenharmony_ci slew_rate = 27500; 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci case 2: 28962306a36Sopenharmony_ci slew_rate = 55000; 29062306a36Sopenharmony_ci break; 29162306a36Sopenharmony_ci case 3: 29262306a36Sopenharmony_ci slew_rate = 100000; 29362306a36Sopenharmony_ci break; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci rinfo->desc.ramp_delay = slew_rate; 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci default: 29862306a36Sopenharmony_ci slew_rate = rval & 0x1; 29962306a36Sopenharmony_ci switch (slew_rate) { 30062306a36Sopenharmony_ci case 0: 30162306a36Sopenharmony_ci slew_rate = 100000; 30262306a36Sopenharmony_ci break; 30362306a36Sopenharmony_ci case 1: 30462306a36Sopenharmony_ci slew_rate = 5000; 30562306a36Sopenharmony_ci break; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci rinfo->desc.ramp_delay = slew_rate; 30862306a36Sopenharmony_ci break; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci return 0; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int max77620_set_slew_rate(struct max77620_regulator *pmic, int id, 31562306a36Sopenharmony_ci int slew_rate) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 31862306a36Sopenharmony_ci unsigned int val; 31962306a36Sopenharmony_ci int ret; 32062306a36Sopenharmony_ci u8 mask; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (rinfo->type == MAX77620_REGULATOR_TYPE_SD) { 32362306a36Sopenharmony_ci if (slew_rate <= 13750) 32462306a36Sopenharmony_ci val = 0; 32562306a36Sopenharmony_ci else if (slew_rate <= 27500) 32662306a36Sopenharmony_ci val = 1; 32762306a36Sopenharmony_ci else if (slew_rate <= 55000) 32862306a36Sopenharmony_ci val = 2; 32962306a36Sopenharmony_ci else 33062306a36Sopenharmony_ci val = 3; 33162306a36Sopenharmony_ci val <<= MAX77620_SD_SR_SHIFT; 33262306a36Sopenharmony_ci mask = MAX77620_SD_SR_MASK; 33362306a36Sopenharmony_ci } else { 33462306a36Sopenharmony_ci if (slew_rate <= 5000) 33562306a36Sopenharmony_ci val = 1; 33662306a36Sopenharmony_ci else 33762306a36Sopenharmony_ci val = 0; 33862306a36Sopenharmony_ci mask = MAX77620_LDO_SLEW_RATE_MASK; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci ret = regmap_update_bits(pmic->rmap, rinfo->cfg_addr, mask, val); 34262306a36Sopenharmony_ci if (ret < 0) { 34362306a36Sopenharmony_ci dev_err(pmic->dev, "Regulator %d slew rate set failed: %d\n", 34462306a36Sopenharmony_ci id, ret); 34562306a36Sopenharmony_ci return ret; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic int max77620_config_power_ok(struct max77620_regulator *pmic, int id) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id]; 35462306a36Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 35562306a36Sopenharmony_ci struct max77620_chip *chip = dev_get_drvdata(pmic->dev->parent); 35662306a36Sopenharmony_ci u8 val, mask; 35762306a36Sopenharmony_ci int ret; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci switch (chip->chip_id) { 36062306a36Sopenharmony_ci case MAX20024: 36162306a36Sopenharmony_ci if (rpdata->power_ok >= 0) { 36262306a36Sopenharmony_ci if (rinfo->type == MAX77620_REGULATOR_TYPE_SD) 36362306a36Sopenharmony_ci mask = MAX20024_SD_CFG1_MPOK_MASK; 36462306a36Sopenharmony_ci else 36562306a36Sopenharmony_ci mask = MAX20024_LDO_CFG2_MPOK_MASK; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci val = rpdata->power_ok ? mask : 0; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci ret = regmap_update_bits(pmic->rmap, rinfo->cfg_addr, 37062306a36Sopenharmony_ci mask, val); 37162306a36Sopenharmony_ci if (ret < 0) { 37262306a36Sopenharmony_ci dev_err(pmic->dev, "Reg 0x%02x update failed %d\n", 37362306a36Sopenharmony_ci rinfo->cfg_addr, ret); 37462306a36Sopenharmony_ci return ret; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci break; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci default: 38062306a36Sopenharmony_ci break; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci return 0; 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic int max77620_init_pmic(struct max77620_regulator *pmic, int id) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id]; 38962306a36Sopenharmony_ci int ret; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci max77620_config_power_ok(pmic, id); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* Update power mode */ 39462306a36Sopenharmony_ci ret = max77620_regulator_get_power_mode(pmic, id); 39562306a36Sopenharmony_ci if (ret < 0) 39662306a36Sopenharmony_ci return ret; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci pmic->current_power_mode[id] = ret; 39962306a36Sopenharmony_ci pmic->enable_power_mode[id] = MAX77620_POWER_MODE_NORMAL; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (rpdata->active_fps_src == MAX77620_FPS_SRC_DEF) { 40262306a36Sopenharmony_ci ret = max77620_regulator_get_fps_src(pmic, id); 40362306a36Sopenharmony_ci if (ret < 0) 40462306a36Sopenharmony_ci return ret; 40562306a36Sopenharmony_ci rpdata->active_fps_src = ret; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci /* If rails are externally control of FPS then enable it always. */ 40962306a36Sopenharmony_ci if (rpdata->active_fps_src == MAX77620_FPS_SRC_NONE) { 41062306a36Sopenharmony_ci ret = max77620_regulator_set_power_mode(pmic, 41162306a36Sopenharmony_ci pmic->enable_power_mode[id], id); 41262306a36Sopenharmony_ci if (ret < 0) 41362306a36Sopenharmony_ci return ret; 41462306a36Sopenharmony_ci } else { 41562306a36Sopenharmony_ci if (pmic->current_power_mode[id] != 41662306a36Sopenharmony_ci pmic->enable_power_mode[id]) { 41762306a36Sopenharmony_ci ret = max77620_regulator_set_power_mode(pmic, 41862306a36Sopenharmony_ci pmic->enable_power_mode[id], id); 41962306a36Sopenharmony_ci if (ret < 0) 42062306a36Sopenharmony_ci return ret; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci ret = max77620_regulator_set_fps_src(pmic, rpdata->active_fps_src, id); 42562306a36Sopenharmony_ci if (ret < 0) 42662306a36Sopenharmony_ci return ret; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci ret = max77620_regulator_set_fps_slots(pmic, id, false); 42962306a36Sopenharmony_ci if (ret < 0) 43062306a36Sopenharmony_ci return ret; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (rpdata->ramp_rate_setting) { 43362306a36Sopenharmony_ci ret = max77620_set_slew_rate(pmic, id, 43462306a36Sopenharmony_ci rpdata->ramp_rate_setting); 43562306a36Sopenharmony_ci if (ret < 0) 43662306a36Sopenharmony_ci return ret; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci return 0; 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic int max77620_regulator_enable(struct regulator_dev *rdev) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct max77620_regulator *pmic = rdev_get_drvdata(rdev); 44562306a36Sopenharmony_ci int id = rdev_get_id(rdev); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (pmic->active_fps_src[id] != MAX77620_FPS_SRC_NONE) 44862306a36Sopenharmony_ci return 0; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci return max77620_regulator_set_power_mode(pmic, 45162306a36Sopenharmony_ci pmic->enable_power_mode[id], id); 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic int max77620_regulator_disable(struct regulator_dev *rdev) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci struct max77620_regulator *pmic = rdev_get_drvdata(rdev); 45762306a36Sopenharmony_ci int id = rdev_get_id(rdev); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (pmic->active_fps_src[id] != MAX77620_FPS_SRC_NONE) 46062306a36Sopenharmony_ci return 0; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci return max77620_regulator_set_power_mode(pmic, 46362306a36Sopenharmony_ci MAX77620_POWER_MODE_DISABLE, id); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic int max77620_regulator_is_enabled(struct regulator_dev *rdev) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct max77620_regulator *pmic = rdev_get_drvdata(rdev); 46962306a36Sopenharmony_ci int id = rdev_get_id(rdev); 47062306a36Sopenharmony_ci int ret; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (pmic->active_fps_src[id] != MAX77620_FPS_SRC_NONE) 47362306a36Sopenharmony_ci return 1; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci ret = max77620_regulator_get_power_mode(pmic, id); 47662306a36Sopenharmony_ci if (ret < 0) 47762306a36Sopenharmony_ci return ret; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (ret != MAX77620_POWER_MODE_DISABLE) 48062306a36Sopenharmony_ci return 1; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci return 0; 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic int max77620_regulator_set_mode(struct regulator_dev *rdev, 48662306a36Sopenharmony_ci unsigned int mode) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct max77620_regulator *pmic = rdev_get_drvdata(rdev); 48962306a36Sopenharmony_ci int id = rdev_get_id(rdev); 49062306a36Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 49162306a36Sopenharmony_ci struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id]; 49262306a36Sopenharmony_ci bool fpwm = false; 49362306a36Sopenharmony_ci int power_mode; 49462306a36Sopenharmony_ci int ret; 49562306a36Sopenharmony_ci u8 val; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci switch (mode) { 49862306a36Sopenharmony_ci case REGULATOR_MODE_FAST: 49962306a36Sopenharmony_ci fpwm = true; 50062306a36Sopenharmony_ci power_mode = MAX77620_POWER_MODE_NORMAL; 50162306a36Sopenharmony_ci break; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci case REGULATOR_MODE_NORMAL: 50462306a36Sopenharmony_ci power_mode = MAX77620_POWER_MODE_NORMAL; 50562306a36Sopenharmony_ci break; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci case REGULATOR_MODE_IDLE: 50862306a36Sopenharmony_ci power_mode = MAX77620_POWER_MODE_LPM; 50962306a36Sopenharmony_ci break; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci default: 51262306a36Sopenharmony_ci dev_err(pmic->dev, "Regulator %d mode %d is invalid\n", 51362306a36Sopenharmony_ci id, mode); 51462306a36Sopenharmony_ci return -EINVAL; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci if (rinfo->type != MAX77620_REGULATOR_TYPE_SD) 51862306a36Sopenharmony_ci goto skip_fpwm; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci val = (fpwm) ? MAX77620_SD_FPWM_MASK : 0; 52162306a36Sopenharmony_ci ret = regmap_update_bits(pmic->rmap, rinfo->cfg_addr, 52262306a36Sopenharmony_ci MAX77620_SD_FPWM_MASK, val); 52362306a36Sopenharmony_ci if (ret < 0) { 52462306a36Sopenharmony_ci dev_err(pmic->dev, "Reg 0x%02x update failed: %d\n", 52562306a36Sopenharmony_ci rinfo->cfg_addr, ret); 52662306a36Sopenharmony_ci return ret; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci rpdata->current_mode = mode; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ciskip_fpwm: 53162306a36Sopenharmony_ci ret = max77620_regulator_set_power_mode(pmic, power_mode, id); 53262306a36Sopenharmony_ci if (ret < 0) 53362306a36Sopenharmony_ci return ret; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci pmic->enable_power_mode[id] = power_mode; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci return 0; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic unsigned int max77620_regulator_get_mode(struct regulator_dev *rdev) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct max77620_regulator *pmic = rdev_get_drvdata(rdev); 54362306a36Sopenharmony_ci int id = rdev_get_id(rdev); 54462306a36Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 54562306a36Sopenharmony_ci int fpwm = 0; 54662306a36Sopenharmony_ci int ret; 54762306a36Sopenharmony_ci int pm_mode, reg_mode; 54862306a36Sopenharmony_ci unsigned int val; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci ret = max77620_regulator_get_power_mode(pmic, id); 55162306a36Sopenharmony_ci if (ret < 0) 55262306a36Sopenharmony_ci return 0; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci pm_mode = ret; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (rinfo->type == MAX77620_REGULATOR_TYPE_SD) { 55762306a36Sopenharmony_ci ret = regmap_read(pmic->rmap, rinfo->cfg_addr, &val); 55862306a36Sopenharmony_ci if (ret < 0) { 55962306a36Sopenharmony_ci dev_err(pmic->dev, "Reg 0x%02x read failed: %d\n", 56062306a36Sopenharmony_ci rinfo->cfg_addr, ret); 56162306a36Sopenharmony_ci return ret; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci fpwm = !!(val & MAX77620_SD_FPWM_MASK); 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci switch (pm_mode) { 56762306a36Sopenharmony_ci case MAX77620_POWER_MODE_NORMAL: 56862306a36Sopenharmony_ci case MAX77620_POWER_MODE_DISABLE: 56962306a36Sopenharmony_ci if (fpwm) 57062306a36Sopenharmony_ci reg_mode = REGULATOR_MODE_FAST; 57162306a36Sopenharmony_ci else 57262306a36Sopenharmony_ci reg_mode = REGULATOR_MODE_NORMAL; 57362306a36Sopenharmony_ci break; 57462306a36Sopenharmony_ci case MAX77620_POWER_MODE_LPM: 57562306a36Sopenharmony_ci case MAX77620_POWER_MODE_GLPM: 57662306a36Sopenharmony_ci reg_mode = REGULATOR_MODE_IDLE; 57762306a36Sopenharmony_ci break; 57862306a36Sopenharmony_ci default: 57962306a36Sopenharmony_ci return 0; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci return reg_mode; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic int max77620_regulator_set_ramp_delay(struct regulator_dev *rdev, 58662306a36Sopenharmony_ci int ramp_delay) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct max77620_regulator *pmic = rdev_get_drvdata(rdev); 58962306a36Sopenharmony_ci int id = rdev_get_id(rdev); 59062306a36Sopenharmony_ci struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id]; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* Device specific ramp rate setting tells that platform has 59362306a36Sopenharmony_ci * different ramp rate from advertised value. In this case, 59462306a36Sopenharmony_ci * do not configure anything and just return success. 59562306a36Sopenharmony_ci */ 59662306a36Sopenharmony_ci if (rpdata->ramp_rate_setting) 59762306a36Sopenharmony_ci return 0; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci return max77620_set_slew_rate(pmic, id, ramp_delay); 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic int max77620_of_parse_cb(struct device_node *np, 60362306a36Sopenharmony_ci const struct regulator_desc *desc, 60462306a36Sopenharmony_ci struct regulator_config *config) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci struct max77620_regulator *pmic = config->driver_data; 60762306a36Sopenharmony_ci struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[desc->id]; 60862306a36Sopenharmony_ci u32 pval; 60962306a36Sopenharmony_ci int ret; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci ret = of_property_read_u32(np, "maxim,active-fps-source", &pval); 61262306a36Sopenharmony_ci rpdata->active_fps_src = (!ret) ? pval : MAX77620_FPS_SRC_DEF; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci ret = of_property_read_u32(np, "maxim,active-fps-power-up-slot", &pval); 61562306a36Sopenharmony_ci rpdata->active_fps_pu_slot = (!ret) ? pval : -1; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci ret = of_property_read_u32( 61862306a36Sopenharmony_ci np, "maxim,active-fps-power-down-slot", &pval); 61962306a36Sopenharmony_ci rpdata->active_fps_pd_slot = (!ret) ? pval : -1; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci ret = of_property_read_u32(np, "maxim,suspend-fps-source", &pval); 62262306a36Sopenharmony_ci rpdata->suspend_fps_src = (!ret) ? pval : -1; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci ret = of_property_read_u32( 62562306a36Sopenharmony_ci np, "maxim,suspend-fps-power-up-slot", &pval); 62662306a36Sopenharmony_ci rpdata->suspend_fps_pu_slot = (!ret) ? pval : -1; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci ret = of_property_read_u32( 62962306a36Sopenharmony_ci np, "maxim,suspend-fps-power-down-slot", &pval); 63062306a36Sopenharmony_ci rpdata->suspend_fps_pd_slot = (!ret) ? pval : -1; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci ret = of_property_read_u32(np, "maxim,power-ok-control", &pval); 63362306a36Sopenharmony_ci if (!ret) 63462306a36Sopenharmony_ci rpdata->power_ok = pval; 63562306a36Sopenharmony_ci else 63662306a36Sopenharmony_ci rpdata->power_ok = -1; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci ret = of_property_read_u32(np, "maxim,ramp-rate-setting", &pval); 63962306a36Sopenharmony_ci rpdata->ramp_rate_setting = (!ret) ? pval : 0; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci return max77620_init_pmic(pmic, desc->id); 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic const struct regulator_ops max77620_regulator_ops = { 64562306a36Sopenharmony_ci .is_enabled = max77620_regulator_is_enabled, 64662306a36Sopenharmony_ci .enable = max77620_regulator_enable, 64762306a36Sopenharmony_ci .disable = max77620_regulator_disable, 64862306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 64962306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 65062306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 65162306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 65262306a36Sopenharmony_ci .set_mode = max77620_regulator_set_mode, 65362306a36Sopenharmony_ci .get_mode = max77620_regulator_get_mode, 65462306a36Sopenharmony_ci .set_ramp_delay = max77620_regulator_set_ramp_delay, 65562306a36Sopenharmony_ci .set_voltage_time_sel = regulator_set_voltage_time_sel, 65662306a36Sopenharmony_ci .set_active_discharge = regulator_set_active_discharge_regmap, 65762306a36Sopenharmony_ci}; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci#define MAX77620_SD_CNF2_ROVS_EN_NONE 0 66062306a36Sopenharmony_ci#define RAIL_SD(_id, _name, _sname, _volt_mask, _min_uV, _max_uV, \ 66162306a36Sopenharmony_ci _step_uV, _rs_add, _rs_mask) \ 66262306a36Sopenharmony_ci [MAX77620_REGULATOR_ID_##_id] = { \ 66362306a36Sopenharmony_ci .type = MAX77620_REGULATOR_TYPE_SD, \ 66462306a36Sopenharmony_ci .volt_addr = MAX77620_REG_##_id, \ 66562306a36Sopenharmony_ci .cfg_addr = MAX77620_REG_##_id##_CFG, \ 66662306a36Sopenharmony_ci .fps_addr = MAX77620_REG_FPS_##_id, \ 66762306a36Sopenharmony_ci .remote_sense_addr = _rs_add, \ 66862306a36Sopenharmony_ci .remote_sense_mask = MAX77620_SD_CNF2_ROVS_EN_##_rs_mask, \ 66962306a36Sopenharmony_ci .power_mode_mask = MAX77620_SD_POWER_MODE_MASK, \ 67062306a36Sopenharmony_ci .power_mode_shift = MAX77620_SD_POWER_MODE_SHIFT, \ 67162306a36Sopenharmony_ci .desc = { \ 67262306a36Sopenharmony_ci .name = max77620_rails(_name), \ 67362306a36Sopenharmony_ci .of_match = of_match_ptr(#_name), \ 67462306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), \ 67562306a36Sopenharmony_ci .of_parse_cb = max77620_of_parse_cb, \ 67662306a36Sopenharmony_ci .supply_name = _sname, \ 67762306a36Sopenharmony_ci .id = MAX77620_REGULATOR_ID_##_id, \ 67862306a36Sopenharmony_ci .ops = &max77620_regulator_ops, \ 67962306a36Sopenharmony_ci .n_voltages = ((_max_uV - _min_uV) / _step_uV) + 1, \ 68062306a36Sopenharmony_ci .min_uV = _min_uV, \ 68162306a36Sopenharmony_ci .uV_step = _step_uV, \ 68262306a36Sopenharmony_ci .enable_time = 500, \ 68362306a36Sopenharmony_ci .vsel_mask = MAX77620_##_volt_mask##_VOLT_MASK, \ 68462306a36Sopenharmony_ci .vsel_reg = MAX77620_REG_##_id, \ 68562306a36Sopenharmony_ci .active_discharge_off = 0, \ 68662306a36Sopenharmony_ci .active_discharge_on = MAX77620_SD_CFG1_ADE_ENABLE, \ 68762306a36Sopenharmony_ci .active_discharge_mask = MAX77620_SD_CFG1_ADE_MASK, \ 68862306a36Sopenharmony_ci .active_discharge_reg = MAX77620_REG_##_id##_CFG, \ 68962306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 69062306a36Sopenharmony_ci .owner = THIS_MODULE, \ 69162306a36Sopenharmony_ci }, \ 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci#define RAIL_LDO(_id, _name, _sname, _type, _min_uV, _max_uV, _step_uV) \ 69562306a36Sopenharmony_ci [MAX77620_REGULATOR_ID_##_id] = { \ 69662306a36Sopenharmony_ci .type = MAX77620_REGULATOR_TYPE_LDO_##_type, \ 69762306a36Sopenharmony_ci .volt_addr = MAX77620_REG_##_id##_CFG, \ 69862306a36Sopenharmony_ci .cfg_addr = MAX77620_REG_##_id##_CFG2, \ 69962306a36Sopenharmony_ci .fps_addr = MAX77620_REG_FPS_##_id, \ 70062306a36Sopenharmony_ci .remote_sense_addr = 0xFF, \ 70162306a36Sopenharmony_ci .power_mode_mask = MAX77620_LDO_POWER_MODE_MASK, \ 70262306a36Sopenharmony_ci .power_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, \ 70362306a36Sopenharmony_ci .desc = { \ 70462306a36Sopenharmony_ci .name = max77620_rails(_name), \ 70562306a36Sopenharmony_ci .of_match = of_match_ptr(#_name), \ 70662306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), \ 70762306a36Sopenharmony_ci .of_parse_cb = max77620_of_parse_cb, \ 70862306a36Sopenharmony_ci .supply_name = _sname, \ 70962306a36Sopenharmony_ci .id = MAX77620_REGULATOR_ID_##_id, \ 71062306a36Sopenharmony_ci .ops = &max77620_regulator_ops, \ 71162306a36Sopenharmony_ci .n_voltages = ((_max_uV - _min_uV) / _step_uV) + 1, \ 71262306a36Sopenharmony_ci .min_uV = _min_uV, \ 71362306a36Sopenharmony_ci .uV_step = _step_uV, \ 71462306a36Sopenharmony_ci .enable_time = 500, \ 71562306a36Sopenharmony_ci .vsel_mask = MAX77620_LDO_VOLT_MASK, \ 71662306a36Sopenharmony_ci .vsel_reg = MAX77620_REG_##_id##_CFG, \ 71762306a36Sopenharmony_ci .active_discharge_off = 0, \ 71862306a36Sopenharmony_ci .active_discharge_on = MAX77620_LDO_CFG2_ADE_ENABLE, \ 71962306a36Sopenharmony_ci .active_discharge_mask = MAX77620_LDO_CFG2_ADE_MASK, \ 72062306a36Sopenharmony_ci .active_discharge_reg = MAX77620_REG_##_id##_CFG2, \ 72162306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 72262306a36Sopenharmony_ci .owner = THIS_MODULE, \ 72362306a36Sopenharmony_ci }, \ 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic struct max77620_regulator_info max77620_regs_info[MAX77620_NUM_REGS] = { 72762306a36Sopenharmony_ci RAIL_SD(SD0, sd0, "in-sd0", SD0, 600000, 1400000, 12500, 0x22, SD0), 72862306a36Sopenharmony_ci RAIL_SD(SD1, sd1, "in-sd1", SD1, 600000, 1550000, 12500, 0x22, SD1), 72962306a36Sopenharmony_ci RAIL_SD(SD2, sd2, "in-sd2", SDX, 600000, 3787500, 12500, 0xFF, NONE), 73062306a36Sopenharmony_ci RAIL_SD(SD3, sd3, "in-sd3", SDX, 600000, 3787500, 12500, 0xFF, NONE), 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci RAIL_LDO(LDO0, ldo0, "in-ldo0-1", N, 800000, 2375000, 25000), 73362306a36Sopenharmony_ci RAIL_LDO(LDO1, ldo1, "in-ldo0-1", N, 800000, 2375000, 25000), 73462306a36Sopenharmony_ci RAIL_LDO(LDO2, ldo2, "in-ldo2", P, 800000, 3950000, 50000), 73562306a36Sopenharmony_ci RAIL_LDO(LDO3, ldo3, "in-ldo3-5", P, 800000, 3950000, 50000), 73662306a36Sopenharmony_ci RAIL_LDO(LDO4, ldo4, "in-ldo4-6", P, 800000, 1587500, 12500), 73762306a36Sopenharmony_ci RAIL_LDO(LDO5, ldo5, "in-ldo3-5", P, 800000, 3950000, 50000), 73862306a36Sopenharmony_ci RAIL_LDO(LDO6, ldo6, "in-ldo4-6", P, 800000, 3950000, 50000), 73962306a36Sopenharmony_ci RAIL_LDO(LDO7, ldo7, "in-ldo7-8", N, 800000, 3950000, 50000), 74062306a36Sopenharmony_ci RAIL_LDO(LDO8, ldo8, "in-ldo7-8", N, 800000, 3950000, 50000), 74162306a36Sopenharmony_ci}; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic struct max77620_regulator_info max20024_regs_info[MAX77620_NUM_REGS] = { 74462306a36Sopenharmony_ci RAIL_SD(SD0, sd0, "in-sd0", SD0, 800000, 1587500, 12500, 0x22, SD0), 74562306a36Sopenharmony_ci RAIL_SD(SD1, sd1, "in-sd1", SD1, 600000, 3387500, 12500, 0x22, SD1), 74662306a36Sopenharmony_ci RAIL_SD(SD2, sd2, "in-sd2", SDX, 600000, 3787500, 12500, 0xFF, NONE), 74762306a36Sopenharmony_ci RAIL_SD(SD3, sd3, "in-sd3", SDX, 600000, 3787500, 12500, 0xFF, NONE), 74862306a36Sopenharmony_ci RAIL_SD(SD4, sd4, "in-sd4", SDX, 600000, 3787500, 12500, 0xFF, NONE), 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci RAIL_LDO(LDO0, ldo0, "in-ldo0-1", N, 800000, 2375000, 25000), 75162306a36Sopenharmony_ci RAIL_LDO(LDO1, ldo1, "in-ldo0-1", N, 800000, 2375000, 25000), 75262306a36Sopenharmony_ci RAIL_LDO(LDO2, ldo2, "in-ldo2", P, 800000, 3950000, 50000), 75362306a36Sopenharmony_ci RAIL_LDO(LDO3, ldo3, "in-ldo3-5", P, 800000, 3950000, 50000), 75462306a36Sopenharmony_ci RAIL_LDO(LDO4, ldo4, "in-ldo4-6", P, 800000, 1587500, 12500), 75562306a36Sopenharmony_ci RAIL_LDO(LDO5, ldo5, "in-ldo3-5", P, 800000, 3950000, 50000), 75662306a36Sopenharmony_ci RAIL_LDO(LDO6, ldo6, "in-ldo4-6", P, 800000, 3950000, 50000), 75762306a36Sopenharmony_ci RAIL_LDO(LDO7, ldo7, "in-ldo7-8", N, 800000, 3950000, 50000), 75862306a36Sopenharmony_ci RAIL_LDO(LDO8, ldo8, "in-ldo7-8", N, 800000, 3950000, 50000), 75962306a36Sopenharmony_ci}; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_cistatic struct max77620_regulator_info max77663_regs_info[MAX77620_NUM_REGS] = { 76262306a36Sopenharmony_ci RAIL_SD(SD0, sd0, "in-sd0", SD0, 600000, 3387500, 12500, 0xFF, NONE), 76362306a36Sopenharmony_ci RAIL_SD(SD1, sd1, "in-sd1", SD1, 800000, 1587500, 12500, 0xFF, NONE), 76462306a36Sopenharmony_ci RAIL_SD(SD2, sd2, "in-sd2", SDX, 600000, 3787500, 12500, 0xFF, NONE), 76562306a36Sopenharmony_ci RAIL_SD(SD3, sd3, "in-sd3", SDX, 600000, 3787500, 12500, 0xFF, NONE), 76662306a36Sopenharmony_ci RAIL_SD(SD4, sd4, "in-sd4", SDX, 600000, 3787500, 12500, 0xFF, NONE), 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci RAIL_LDO(LDO0, ldo0, "in-ldo0-1", N, 800000, 2375000, 25000), 76962306a36Sopenharmony_ci RAIL_LDO(LDO1, ldo1, "in-ldo0-1", N, 800000, 2375000, 25000), 77062306a36Sopenharmony_ci RAIL_LDO(LDO2, ldo2, "in-ldo2", P, 800000, 3950000, 50000), 77162306a36Sopenharmony_ci RAIL_LDO(LDO3, ldo3, "in-ldo3-5", P, 800000, 3950000, 50000), 77262306a36Sopenharmony_ci RAIL_LDO(LDO4, ldo4, "in-ldo4-6", P, 800000, 1587500, 12500), 77362306a36Sopenharmony_ci RAIL_LDO(LDO5, ldo5, "in-ldo3-5", P, 800000, 3950000, 50000), 77462306a36Sopenharmony_ci RAIL_LDO(LDO6, ldo6, "in-ldo4-6", P, 800000, 3950000, 50000), 77562306a36Sopenharmony_ci RAIL_LDO(LDO7, ldo7, "in-ldo7-8", N, 800000, 3950000, 50000), 77662306a36Sopenharmony_ci RAIL_LDO(LDO8, ldo8, "in-ldo7-8", N, 800000, 3950000, 50000), 77762306a36Sopenharmony_ci}; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_cistatic int max77620_regulator_probe(struct platform_device *pdev) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci struct max77620_chip *max77620_chip = dev_get_drvdata(pdev->dev.parent); 78262306a36Sopenharmony_ci struct max77620_regulator_info *rinfo; 78362306a36Sopenharmony_ci struct device *dev = &pdev->dev; 78462306a36Sopenharmony_ci struct regulator_config config = { }; 78562306a36Sopenharmony_ci struct max77620_regulator *pmic; 78662306a36Sopenharmony_ci int ret = 0; 78762306a36Sopenharmony_ci int id; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); 79062306a36Sopenharmony_ci if (!pmic) 79162306a36Sopenharmony_ci return -ENOMEM; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci platform_set_drvdata(pdev, pmic); 79462306a36Sopenharmony_ci pmic->dev = dev; 79562306a36Sopenharmony_ci pmic->rmap = max77620_chip->rmap; 79662306a36Sopenharmony_ci if (!dev->of_node) 79762306a36Sopenharmony_ci dev->of_node = pdev->dev.parent->of_node; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci switch (max77620_chip->chip_id) { 80062306a36Sopenharmony_ci case MAX77620: 80162306a36Sopenharmony_ci rinfo = max77620_regs_info; 80262306a36Sopenharmony_ci break; 80362306a36Sopenharmony_ci case MAX20024: 80462306a36Sopenharmony_ci rinfo = max20024_regs_info; 80562306a36Sopenharmony_ci break; 80662306a36Sopenharmony_ci case MAX77663: 80762306a36Sopenharmony_ci rinfo = max77663_regs_info; 80862306a36Sopenharmony_ci break; 80962306a36Sopenharmony_ci default: 81062306a36Sopenharmony_ci return -EINVAL; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci config.regmap = pmic->rmap; 81462306a36Sopenharmony_ci config.dev = dev; 81562306a36Sopenharmony_ci config.driver_data = pmic; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci /* 81862306a36Sopenharmony_ci * Set of_node_reuse flag to prevent driver core from attempting to 81962306a36Sopenharmony_ci * claim any pinmux resources already claimed by the parent device. 82062306a36Sopenharmony_ci * Otherwise PMIC driver will fail to re-probe. 82162306a36Sopenharmony_ci */ 82262306a36Sopenharmony_ci device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci for (id = 0; id < MAX77620_NUM_REGS; id++) { 82562306a36Sopenharmony_ci struct regulator_dev *rdev; 82662306a36Sopenharmony_ci struct regulator_desc *rdesc; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci if ((max77620_chip->chip_id == MAX77620) && 82962306a36Sopenharmony_ci (id == MAX77620_REGULATOR_ID_SD4)) 83062306a36Sopenharmony_ci continue; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci rdesc = &rinfo[id].desc; 83362306a36Sopenharmony_ci pmic->rinfo[id] = &rinfo[id]; 83462306a36Sopenharmony_ci pmic->enable_power_mode[id] = MAX77620_POWER_MODE_NORMAL; 83562306a36Sopenharmony_ci pmic->reg_pdata[id].active_fps_src = -1; 83662306a36Sopenharmony_ci pmic->reg_pdata[id].active_fps_pd_slot = -1; 83762306a36Sopenharmony_ci pmic->reg_pdata[id].active_fps_pu_slot = -1; 83862306a36Sopenharmony_ci pmic->reg_pdata[id].suspend_fps_src = -1; 83962306a36Sopenharmony_ci pmic->reg_pdata[id].suspend_fps_pd_slot = -1; 84062306a36Sopenharmony_ci pmic->reg_pdata[id].suspend_fps_pu_slot = -1; 84162306a36Sopenharmony_ci pmic->reg_pdata[id].power_ok = -1; 84262306a36Sopenharmony_ci pmic->reg_pdata[id].ramp_rate_setting = -1; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci ret = max77620_read_slew_rate(pmic, id); 84562306a36Sopenharmony_ci if (ret < 0) 84662306a36Sopenharmony_ci return ret; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci rdev = devm_regulator_register(dev, rdesc, &config); 84962306a36Sopenharmony_ci if (IS_ERR(rdev)) 85062306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(rdev), 85162306a36Sopenharmony_ci "Regulator registration %s failed\n", 85262306a36Sopenharmony_ci rdesc->name); 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci return 0; 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 85962306a36Sopenharmony_cistatic int max77620_regulator_suspend(struct device *dev) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci struct max77620_regulator *pmic = dev_get_drvdata(dev); 86262306a36Sopenharmony_ci struct max77620_regulator_pdata *reg_pdata; 86362306a36Sopenharmony_ci int id; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci for (id = 0; id < MAX77620_NUM_REGS; id++) { 86662306a36Sopenharmony_ci reg_pdata = &pmic->reg_pdata[id]; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci max77620_regulator_set_fps_slots(pmic, id, true); 86962306a36Sopenharmony_ci if (reg_pdata->suspend_fps_src < 0) 87062306a36Sopenharmony_ci continue; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci max77620_regulator_set_fps_src(pmic, reg_pdata->suspend_fps_src, 87362306a36Sopenharmony_ci id); 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci return 0; 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_cistatic int max77620_regulator_resume(struct device *dev) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci struct max77620_regulator *pmic = dev_get_drvdata(dev); 88262306a36Sopenharmony_ci struct max77620_regulator_pdata *reg_pdata; 88362306a36Sopenharmony_ci int id; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci for (id = 0; id < MAX77620_NUM_REGS; id++) { 88662306a36Sopenharmony_ci reg_pdata = &pmic->reg_pdata[id]; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci max77620_config_power_ok(pmic, id); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci max77620_regulator_set_fps_slots(pmic, id, false); 89162306a36Sopenharmony_ci if (reg_pdata->active_fps_src < 0) 89262306a36Sopenharmony_ci continue; 89362306a36Sopenharmony_ci max77620_regulator_set_fps_src(pmic, reg_pdata->active_fps_src, 89462306a36Sopenharmony_ci id); 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci return 0; 89862306a36Sopenharmony_ci} 89962306a36Sopenharmony_ci#endif 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic const struct dev_pm_ops max77620_regulator_pm_ops = { 90262306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(max77620_regulator_suspend, 90362306a36Sopenharmony_ci max77620_regulator_resume) 90462306a36Sopenharmony_ci}; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_cistatic const struct platform_device_id max77620_regulator_devtype[] = { 90762306a36Sopenharmony_ci { .name = "max77620-pmic", }, 90862306a36Sopenharmony_ci { .name = "max20024-pmic", }, 90962306a36Sopenharmony_ci { .name = "max77663-pmic", }, 91062306a36Sopenharmony_ci {}, 91162306a36Sopenharmony_ci}; 91262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, max77620_regulator_devtype); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_cistatic struct platform_driver max77620_regulator_driver = { 91562306a36Sopenharmony_ci .probe = max77620_regulator_probe, 91662306a36Sopenharmony_ci .id_table = max77620_regulator_devtype, 91762306a36Sopenharmony_ci .driver = { 91862306a36Sopenharmony_ci .name = "max77620-pmic", 91962306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 92062306a36Sopenharmony_ci .pm = &max77620_regulator_pm_ops, 92162306a36Sopenharmony_ci }, 92262306a36Sopenharmony_ci}; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_cimodule_platform_driver(max77620_regulator_driver); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ciMODULE_DESCRIPTION("MAX77620/MAX20024 regulator driver"); 92762306a36Sopenharmony_ciMODULE_AUTHOR("Mallikarjun Kasoju <mkasoju@nvidia.com>"); 92862306a36Sopenharmony_ciMODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); 92962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 930