mirror of https://github.com/torvalds/linux.git
regulator: pca9450: Fix control register for LDO5
For LDO5 we need to be able to check the status of the SD_VSEL input in order to know which control register is used. Read the status of the SD_VSEL signal via GPIO and use the correct register accordingly. To use this, the LDO5 node in the devicetree needs the sd-vsel-gpios property to reference the GPIO that is used to read back the SD_VSEL status internally. Please note that the SION bit in the IOMUX must be set if the signal is muxed as VSELECT and controlled by the USDHC controller. Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de> Link: https://patch.msgid.link/20241218152842.97483-5-frieder@fris.de Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
c73be62caa
commit
3ce6f4f943
|
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
|
@ -31,6 +32,7 @@ struct pca9450_regulator_desc {
|
||||||
struct pca9450 {
|
struct pca9450 {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
|
struct gpio_desc *sd_vsel_gpio;
|
||||||
enum pca9450_chip_type type;
|
enum pca9450_chip_type type;
|
||||||
unsigned int rcnt;
|
unsigned int rcnt;
|
||||||
int irq;
|
int irq;
|
||||||
|
|
@ -96,6 +98,58 @@ static const struct regulator_ops pca9450_ldo_regulator_ops = {
|
||||||
.get_voltage_sel = regulator_get_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_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 = regulator_enable_regmap,
|
||||||
|
.disable = regulator_disable_regmap,
|
||||||
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
.list_voltage = regulator_list_voltage_linear_range,
|
||||||
|
.set_voltage_sel = pca9450_ldo5_set_voltage_sel_regmap,
|
||||||
|
.get_voltage_sel = pca9450_ldo5_get_voltage_sel_regmap,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BUCK1/2/3
|
* BUCK1/2/3
|
||||||
* 0.60 to 2.1875V (12.5mV step)
|
* 0.60 to 2.1875V (12.5mV step)
|
||||||
|
|
@ -451,7 +505,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
|
||||||
.of_match = of_match_ptr("LDO5"),
|
.of_match = of_match_ptr("LDO5"),
|
||||||
.regulators_node = of_match_ptr("regulators"),
|
.regulators_node = of_match_ptr("regulators"),
|
||||||
.id = PCA9450_LDO5,
|
.id = PCA9450_LDO5,
|
||||||
.ops = &pca9450_ldo_regulator_ops,
|
.ops = &pca9450_ldo5_regulator_ops,
|
||||||
.type = REGULATOR_VOLTAGE,
|
.type = REGULATOR_VOLTAGE,
|
||||||
.n_voltages = PCA9450_LDO5_VOLTAGE_NUM,
|
.n_voltages = PCA9450_LDO5_VOLTAGE_NUM,
|
||||||
.linear_ranges = pca9450_ldo5_volts,
|
.linear_ranges = pca9450_ldo5_volts,
|
||||||
|
|
@ -665,7 +719,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
|
||||||
.of_match = of_match_ptr("LDO5"),
|
.of_match = of_match_ptr("LDO5"),
|
||||||
.regulators_node = of_match_ptr("regulators"),
|
.regulators_node = of_match_ptr("regulators"),
|
||||||
.id = PCA9450_LDO5,
|
.id = PCA9450_LDO5,
|
||||||
.ops = &pca9450_ldo_regulator_ops,
|
.ops = &pca9450_ldo5_regulator_ops,
|
||||||
.type = REGULATOR_VOLTAGE,
|
.type = REGULATOR_VOLTAGE,
|
||||||
.n_voltages = PCA9450_LDO5_VOLTAGE_NUM,
|
.n_voltages = PCA9450_LDO5_VOLTAGE_NUM,
|
||||||
.linear_ranges = pca9450_ldo5_volts,
|
.linear_ranges = pca9450_ldo5_volts,
|
||||||
|
|
@ -855,7 +909,7 @@ static const struct pca9450_regulator_desc pca9451a_regulators[] = {
|
||||||
.of_match = of_match_ptr("LDO5"),
|
.of_match = of_match_ptr("LDO5"),
|
||||||
.regulators_node = of_match_ptr("regulators"),
|
.regulators_node = of_match_ptr("regulators"),
|
||||||
.id = PCA9450_LDO5,
|
.id = PCA9450_LDO5,
|
||||||
.ops = &pca9450_ldo_regulator_ops,
|
.ops = &pca9450_ldo5_regulator_ops,
|
||||||
.type = REGULATOR_VOLTAGE,
|
.type = REGULATOR_VOLTAGE,
|
||||||
.n_voltages = PCA9450_LDO5_VOLTAGE_NUM,
|
.n_voltages = PCA9450_LDO5_VOLTAGE_NUM,
|
||||||
.linear_ranges = pca9450_ldo5_volts,
|
.linear_ranges = pca9450_ldo5_volts,
|
||||||
|
|
@ -913,6 +967,7 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
|
||||||
of_device_get_match_data(&i2c->dev);
|
of_device_get_match_data(&i2c->dev);
|
||||||
const struct pca9450_regulator_desc *regulator_desc;
|
const struct pca9450_regulator_desc *regulator_desc;
|
||||||
struct regulator_config config = { };
|
struct regulator_config config = { };
|
||||||
|
struct regulator_dev *ldo5;
|
||||||
struct pca9450 *pca9450;
|
struct pca9450 *pca9450;
|
||||||
unsigned int device_id, i;
|
unsigned int device_id, i;
|
||||||
unsigned int reset_ctrl;
|
unsigned int reset_ctrl;
|
||||||
|
|
@ -978,11 +1033,15 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
|
||||||
|
|
||||||
config.regmap = pca9450->regmap;
|
config.regmap = pca9450->regmap;
|
||||||
config.dev = pca9450->dev;
|
config.dev = pca9450->dev;
|
||||||
|
config.driver_data = pca9450;
|
||||||
|
|
||||||
rdev = devm_regulator_register(pca9450->dev, desc, &config);
|
rdev = devm_regulator_register(pca9450->dev, desc, &config);
|
||||||
if (IS_ERR(rdev))
|
if (IS_ERR(rdev))
|
||||||
return dev_err_probe(pca9450->dev, PTR_ERR(rdev),
|
return dev_err_probe(pca9450->dev, PTR_ERR(rdev),
|
||||||
"Failed to register regulator(%s)\n", desc->name);
|
"Failed to register regulator(%s)\n", desc->name);
|
||||||
|
|
||||||
|
if (!strcmp(desc->name, "ldo5"))
|
||||||
|
ldo5 = rdev;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pca9450->irq) {
|
if (pca9450->irq) {
|
||||||
|
|
@ -1029,6 +1088,30 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
|
||||||
"Failed to enable I2C level translator\n");
|
"Failed to enable I2C level translator\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For LDO5 we need to be able to check the status of the SD_VSEL input in
|
||||||
|
* order to know which control register is used. Most boards connect SD_VSEL
|
||||||
|
* to the VSELECT signal, so we can use the GPIO that is internally routed
|
||||||
|
* to this signal (if SION bit is set in IOMUX).
|
||||||
|
*/
|
||||||
|
pca9450->sd_vsel_gpio = gpiod_get_optional(&ldo5->dev, "sd-vsel", GPIOD_IN);
|
||||||
|
if (IS_ERR(pca9450->sd_vsel_gpio)) {
|
||||||
|
dev_err(&i2c->dev, "Failed to get SD_VSEL GPIO\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For LDO5 we need to be able to check the status of the SD_VSEL input in
|
||||||
|
* order to know which control register is used. Most boards connect SD_VSEL
|
||||||
|
* to the VSELECT signal, so we can use the GPIO that is internally routed
|
||||||
|
* to this signal (if SION bit is set in IOMUX).
|
||||||
|
*/
|
||||||
|
pca9450->sd_vsel_gpio = gpiod_get_optional(&ldo5->dev, "sd-vsel", GPIOD_IN);
|
||||||
|
if (IS_ERR(pca9450->sd_vsel_gpio)) {
|
||||||
|
dev_err(&i2c->dev, "Failed to get SD_VSEL GPIO\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
dev_info(&i2c->dev, "%s probed.\n",
|
dev_info(&i2c->dev, "%s probed.\n",
|
||||||
type == PCA9450_TYPE_PCA9450A ? "pca9450a" :
|
type == PCA9450_TYPE_PCA9450A ? "pca9450a" :
|
||||||
(type == PCA9450_TYPE_PCA9451A ? "pca9451a" : "pca9450bc"));
|
(type == PCA9450_TYPE_PCA9451A ? "pca9451a" : "pca9450bc"));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue