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 { 117 struct device *dev = &client->dev; 118 struct device_node *np = dev->of_node; 119 struct sy8824_device_info *di; 120 struct regulator_config config = { }; 121 struct regmap *regmap; 122 int ret; 123 124 di = devm_kzalloc(dev, sizeof(struct sy8824_device_info), GFP_KERNEL); 125 if (!di) 126 return -ENOMEM; 127 128 di->regulator = of_get_regulator_init_data(dev, np, &di->desc); 129 if (!di->regulator) { 130 dev_err(dev, "Platform data not found!\n"); 131 return -EINVAL; 132 } 133 134 di->dev = dev; 135 di->cfg = of_device_get_match_data(dev); 136 137 regmap = devm_regmap_init_i2c(client, &sy8824_regmap_config); 138 if (IS_ERR(regmap)) { 139 dev_err(dev, "Failed to allocate regmap!\n"); 140 return PTR_ERR(regmap); 141 } 142 i2c_set_clientdata(client, di); 143 144 config.dev = di->dev; 145 config.init_data = di->regulator; 146 config.regmap = regmap; 147 config.driver_data = di; 148 config.of_node = np; 149 150 ret = sy8824_regulator_register(di, &config); 151 if (ret < 0) 152 dev_err(dev, "Failed to register regulator!\n"); 153 return ret; 154 } 155 156 static const struct sy8824_config sy8824c_cfg = { 157 .vol_reg = 0x00, 158 .mode_reg = 0x00, 159 .enable_reg = 0x00, 160 .vsel_min = 762500, 161 .vsel_step = 12500, 162 .vsel_count = 64, 163 }; 164 165 static const struct sy8824_config sy8824e_cfg = { 166 .vol_reg = 0x00, 167 .mode_reg = 0x00, 168 .enable_reg = 0x00, 169 .vsel_min = 700000, 170 .vsel_step = 12500, 171 .vsel_count = 64, 172 }; 173 174 static const struct sy8824_config sy20276_cfg = { 175 .vol_reg = 0x00, 176 .mode_reg = 0x01, 177 .enable_reg = 0x01, 178 .vsel_min = 600000, 179 .vsel_step = 10000, 180 .vsel_count = 128, 181 }; 182 183 static const struct sy8824_config sy20278_cfg = { 184 .vol_reg = 0x00, 185 .mode_reg = 0x01, 186 .enable_reg = 0x01, 187 .vsel_min = 762500, 188 .vsel_step = 12500, 189 .vsel_count = 64, 190 }; 191 192 static const struct of_device_id sy8824_dt_ids[] = { 193 { 194 .compatible = "silergy,sy8824c", 195 .data = &sy8824c_cfg 196 }, 197 { 198 .compatible = "silergy,sy8824e", 199 .data = &sy8824e_cfg 200 }, 201 { 202 .compatible = "silergy,sy20276", 203 .data = &sy20276_cfg 204 }, 205 { 206 .compatible = "silergy,sy20278", 207 .data = &sy20278_cfg 208 }, 209 { } 210 }; 211 MODULE_DEVICE_TABLE(of, sy8824_dt_ids); 212 213 static const struct i2c_device_id sy8824_id[] = { 214 { "sy8824", }, 215 { }, 216 }; 217 MODULE_DEVICE_TABLE(i2c, sy8824_id); 218 219 static struct i2c_driver sy8824_regulator_driver = { 220 .driver = { 221 .name = "sy8824-regulator", 222 .of_match_table = of_match_ptr(sy8824_dt_ids), 223 }, 224 .probe_new = sy8824_i2c_probe, 225 .id_table = sy8824_id, 226 }; 227 module_i2c_driver(sy8824_regulator_driver); 228 229 MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>"); 230 MODULE_DESCRIPTION("SY8824C/SY8824E regulator driver"); 231 MODULE_LICENSE("GPL v2"); 232