android_kernel_oneplus_msm8998/drivers/regulator/max20010-regulator.c

491 lines
13 KiB
C
Raw Permalink Normal View History

/* Copyright (c) 2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/module.h>
#include <linux/param.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/of_device.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/regmap.h>
struct voltage_range {
int vrange_sel;
int min_uV;
int max_uV;
int step_uV;
};
struct max20010_slew_rate {
int slew_sel;
int soft_start;
int dvs;
};
struct max20010_device_info {
struct device *dev;
struct regulator_dev *rdev;
struct regulator_init_data *init_data;
struct regmap *regmap;
const struct voltage_range *range;
const struct max20010_slew_rate *slew_rate;
unsigned vout_sel;
bool enabled;
};
#define MAX20010_ID_REG 0x00
#define MAX20010_VMAX_REG 0x02
#define MAX20010_VMAX_MASK GENMASK(6, 0)
#define MAX20010_CONFIG_REG 0x05
#define MAX20010_CONFIG_SYNC_IO_MASK GENMASK(1, 0)
#define MAX20010_CONFIG_MODE_MASK BIT(3)
#define MAX20010_CONFIG_MODE_SYNC 0
#define MAX20010_CONFIG_MODE_FPWM 8
#define MAX20010_CONFIG_VSTEP_MASK BIT(7)
#define MAX20010_CONFIG_VSTEP_SHIFT 7
#define MAX20010_SLEW_REG 0x06
#define MAX20010_SLEW_MASK GENMASK(3, 0)
#define MAX20010_VSET_REG 0x07
#define MAX20010_VSET_MASK GENMASK(6, 0)
static const struct max20010_slew_rate slew_rates[] = {
{0, 22000, 22000},
{1, 11000, 22000},
{2, 5500, 22000},
{3, 11000, 11000},
{4, 5500, 11000},
{5, 44000, 44000},
{6, 22000, 44000},
{7, 11000, 44000},
{8, 5500, 44000},
{9, 5500, 5500},
};
static const struct voltage_range max20010_range0 = {0, 500000, 1270000, 10000};
static const struct voltage_range max20010_range1 = {1, 625000, 1587500, 12500};
static const struct regmap_config max20010_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = MAX20010_VSET_REG,
};
static int max20010_set_voltage_sel(struct regulator_dev *rdev, unsigned sel)
{
struct max20010_device_info *info = rdev_get_drvdata(rdev);
int rc = 0;
/* Set the voltage only if the regulator was enabled earlier */
if (info->enabled) {
rc = regulator_set_voltage_sel_regmap(rdev, sel);
if (rc) {
dev_err(info->dev,
"regulator set voltage failed for selector = 0x%2x, rc=%d\n",
sel, rc);
return rc;
}
}
info->vout_sel = sel;
return rc;
}
static int max20010_regulator_is_enabled(struct regulator_dev *rdev)
{
struct max20010_device_info *info = rdev_get_drvdata(rdev);
return (info->enabled == true) ? 1 : 0;
}
static int max20010_regulator_enable(struct regulator_dev *rdev)
{
struct max20010_device_info *info = rdev_get_drvdata(rdev);
int rc = 0;
rc = regulator_set_voltage_sel_regmap(rdev, info->vout_sel);
if (rc) {
dev_err(info->dev, "regulator enable failed, rc=%d\n", rc);
return rc;
}
info->enabled = true;
return rc;
}
static int max20010_regulator_disable(struct regulator_dev *rdev)
{
struct max20010_device_info *info = rdev_get_drvdata(rdev);
int rc = 0;
rc = regulator_set_voltage_sel_regmap(rdev, 0x0);
if (rc) {
dev_err(info->dev, "regulator disable failed, rc=%d\n", rc);
return rc;
}
info->enabled = false;
return rc;
}
static inline unsigned int max20010_map_mode(unsigned int mode)
{
return (mode == MAX20010_CONFIG_MODE_FPWM) ?
REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE;
}
static int max20010_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
struct max20010_device_info *info = rdev_get_drvdata(rdev);
int rc = 0;
switch (mode) {
case REGULATOR_MODE_NORMAL:
rc = regmap_update_bits(info->regmap, MAX20010_CONFIG_REG,
MAX20010_CONFIG_MODE_MASK,
MAX20010_CONFIG_MODE_FPWM);
break;
case REGULATOR_MODE_IDLE:
rc = regmap_update_bits(info->regmap, MAX20010_CONFIG_REG,
(MAX20010_CONFIG_MODE_MASK
| MAX20010_CONFIG_SYNC_IO_MASK),
MAX20010_CONFIG_MODE_SYNC);
break;
default:
return -EINVAL;
}
if (rc)
dev_err(info->dev, "failed to set %s mode, rc=%d\n",
mode == REGULATOR_MODE_NORMAL ? "Force PWM" : "SYNC",
rc);
return rc;
}
static unsigned int max20010_get_mode(struct regulator_dev *rdev)
{
struct max20010_device_info *info = rdev_get_drvdata(rdev);
unsigned int val;
int rc = 0;
rc = regmap_read(info->regmap, MAX20010_CONFIG_REG, &val);
if (rc) {
dev_err(info->dev, "failed to read mode configuration, rc=%d\n",
rc);
return rc;
}
return max20010_map_mode(val & MAX20010_CONFIG_MODE_MASK);
}
static int max20010_enable_time(struct regulator_dev *rdev)
{
struct max20010_device_info *info = rdev_get_drvdata(rdev);
int volt_uV;
volt_uV = regulator_list_voltage_linear(rdev, info->vout_sel);
return DIV_ROUND_UP(volt_uV, info->slew_rate->soft_start);
}
static struct regulator_ops max20010_regulator_ops = {
.set_voltage_sel = max20010_set_voltage_sel,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
.map_voltage = regulator_map_voltage_linear,
.list_voltage = regulator_list_voltage_linear,
.is_enabled = max20010_regulator_is_enabled,
.enable = max20010_regulator_enable,
.disable = max20010_regulator_disable,
.set_mode = max20010_set_mode,
.get_mode = max20010_get_mode,
.enable_time = max20010_enable_time,
};
static struct regulator_desc rdesc = {
.name = "max20010-reg",
.supply_name = "vin",
.owner = THIS_MODULE,
.ops = &max20010_regulator_ops,
.type = REGULATOR_VOLTAGE,
.linear_min_sel = 1,
.vsel_reg = MAX20010_VSET_REG,
.vsel_mask = MAX20010_VSET_MASK,
.of_map_mode = max20010_map_mode,
};
static int max20010_device_setup(struct max20010_device_info *info)
{
int max_uV, rc = 0;
unsigned int val;
rc = regmap_update_bits(info->regmap, MAX20010_CONFIG_REG,
MAX20010_CONFIG_VSTEP_MASK,
(info->range->vrange_sel
<< MAX20010_CONFIG_VSTEP_SHIFT));
if (rc) {
dev_err(info->dev, "failed to update vstep configuration, rc=%d\n",
rc);
return rc;
}
max_uV = min(info->init_data->constraints.max_uV, info->range->max_uV);
val = DIV_ROUND_UP(max_uV - info->range->min_uV,
info->range->step_uV) + 1;
rc = regmap_update_bits(info->regmap, MAX20010_VMAX_REG,
MAX20010_VMAX_MASK, val);
if (rc) {
dev_err(info->dev, "failed to write VMAX configuration, rc=%d\n",
rc);
return rc;
}
rc = regmap_update_bits(info->regmap, MAX20010_SLEW_REG,
MAX20010_SLEW_MASK, info->slew_rate->slew_sel);
if (rc) {
dev_err(info->dev, "failed to write slew configuration, rc=%d\n",
rc);
return rc;
}
/* Store default voltage register value */
rc = regmap_read(info->regmap, MAX20010_VSET_REG, &val);
if (rc) {
dev_err(info->dev, "failed to read voltage register, rc=%d\n",
rc);
return rc;
}
info->vout_sel = val & MAX20010_VSET_MASK;
info->enabled = (info->vout_sel != 0x0) ? true : false;
return rc;
}
static int max20010_parse_init_data(struct max20010_device_info *info)
{
struct device_node *of_node = info->dev->of_node;
int i, slew_index, ss_slew_rate, dvs_slew_rate, rc = 0;
unsigned int val;
if (of_find_property(of_node, "maxim,vrange-sel", NULL)) {
rc = of_property_read_u32(of_node, "maxim,vrange-sel", &val);
if (rc) {
dev_err(info->dev, "maxim,vrange-sel property read failed, rc=%d\n",
rc);
return rc;
} else if (val > 1) {
dev_err(info->dev, "unsupported vrange-sel value = %d, should be either 0 or 1\n",
val);
return -EINVAL;
}
} else {
/* Read default voltage range value */
rc = regmap_read(info->regmap, MAX20010_CONFIG_REG, &val);
if (rc) {
dev_err(info->dev, "failed to read config register, rc=%d\n",
rc);
return rc;
}
val = (val & MAX20010_CONFIG_VSTEP_MASK)
>> MAX20010_CONFIG_VSTEP_SHIFT;
}
info->range = (val == 0) ? &max20010_range0 : &max20010_range1;
/*
* Verify the min and max constraints specified through regulator device
* properties are fit with in that of the selected voltage range of the
* device.
*/
if (info->init_data->constraints.min_uV < info->range->min_uV ||
info->init_data->constraints.max_uV > info->range->max_uV) {
dev_err(info->dev,
"Regulator min/max constraints are not fit with in the device min/max constraints\n");
return -EINVAL;
}
/*
* Read soft-start and dvs slew rates from device node. Use default
* values if not specified.
*
* Read the register default values and modify them with the slew-rates
* defined through device node.
*/
rc = regmap_read(info->regmap, MAX20010_SLEW_REG, &val);
if (rc) {
dev_err(info->dev, "failed to read slew register, rc=%d\n",
rc);
return rc;
}
slew_index = val & MAX20010_SLEW_MASK;
if (slew_index >= ARRAY_SIZE(slew_rates)) {
dev_err(info->dev, "unsupported default slew configuration\n");
return -EINVAL;
}
ss_slew_rate = slew_rates[slew_index].soft_start;
dvs_slew_rate = slew_rates[slew_index].dvs;
if (of_find_property(of_node, "maxim,soft-start-slew-rate", NULL)) {
rc = of_property_read_u32(of_node, "maxim,soft-start-slew-rate",
&val);
if (rc) {
dev_err(info->dev, "maxim,soft-start-slew-rate read failed, rc=%d\n",
rc);
return rc;
}
ss_slew_rate = val;
}
if (of_find_property(of_node, "maxim,dvs-slew-rate", NULL)) {
rc = of_property_read_u32(of_node, "maxim,dvs-slew-rate",
&val);
if (rc) {
dev_err(info->dev, "maxim,dvs-slew-rate read failed, rc=%d\n",
rc);
return rc;
}
dvs_slew_rate = val;
}
for (i = 0; i < ARRAY_SIZE(slew_rates); i++) {
if (ss_slew_rate == slew_rates[i].soft_start
&& dvs_slew_rate == slew_rates[i].dvs) {
info->slew_rate = &slew_rates[i];
break;
}
}
if (i == ARRAY_SIZE(slew_rates)) {
dev_err(info->dev, "invalid slew-rate values are specified.\n");
return -EINVAL;
}
return rc;
}
static int max20010_regulator_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max20010_device_info *info;
struct regulator_config config = { };
int val, rc = 0;
info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
info->dev = &client->dev;
info->init_data = of_get_regulator_init_data(info->dev,
info->dev->of_node, &rdesc);
if (!info->init_data) {
dev_err(info->dev, "regulator init_data is missing\n");
return -ENODEV;
}
info->init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_MODE;
info->init_data->constraints.valid_modes_mask
= REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE;
info->regmap = devm_regmap_init_i2c(client, &max20010_regmap_config);
if (IS_ERR(info->regmap)) {
dev_err(info->dev, "Error in allocating regmap\n");
return PTR_ERR(info->regmap);
}
i2c_set_clientdata(client, info);
/* Get chip Id */
rc = regmap_read(info->regmap, MAX20010_ID_REG, &val);
if (rc) {
dev_err(info->dev, "Failed to get chip ID!\n");
return rc;
}
rc = max20010_parse_init_data(info);
if (rc) {
dev_err(info->dev, "max20010 init data parsing failed, rc=%d\n",
rc);
return rc;
}
rc = max20010_device_setup(info);
if (rc) {
dev_err(info->dev, "Failed to setup device, rc=%d\n",
rc);
return rc;
}
config.dev = info->dev;
config.init_data = info->init_data;
config.regmap = info->regmap;
config.driver_data = info;
config.of_node = client->dev.of_node;
rdesc.min_uV = info->range->min_uV;
rdesc.uV_step = info->range->step_uV;
rdesc.n_voltages = DIV_ROUND_UP((info->range->max_uV
- info->range->min_uV),
info->range->step_uV);
rdesc.ramp_delay = info->slew_rate->dvs;
info->rdev = devm_regulator_register(info->dev, &rdesc, &config);
if (IS_ERR(info->rdev)) {
dev_err(info->dev, "Failed to register regulator, rc=%d\n", rc);
return PTR_ERR(info->rdev);
}
dev_info(info->dev, "Detected regulator MAX20010 PID = %d : voltage-range(%d) : (%d - %d) uV, step = %d uV\n",
val, info->range->vrange_sel, info->range->min_uV,
info->range->max_uV, info->range->step_uV);
return rc;
}
static const struct of_device_id max20010_match_table[] = {
{.compatible = "maxim,max20010", },
{ },
};
MODULE_DEVICE_TABLE(of, max20010_match_table);
static const struct i2c_device_id max20010_id[] = {
{"max20010", -1},
{ },
};
MODULE_DEVICE_TABLE(i2c, max20010_id);
static struct i2c_driver max20010_regulator_driver = {
.driver = {
.name = "max20010-regulator",
.owner = THIS_MODULE,
.of_match_table = max20010_match_table,
},
.probe = max20010_regulator_probe,
.id_table = max20010_id,
};
module_i2c_driver(max20010_regulator_driver);
MODULE_DESCRIPTION("MAX20010 regulator driver");
MODULE_LICENSE("GPL v2");