1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // SY8824C/SY8824E regulator driver 4 // 5 // Copyright (C) 2019 Synaptics Incorporated 6 // 7 // Author: Jisheng Zhang <jszhang@kernel.org> 8 9 #include <linux/module.h> 10 #include <linux/i2c.h> 11 #include <linux/of_device.h> 12 #include <linux/regmap.h> 13 #include <linux/regulator/driver.h> 14 #include <linux/regulator/of_regulator.h> 15 16 #define SY8824C_BUCK_EN (1 << 7) 17 #define SY8824C_MODE (1 << 6) 18 19 struct sy8824_config { 20 /* registers */ 21 unsigned int vol_reg; 22 unsigned int mode_reg; 23 unsigned int enable_reg; 24 /* Voltage range and step(linear) */ 25 unsigned int vsel_min; 26 unsigned int vsel_step; 27 unsigned int vsel_count; 28 }; 29 30 struct sy8824_device_info { 31 struct device *dev; 32 struct regulator_desc desc; 33 struct regulator_init_data *regulator; 34 const struct sy8824_config *cfg; 35 }; 36 37 static int sy8824_set_mode(struct regulator_dev *rdev, unsigned int mode) 38 { 39 struct sy8824_device_info *di = rdev_get_drvdata(rdev); 40 const struct sy8824_config *cfg = di->cfg; 41 42 switch (mode) { 43 case REGULATOR_MODE_FAST: 44 regmap_update_bits(rdev->regmap, cfg->mode_reg, 45 SY8824C_MODE, SY8824C_MODE); 46 break; 47 case REGULATOR_MODE_NORMAL: 48 regmap_update_bits(rdev->regmap, cfg->mode_reg, 49 SY8824C_MODE, 0); 50 break; 51 default: 52 return -EINVAL; 53 } 54 return 0; 55 } 56 57 static unsigned int sy8824_get_mode(struct regulator_dev *rdev) 58 { 59 struct sy8824_device_info *di = rdev_get_drvdata(rdev); 60 const struct sy8824_config *cfg = di->cfg; 61 u32 val; 62 int ret = 0; 63 64 ret = regmap_read(rdev->regmap, cfg->mode_reg, &val); 65 if (ret < 0) 66 return ret; 67 if (val & SY8824C_MODE) 68 return REGULATOR_MODE_FAST; 69 else 70 return REGULATOR_MODE_NORMAL; 71 } 72 73 static const struct regulator_ops sy8824_regulator_ops = { 74 .set_voltage_sel = regulator_set_voltage_sel_regmap, 75 .get_voltage_sel = regulator_get_voltage_sel_regmap, 76 .set_voltage_time_sel = regulator_set_voltage_time_sel, 77 .map_voltage = regulator_map_voltage_linear, 78 .list_voltage = regulator_list_voltage_linear, 79 .enable = regulator_enable_regmap, 80 .disable = regulator_disable_regmap, 81 .is_enabled = regulator_is_enabled_regmap, 82 .set_mode = sy8824_set_mode, 83 .get_mode = sy8824_get_mode, 84 }; 85 86 static int sy8824_regulator_register(struct sy8824_device_info *di, 87 struct regulator_config *config) 88 { 89 struct regulator_desc *rdesc = &di->desc; 90 const struct sy8824_config *cfg = di->cfg; 91 struct regulator_dev *rdev; 92 93 rdesc->name = "sy8824-reg"; 94 rdesc->supply_name = "vin"; 95 rdesc->ops = &sy8824_regulator_ops; 96 rdesc->type = REGULATOR_VOLTAGE; 97 rdesc->n_voltages = cfg->vsel_count; 98 rdesc->enable_reg = cfg->enable_reg; 99 rdesc->enable_mask = SY8824C_BUCK_EN; 100 rdesc->min_uV = cfg->vsel_min; 101 rdesc->uV_step = cfg->vsel_step; 102 rdesc->vsel_reg = cfg->vol_reg; 103 rdesc->vsel_mask = cfg->vsel_count - 1; 104 rdesc->owner = THIS_MODULE; 105 106 rdev = devm_regulator_register(di->dev, &di->desc, config); 107 return PTR_ERR_OR_ZERO(rdev); 108 } 109 110 static const struct regmap_config sy8824_regmap_config = { 111 .reg_bits = 8, 112 .val_bits = 8, 113 }; 114 115 static int sy8824_i2c_probe(struct i2c_client *client, 116 const struct i2c_device_id *id) 117 { 118 struct device *dev = &client->dev; 119 struct device_node *np = dev->of_node; 120 struct sy8824_device_info *di; 121 struct regulator_config config = { }; 122 struct regmap *regmap; 123 int ret; 124 125 di = devm_kzalloc(dev, sizeof(struct sy8824_device_info), GFP_KERNEL); 126 if (!di) 127 return -ENOMEM; 128 129 di->regulator = of_get_regulator_init_data(dev, np, &di->desc); 130 if (!di->regulator) { 131 dev_err(dev, "Platform data not found!\n"); 132 return -EINVAL; 133 } 134 135 di->dev = dev; 136 di->cfg = of_device_get_match_data(dev); 137 138 regmap = devm_regmap_init_i2c(client, &sy8824_regmap_config); 139 if (IS_ERR(regmap)) { 140 dev_err(dev, "Failed to allocate regmap!\n"); 141 return PTR_ERR(regmap); 142 } 143 i2c_set_clientdata(client, di); 144 145 config.dev = di->dev; 146 config.init_data = di->regulator; 147 config.regmap = regmap; 148 config.driver_data = di; 149 config.of_node = np; 150 151 ret = sy8824_regulator_register(di, &config); 152 if (ret < 0) 153 dev_err(dev, "Failed to register regulator!\n"); 154 return ret; 155 } 156 157 static const struct sy8824_config sy8824c_cfg = { 158 .vol_reg = 0x00, 159 .mode_reg = 0x00, 160 .enable_reg = 0x00, 161 .vsel_min = 762500, 162 .vsel_step = 12500, 163 .vsel_count = 64, 164 }; 165 166 static const struct sy8824_config sy8824e_cfg = { 167 .vol_reg = 0x00, 168 .mode_reg = 0x00, 169 .enable_reg = 0x00, 170 .vsel_min = 700000, 171 .vsel_step = 12500, 172 .vsel_count = 64, 173 }; 174 175 static const struct sy8824_config sy20276_cfg = { 176 .vol_reg = 0x00, 177 .mode_reg = 0x01, 178 .enable_reg = 0x01, 179 .vsel_min = 600000, 180 .vsel_step = 10000, 181 .vsel_count = 128, 182 }; 183 184 static const struct sy8824_config sy20278_cfg = { 185 .vol_reg = 0x00, 186 .mode_reg = 0x01, 187 .enable_reg = 0x01, 188 .vsel_min = 762500, 189 .vsel_step = 12500, 190 .vsel_count = 64, 191 }; 192 193 static const struct of_device_id sy8824_dt_ids[] = { 194 { 195 .compatible = "silergy,sy8824c", 196 .data = &sy8824c_cfg 197 }, 198 { 199 .compatible = "silergy,sy8824e", 200 .data = &sy8824e_cfg 201 }, 202 { 203 .compatible = "silergy,sy20276", 204 .data = &sy20276_cfg 205 }, 206 { 207 .compatible = "silergy,sy20278", 208 .data = &sy20278_cfg 209 }, 210 { } 211 }; 212 MODULE_DEVICE_TABLE(of, sy8824_dt_ids); 213 214 static const struct i2c_device_id sy8824_id[] = { 215 { "sy8824", }, 216 { }, 217 }; 218 MODULE_DEVICE_TABLE(i2c, sy8824_id); 219 220 static struct i2c_driver sy8824_regulator_driver = { 221 .driver = { 222 .name = "sy8824-regulator", 223 .of_match_table = of_match_ptr(sy8824_dt_ids), 224 }, 225 .probe = sy8824_i2c_probe, 226 .id_table = sy8824_id, 227 }; 228 module_i2c_driver(sy8824_regulator_driver); 229 230 MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>"); 231 MODULE_DESCRIPTION("SY8824C/SY8824E regulator driver"); 232 MODULE_LICENSE("GPL v2"); 233