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