// SPDX-License-Identifier: GPL-2.0-only
/*
* Maxim MAX77620 Regulator driver
*
* Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved.
*
* Author: Mallikarjun Kasoju <mkasoju@nvidia.com>
* Laxman Dewangan <ldewangan@nvidia.com>
*/
#include <linux/init.h>
#include <linux/mfd/max77620.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#define max77620_rails(_name) "max77620-"#_name
/* Power Mode */
#define MAX77620_POWER_MODE_NORMAL 3
#define MAX77620_POWER_MODE_LPM 2
#define MAX77620_POWER_MODE_GLPM 1
#define MAX77620_POWER_MODE_DISABLE 0
/* SD Slew Rate */
#define MAX77620_SD_SR_13_75 0
#define MAX77620_SD_SR_27_5 1
#define MAX77620_SD_SR_55 2
#define MAX77620_SD_SR_100 3
enum max77620_regulators {
MAX77620_REGULATOR_ID_SD0,
MAX77620_REGULATOR_ID_SD1,
MAX77620_REGULATOR_ID_SD2,
MAX77620_REGULATOR_ID_SD3,
MAX77620_REGULATOR_ID_SD4,
MAX77620_REGULATOR_ID_LDO0,
MAX77620_REGULATOR_ID_LDO1,
MAX77620_REGULATOR_ID_LDO2,
MAX77620_REGULATOR_ID_LDO3,
MAX77620_REGULATOR_ID_LDO4,
MAX77620_REGULATOR_ID_LDO5,
MAX77620_REGULATOR_ID_LDO6,
MAX77620_REGULATOR_ID_LDO7,
MAX77620_REGULATOR_ID_LDO8,
MAX77620_NUM_REGS,
};
/* Regulator types */
enum max77620_regulator_type {
MAX77620_REGULATOR_TYPE_SD,
MAX77620_REGULATOR_TYPE_LDO_N,
MAX77620_REGULATOR_TYPE_LDO_P,
};
struct max77620_regulator_info {
u8 type;
u8 fps_addr;
u8 volt_addr;
u8 cfg_addr;
u8 power_mode_mask;
u8 power_mode_shift;
u8 remote_sense_addr;
u8 remote_sense_mask;
struct regulator_desc desc;
};
struct max77620_regulator_pdata {
int active_fps_src;
int active_fps_pd_slot;
int active_fps_pu_slot;
int suspend_fps_src;
int suspend_fps_pd_slot;
int suspend_fps_pu_slot;
int current_mode;
int power_ok;
int ramp_rate_setting;
};
struct max77620_regulator {
struct device *dev;
struct regmap *rmap;
struct max77620_regulator_info *rinfo[MAX77620_NUM_REGS];
struct max77620_regulator_pdata reg_pdata[MAX77620_NUM_REGS];
int enable_power_mode[MAX77620_NUM_REGS];
int current_power_mode[MAX77620_NUM_REGS];
int active_fps_src[MAX77620_NUM_REGS];
};
#define fps_src_name(fps_src) \
(fps_src == MAX77620_FPS_SRC_0 ? "FPS_SRC_0" : \
fps_src == MAX77620_FPS_SRC_1 ? "FPS_SRC_1" : \
fps_src == MAX77620_FPS_SRC_2 ? "FPS_SRC_2" : "FPS_SRC_NONE")
static int max77620_regulator_get_fps_src(struct max77620_regulator *pmic,
int id)
{
struct max77620_regulator_info *rinfo = pmic->rinfo[id];
unsigned int val;
int ret;
ret = regmap_read(pmic->rmap, rinfo->fps_addr, &val);
if (ret < 0) {
dev_err(pmic->dev, "Reg 0x%02x read failed %d\n",
rinfo->fps_addr, ret);
return ret;
}
return (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT;
}
static int max77620_regulator_set_fps_src(struct max77620_regulator *pmic,
int fps_src, int id)
{
struct max77620_regulator_info *rinfo = pmic->rinfo[id];
unsigned int val;
int ret;
if (!rinfo)
return 0;
switch (fps_src) {
case MAX77620_FPS_SRC_0:
case MAX77620_FPS_SRC_1:
case MAX77620_FPS_SRC_2:
case MAX77620_FPS_SRC_NONE:
break;
case MAX77620_FPS_SRC_DEF:
ret = regmap_read(pmic->rmap, rinfo->fps_addr, &val);
if (ret < 0) {
dev_err(pmic->dev, "Reg 0x%02x read failed %d\n",
rinfo->fps_addr, ret);
return ret;
}
ret = (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT;
pmic->active_fps_src[id] = ret;
return 0;
default:
dev_err(pmic->dev, "Invalid FPS %d for regulator %d\n",
fps_src, id);
return -EINVAL;
}
ret = regmap_update_bits(pmic->rmap, rinfo->fps_addr,
MAX77620_FPS_SRC_MASK,
fps_src << MAX77620_FPS_SRC_SHIFT);
if (ret < 0) {
dev_err(pmic->dev, "Reg 0x%02x update failed %d\n",
rinfo->fps_addr, ret);
return ret;
}
pmic->active_fps_src[id] = fps_src;
return 0;
}
static int max77620_regulator_set_fps_slots(struct max77620_regulator *pmic,
int id, bool is_suspend)
{
struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id];
struct max77620_regulator_info *rinfo = pmic->rinfo[id];
unsigned int val = 0;
unsigned int mask = 0;
int pu = rpdata->active_fps_pu_slot;
int pd = rpdata->active_fps_pd_slot;
int ret = 0;
if (!rinfo)
return 0;
if (is_suspend) {
pu = rpdata->suspend_fps_pu_slot;
pd = rpdata->suspend_fps_pd_slot;
}
/* FPS power up period setting */
if (pu >= 0) {
val |= (pu << MAX77620_FPS_PU_PERIOD_SHIFT);
mask |= MAX77620_FPS_PU_PERIO