1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. 4 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 5 * Copyright (c) 2024 Linaro Limited 6 */ 7 8 #include <linux/array_size.h> 9 #include <linux/bits.h> 10 #include <linux/device.h> 11 #include <linux/math.h> 12 #include <linux/module.h> 13 #include <linux/of.h> 14 #include <linux/platform_device.h> 15 #include <linux/regmap.h> 16 #include <linux/regulator/driver.h> 17 18 #include <asm/byteorder.h> 19 20 #define DEFAULT_VOLTAGE_STEPPER_RATE 38400 21 22 #define LDO_STEPPER_CTL_REG 0x3b 23 #define STEP_RATE_MASK GENMASK(1, 0) 24 25 #define LDO_VSET_LB_REG 0x40 26 27 #define LDO_ENABLE_REG 0x46 28 #define ENABLE_BIT BIT(7) 29 30 struct pm8008_regulator { 31 struct regmap *regmap; 32 struct regulator_desc desc; 33 unsigned int base; 34 }; 35 36 struct pm8008_regulator_data { 37 const char *name; 38 const char *supply_name; 39 unsigned int base; 40 int min_dropout_uV; 41 const struct linear_range *voltage_range; 42 }; 43 44 static const struct linear_range nldo_ranges[] = { 45 REGULATOR_LINEAR_RANGE(528000, 0, 122, 8000), 46 }; 47 48 static const struct linear_range pldo_ranges[] = { 49 REGULATOR_LINEAR_RANGE(1504000, 0, 237, 8000), 50 }; 51 52 static const struct pm8008_regulator_data pm8008_reg_data[] = { 53 { "ldo1", "vdd-l1-l2", 0x4000, 225000, nldo_ranges, }, 54 { "ldo2", "vdd-l1-l2", 0x4100, 225000, nldo_ranges, }, 55 { "ldo3", "vdd-l3-l4", 0x4200, 300000, pldo_ranges, }, 56 { "ldo4", "vdd-l3-l4", 0x4300, 300000, pldo_ranges, }, 57 { "ldo5", "vdd-l5", 0x4400, 200000, pldo_ranges, }, 58 { "ldo6", "vdd-l6", 0x4500, 200000, pldo_ranges, }, 59 { "ldo7", "vdd-l7", 0x4600, 200000, pldo_ranges, }, 60 }; 61 62 static int pm8008_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel) 63 { 64 struct pm8008_regulator *preg = rdev_get_drvdata(rdev); 65 unsigned int mV; 66 __le16 val; 67 int ret; 68 69 ret = regulator_list_voltage_linear_range(rdev, sel); 70 if (ret < 0) 71 return ret; 72 73 mV = DIV_ROUND_UP(ret, 1000); 74 75 val = cpu_to_le16(mV); 76 77 ret = regmap_bulk_write(preg->regmap, preg->base + LDO_VSET_LB_REG, 78 &val, sizeof(val)); 79 if (ret < 0) 80 return ret; 81 82 return 0; 83 } 84 85 static int pm8008_regulator_get_voltage_sel(struct regulator_dev *rdev) 86 { 87 struct pm8008_regulator *preg = rdev_get_drvdata(rdev); 88 unsigned int uV; 89 __le16 val; 90 int ret; 91 92 ret = regmap_bulk_read(preg->regmap, preg->base + LDO_VSET_LB_REG, 93 &val, sizeof(val)); 94 if (ret < 0) 95 return ret; 96 97 uV = le16_to_cpu(val) * 1000; 98 99 return (uV - preg->desc.min_uV) / preg->desc.uV_step; 100 } 101 102 static const struct regulator_ops pm8008_regulator_ops = { 103 .list_voltage = regulator_list_voltage_linear, 104 .set_voltage_sel = pm8008_regulator_set_voltage_sel, 105 .get_voltage_sel = pm8008_regulator_get_voltage_sel, 106 .enable = regulator_enable_regmap, 107 .disable = regulator_disable_regmap, 108 .is_enabled = regulator_is_enabled_regmap, 109 }; 110 111 static int pm8008_regulator_probe(struct platform_device *pdev) 112 { 113 const struct pm8008_regulator_data *data; 114 struct regulator_config config = {}; 115 struct device *dev = &pdev->dev; 116 struct pm8008_regulator *preg; 117 struct regulator_desc *desc; 118 struct regulator_dev *rdev; 119 struct regmap *regmap; 120 unsigned int val; 121 int ret, i; 122 123 regmap = dev_get_regmap(dev->parent, "secondary"); 124 if (!regmap) 125 return -EINVAL; 126 127 for (i = 0; i < ARRAY_SIZE(pm8008_reg_data); i++) { 128 data = &pm8008_reg_data[i]; 129 130 preg = devm_kzalloc(dev, sizeof(*preg), GFP_KERNEL); 131 if (!preg) 132 return -ENOMEM; 133 134 preg->regmap = regmap; 135 preg->base = data->base; 136 137 desc = &preg->desc; 138 139 desc->name = data->name; 140 desc->supply_name = data->supply_name; 141 desc->of_match = data->name; 142 desc->regulators_node = of_match_ptr("regulators"); 143 desc->ops = &pm8008_regulator_ops; 144 desc->type = REGULATOR_VOLTAGE; 145 desc->owner = THIS_MODULE; 146 147 desc->linear_ranges = data->voltage_range; 148 desc->n_linear_ranges = 1; 149 desc->uV_step = desc->linear_ranges[0].step; 150 desc->min_uV = desc->linear_ranges[0].min; 151 desc->n_voltages = linear_range_values_in_range(&desc->linear_ranges[0]); 152 153 ret = regmap_read(regmap, preg->base + LDO_STEPPER_CTL_REG, &val); 154 if (ret < 0) { 155 dev_err(dev, "failed to read step rate: %d\n", ret); 156 return ret; 157 } 158 val &= STEP_RATE_MASK; 159 desc->ramp_delay = DEFAULT_VOLTAGE_STEPPER_RATE >> val; 160 161 desc->min_dropout_uV = data->min_dropout_uV; 162 163 desc->enable_reg = preg->base + LDO_ENABLE_REG; 164 desc->enable_mask = ENABLE_BIT; 165 166 config.dev = dev->parent; 167 config.driver_data = preg; 168 config.regmap = regmap; 169 170 rdev = devm_regulator_register(dev, desc, &config); 171 if (IS_ERR(rdev)) { 172 ret = PTR_ERR(rdev); 173 dev_err(dev, "failed to register regulator %s: %d\n", 174 desc->name, ret); 175 return ret; 176 } 177 } 178 179 return 0; 180 } 181 182 static const struct platform_device_id pm8008_regulator_id_table[] = { 183 { "pm8008-regulator" }, 184 { } 185 }; 186 MODULE_DEVICE_TABLE(platform, pm8008_regulator_id_table); 187 188 static struct platform_driver pm8008_regulator_driver = { 189 .driver = { 190 .name = "qcom-pm8008-regulator", 191 }, 192 .probe = pm8008_regulator_probe, 193 .id_table = pm8008_regulator_id_table, 194 }; 195 module_platform_driver(pm8008_regulator_driver); 196 197 MODULE_DESCRIPTION("Qualcomm PM8008 PMIC regulator driver"); 198 MODULE_LICENSE("GPL"); 199