blob: b8728c6e6a599233e7f4032739647f499069a8c0 [file] [log] [blame]
/*
* Regulators driver for ASR PM813
*
* Copyright 2021 ASR Microelectronics (Shanghai) Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/mfd/88pm80x.h>
#include <linux/mfd/pm813.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/cputype.h>
#include <linux/regulator/of_regulator.h>
/* LDO1 with DVC[0..3] */
#define PM813_LDO1_VOUT (0x71) /* VOUT1 */
#define PM813_LDO2_VOUT (0x74)
#define PM813_LDO3_VOUT (0x77)
#define PM813_LDO4_VOUT (0x7A)
#define PM813_LDO5_VOUT (0x7D)
#define PM813_LDO6_VOUT (0x80)
#define PM813_LDO7_VOUT (0x83)
#define PM813_LDO8_VOUT (0x86)
#define PM813_LDO9_VOUT (0x89)
#define PM813_LDO10_VOUT (0x8C)
#define PM813_LDO11_VOUT (0x8F)
#define PM813_LDO12_VOUT (0x92)
#define PM813_LDO13_VOUT (0x95)
/* BUCK1 with DVC[0..3] */
#define PM813_BUCK1 (0x2A)
#define PM813_BUCK2 (0x30)
#define PM813_BUCK3 (0x40)
#define PM813_BUCK1_ENA (0x20)
#define PM813_BUCK2_ENA (0x30)
#define PM813_BUCK3_ENA (0x40)
#define PM813_LDO1_ENA (0x71) /* VOUT1 */
#define PM813_LDO2_ENA (0x74)
#define PM813_LDO3_ENA (0x77)
#define PM813_LDO4_ENA (0x7A)
#define PM813_LDO5_ENA (0x7D)
#define PM813_LDO6_ENA (0x80)
#define PM813_LDO7_ENA (0x83)
#define PM813_LDO8_ENA (0x86)
#define PM813_LDO9_ENA (0x89)
#define PM813_LDO10_ENA (0x8C)
#define PM813_LDO11_ENA (0x8F)
#define PM813_LDO12_ENA (0x92)
#define PM813_LDO13_ENA (0x95)
#define MAX_SLEEP_CURRENT 5000
#define REGULATOR_SLEEP_MODE_DIS 0
#define REGULATOR_SLEEP_MODE_EN 1
/*
* Convert voltage value to reg value for BUCK1
*/
#define BUCK1_VOL2REG(vol) \
(((vol) > 1587500) \
? ((((vol)-1600000)/50000) + 0x50) \
: (((vol)-600000)/12500))
#define BUCK1_REG2VOL(reg) \
(((reg) < 0x50) \
? (reg * 12500 + 600000) \
: ((reg - 0x50) * 50000 + 1600000))
struct pm813_regulator_volt_range {
int min_uv;
int max_uv;
int step_uv;
/* the register value for min_uv */
int min_val;
};
struct pm813_regulator_info {
struct regulator_desc desc;;
int max_ua;
unsigned int sleep_enable_bit;
unsigned int sleep_enable_reg;
struct pm813_regulator_volt_range *volt;
unsigned int ranges;
};
struct pm813_regulators {
struct regulator_dev *regulators[PM813_ID_RG_MAX];
struct pm80x_chip *chip;
struct regmap *map;
};
/*
* vreg - the buck regs string.
* ereg - the string for the enable register.
* ebit - the bit number in the enable register.
* amax - the current
* Buck has 2 kinds of voltage steps. It is easy to find voltage by ranges,
* not the constant voltage table.
*/
#define PM813_BUCK(vreg, ereg, ebit, amax, sebit, sereg, volt_ranges) \
{ \
.desc = { \
.name = #vreg, \
.ops = &pm813_volt_range_ops, \
.type = REGULATOR_VOLTAGE, \
.id = PM813_ID_##vreg, \
.owner = THIS_MODULE, \
.vsel_reg = PM813_##vreg, \
.vsel_mask = 0x7f, \
.enable_reg = PM813_##ereg, \
.enable_mask = 1 << (ebit), \
}, \
.max_ua = (amax), \
.volt = (volt_ranges), \
.ranges = ARRAY_SIZE(volt_ranges), \
.sleep_enable_bit = sebit, \
.sleep_enable_reg = PM813_##sereg, \
}
/*
* vreg - the LDO regs string
* ereg - the string for the enable register.
* ebit - the bit number in the enable register.
* amax - the current
* volt_table - the LDO voltage table
* For all the LDOes, there are too many ranges. Using volt_table will be
* simpler and faster.
*/
#define PM813_LDO(vreg, ereg, ebit, amax, sebit, sereg, ldo_volt_table) \
{ \
.desc = { \
.name = #vreg, \
.ops = &pm813_volt_table_ops, \
.type = REGULATOR_VOLTAGE, \
.id = PM813_ID_##vreg, \
.owner = THIS_MODULE, \
.n_voltages = ARRAY_SIZE(ldo_volt_table), \
.vsel_reg = PM813_##vreg##_VOUT, \
.vsel_mask = 0x3c, \
.enable_reg = PM813_##ereg, \
.enable_mask = 1 << (ebit), \
.volt_table = ldo_volt_table, \
}, \
.max_ua = (amax), \
.sleep_enable_bit = sebit, \
.sleep_enable_reg = PM813_##sereg, \
}
/* Ranges are sorted in ascending order. */
static struct pm813_regulator_volt_range buck1_5_volt_range[] = {
{600000, 1587500, 12500, 0x0},
{1600000, 3950000, 50000, 0x50},
};
/* LDO 1~6 have same voltage table. */
static const unsigned int ldo1_4_volt_table[] = {
1200000, 1250000, 1700000, 1800000, 1850000, 1900000, 2500000, 2600000,
2700000, 2750000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000,
};
static const unsigned int ldo5_6_volt_table[] = {
1700000, 1800000, 1900000, 2500000, 2800000, 2900000, 3100000, 3300000,
};
static const unsigned int pm813s_ldo_volt_table[] = {
1200000, 1250000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000,
1900000, 2750000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000,
};
int pm813_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
struct pm813_regulator_info *info = rdev_get_drvdata(rdev);
unsigned int val, sleep_bit, sleep_enable_mask, reg;
sleep_bit = info->sleep_enable_bit;
sleep_enable_mask = (0x3 << sleep_bit);
/*
* if mode is REGULATOR_SLEEP_MODE_EN, enable related LDO sleep mode
* else disable related LDO sleep mode.
*/
switch (mode) {
case REGULATOR_MODE_IDLE:
val = (0x2 << sleep_bit);
break;
case REGULATOR_MODE_NORMAL:
val = (0x3 << sleep_bit);
break;
default:
dev_err(rdev_get_dev(rdev), "No right mode to set!\n");
return -EINVAL;
}
reg = info->sleep_enable_reg;
return regmap_update_bits(rdev->regmap, reg, sleep_enable_mask, val);
}
static unsigned int pm813_get_optimum_mode(struct regulator_dev *rdev,
int input_uV, int output_uV,
int output_uA)
{
struct pm813_regulator_info *info = rdev_get_drvdata(rdev);
if (info == NULL) {
dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
return REGULATOR_MODE_IDLE;
}
if (output_uA < 0) {
dev_err(rdev_get_dev(rdev), "wrong current input, current < 0!!!\n");
return REGULATOR_MODE_IDLE;
}
/*
* get_optimum_mode be called at enbale/disable_regulator function.
* If output_uA is not set it will be 0,
* set its defult value to be REGULATOR_MODE_IDLE.
*/
return (MAX_SLEEP_CURRENT > output_uA) ? REGULATOR_MODE_IDLE :
REGULATOR_MODE_NORMAL;
}
static int pm813_get_current_limit(struct regulator_dev *rdev)
{
struct pm813_regulator_info *info = rdev_get_drvdata(rdev);
return info->max_ua;
}
static int pm813_set_voltage(struct regulator_dev *rdev,
int min_uv, int max_uv, unsigned *selector)
{
struct pm813_regulator_info *info = rdev_get_drvdata(rdev);
struct pm813_regulator_volt_range *range;
int i, best_index = -1;
if (info->volt == NULL)
return -EINVAL;
/*
* Ranges are sorted in ascending order. So if we found a best_uv
* in this range, we can break out.
*/
for (i = 0; i < info->ranges; i++) {
range = &info->volt[i];
if (min_uv <= range->max_uv && max_uv >= range->min_uv) {
if (min_uv <= range->min_uv)
best_index = 0;
else
best_index = (min_uv - range->min_uv +
range->step_uv - 1) / range->step_uv;
break;
}
}
if (best_index == -1)
return -EINVAL;
*selector = best_index + range->min_val;
return regulator_set_voltage_sel_regmap(rdev, *selector);
}
static int pm813_get_voltage(struct regulator_dev *rdev)
{
struct pm813_regulator_info *info = rdev_get_drvdata(rdev);
struct pm813_regulator_volt_range *range;
int i, val, max_val, volt = -EINVAL;
if (info->volt == NULL)
return -EINVAL;
val = regulator_get_voltage_sel_regmap(rdev);
if (val < 0)
return val;
/* get the voltage via the register value */
for (i = 0; i < info->ranges; i++) {
range = &info->volt[i];
max_val = (range->max_uv - range->min_uv) / range->step_uv
+ range->min_val;
if (val >= range->min_val && val <= max_val) {
volt = (val - range->min_val) * range->step_uv
+ range->min_uv;
break;
}
}
return volt;
}
static struct regulator_ops pm813_volt_range_ops = {
.set_voltage = pm813_set_voltage,
.get_voltage = pm813_get_voltage,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.get_current_limit = pm813_get_current_limit,
.get_optimum_mode = pm813_get_optimum_mode,
.set_mode = pm813_set_mode,
};
static struct regulator_ops pm813_volt_table_ops = {
.list_voltage = regulator_list_voltage_table,
.map_voltage = regulator_map_voltage_iterate,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.get_current_limit = pm813_get_current_limit,
.get_optimum_mode = pm813_get_optimum_mode,
.set_mode = pm813_set_mode,
};
/* The array is indexed by id(PM813_ID_XXX) */
static struct pm813_regulator_info pm813_regulator_info[] = {
PM813_BUCK(BUCK1, BUCK1_ENA, 7, 1600000, 3, BUCK_SLP1,
buck1_5_volt_range),
PM813_BUCK(BUCK2, BUCK2_ENA, 7, 800000, 3, BUCK_SLP2,
buck1_5_volt_range),
PM813_BUCK(BUCK3, BUCK3_ENA, 7, 800000, 3, BUCK_SLP3,
buck1_5_volt_range),
PM813_LDO(LDO1, LDO1_ENA, 6, 200000, 4, LDO_SLP1,
ldo1_4_volt_table),
PM813_LDO(LDO2, LDO2_ENA, 6, 200000, 4, LDO_SLP2,
ldo1_4_volt_table),
PM813_LDO(LDO3, LDO3_ENA, 6, 200000, 4, LDO_SLP3,
ldo1_4_volt_table),
PM813_LDO(LDO4, LDO4_ENA, 6, 200000, 4, LDO_SLP4,
ldo1_4_volt_table),
PM813_LDO(LDO5, LDO5_ENA, 6, 400000, 4, LDO_SLP5,
ldo5_6_volt_table),
PM813_LDO(LDO6, LDO6_ENA, 6, 200000, 4, LDO_SLP6,
ldo1_4_volt_table),
PM813_LDO(LDO7, LDO7_ENA, 6, 200000, 4, LDO_SLP7,
ldo1_4_volt_table),
PM813_LDO(LDO8, LDO8_ENA, 6, 200000, 4, LDO_SLP8,
ldo1_4_volt_table),
PM813_LDO(LDO9, LDO9_ENA, 6, 200000, 4, LDO_SLP9,
ldo1_4_volt_table),
PM813_LDO(LDO10, LDO10_ENA, 6, 200000, 4, LDO_SLP10,
ldo1_4_volt_table),
PM813_LDO(LDO11, LDO11_ENA, 6, 200000, 4, LDO_SLP11,
ldo1_4_volt_table),
PM813_LDO(LDO12, LDO12_ENA, 6, 200000, 4, LDO_SLP12,
ldo1_4_volt_table),
PM813_LDO(LDO13, LDO13_ENA, 6, 400000, 4, LDO_SLP13,
ldo5_6_volt_table),
};
#define PM813_REGULATOR_OF_MATCH(id) \
{ \
.name = "PM813-" #id, \
.driver_data = &pm813_regulator_info[PM813_ID_##id], \
}
static struct of_regulator_match pm813_regulator_matches[] = {
PM813_REGULATOR_OF_MATCH(BUCK1),
PM813_REGULATOR_OF_MATCH(BUCK2),
PM813_REGULATOR_OF_MATCH(BUCK3),
PM813_REGULATOR_OF_MATCH(LDO1),
PM813_REGULATOR_OF_MATCH(LDO2),
/* PM813_REGULATOR_OF_MATCH(LDO3), */
PM813_REGULATOR_OF_MATCH(LDO4),
PM813_REGULATOR_OF_MATCH(LDO5),
PM813_REGULATOR_OF_MATCH(LDO6),
PM813_REGULATOR_OF_MATCH(LDO7),
/* PM813_REGULATOR_OF_MATCH(LDO8), */
PM813_REGULATOR_OF_MATCH(LDO9),
PM813_REGULATOR_OF_MATCH(LDO10),
PM813_REGULATOR_OF_MATCH(LDO11),
PM813_REGULATOR_OF_MATCH(LDO12),
PM813_REGULATOR_OF_MATCH(LDO13),
};
static struct of_regulator_match pm813_regulator_matches_1906[] = {
PM813_REGULATOR_OF_MATCH(BUCK1),
PM813_REGULATOR_OF_MATCH(BUCK2),
PM813_REGULATOR_OF_MATCH(BUCK3),
PM813_REGULATOR_OF_MATCH(LDO1),
PM813_REGULATOR_OF_MATCH(LDO2),
/* PM813_REGULATOR_OF_MATCH(LDO3), */
PM813_REGULATOR_OF_MATCH(LDO4),
PM813_REGULATOR_OF_MATCH(LDO5),
PM813_REGULATOR_OF_MATCH(LDO6),
PM813_REGULATOR_OF_MATCH(LDO7),
PM813_REGULATOR_OF_MATCH(LDO8),
PM813_REGULATOR_OF_MATCH(LDO9),
PM813_REGULATOR_OF_MATCH(LDO10),
PM813_REGULATOR_OF_MATCH(LDO11),
PM813_REGULATOR_OF_MATCH(LDO12),
PM813_REGULATOR_OF_MATCH(LDO13),
};
static int pm813_regulator_dt_init(struct platform_device *pdev,
struct of_regulator_match **regulator_matches, int *range)
{
struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct device_node *np = pdev->dev.of_node;
if (chip->type == CHIP_PM813) {
if (cpu_is_asr1906()) {
*regulator_matches = pm813_regulator_matches_1906;
*range = ARRAY_SIZE(pm813_regulator_matches_1906);
}
else {
*regulator_matches = pm813_regulator_matches;
*range = ARRAY_SIZE(pm813_regulator_matches);
}
} else
return -ENODEV;
return of_regulator_match(&pdev->dev, np, *regulator_matches, *range);
}
static int pm813_regulator_probe(struct platform_device *pdev)
{
struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct pm80x_platform_data *pdata = pdev->dev.parent->platform_data;
struct pm813_regulators *pm813_data;
struct pm813_regulator_info *info;
struct regulator_config config = { };
struct regulator_init_data *init_data;
int i, ret, range = 0;
struct of_regulator_match *regulator_matches = NULL;
if (!pdata || pdata->num_regulators == 0) {
if (IS_ENABLED(CONFIG_OF)) {
ret = pm813_regulator_dt_init(pdev, &regulator_matches,
&range);
if (ret < 0)
return ret;
} else {
return -ENODEV;
}
} else if (pdata->num_regulators) {
/* Check whether num_regulator is valid. */
unsigned int count = 0;
for (i = 0; pdata->regulators[i]; i++)
count++;
if (count != pdata->num_regulators)
return -EINVAL;
} else {
return -EINVAL;
}
pm813_data = devm_kzalloc(&pdev->dev, sizeof(*pm813_data),
GFP_KERNEL);
if (!pm813_data) {
dev_err(&pdev->dev, "Failed to allocate PM813_regualtors");
return -ENOMEM;
}
pm813_data->map = chip->subchip->regmap_power;
pm813_data->chip = chip;
platform_set_drvdata(pdev, pm813_data);
for (i = 0; i < range; i++) {
if (!pdata || pdata->num_regulators == 0)
init_data = regulator_matches->init_data;
else
init_data = pdata->regulators[i];
if (!init_data) {
dev_err(&pdev->dev, "%s not matched!\n",
regulator_matches->name);
regulator_matches++;
continue;
}
info = regulator_matches->driver_data;
config.dev = &pdev->dev;
config.init_data = init_data;
config.driver_data = info;
config.regmap = pm813_data->map;
config.of_node = regulator_matches->of_node;
pm813_data->regulators[i] =
regulator_register(&info->desc, &config);
if (IS_ERR(pm813_data->regulators[i])) {
ret = PTR_ERR(pm813_data->regulators[i]);
dev_err(&pdev->dev, "Failed to register %s\n",
info->desc.name);
while (--i >= 0 && pm813_data->regulators[i])
regulator_unregister(pm813_data->regulators[i]);
return ret;
}
pm813_data->regulators[i]->constraints->valid_ops_mask |=
(REGULATOR_CHANGE_DRMS | REGULATOR_CHANGE_MODE);
pm813_data->regulators[i]->constraints->valid_modes_mask |=
(REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE);
pm813_data->regulators[i]->constraints->input_uV = 1000;
regulator_matches++;
}
return 0;
}
static int pm813_regulator_remove(struct platform_device *pdev)
{
struct pm813_regulators *pm813_data = platform_get_drvdata(pdev);
int i;
for (i = 0; pm813_data->regulators[i] && i < PM813_ID_RG_MAX; i++)
regulator_unregister(pm813_data->regulators[i]);
return 0;
}
static struct platform_driver pm813_regulator_driver = {
.driver = {
.name = "pm813-regulator",
.owner = THIS_MODULE,
},
.probe = pm813_regulator_probe,
.remove = pm813_regulator_remove,
};
static int __init pm813_regulator_init(void)
{
return platform_driver_register(&pm813_regulator_driver);
}
subsys_initcall(pm813_regulator_init);
static void __exit pm813_regulator_exit(void)
{
platform_driver_unregister(&pm813_regulator_driver);
}
module_exit(pm813_regulator_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Regulator Driver for ASR PM813 PMIC");
MODULE_ALIAS("platform:PM813-regulator");