Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Frieder Schrempf and committed by
Mark Brown
3ce6f4f9 c73be62c

+86 -3
+86 -3
drivers/regulator/pca9450-regulator.c
··· 5 5 */ 6 6 7 7 #include <linux/err.h> 8 + #include <linux/gpio/consumer.h> 8 9 #include <linux/i2c.h> 9 10 #include <linux/interrupt.h> 10 11 #include <linux/kernel.h> ··· 32 31 struct pca9450 { 33 32 struct device *dev; 34 33 struct regmap *regmap; 34 + struct gpio_desc *sd_vsel_gpio; 35 35 enum pca9450_chip_type type; 36 36 unsigned int rcnt; 37 37 int irq; ··· 96 94 .list_voltage = regulator_list_voltage_linear_range, 97 95 .set_voltage_sel = regulator_set_voltage_sel_regmap, 98 96 .get_voltage_sel = regulator_get_voltage_sel_regmap, 97 + }; 98 + 99 + static unsigned int pca9450_ldo5_get_reg_voltage_sel(struct regulator_dev *rdev) 100 + { 101 + struct pca9450 *pca9450 = rdev_get_drvdata(rdev); 102 + 103 + if (pca9450->sd_vsel_gpio && !gpiod_get_value(pca9450->sd_vsel_gpio)) 104 + return PCA9450_REG_LDO5CTRL_L; 105 + 106 + return rdev->desc->vsel_reg; 107 + } 108 + 109 + static int pca9450_ldo5_get_voltage_sel_regmap(struct regulator_dev *rdev) 110 + { 111 + unsigned int val; 112 + int ret; 113 + 114 + ret = regmap_read(rdev->regmap, pca9450_ldo5_get_reg_voltage_sel(rdev), &val); 115 + if (ret != 0) 116 + return ret; 117 + 118 + val &= rdev->desc->vsel_mask; 119 + val >>= ffs(rdev->desc->vsel_mask) - 1; 120 + 121 + return val; 122 + } 123 + 124 + static int pca9450_ldo5_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned int sel) 125 + { 126 + int ret; 127 + 128 + sel <<= ffs(rdev->desc->vsel_mask) - 1; 129 + 130 + ret = regmap_update_bits(rdev->regmap, pca9450_ldo5_get_reg_voltage_sel(rdev), 131 + rdev->desc->vsel_mask, sel); 132 + if (ret) 133 + return ret; 134 + 135 + if (rdev->desc->apply_bit) 136 + ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg, 137 + rdev->desc->apply_bit, 138 + rdev->desc->apply_bit); 139 + return ret; 140 + } 141 + 142 + static const struct regulator_ops pca9450_ldo5_regulator_ops = { 143 + .enable = regulator_enable_regmap, 144 + .disable = regulator_disable_regmap, 145 + .is_enabled = regulator_is_enabled_regmap, 146 + .list_voltage = regulator_list_voltage_linear_range, 147 + .set_voltage_sel = pca9450_ldo5_set_voltage_sel_regmap, 148 + .get_voltage_sel = pca9450_ldo5_get_voltage_sel_regmap, 99 149 }; 100 150 101 151 /* ··· 505 451 .of_match = of_match_ptr("LDO5"), 506 452 .regulators_node = of_match_ptr("regulators"), 507 453 .id = PCA9450_LDO5, 508 - .ops = &pca9450_ldo_regulator_ops, 454 + .ops = &pca9450_ldo5_regulator_ops, 509 455 .type = REGULATOR_VOLTAGE, 510 456 .n_voltages = PCA9450_LDO5_VOLTAGE_NUM, 511 457 .linear_ranges = pca9450_ldo5_volts, ··· 719 665 .of_match = of_match_ptr("LDO5"), 720 666 .regulators_node = of_match_ptr("regulators"), 721 667 .id = PCA9450_LDO5, 722 - .ops = &pca9450_ldo_regulator_ops, 668 + .ops = &pca9450_ldo5_regulator_ops, 723 669 .type = REGULATOR_VOLTAGE, 724 670 .n_voltages = PCA9450_LDO5_VOLTAGE_NUM, 725 671 .linear_ranges = pca9450_ldo5_volts, ··· 909 855 .of_match = of_match_ptr("LDO5"), 910 856 .regulators_node = of_match_ptr("regulators"), 911 857 .id = PCA9450_LDO5, 912 - .ops = &pca9450_ldo_regulator_ops, 858 + .ops = &pca9450_ldo5_regulator_ops, 913 859 .type = REGULATOR_VOLTAGE, 914 860 .n_voltages = PCA9450_LDO5_VOLTAGE_NUM, 915 861 .linear_ranges = pca9450_ldo5_volts, ··· 967 913 of_device_get_match_data(&i2c->dev); 968 914 const struct pca9450_regulator_desc *regulator_desc; 969 915 struct regulator_config config = { }; 916 + struct regulator_dev *ldo5; 970 917 struct pca9450 *pca9450; 971 918 unsigned int device_id, i; 972 919 unsigned int reset_ctrl; ··· 1033 978 1034 979 config.regmap = pca9450->regmap; 1035 980 config.dev = pca9450->dev; 981 + config.driver_data = pca9450; 1036 982 1037 983 rdev = devm_regulator_register(pca9450->dev, desc, &config); 1038 984 if (IS_ERR(rdev)) 1039 985 return dev_err_probe(pca9450->dev, PTR_ERR(rdev), 1040 986 "Failed to register regulator(%s)\n", desc->name); 987 + 988 + if (!strcmp(desc->name, "ldo5")) 989 + ldo5 = rdev; 1041 990 } 1042 991 1043 992 if (pca9450->irq) { ··· 1086 1027 if (ret) 1087 1028 return dev_err_probe(&i2c->dev, ret, 1088 1029 "Failed to enable I2C level translator\n"); 1030 + } 1031 + 1032 + /* 1033 + * For LDO5 we need to be able to check the status of the SD_VSEL input in 1034 + * order to know which control register is used. Most boards connect SD_VSEL 1035 + * to the VSELECT signal, so we can use the GPIO that is internally routed 1036 + * to this signal (if SION bit is set in IOMUX). 1037 + */ 1038 + pca9450->sd_vsel_gpio = gpiod_get_optional(&ldo5->dev, "sd-vsel", GPIOD_IN); 1039 + if (IS_ERR(pca9450->sd_vsel_gpio)) { 1040 + dev_err(&i2c->dev, "Failed to get SD_VSEL GPIO\n"); 1041 + return ret; 1042 + } 1043 + 1044 + /* 1045 + * For LDO5 we need to be able to check the status of the SD_VSEL input in 1046 + * order to know which control register is used. Most boards connect SD_VSEL 1047 + * to the VSELECT signal, so we can use the GPIO that is internally routed 1048 + * to this signal (if SION bit is set in IOMUX). 1049 + */ 1050 + pca9450->sd_vsel_gpio = gpiod_get_optional(&ldo5->dev, "sd-vsel", GPIOD_IN); 1051 + if (IS_ERR(pca9450->sd_vsel_gpio)) { 1052 + dev_err(&i2c->dev, "Failed to get SD_VSEL GPIO\n"); 1053 + return ret; 1089 1054 } 1090 1055 1091 1056 dev_info(&i2c->dev, "%s probed.\n",