xref: /openbmc/linux/drivers/regulator/sy8827n.c (revision 045a44d4)
138fc6f29SJisheng Zhang // SPDX-License-Identifier: GPL-2.0
238fc6f29SJisheng Zhang //
338fc6f29SJisheng Zhang // SY8827N regulator driver
438fc6f29SJisheng Zhang //
538fc6f29SJisheng Zhang // Copyright (C) 2020 Synaptics Incorporated
638fc6f29SJisheng Zhang //
738fc6f29SJisheng Zhang // Author: Jisheng Zhang <jszhang@kernel.org>
838fc6f29SJisheng Zhang 
938fc6f29SJisheng Zhang #include <linux/gpio/consumer.h>
1038fc6f29SJisheng Zhang #include <linux/module.h>
1138fc6f29SJisheng Zhang #include <linux/i2c.h>
12*045a44d4SRob Herring #include <linux/of.h>
1338fc6f29SJisheng Zhang #include <linux/regmap.h>
1438fc6f29SJisheng Zhang #include <linux/regulator/driver.h>
1538fc6f29SJisheng Zhang #include <linux/regulator/of_regulator.h>
1638fc6f29SJisheng Zhang 
1738fc6f29SJisheng Zhang #define SY8827N_VSEL0		0
1838fc6f29SJisheng Zhang #define   SY8827N_BUCK_EN	(1 << 7)
1938fc6f29SJisheng Zhang #define   SY8827N_MODE		(1 << 6)
2038fc6f29SJisheng Zhang #define SY8827N_VSEL1		1
2138fc6f29SJisheng Zhang #define SY8827N_CTRL		2
226bdd1c67SJisheng Zhang #define SY8827N_ID1		3
236bdd1c67SJisheng Zhang #define SY8827N_ID2		4
246bdd1c67SJisheng Zhang #define SY8827N_PGOOD		5
256bdd1c67SJisheng Zhang #define SY8827N_MAX		(SY8827N_PGOOD + 1)
2638fc6f29SJisheng Zhang 
2738fc6f29SJisheng Zhang #define SY8827N_NVOLTAGES	64
2838fc6f29SJisheng Zhang #define SY8827N_VSELMIN		600000
2938fc6f29SJisheng Zhang #define SY8827N_VSELSTEP	12500
3038fc6f29SJisheng Zhang 
3138fc6f29SJisheng Zhang struct sy8827n_device_info {
3238fc6f29SJisheng Zhang 	struct device *dev;
3338fc6f29SJisheng Zhang 	struct regulator_desc desc;
3438fc6f29SJisheng Zhang 	struct regulator_init_data *regulator;
3538fc6f29SJisheng Zhang 	struct gpio_desc *en_gpio;
3638fc6f29SJisheng Zhang 	unsigned int vsel_reg;
3738fc6f29SJisheng Zhang };
3838fc6f29SJisheng Zhang 
sy8827n_set_mode(struct regulator_dev * rdev,unsigned int mode)3938fc6f29SJisheng Zhang static int sy8827n_set_mode(struct regulator_dev *rdev, unsigned int mode)
4038fc6f29SJisheng Zhang {
4138fc6f29SJisheng Zhang 	struct sy8827n_device_info *di = rdev_get_drvdata(rdev);
4238fc6f29SJisheng Zhang 
4338fc6f29SJisheng Zhang 	switch (mode) {
4438fc6f29SJisheng Zhang 	case REGULATOR_MODE_FAST:
4538fc6f29SJisheng Zhang 		regmap_update_bits(rdev->regmap, di->vsel_reg,
4638fc6f29SJisheng Zhang 				   SY8827N_MODE, SY8827N_MODE);
4738fc6f29SJisheng Zhang 		break;
4838fc6f29SJisheng Zhang 	case REGULATOR_MODE_NORMAL:
4938fc6f29SJisheng Zhang 		regmap_update_bits(rdev->regmap, di->vsel_reg,
5038fc6f29SJisheng Zhang 				   SY8827N_MODE, 0);
5138fc6f29SJisheng Zhang 		break;
5238fc6f29SJisheng Zhang 	default:
5338fc6f29SJisheng Zhang 		return -EINVAL;
5438fc6f29SJisheng Zhang 	}
5538fc6f29SJisheng Zhang 	return 0;
5638fc6f29SJisheng Zhang }
5738fc6f29SJisheng Zhang 
sy8827n_get_mode(struct regulator_dev * rdev)5838fc6f29SJisheng Zhang static unsigned int sy8827n_get_mode(struct regulator_dev *rdev)
5938fc6f29SJisheng Zhang {
6038fc6f29SJisheng Zhang 	struct sy8827n_device_info *di = rdev_get_drvdata(rdev);
6138fc6f29SJisheng Zhang 	u32 val;
6238fc6f29SJisheng Zhang 	int ret = 0;
6338fc6f29SJisheng Zhang 
6438fc6f29SJisheng Zhang 	ret = regmap_read(rdev->regmap, di->vsel_reg, &val);
6538fc6f29SJisheng Zhang 	if (ret < 0)
6638fc6f29SJisheng Zhang 		return ret;
6738fc6f29SJisheng Zhang 	if (val & SY8827N_MODE)
6838fc6f29SJisheng Zhang 		return REGULATOR_MODE_FAST;
6938fc6f29SJisheng Zhang 	else
7038fc6f29SJisheng Zhang 		return REGULATOR_MODE_NORMAL;
7138fc6f29SJisheng Zhang }
7238fc6f29SJisheng Zhang 
7338fc6f29SJisheng Zhang static const struct regulator_ops sy8827n_regulator_ops = {
7438fc6f29SJisheng Zhang 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
7538fc6f29SJisheng Zhang 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
7638fc6f29SJisheng Zhang 	.set_voltage_time_sel = regulator_set_voltage_time_sel,
7738fc6f29SJisheng Zhang 	.map_voltage = regulator_map_voltage_linear,
7838fc6f29SJisheng Zhang 	.list_voltage = regulator_list_voltage_linear,
7938fc6f29SJisheng Zhang 	.enable = regulator_enable_regmap,
8038fc6f29SJisheng Zhang 	.disable = regulator_disable_regmap,
8138fc6f29SJisheng Zhang 	.is_enabled = regulator_is_enabled_regmap,
8238fc6f29SJisheng Zhang 	.set_mode = sy8827n_set_mode,
8338fc6f29SJisheng Zhang 	.get_mode = sy8827n_get_mode,
8438fc6f29SJisheng Zhang };
8538fc6f29SJisheng Zhang 
sy8827n_regulator_register(struct sy8827n_device_info * di,struct regulator_config * config)8638fc6f29SJisheng Zhang static int sy8827n_regulator_register(struct sy8827n_device_info *di,
8738fc6f29SJisheng Zhang 			struct regulator_config *config)
8838fc6f29SJisheng Zhang {
8938fc6f29SJisheng Zhang 	struct regulator_desc *rdesc = &di->desc;
9038fc6f29SJisheng Zhang 	struct regulator_dev *rdev;
9138fc6f29SJisheng Zhang 
9238fc6f29SJisheng Zhang 	rdesc->name = "sy8827n-reg";
9338fc6f29SJisheng Zhang 	rdesc->supply_name = "vin";
9438fc6f29SJisheng Zhang 	rdesc->ops = &sy8827n_regulator_ops;
9538fc6f29SJisheng Zhang 	rdesc->type = REGULATOR_VOLTAGE;
9638fc6f29SJisheng Zhang 	rdesc->n_voltages = SY8827N_NVOLTAGES;
9738fc6f29SJisheng Zhang 	rdesc->enable_reg = di->vsel_reg;
9838fc6f29SJisheng Zhang 	rdesc->enable_mask = SY8827N_BUCK_EN;
9938fc6f29SJisheng Zhang 	rdesc->min_uV = SY8827N_VSELMIN;
10038fc6f29SJisheng Zhang 	rdesc->uV_step = SY8827N_VSELSTEP;
10138fc6f29SJisheng Zhang 	rdesc->vsel_reg = di->vsel_reg;
10238fc6f29SJisheng Zhang 	rdesc->vsel_mask = rdesc->n_voltages - 1;
10338fc6f29SJisheng Zhang 	rdesc->owner = THIS_MODULE;
10438fc6f29SJisheng Zhang 
10538fc6f29SJisheng Zhang 	rdev = devm_regulator_register(di->dev, &di->desc, config);
10638fc6f29SJisheng Zhang 	return PTR_ERR_OR_ZERO(rdev);
10738fc6f29SJisheng Zhang }
10838fc6f29SJisheng Zhang 
sy8827n_volatile_reg(struct device * dev,unsigned int reg)1096bdd1c67SJisheng Zhang static bool sy8827n_volatile_reg(struct device *dev, unsigned int reg)
1106bdd1c67SJisheng Zhang {
1116bdd1c67SJisheng Zhang 	if (reg == SY8827N_PGOOD)
1126bdd1c67SJisheng Zhang 		return true;
1136bdd1c67SJisheng Zhang 	return false;
1146bdd1c67SJisheng Zhang }
1156bdd1c67SJisheng Zhang 
11638fc6f29SJisheng Zhang static const struct regmap_config sy8827n_regmap_config = {
11738fc6f29SJisheng Zhang 	.reg_bits = 8,
11838fc6f29SJisheng Zhang 	.val_bits = 8,
1196bdd1c67SJisheng Zhang 	.volatile_reg = sy8827n_volatile_reg,
1206bdd1c67SJisheng Zhang 	.num_reg_defaults_raw = SY8827N_MAX,
1216bdd1c67SJisheng Zhang 	.cache_type = REGCACHE_FLAT,
12238fc6f29SJisheng Zhang };
12338fc6f29SJisheng Zhang 
sy8827n_i2c_probe(struct i2c_client * client)12438fc6f29SJisheng Zhang static int sy8827n_i2c_probe(struct i2c_client *client)
12538fc6f29SJisheng Zhang {
12638fc6f29SJisheng Zhang 	struct device *dev = &client->dev;
12738fc6f29SJisheng Zhang 	struct device_node *np = dev->of_node;
12838fc6f29SJisheng Zhang 	struct sy8827n_device_info *di;
12938fc6f29SJisheng Zhang 	struct regulator_config config = { };
13038fc6f29SJisheng Zhang 	struct regmap *regmap;
13138fc6f29SJisheng Zhang 	int ret;
13238fc6f29SJisheng Zhang 
13338fc6f29SJisheng Zhang 	di = devm_kzalloc(dev, sizeof(struct sy8827n_device_info), GFP_KERNEL);
13438fc6f29SJisheng Zhang 	if (!di)
13538fc6f29SJisheng Zhang 		return -ENOMEM;
13638fc6f29SJisheng Zhang 
13738fc6f29SJisheng Zhang 	di->regulator = of_get_regulator_init_data(dev, np, &di->desc);
13838fc6f29SJisheng Zhang 	if (!di->regulator) {
13938fc6f29SJisheng Zhang 		dev_err(dev, "Platform data not found!\n");
14038fc6f29SJisheng Zhang 		return -EINVAL;
14138fc6f29SJisheng Zhang 	}
14238fc6f29SJisheng Zhang 
14338fc6f29SJisheng Zhang 	di->en_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
14438fc6f29SJisheng Zhang 	if (IS_ERR(di->en_gpio))
14538fc6f29SJisheng Zhang 		return PTR_ERR(di->en_gpio);
14638fc6f29SJisheng Zhang 
14738fc6f29SJisheng Zhang 	if (of_property_read_bool(np, "silergy,vsel-state-high"))
14838fc6f29SJisheng Zhang 		di->vsel_reg = SY8827N_VSEL1;
14938fc6f29SJisheng Zhang 	else
15038fc6f29SJisheng Zhang 		di->vsel_reg = SY8827N_VSEL0;
15138fc6f29SJisheng Zhang 
15238fc6f29SJisheng Zhang 	di->dev = dev;
15338fc6f29SJisheng Zhang 
15438fc6f29SJisheng Zhang 	regmap = devm_regmap_init_i2c(client, &sy8827n_regmap_config);
15538fc6f29SJisheng Zhang 	if (IS_ERR(regmap)) {
15638fc6f29SJisheng Zhang 		dev_err(dev, "Failed to allocate regmap!\n");
15738fc6f29SJisheng Zhang 		return PTR_ERR(regmap);
15838fc6f29SJisheng Zhang 	}
15938fc6f29SJisheng Zhang 	i2c_set_clientdata(client, di);
16038fc6f29SJisheng Zhang 
16138fc6f29SJisheng Zhang 	config.dev = di->dev;
16238fc6f29SJisheng Zhang 	config.init_data = di->regulator;
16338fc6f29SJisheng Zhang 	config.regmap = regmap;
16438fc6f29SJisheng Zhang 	config.driver_data = di;
16538fc6f29SJisheng Zhang 	config.of_node = np;
16638fc6f29SJisheng Zhang 
16738fc6f29SJisheng Zhang 	ret = sy8827n_regulator_register(di, &config);
16838fc6f29SJisheng Zhang 	if (ret < 0)
16938fc6f29SJisheng Zhang 		dev_err(dev, "Failed to register regulator!\n");
17038fc6f29SJisheng Zhang 	return ret;
17138fc6f29SJisheng Zhang }
17238fc6f29SJisheng Zhang 
17338fc6f29SJisheng Zhang static const struct of_device_id sy8827n_dt_ids[] = {
17438fc6f29SJisheng Zhang 	{
17538fc6f29SJisheng Zhang 		.compatible = "silergy,sy8827n",
17638fc6f29SJisheng Zhang 	},
17738fc6f29SJisheng Zhang 	{ }
17838fc6f29SJisheng Zhang };
17938fc6f29SJisheng Zhang MODULE_DEVICE_TABLE(of, sy8827n_dt_ids);
18038fc6f29SJisheng Zhang 
18138fc6f29SJisheng Zhang static const struct i2c_device_id sy8827n_id[] = {
18238fc6f29SJisheng Zhang 	{ "sy8827n", },
18338fc6f29SJisheng Zhang 	{ },
18438fc6f29SJisheng Zhang };
18538fc6f29SJisheng Zhang MODULE_DEVICE_TABLE(i2c, sy8827n_id);
18638fc6f29SJisheng Zhang 
18738fc6f29SJisheng Zhang static struct i2c_driver sy8827n_regulator_driver = {
18838fc6f29SJisheng Zhang 	.driver = {
18938fc6f29SJisheng Zhang 		.name = "sy8827n-regulator",
19067dc71c6SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
191c4b02c92SJean Delvare 		.of_match_table = sy8827n_dt_ids,
19238fc6f29SJisheng Zhang 	},
193964e1865SUwe Kleine-König 	.probe = sy8827n_i2c_probe,
19438fc6f29SJisheng Zhang 	.id_table = sy8827n_id,
19538fc6f29SJisheng Zhang };
19638fc6f29SJisheng Zhang module_i2c_driver(sy8827n_regulator_driver);
19738fc6f29SJisheng Zhang 
19838fc6f29SJisheng Zhang MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
19938fc6f29SJisheng Zhang MODULE_DESCRIPTION("SY8827N regulator driver");
20038fc6f29SJisheng Zhang MODULE_LICENSE("GPL v2");
201