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