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