1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // Device driver for regulators in Hi655x IC 4 // 5 // Copyright (c) 2016 HiSilicon Ltd. 6 // 7 // Authors: 8 // Chen Feng <puck.chen@hisilicon.com> 9 // Fei Wang <w.f@huawei.com> 10 11 #include <linux/bitops.h> 12 #include <linux/device.h> 13 #include <linux/err.h> 14 #include <linux/module.h> 15 #include <linux/io.h> 16 #include <linux/of.h> 17 #include <linux/platform_device.h> 18 #include <linux/regmap.h> 19 #include <linux/regulator/driver.h> 20 #include <linux/regulator/machine.h> 21 #include <linux/regulator/of_regulator.h> 22 #include <linux/mfd/hi655x-pmic.h> 23 24 struct hi655x_regulator { 25 unsigned int disable_reg; 26 unsigned int status_reg; 27 struct regulator_desc rdesc; 28 }; 29 30 /* LDO7 & LDO10 */ 31 static const unsigned int ldo7_voltages[] = { 32 1800000, 1850000, 2850000, 2900000, 33 3000000, 3100000, 3200000, 3300000, 34 }; 35 36 static const unsigned int ldo19_voltages[] = { 37 1800000, 1850000, 1900000, 1750000, 38 2800000, 2850000, 2900000, 3000000, 39 }; 40 41 static const unsigned int ldo22_voltages[] = { 42 900000, 1000000, 1050000, 1100000, 43 1150000, 1175000, 1185000, 1200000, 44 }; 45 46 enum hi655x_regulator_id { 47 HI655X_LDO0, 48 HI655X_LDO1, 49 HI655X_LDO2, 50 HI655X_LDO3, 51 HI655X_LDO4, 52 HI655X_LDO5, 53 HI655X_LDO6, 54 HI655X_LDO7, 55 HI655X_LDO8, 56 HI655X_LDO9, 57 HI655X_LDO10, 58 HI655X_LDO11, 59 HI655X_LDO12, 60 HI655X_LDO13, 61 HI655X_LDO14, 62 HI655X_LDO15, 63 HI655X_LDO16, 64 HI655X_LDO17, 65 HI655X_LDO18, 66 HI655X_LDO19, 67 HI655X_LDO20, 68 HI655X_LDO21, 69 HI655X_LDO22, 70 }; 71 72 static int hi655x_is_enabled(struct regulator_dev *rdev) 73 { 74 unsigned int value = 0; 75 const struct hi655x_regulator *regulator = rdev_get_drvdata(rdev); 76 77 regmap_read(rdev->regmap, regulator->status_reg, &value); 78 return (value & rdev->desc->enable_mask); 79 } 80 81 static int hi655x_disable(struct regulator_dev *rdev) 82 { 83 const struct hi655x_regulator *regulator = rdev_get_drvdata(rdev); 84 85 return regmap_write(rdev->regmap, regulator->disable_reg, 86 rdev->desc->enable_mask); 87 } 88 89 static const struct regulator_ops hi655x_regulator_ops = { 90 .enable = regulator_enable_regmap, 91 .disable = hi655x_disable, 92 .is_enabled = hi655x_is_enabled, 93 .list_voltage = regulator_list_voltage_table, 94 .get_voltage_sel = regulator_get_voltage_sel_regmap, 95 .set_voltage_sel = regulator_set_voltage_sel_regmap, 96 }; 97 98 static const struct regulator_ops hi655x_ldo_linear_ops = { 99 .enable = regulator_enable_regmap, 100 .disable = hi655x_disable, 101 .is_enabled = hi655x_is_enabled, 102 .list_voltage = regulator_list_voltage_linear, 103 .get_voltage_sel = regulator_get_voltage_sel_regmap, 104 .set_voltage_sel = regulator_set_voltage_sel_regmap, 105 }; 106 107 #define HI655X_LDO(_ID, vreg, vmask, ereg, dreg, \ 108 sreg, cmask, vtable) { \ 109 .rdesc = { \ 110 .name = #_ID, \ 111 .of_match = of_match_ptr(#_ID), \ 112 .ops = &hi655x_regulator_ops, \ 113 .regulators_node = of_match_ptr("regulators"), \ 114 .type = REGULATOR_VOLTAGE, \ 115 .id = HI655X_##_ID, \ 116 .owner = THIS_MODULE, \ 117 .n_voltages = ARRAY_SIZE(vtable), \ 118 .volt_table = vtable, \ 119 .vsel_reg = HI655X_BUS_ADDR(vreg), \ 120 .vsel_mask = vmask, \ 121 .enable_reg = HI655X_BUS_ADDR(ereg), \ 122 .enable_mask = BIT(cmask), \ 123 }, \ 124 .disable_reg = HI655X_BUS_ADDR(dreg), \ 125 .status_reg = HI655X_BUS_ADDR(sreg), \ 126 } 127 128 #define HI655X_LDO_LINEAR(_ID, vreg, vmask, ereg, dreg, \ 129 sreg, cmask, minv, nvolt, vstep) { \ 130 .rdesc = { \ 131 .name = #_ID, \ 132 .of_match = of_match_ptr(#_ID), \ 133 .ops = &hi655x_ldo_linear_ops, \ 134 .regulators_node = of_match_ptr("regulators"), \ 135 .type = REGULATOR_VOLTAGE, \ 136 .id = HI655X_##_ID, \ 137 .owner = THIS_MODULE, \ 138 .min_uV = minv, \ 139 .n_voltages = nvolt, \ 140 .uV_step = vstep, \ 141 .vsel_reg = HI655X_BUS_ADDR(vreg), \ 142 .vsel_mask = vmask, \ 143 .enable_reg = HI655X_BUS_ADDR(ereg), \ 144 .enable_mask = BIT(cmask), \ 145 }, \ 146 .disable_reg = HI655X_BUS_ADDR(dreg), \ 147 .status_reg = HI655X_BUS_ADDR(sreg), \ 148 } 149 150 static const struct hi655x_regulator regulators[] = { 151 HI655X_LDO_LINEAR(LDO2, 0x72, 0x07, 0x29, 0x2a, 0x2b, 0x01, 152 2500000, 8, 100000), 153 HI655X_LDO(LDO7, 0x78, 0x07, 0x29, 0x2a, 0x2b, 0x06, ldo7_voltages), 154 HI655X_LDO(LDO10, 0x78, 0x07, 0x29, 0x2a, 0x2b, 0x01, ldo7_voltages), 155 HI655X_LDO_LINEAR(LDO13, 0x7e, 0x07, 0x2c, 0x2d, 0x2e, 0x04, 156 1600000, 8, 50000), 157 HI655X_LDO_LINEAR(LDO14, 0x7f, 0x07, 0x2c, 0x2d, 0x2e, 0x05, 158 2500000, 8, 100000), 159 HI655X_LDO_LINEAR(LDO15, 0x80, 0x07, 0x2c, 0x2d, 0x2e, 0x06, 160 1600000, 8, 50000), 161 HI655X_LDO_LINEAR(LDO17, 0x82, 0x07, 0x2f, 0x30, 0x31, 0x00, 162 2500000, 8, 100000), 163 HI655X_LDO(LDO19, 0x84, 0x07, 0x2f, 0x30, 0x31, 0x02, ldo19_voltages), 164 HI655X_LDO_LINEAR(LDO21, 0x86, 0x07, 0x2f, 0x30, 0x31, 0x04, 165 1650000, 8, 50000), 166 HI655X_LDO(LDO22, 0x87, 0x07, 0x2f, 0x30, 0x31, 0x05, ldo22_voltages), 167 }; 168 169 static int hi655x_regulator_probe(struct platform_device *pdev) 170 { 171 unsigned int i; 172 struct hi655x_pmic *pmic; 173 struct regulator_config config = { }; 174 struct regulator_dev *rdev; 175 176 pmic = dev_get_drvdata(pdev->dev.parent); 177 if (!pmic) { 178 dev_err(&pdev->dev, "no pmic in the regulator parent node\n"); 179 return -ENODEV; 180 } 181 182 config.dev = pdev->dev.parent; 183 config.regmap = pmic->regmap; 184 for (i = 0; i < ARRAY_SIZE(regulators); i++) { 185 config.driver_data = (void *) ®ulators[i]; 186 187 rdev = devm_regulator_register(&pdev->dev, 188 ®ulators[i].rdesc, 189 &config); 190 if (IS_ERR(rdev)) { 191 dev_err(&pdev->dev, "failed to register regulator %s\n", 192 regulators[i].rdesc.name); 193 return PTR_ERR(rdev); 194 } 195 } 196 return 0; 197 } 198 199 static const struct platform_device_id hi655x_regulator_table[] = { 200 { .name = "hi655x-regulator" }, 201 {}, 202 }; 203 MODULE_DEVICE_TABLE(platform, hi655x_regulator_table); 204 205 static struct platform_driver hi655x_regulator_driver = { 206 .id_table = hi655x_regulator_table, 207 .driver = { 208 .name = "hi655x-regulator", 209 .probe_type = PROBE_PREFER_ASYNCHRONOUS, 210 }, 211 .probe = hi655x_regulator_probe, 212 }; 213 module_platform_driver(hi655x_regulator_driver); 214 215 MODULE_AUTHOR("Chen Feng <puck.chen@hisilicon.com>"); 216 MODULE_DESCRIPTION("Hisilicon Hi655x regulator driver"); 217 MODULE_LICENSE("GPL v2"); 218