xref: /openbmc/linux/drivers/regulator/sy8827n.c (revision 38fc6f29)
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>
1238fc6f29SJisheng Zhang #include <linux/of_device.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
2238fc6f29SJisheng Zhang 
2338fc6f29SJisheng Zhang #define SY8827N_NVOLTAGES	64
2438fc6f29SJisheng Zhang #define SY8827N_VSELMIN		600000
2538fc6f29SJisheng Zhang #define SY8827N_VSELSTEP	12500
2638fc6f29SJisheng Zhang 
2738fc6f29SJisheng Zhang struct sy8827n_device_info {
2838fc6f29SJisheng Zhang 	struct device *dev;
2938fc6f29SJisheng Zhang 	struct regulator_desc desc;
3038fc6f29SJisheng Zhang 	struct regulator_init_data *regulator;
3138fc6f29SJisheng Zhang 	struct gpio_desc *en_gpio;
3238fc6f29SJisheng Zhang 	unsigned int vsel_reg;
3338fc6f29SJisheng Zhang };
3438fc6f29SJisheng Zhang 
3538fc6f29SJisheng Zhang static int sy8827n_set_mode(struct regulator_dev *rdev, unsigned int mode)
3638fc6f29SJisheng Zhang {
3738fc6f29SJisheng Zhang 	struct sy8827n_device_info *di = rdev_get_drvdata(rdev);
3838fc6f29SJisheng Zhang 
3938fc6f29SJisheng Zhang 	switch (mode) {
4038fc6f29SJisheng Zhang 	case REGULATOR_MODE_FAST:
4138fc6f29SJisheng Zhang 		regmap_update_bits(rdev->regmap, di->vsel_reg,
4238fc6f29SJisheng Zhang 				   SY8827N_MODE, SY8827N_MODE);
4338fc6f29SJisheng Zhang 		break;
4438fc6f29SJisheng Zhang 	case REGULATOR_MODE_NORMAL:
4538fc6f29SJisheng Zhang 		regmap_update_bits(rdev->regmap, di->vsel_reg,
4638fc6f29SJisheng Zhang 				   SY8827N_MODE, 0);
4738fc6f29SJisheng Zhang 		break;
4838fc6f29SJisheng Zhang 	default:
4938fc6f29SJisheng Zhang 		return -EINVAL;
5038fc6f29SJisheng Zhang 	}
5138fc6f29SJisheng Zhang 	return 0;
5238fc6f29SJisheng Zhang }
5338fc6f29SJisheng Zhang 
5438fc6f29SJisheng Zhang static unsigned int sy8827n_get_mode(struct regulator_dev *rdev)
5538fc6f29SJisheng Zhang {
5638fc6f29SJisheng Zhang 	struct sy8827n_device_info *di = rdev_get_drvdata(rdev);
5738fc6f29SJisheng Zhang 	u32 val;
5838fc6f29SJisheng Zhang 	int ret = 0;
5938fc6f29SJisheng Zhang 
6038fc6f29SJisheng Zhang 	ret = regmap_read(rdev->regmap, di->vsel_reg, &val);
6138fc6f29SJisheng Zhang 	if (ret < 0)
6238fc6f29SJisheng Zhang 		return ret;
6338fc6f29SJisheng Zhang 	if (val & SY8827N_MODE)
6438fc6f29SJisheng Zhang 		return REGULATOR_MODE_FAST;
6538fc6f29SJisheng Zhang 	else
6638fc6f29SJisheng Zhang 		return REGULATOR_MODE_NORMAL;
6738fc6f29SJisheng Zhang }
6838fc6f29SJisheng Zhang 
6938fc6f29SJisheng Zhang static const struct regulator_ops sy8827n_regulator_ops = {
7038fc6f29SJisheng Zhang 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
7138fc6f29SJisheng Zhang 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
7238fc6f29SJisheng Zhang 	.set_voltage_time_sel = regulator_set_voltage_time_sel,
7338fc6f29SJisheng Zhang 	.map_voltage = regulator_map_voltage_linear,
7438fc6f29SJisheng Zhang 	.list_voltage = regulator_list_voltage_linear,
7538fc6f29SJisheng Zhang 	.enable = regulator_enable_regmap,
7638fc6f29SJisheng Zhang 	.disable = regulator_disable_regmap,
7738fc6f29SJisheng Zhang 	.is_enabled = regulator_is_enabled_regmap,
7838fc6f29SJisheng Zhang 	.set_mode = sy8827n_set_mode,
7938fc6f29SJisheng Zhang 	.get_mode = sy8827n_get_mode,
8038fc6f29SJisheng Zhang };
8138fc6f29SJisheng Zhang 
8238fc6f29SJisheng Zhang static int sy8827n_regulator_register(struct sy8827n_device_info *di,
8338fc6f29SJisheng Zhang 			struct regulator_config *config)
8438fc6f29SJisheng Zhang {
8538fc6f29SJisheng Zhang 	struct regulator_desc *rdesc = &di->desc;
8638fc6f29SJisheng Zhang 	struct regulator_dev *rdev;
8738fc6f29SJisheng Zhang 
8838fc6f29SJisheng Zhang 	rdesc->name = "sy8827n-reg";
8938fc6f29SJisheng Zhang 	rdesc->supply_name = "vin";
9038fc6f29SJisheng Zhang 	rdesc->ops = &sy8827n_regulator_ops;
9138fc6f29SJisheng Zhang 	rdesc->type = REGULATOR_VOLTAGE;
9238fc6f29SJisheng Zhang 	rdesc->n_voltages = SY8827N_NVOLTAGES;
9338fc6f29SJisheng Zhang 	rdesc->enable_reg = di->vsel_reg;
9438fc6f29SJisheng Zhang 	rdesc->enable_mask = SY8827N_BUCK_EN;
9538fc6f29SJisheng Zhang 	rdesc->min_uV = SY8827N_VSELMIN;
9638fc6f29SJisheng Zhang 	rdesc->uV_step = SY8827N_VSELSTEP;
9738fc6f29SJisheng Zhang 	rdesc->vsel_reg = di->vsel_reg;
9838fc6f29SJisheng Zhang 	rdesc->vsel_mask = rdesc->n_voltages - 1;
9938fc6f29SJisheng Zhang 	rdesc->owner = THIS_MODULE;
10038fc6f29SJisheng Zhang 
10138fc6f29SJisheng Zhang 	rdev = devm_regulator_register(di->dev, &di->desc, config);
10238fc6f29SJisheng Zhang 	return PTR_ERR_OR_ZERO(rdev);
10338fc6f29SJisheng Zhang }
10438fc6f29SJisheng Zhang 
10538fc6f29SJisheng Zhang static const struct regmap_config sy8827n_regmap_config = {
10638fc6f29SJisheng Zhang 	.reg_bits = 8,
10738fc6f29SJisheng Zhang 	.val_bits = 8,
10838fc6f29SJisheng Zhang };
10938fc6f29SJisheng Zhang 
11038fc6f29SJisheng Zhang static int sy8827n_i2c_probe(struct i2c_client *client)
11138fc6f29SJisheng Zhang {
11238fc6f29SJisheng Zhang 	struct device *dev = &client->dev;
11338fc6f29SJisheng Zhang 	struct device_node *np = dev->of_node;
11438fc6f29SJisheng Zhang 	struct sy8827n_device_info *di;
11538fc6f29SJisheng Zhang 	struct regulator_config config = { };
11638fc6f29SJisheng Zhang 	struct regmap *regmap;
11738fc6f29SJisheng Zhang 	int ret;
11838fc6f29SJisheng Zhang 
11938fc6f29SJisheng Zhang 	di = devm_kzalloc(dev, sizeof(struct sy8827n_device_info), GFP_KERNEL);
12038fc6f29SJisheng Zhang 	if (!di)
12138fc6f29SJisheng Zhang 		return -ENOMEM;
12238fc6f29SJisheng Zhang 
12338fc6f29SJisheng Zhang 	di->regulator = of_get_regulator_init_data(dev, np, &di->desc);
12438fc6f29SJisheng Zhang 	if (!di->regulator) {
12538fc6f29SJisheng Zhang 		dev_err(dev, "Platform data not found!\n");
12638fc6f29SJisheng Zhang 		return -EINVAL;
12738fc6f29SJisheng Zhang 	}
12838fc6f29SJisheng Zhang 
12938fc6f29SJisheng Zhang 	di->en_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
13038fc6f29SJisheng Zhang 	if (IS_ERR(di->en_gpio))
13138fc6f29SJisheng Zhang 		return PTR_ERR(di->en_gpio);
13238fc6f29SJisheng Zhang 
13338fc6f29SJisheng Zhang 	if (of_property_read_bool(np, "silergy,vsel-state-high"))
13438fc6f29SJisheng Zhang 		di->vsel_reg = SY8827N_VSEL1;
13538fc6f29SJisheng Zhang 	else
13638fc6f29SJisheng Zhang 		di->vsel_reg = SY8827N_VSEL0;
13738fc6f29SJisheng Zhang 
13838fc6f29SJisheng Zhang 	di->dev = dev;
13938fc6f29SJisheng Zhang 
14038fc6f29SJisheng Zhang 	regmap = devm_regmap_init_i2c(client, &sy8827n_regmap_config);
14138fc6f29SJisheng Zhang 	if (IS_ERR(regmap)) {
14238fc6f29SJisheng Zhang 		dev_err(dev, "Failed to allocate regmap!\n");
14338fc6f29SJisheng Zhang 		return PTR_ERR(regmap);
14438fc6f29SJisheng Zhang 	}
14538fc6f29SJisheng Zhang 	i2c_set_clientdata(client, di);
14638fc6f29SJisheng Zhang 
14738fc6f29SJisheng Zhang 	config.dev = di->dev;
14838fc6f29SJisheng Zhang 	config.init_data = di->regulator;
14938fc6f29SJisheng Zhang 	config.regmap = regmap;
15038fc6f29SJisheng Zhang 	config.driver_data = di;
15138fc6f29SJisheng Zhang 	config.of_node = np;
15238fc6f29SJisheng Zhang 
15338fc6f29SJisheng Zhang 	ret = sy8827n_regulator_register(di, &config);
15438fc6f29SJisheng Zhang 	if (ret < 0)
15538fc6f29SJisheng Zhang 		dev_err(dev, "Failed to register regulator!\n");
15638fc6f29SJisheng Zhang 	return ret;
15738fc6f29SJisheng Zhang }
15838fc6f29SJisheng Zhang 
15938fc6f29SJisheng Zhang static const struct of_device_id sy8827n_dt_ids[] = {
16038fc6f29SJisheng Zhang 	{
16138fc6f29SJisheng Zhang 		.compatible = "silergy,sy8827n",
16238fc6f29SJisheng Zhang 	},
16338fc6f29SJisheng Zhang 	{ }
16438fc6f29SJisheng Zhang };
16538fc6f29SJisheng Zhang MODULE_DEVICE_TABLE(of, sy8827n_dt_ids);
16638fc6f29SJisheng Zhang 
16738fc6f29SJisheng Zhang static const struct i2c_device_id sy8827n_id[] = {
16838fc6f29SJisheng Zhang 	{ "sy8827n", },
16938fc6f29SJisheng Zhang 	{ },
17038fc6f29SJisheng Zhang };
17138fc6f29SJisheng Zhang MODULE_DEVICE_TABLE(i2c, sy8827n_id);
17238fc6f29SJisheng Zhang 
17338fc6f29SJisheng Zhang static struct i2c_driver sy8827n_regulator_driver = {
17438fc6f29SJisheng Zhang 	.driver = {
17538fc6f29SJisheng Zhang 		.name = "sy8827n-regulator",
17638fc6f29SJisheng Zhang 		.of_match_table = of_match_ptr(sy8827n_dt_ids),
17738fc6f29SJisheng Zhang 	},
17838fc6f29SJisheng Zhang 	.probe_new = sy8827n_i2c_probe,
17938fc6f29SJisheng Zhang 	.id_table = sy8827n_id,
18038fc6f29SJisheng Zhang };
18138fc6f29SJisheng Zhang module_i2c_driver(sy8827n_regulator_driver);
18238fc6f29SJisheng Zhang 
18338fc6f29SJisheng Zhang MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
18438fc6f29SJisheng Zhang MODULE_DESCRIPTION("SY8827N regulator driver");
18538fc6f29SJisheng Zhang MODULE_LICENSE("GPL v2");
186