15bbbfc7fSChiYuan Huang // SPDX-License-Identifier: GPL-2.0+
25bbbfc7fSChiYuan Huang 
35bbbfc7fSChiYuan Huang #include <linux/gpio/consumer.h>
45bbbfc7fSChiYuan Huang #include <linux/i2c.h>
55bbbfc7fSChiYuan Huang #include <linux/kernel.h>
65bbbfc7fSChiYuan Huang #include <linux/module.h>
75bbbfc7fSChiYuan Huang #include <linux/of.h>
85bbbfc7fSChiYuan Huang #include <linux/regmap.h>
95bbbfc7fSChiYuan Huang #include <linux/regulator/driver.h>
105bbbfc7fSChiYuan Huang 
115bbbfc7fSChiYuan Huang #define RT4801_REG_VOP	0x00
125bbbfc7fSChiYuan Huang #define RT4801_REG_VON	0x01
135bbbfc7fSChiYuan Huang #define RT4801_REG_APPS	0x03
145bbbfc7fSChiYuan Huang 
155bbbfc7fSChiYuan Huang #define VOUT_MASK	0x1F
165bbbfc7fSChiYuan Huang 
175bbbfc7fSChiYuan Huang #define MIN_UV		4000000
185bbbfc7fSChiYuan Huang #define STEP_UV		100000
195bbbfc7fSChiYuan Huang #define MAX_UV		6000000
205bbbfc7fSChiYuan Huang #define N_VOLTAGES	((MAX_UV - MIN_UV) / STEP_UV + 1)
215bbbfc7fSChiYuan Huang 
225bbbfc7fSChiYuan Huang #define DSV_OUT_POS	0
235bbbfc7fSChiYuan Huang #define DSV_OUT_NEG	1
245bbbfc7fSChiYuan Huang #define DSV_OUT_MAX	2
255bbbfc7fSChiYuan Huang 
265bbbfc7fSChiYuan Huang #define DSVP_ENABLE	BIT(0)
275bbbfc7fSChiYuan Huang #define DSVN_ENABLE	BIT(1)
285bbbfc7fSChiYuan Huang #define DSVALL_ENABLE	(DSVP_ENABLE | DSVN_ENABLE)
295bbbfc7fSChiYuan Huang 
305bbbfc7fSChiYuan Huang struct rt4801_priv {
315bbbfc7fSChiYuan Huang 	struct device *dev;
3269635691SKrzysztof Kozlowski 	struct gpio_desc *enable_gpios[DSV_OUT_MAX];
335bbbfc7fSChiYuan Huang 	unsigned int enable_flag;
345bbbfc7fSChiYuan Huang 	unsigned int volt_sel[DSV_OUT_MAX];
355bbbfc7fSChiYuan Huang };
365bbbfc7fSChiYuan Huang 
rt4801_of_parse_cb(struct device_node * np,const struct regulator_desc * desc,struct regulator_config * config)3769635691SKrzysztof Kozlowski static int rt4801_of_parse_cb(struct device_node *np,
3869635691SKrzysztof Kozlowski 			      const struct regulator_desc *desc,
3969635691SKrzysztof Kozlowski 			      struct regulator_config *config)
4069635691SKrzysztof Kozlowski {
4169635691SKrzysztof Kozlowski 	struct rt4801_priv *priv = config->driver_data;
4269635691SKrzysztof Kozlowski 	int id = desc->id;
4369635691SKrzysztof Kozlowski 
4469635691SKrzysztof Kozlowski 	if (priv->enable_gpios[id]) {
4569635691SKrzysztof Kozlowski 		dev_warn(priv->dev, "duplicated enable-gpios property\n");
4669635691SKrzysztof Kozlowski 		return 0;
4769635691SKrzysztof Kozlowski 	}
4869635691SKrzysztof Kozlowski 	priv->enable_gpios[id] = devm_fwnode_gpiod_get_index(priv->dev,
4969635691SKrzysztof Kozlowski 							     of_fwnode_handle(np),
5069635691SKrzysztof Kozlowski 							     "enable", 0,
5169635691SKrzysztof Kozlowski 							     GPIOD_OUT_HIGH,
5269635691SKrzysztof Kozlowski 							     "rt4801");
5369635691SKrzysztof Kozlowski 	if (IS_ERR(priv->enable_gpios[id]))
5469635691SKrzysztof Kozlowski 		priv->enable_gpios[id] = NULL;
5569635691SKrzysztof Kozlowski 
5669635691SKrzysztof Kozlowski 	return 0;
5769635691SKrzysztof Kozlowski }
5869635691SKrzysztof Kozlowski 
rt4801_set_voltage_sel(struct regulator_dev * rdev,unsigned int selector)595bbbfc7fSChiYuan Huang static int rt4801_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector)
605bbbfc7fSChiYuan Huang {
615bbbfc7fSChiYuan Huang 	struct rt4801_priv *priv = rdev_get_drvdata(rdev);
625bbbfc7fSChiYuan Huang 	int id = rdev_get_id(rdev), ret;
635bbbfc7fSChiYuan Huang 
645bbbfc7fSChiYuan Huang 	if (priv->enable_flag & BIT(id)) {
655bbbfc7fSChiYuan Huang 		ret = regulator_set_voltage_sel_regmap(rdev, selector);
665bbbfc7fSChiYuan Huang 		if (ret)
675bbbfc7fSChiYuan Huang 			return ret;
685bbbfc7fSChiYuan Huang 	}
695bbbfc7fSChiYuan Huang 
705bbbfc7fSChiYuan Huang 	priv->volt_sel[id] = selector;
715bbbfc7fSChiYuan Huang 	return 0;
725bbbfc7fSChiYuan Huang }
735bbbfc7fSChiYuan Huang 
rt4801_get_voltage_sel(struct regulator_dev * rdev)745bbbfc7fSChiYuan Huang static int rt4801_get_voltage_sel(struct regulator_dev *rdev)
755bbbfc7fSChiYuan Huang {
765bbbfc7fSChiYuan Huang 	struct rt4801_priv *priv = rdev_get_drvdata(rdev);
775bbbfc7fSChiYuan Huang 	int id = rdev_get_id(rdev);
785bbbfc7fSChiYuan Huang 
795bbbfc7fSChiYuan Huang 	if (priv->enable_flag & BIT(id))
805bbbfc7fSChiYuan Huang 		return regulator_get_voltage_sel_regmap(rdev);
815bbbfc7fSChiYuan Huang 
825bbbfc7fSChiYuan Huang 	return priv->volt_sel[id];
835bbbfc7fSChiYuan Huang }
845bbbfc7fSChiYuan Huang 
rt4801_enable(struct regulator_dev * rdev)855bbbfc7fSChiYuan Huang static int rt4801_enable(struct regulator_dev *rdev)
865bbbfc7fSChiYuan Huang {
875bbbfc7fSChiYuan Huang 	struct rt4801_priv *priv = rdev_get_drvdata(rdev);
885bbbfc7fSChiYuan Huang 	int id = rdev_get_id(rdev), ret;
895bbbfc7fSChiYuan Huang 
9069635691SKrzysztof Kozlowski 	if (!priv->enable_gpios[id]) {
915bbbfc7fSChiYuan Huang 		dev_warn(&rdev->dev, "no dedicated gpio can control\n");
925bbbfc7fSChiYuan Huang 		goto bypass_gpio;
935bbbfc7fSChiYuan Huang 	}
945bbbfc7fSChiYuan Huang 
9569635691SKrzysztof Kozlowski 	gpiod_set_value(priv->enable_gpios[id], 1);
965bbbfc7fSChiYuan Huang 
975bbbfc7fSChiYuan Huang bypass_gpio:
985bbbfc7fSChiYuan Huang 	ret = regmap_write(rdev->regmap, rdev->desc->vsel_reg, priv->volt_sel[id]);
995bbbfc7fSChiYuan Huang 	if (ret)
1005bbbfc7fSChiYuan Huang 		return ret;
1015bbbfc7fSChiYuan Huang 
1025bbbfc7fSChiYuan Huang 	priv->enable_flag |= BIT(id);
1035bbbfc7fSChiYuan Huang 	return 0;
1045bbbfc7fSChiYuan Huang }
1055bbbfc7fSChiYuan Huang 
rt4801_disable(struct regulator_dev * rdev)1065bbbfc7fSChiYuan Huang static int rt4801_disable(struct regulator_dev *rdev)
1075bbbfc7fSChiYuan Huang {
1085bbbfc7fSChiYuan Huang 	struct rt4801_priv *priv = rdev_get_drvdata(rdev);
1095bbbfc7fSChiYuan Huang 	int id = rdev_get_id(rdev);
1105bbbfc7fSChiYuan Huang 
11169635691SKrzysztof Kozlowski 	if (!priv->enable_gpios[id]) {
1125bbbfc7fSChiYuan Huang 		dev_warn(&rdev->dev, "no dedicated gpio can control\n");
1135bbbfc7fSChiYuan Huang 		goto bypass_gpio;
1145bbbfc7fSChiYuan Huang 	}
1155bbbfc7fSChiYuan Huang 
11669635691SKrzysztof Kozlowski 	gpiod_set_value(priv->enable_gpios[id], 0);
1175bbbfc7fSChiYuan Huang 
1185bbbfc7fSChiYuan Huang bypass_gpio:
1195bbbfc7fSChiYuan Huang 	priv->enable_flag &= ~BIT(id);
1205bbbfc7fSChiYuan Huang 	return 0;
1215bbbfc7fSChiYuan Huang }
1225bbbfc7fSChiYuan Huang 
rt4801_is_enabled(struct regulator_dev * rdev)1235bbbfc7fSChiYuan Huang static int rt4801_is_enabled(struct regulator_dev *rdev)
1245bbbfc7fSChiYuan Huang {
1255bbbfc7fSChiYuan Huang 	struct rt4801_priv *priv = rdev_get_drvdata(rdev);
1265bbbfc7fSChiYuan Huang 	int id = rdev_get_id(rdev);
1275bbbfc7fSChiYuan Huang 
1285bbbfc7fSChiYuan Huang 	return !!(priv->enable_flag & BIT(id));
1295bbbfc7fSChiYuan Huang }
1305bbbfc7fSChiYuan Huang 
1315bbbfc7fSChiYuan Huang static const struct regulator_ops rt4801_regulator_ops = {
1325bbbfc7fSChiYuan Huang 	.list_voltage = regulator_list_voltage_linear,
1335bbbfc7fSChiYuan Huang 	.set_voltage_sel = rt4801_set_voltage_sel,
1345bbbfc7fSChiYuan Huang 	.get_voltage_sel = rt4801_get_voltage_sel,
1355bbbfc7fSChiYuan Huang 	.enable = rt4801_enable,
1365bbbfc7fSChiYuan Huang 	.disable = rt4801_disable,
1375bbbfc7fSChiYuan Huang 	.is_enabled = rt4801_is_enabled,
1385bbbfc7fSChiYuan Huang };
1395bbbfc7fSChiYuan Huang 
1405bbbfc7fSChiYuan Huang static const struct regulator_desc rt4801_regulator_descs[] = {
1415bbbfc7fSChiYuan Huang 	{
1425bbbfc7fSChiYuan Huang 		.name = "DSVP",
1435bbbfc7fSChiYuan Huang 		.ops = &rt4801_regulator_ops,
1445bbbfc7fSChiYuan Huang 		.of_match = of_match_ptr("DSVP"),
14569635691SKrzysztof Kozlowski 		.of_parse_cb = rt4801_of_parse_cb,
1465bbbfc7fSChiYuan Huang 		.type = REGULATOR_VOLTAGE,
1475bbbfc7fSChiYuan Huang 		.id = DSV_OUT_POS,
1485bbbfc7fSChiYuan Huang 		.min_uV = MIN_UV,
1495bbbfc7fSChiYuan Huang 		.uV_step = STEP_UV,
1505bbbfc7fSChiYuan Huang 		.n_voltages = N_VOLTAGES,
1515bbbfc7fSChiYuan Huang 		.owner = THIS_MODULE,
1525bbbfc7fSChiYuan Huang 		.vsel_reg = RT4801_REG_VOP,
1535bbbfc7fSChiYuan Huang 		.vsel_mask = VOUT_MASK,
1545bbbfc7fSChiYuan Huang 	},
1555bbbfc7fSChiYuan Huang 	{
1565bbbfc7fSChiYuan Huang 		.name = "DSVN",
1575bbbfc7fSChiYuan Huang 		.ops = &rt4801_regulator_ops,
1585bbbfc7fSChiYuan Huang 		.of_match = of_match_ptr("DSVN"),
15969635691SKrzysztof Kozlowski 		.of_parse_cb = rt4801_of_parse_cb,
1605bbbfc7fSChiYuan Huang 		.type = REGULATOR_VOLTAGE,
1615bbbfc7fSChiYuan Huang 		.id = DSV_OUT_NEG,
1625bbbfc7fSChiYuan Huang 		.min_uV = MIN_UV,
1635bbbfc7fSChiYuan Huang 		.uV_step = STEP_UV,
1645bbbfc7fSChiYuan Huang 		.n_voltages = N_VOLTAGES,
1655bbbfc7fSChiYuan Huang 		.owner = THIS_MODULE,
1665bbbfc7fSChiYuan Huang 		.vsel_reg = RT4801_REG_VON,
1675bbbfc7fSChiYuan Huang 		.vsel_mask = VOUT_MASK,
1685bbbfc7fSChiYuan Huang 	},
1695bbbfc7fSChiYuan Huang };
1705bbbfc7fSChiYuan Huang 
1715bbbfc7fSChiYuan Huang static const struct regmap_config rt4801_regmap_config = {
1725bbbfc7fSChiYuan Huang 	.reg_bits = 8,
1735bbbfc7fSChiYuan Huang 	.val_bits = 8,
1745bbbfc7fSChiYuan Huang 	.max_register = RT4801_REG_APPS,
1755bbbfc7fSChiYuan Huang };
1765bbbfc7fSChiYuan Huang 
rt4801_probe(struct i2c_client * i2c)1775bbbfc7fSChiYuan Huang static int rt4801_probe(struct i2c_client *i2c)
1785bbbfc7fSChiYuan Huang {
1795bbbfc7fSChiYuan Huang 	struct rt4801_priv *priv;
1805bbbfc7fSChiYuan Huang 	struct regmap *regmap;
1815bbbfc7fSChiYuan Huang 	int i;
1825bbbfc7fSChiYuan Huang 
1835bbbfc7fSChiYuan Huang 	priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
1845bbbfc7fSChiYuan Huang 	if (!priv)
1855bbbfc7fSChiYuan Huang 		return -ENOMEM;
1865bbbfc7fSChiYuan Huang 
1875bbbfc7fSChiYuan Huang 	priv->dev = &i2c->dev;
1885bbbfc7fSChiYuan Huang 	/* bootloader will on, driver only reconfigure enable to all output high */
1895bbbfc7fSChiYuan Huang 	priv->enable_flag = DSVALL_ENABLE;
1905bbbfc7fSChiYuan Huang 
1915bbbfc7fSChiYuan Huang 	regmap = devm_regmap_init_i2c(i2c, &rt4801_regmap_config);
1925bbbfc7fSChiYuan Huang 	if (IS_ERR(regmap)) {
1935bbbfc7fSChiYuan Huang 		dev_err(&i2c->dev, "Failed to init regmap\n");
1945bbbfc7fSChiYuan Huang 		return PTR_ERR(regmap);
1955bbbfc7fSChiYuan Huang 	}
1965bbbfc7fSChiYuan Huang 
19769635691SKrzysztof Kozlowski 	for (i = 0; i < DSV_OUT_MAX; i++) {
19869635691SKrzysztof Kozlowski 		priv->enable_gpios[i] = devm_gpiod_get_index_optional(&i2c->dev,
19969635691SKrzysztof Kozlowski 								      "enable",
20069635691SKrzysztof Kozlowski 								      i,
20169635691SKrzysztof Kozlowski 								      GPIOD_OUT_HIGH);
20269635691SKrzysztof Kozlowski 		if (IS_ERR(priv->enable_gpios[i])) {
2035bbbfc7fSChiYuan Huang 			dev_err(&i2c->dev, "Failed to get gpios\n");
20469635691SKrzysztof Kozlowski 			return PTR_ERR(priv->enable_gpios[i]);
20569635691SKrzysztof Kozlowski 		}
2065bbbfc7fSChiYuan Huang 	}
2075bbbfc7fSChiYuan Huang 
2085bbbfc7fSChiYuan Huang 	for (i = 0; i < DSV_OUT_MAX; i++) {
2095bbbfc7fSChiYuan Huang 		const struct regulator_desc *desc = rt4801_regulator_descs + i;
2105bbbfc7fSChiYuan Huang 		struct regulator_config config = { .dev = &i2c->dev, .driver_data = priv,
2115bbbfc7fSChiYuan Huang 						   .regmap = regmap, };
2125bbbfc7fSChiYuan Huang 		struct regulator_dev *rdev;
2135bbbfc7fSChiYuan Huang 		unsigned int val;
2145bbbfc7fSChiYuan Huang 		int ret;
2155bbbfc7fSChiYuan Huang 
2165bbbfc7fSChiYuan Huang 		/* initialize volt_sel variable */
2175bbbfc7fSChiYuan Huang 		ret = regmap_read(regmap, desc->vsel_reg, &val);
2185bbbfc7fSChiYuan Huang 		if (ret)
2195bbbfc7fSChiYuan Huang 			return ret;
2205bbbfc7fSChiYuan Huang 
2215bbbfc7fSChiYuan Huang 		priv->volt_sel[i] = val & desc->vsel_mask;
2225bbbfc7fSChiYuan Huang 
2235bbbfc7fSChiYuan Huang 		rdev = devm_regulator_register(&i2c->dev, desc, &config);
2245bbbfc7fSChiYuan Huang 		if (IS_ERR(rdev)) {
2255bbbfc7fSChiYuan Huang 			dev_err(&i2c->dev, "Failed to register [%d] regulator\n", i);
2265bbbfc7fSChiYuan Huang 			return PTR_ERR(rdev);
2275bbbfc7fSChiYuan Huang 		}
2285bbbfc7fSChiYuan Huang 	}
2295bbbfc7fSChiYuan Huang 
2305bbbfc7fSChiYuan Huang 	return 0;
2315bbbfc7fSChiYuan Huang }
2325bbbfc7fSChiYuan Huang 
233c8b2c894SChiYuan Huang static const struct of_device_id __maybe_unused rt4801_of_id[] = {
2345bbbfc7fSChiYuan Huang 	{ .compatible = "richtek,rt4801", },
2355bbbfc7fSChiYuan Huang 	{ },
2365bbbfc7fSChiYuan Huang };
2375bbbfc7fSChiYuan Huang MODULE_DEVICE_TABLE(of, rt4801_of_id);
2385bbbfc7fSChiYuan Huang 
2395bbbfc7fSChiYuan Huang static struct i2c_driver rt4801_driver = {
2405bbbfc7fSChiYuan Huang 	.driver = {
2415bbbfc7fSChiYuan Huang 		.name = "rt4801",
24267dc71c6SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
2435bbbfc7fSChiYuan Huang 		.of_match_table = of_match_ptr(rt4801_of_id),
2445bbbfc7fSChiYuan Huang 	},
245*964e1865SUwe Kleine-König 	.probe = rt4801_probe,
2465bbbfc7fSChiYuan Huang };
2475bbbfc7fSChiYuan Huang module_i2c_driver(rt4801_driver);
2485bbbfc7fSChiYuan Huang 
2495bbbfc7fSChiYuan Huang MODULE_AUTHOR("ChiYuan Hwang <cy_huang@richtek.com>");
2505bbbfc7fSChiYuan Huang MODULE_DESCRIPTION("Richtek RT4801 Display Bias Driver");
2515bbbfc7fSChiYuan Huang MODULE_LICENSE("GPL v2");
252