// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2020 NXP.
* NXP PCA9450 pmic driver
*/
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/pca9450.h>
struct pc9450_dvs_config {
unsigned int run_reg; /* dvs0 */
unsigned int run_mask;
unsigned int standby_reg; /* dvs1 */
unsigned int standby_mask;
};
struct pca9450_regulator_desc {
struct regulator_desc desc;
const struct pc9450_dvs_config dvs;
};
struct pca9450 {
struct device *dev;
struct regmap *regmap;
struct gpio_desc *sd_vsel_gpio;
enum pca9450_chip_type type;
unsigned int rcnt;
int irq;
};
static const struct regmap_range pca9450_status_range = {
.range_min = PCA9450_REG_INT1,
.range_max = PCA9450_REG_PWRON_STAT,
};
static const struct regmap_access_table pca9450_volatile_regs = {
.yes_ranges = &pca9450_status_range,
.n_yes_ranges = 1,
};
static const struct regmap_config pca9450_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_table = &pca9450_volatile_regs,
.max_register = PCA9450_MAX_REGISTER - 1,
.cache_type = REGCACHE_MAPLE,
};
/*
* BUCK1/2/3
* BUCK1RAM[1:0] BUCK1 DVS ramp rate setting
* 00: 25mV/1usec
* 01: 25mV/2usec
* 10: 25mV/4usec
* 11: 25mV/8usec
*/
static const unsigned int pca9450_dvs_buck_ramp_table[] = {
25000, 12500, 6250, 3125
};
static const struct regulator_ops pca9450_dvs_buck_regulator_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear_range,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_ramp_delay = regulator_set_ramp_delay_regmap,
};
static const struct regulator_ops pca9450_buck_regulator_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear_range,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
};
static const struct regulator_ops pca9450_ldo_regulator_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear_range,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
};
/*
* BUCK1/2/3
* 0.60 to 2.1875V (12.5mV step)
*/
static const struct linear_range pca9450_dvs_buck_volts[] = {
REGULATOR_LINEAR_RANGE(600000, 0x00, 0x7F, 12500),
};
/*
* BUCK1/3
* 0.65 to 2.2375V (12.5mV step)
*/
static const struct linear_range pca9451a_dvs_buck_volts[] = {
REGULATOR_LINEAR_RANGE(650000, 0x00, 0x7F, 12500),
};
/*
* BUCK4/5/6
* 0.6V to 3.4V (25mV step)
*/
static const struct linear_range pca9450_buck_volts[] = {
REGULATOR_LINEAR_RANGE(600000, 0x00, 0x70, 25000),
REGULATOR_LINEAR_RANGE(3400000, 0x71, 0x7F, 0),
};
/*
* LDO1
* 1.6 to 3.3V ()
*/
static const struct linear_range pca9450_ldo1_volts[] = {
REGULATOR_LINEAR_RANGE(1600000, 0x00, 0x03, 100000),
REGULATOR_LINEAR_RANGE(3000000, 0x04, 0x07, 100000),
};
/*
* LDO2
* 0.8 to 1.15V (50mV step)
*/
static const struct linear_range pca9450_ldo2_volts[] = {
REGULATOR_LINEAR_RANGE(800000, 0x00, 0x07, 50000),
};
/*
* LDO3/4
* 0.8 to 3.3V (100mV step)
*/
static const struct linear_range pca9450_ldo34_volts[] = {
REGULATOR_LINEAR_RANGE(800000, 0x00, 0x19, 100000),
REGULATOR_LINEAR_RANGE(3300000, 0x1A, 0x1F, 0),
};
/*
* LDO5
* 1.8 to 3.3V (100mV step)
*/
static const struct linear_range pca9450_ldo5_volts[] = {
REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
};
static int buck_set_dvs(const struct regulator_desc *desc,
struct device_node *np, struct regmap *regmap,
char *prop, unsigned int reg, unsigned int mask)
{
int ret, i;
uint32_t uv;
ret = of_property_read_u32(np, prop, &uv);
if (ret == -EINVAL)
return 0;
else if (ret)
return ret;
for (i = 0; i < desc->n_voltages; i++) {
ret = regulator_desc_list_voltage_linear_range(desc, i);
if (ret < 0)
continue;
if (ret == uv) {
i <<= ffs(desc->vsel_mask) - 1;
ret = regmap_update_bits(regmap, reg, mask, i);
break;
}
}
if (ret == 0) {
struct pca9450_regulator_desc *regulator = containe