sy8827n.c (5105B)
1// SPDX-License-Identifier: GPL-2.0 2// 3// SY8827N regulator driver 4// 5// Copyright (C) 2020 Synaptics Incorporated 6// 7// Author: Jisheng Zhang <jszhang@kernel.org> 8 9#include <linux/gpio/consumer.h> 10#include <linux/module.h> 11#include <linux/i2c.h> 12#include <linux/of_device.h> 13#include <linux/regmap.h> 14#include <linux/regulator/driver.h> 15#include <linux/regulator/of_regulator.h> 16 17#define SY8827N_VSEL0 0 18#define SY8827N_BUCK_EN (1 << 7) 19#define SY8827N_MODE (1 << 6) 20#define SY8827N_VSEL1 1 21#define SY8827N_CTRL 2 22#define SY8827N_ID1 3 23#define SY8827N_ID2 4 24#define SY8827N_PGOOD 5 25#define SY8827N_MAX (SY8827N_PGOOD + 1) 26 27#define SY8827N_NVOLTAGES 64 28#define SY8827N_VSELMIN 600000 29#define SY8827N_VSELSTEP 12500 30 31struct sy8827n_device_info { 32 struct device *dev; 33 struct regulator_desc desc; 34 struct regulator_init_data *regulator; 35 struct gpio_desc *en_gpio; 36 unsigned int vsel_reg; 37}; 38 39static int sy8827n_set_mode(struct regulator_dev *rdev, unsigned int mode) 40{ 41 struct sy8827n_device_info *di = rdev_get_drvdata(rdev); 42 43 switch (mode) { 44 case REGULATOR_MODE_FAST: 45 regmap_update_bits(rdev->regmap, di->vsel_reg, 46 SY8827N_MODE, SY8827N_MODE); 47 break; 48 case REGULATOR_MODE_NORMAL: 49 regmap_update_bits(rdev->regmap, di->vsel_reg, 50 SY8827N_MODE, 0); 51 break; 52 default: 53 return -EINVAL; 54 } 55 return 0; 56} 57 58static unsigned int sy8827n_get_mode(struct regulator_dev *rdev) 59{ 60 struct sy8827n_device_info *di = rdev_get_drvdata(rdev); 61 u32 val; 62 int ret = 0; 63 64 ret = regmap_read(rdev->regmap, di->vsel_reg, &val); 65 if (ret < 0) 66 return ret; 67 if (val & SY8827N_MODE) 68 return REGULATOR_MODE_FAST; 69 else 70 return REGULATOR_MODE_NORMAL; 71} 72 73static const struct regulator_ops sy8827n_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 = sy8827n_set_mode, 83 .get_mode = sy8827n_get_mode, 84}; 85 86static int sy8827n_regulator_register(struct sy8827n_device_info *di, 87 struct regulator_config *config) 88{ 89 struct regulator_desc *rdesc = &di->desc; 90 struct regulator_dev *rdev; 91 92 rdesc->name = "sy8827n-reg"; 93 rdesc->supply_name = "vin"; 94 rdesc->ops = &sy8827n_regulator_ops; 95 rdesc->type = REGULATOR_VOLTAGE; 96 rdesc->n_voltages = SY8827N_NVOLTAGES; 97 rdesc->enable_reg = di->vsel_reg; 98 rdesc->enable_mask = SY8827N_BUCK_EN; 99 rdesc->min_uV = SY8827N_VSELMIN; 100 rdesc->uV_step = SY8827N_VSELSTEP; 101 rdesc->vsel_reg = di->vsel_reg; 102 rdesc->vsel_mask = rdesc->n_voltages - 1; 103 rdesc->owner = THIS_MODULE; 104 105 rdev = devm_regulator_register(di->dev, &di->desc, config); 106 return PTR_ERR_OR_ZERO(rdev); 107} 108 109static bool sy8827n_volatile_reg(struct device *dev, unsigned int reg) 110{ 111 if (reg == SY8827N_PGOOD) 112 return true; 113 return false; 114} 115 116static const struct regmap_config sy8827n_regmap_config = { 117 .reg_bits = 8, 118 .val_bits = 8, 119 .volatile_reg = sy8827n_volatile_reg, 120 .num_reg_defaults_raw = SY8827N_MAX, 121 .cache_type = REGCACHE_FLAT, 122}; 123 124static int sy8827n_i2c_probe(struct i2c_client *client) 125{ 126 struct device *dev = &client->dev; 127 struct device_node *np = dev->of_node; 128 struct sy8827n_device_info *di; 129 struct regulator_config config = { }; 130 struct regmap *regmap; 131 int ret; 132 133 di = devm_kzalloc(dev, sizeof(struct sy8827n_device_info), GFP_KERNEL); 134 if (!di) 135 return -ENOMEM; 136 137 di->regulator = of_get_regulator_init_data(dev, np, &di->desc); 138 if (!di->regulator) { 139 dev_err(dev, "Platform data not found!\n"); 140 return -EINVAL; 141 } 142 143 di->en_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); 144 if (IS_ERR(di->en_gpio)) 145 return PTR_ERR(di->en_gpio); 146 147 if (of_property_read_bool(np, "silergy,vsel-state-high")) 148 di->vsel_reg = SY8827N_VSEL1; 149 else 150 di->vsel_reg = SY8827N_VSEL0; 151 152 di->dev = dev; 153 154 regmap = devm_regmap_init_i2c(client, &sy8827n_regmap_config); 155 if (IS_ERR(regmap)) { 156 dev_err(dev, "Failed to allocate regmap!\n"); 157 return PTR_ERR(regmap); 158 } 159 i2c_set_clientdata(client, di); 160 161 config.dev = di->dev; 162 config.init_data = di->regulator; 163 config.regmap = regmap; 164 config.driver_data = di; 165 config.of_node = np; 166 167 ret = sy8827n_regulator_register(di, &config); 168 if (ret < 0) 169 dev_err(dev, "Failed to register regulator!\n"); 170 return ret; 171} 172 173#ifdef CONFIG_OF 174static const struct of_device_id sy8827n_dt_ids[] = { 175 { 176 .compatible = "silergy,sy8827n", 177 }, 178 { } 179}; 180MODULE_DEVICE_TABLE(of, sy8827n_dt_ids); 181#endif 182 183static const struct i2c_device_id sy8827n_id[] = { 184 { "sy8827n", }, 185 { }, 186}; 187MODULE_DEVICE_TABLE(i2c, sy8827n_id); 188 189static struct i2c_driver sy8827n_regulator_driver = { 190 .driver = { 191 .name = "sy8827n-regulator", 192 .of_match_table = of_match_ptr(sy8827n_dt_ids), 193 }, 194 .probe_new = sy8827n_i2c_probe, 195 .id_table = sy8827n_id, 196}; 197module_i2c_driver(sy8827n_regulator_driver); 198 199MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>"); 200MODULE_DESCRIPTION("SY8827N regulator driver"); 201MODULE_LICENSE("GPL v2");