// 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;
bool sd_vsel_fixed_low;
};
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,
};
static unsigned int pca9450_ldo5_get_reg_voltage_sel(struct regulator_dev *rdev)
{
struct pca9450 *pca9450 = rdev_get_drvdata(rdev);
if (pca9450->sd_vsel_fixed_low)
return PCA9450_REG_LDO5CTRL_L;
if (pca9450->sd_vsel_gpio && !gpiod_get_value(pca9450->sd_vsel_gpio))
return PCA9450_REG_LDO5CTRL_L;
return rdev->desc->vsel_reg;
}
static int pca9450_ldo5_get_voltage_sel_regmap(struct regulator_dev *rdev)
{
unsigned int val;
int ret;
ret = regmap_read(rdev->regmap, pca9450_ldo5_get_reg_voltage_sel(rdev), &val);
if (ret != 0)
return ret;
val &= rdev->desc->vsel_mask;
val >>= ffs(rdev->desc->vsel_mask) - 1;
return val;
}
static int pca9450_ldo5_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned int sel)
{
int ret;
sel <<= ffs(rdev->desc->vsel_mask) - 1;
ret = regmap_update_bits(rdev->regmap, pca9450_ldo5_get_reg_voltage_sel(rdev),
rdev->desc->vsel_mask, sel);
if (ret)
return ret;
if (rdev->desc->apply_bit)
ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
rdev->desc->apply_bit,
rdev->desc->apply_bit);
return ret;
}
static const struct regulator_ops pca9450_ldo5_regulator_ops = {
.enable =