xref: /openbmc/linux/drivers/regulator/rt5739.c (revision 6f5e2858)
14536f3b9SChiYuan Huang // SPDX-License-Identifier: GPL-2.0-only
24536f3b9SChiYuan Huang /*
34536f3b9SChiYuan Huang  * Device driver for RT5739 regulator
44536f3b9SChiYuan Huang  *
54536f3b9SChiYuan Huang  * Copyright (C) 2023 Richtek Technology Corp.
64536f3b9SChiYuan Huang  *
74536f3b9SChiYuan Huang  * Author: ChiYuan Huang <cy_huang@richtek.com>
84536f3b9SChiYuan Huang  */
94536f3b9SChiYuan Huang 
104536f3b9SChiYuan Huang #include <linux/bits.h>
114536f3b9SChiYuan Huang #include <linux/gpio/consumer.h>
124536f3b9SChiYuan Huang #include <linux/i2c.h>
134536f3b9SChiYuan Huang #include <linux/kernel.h>
144536f3b9SChiYuan Huang #include <linux/mod_devicetable.h>
154536f3b9SChiYuan Huang #include <linux/property.h>
164536f3b9SChiYuan Huang #include <linux/regmap.h>
174536f3b9SChiYuan Huang #include <linux/regulator/driver.h>
184536f3b9SChiYuan Huang #include <linux/regulator/of_regulator.h>
194536f3b9SChiYuan Huang 
204536f3b9SChiYuan Huang #define RT5739_AUTO_MODE	0
214536f3b9SChiYuan Huang #define RT5739_FPWM_MODE	1
224536f3b9SChiYuan Huang 
234536f3b9SChiYuan Huang #define RT5739_REG_NSEL0	0x00
244536f3b9SChiYuan Huang #define RT5739_REG_NSEL1	0x01
254536f3b9SChiYuan Huang #define RT5739_REG_CNTL1	0x02
264536f3b9SChiYuan Huang #define RT5739_REG_ID1		0x03
274536f3b9SChiYuan Huang #define RT5739_REG_CNTL2	0x06
284536f3b9SChiYuan Huang #define RT5739_REG_CNTL4	0x08
294536f3b9SChiYuan Huang 
304536f3b9SChiYuan Huang #define RT5739_VSEL_MASK	GENMASK(7, 0)
314536f3b9SChiYuan Huang #define RT5739_MODEVSEL1_MASK	BIT(1)
324536f3b9SChiYuan Huang #define RT5739_MODEVSEL0_MASK	BIT(0)
334536f3b9SChiYuan Huang #define RT5739_VID_MASK		GENMASK(7, 5)
34*6f5e2858SChiYuan Huang #define RT5739_DID_MASK		GENMASK(3, 0)
354536f3b9SChiYuan Huang #define RT5739_ACTD_MASK	BIT(7)
364536f3b9SChiYuan Huang #define RT5739_ENVSEL1_MASK	BIT(1)
374536f3b9SChiYuan Huang #define RT5739_ENVSEL0_MASK	BIT(0)
384536f3b9SChiYuan Huang 
39*6f5e2858SChiYuan Huang #define RT5733_CHIPDIE_ID	0x1
40*6f5e2858SChiYuan Huang #define RT5733_VOLT_MINUV	270000
41*6f5e2858SChiYuan Huang #define RT5733_VOLT_MAXUV	1401250
42*6f5e2858SChiYuan Huang #define RT5733_VOLT_STPUV	6250
43*6f5e2858SChiYuan Huang #define RT5733_N_VOLTS		182
44*6f5e2858SChiYuan Huang 
454536f3b9SChiYuan Huang #define RT5739_VOLT_MINUV	300000
464536f3b9SChiYuan Huang #define RT5739_VOLT_MAXUV	1300000
474536f3b9SChiYuan Huang #define RT5739_VOLT_STPUV	5000
484536f3b9SChiYuan Huang #define RT5739_N_VOLTS		201
494536f3b9SChiYuan Huang #define RT5739_I2CRDY_TIMEUS	1000
504536f3b9SChiYuan Huang 
rt5739_set_mode(struct regulator_dev * rdev,unsigned int mode)514536f3b9SChiYuan Huang static int rt5739_set_mode(struct regulator_dev *rdev, unsigned int mode)
524536f3b9SChiYuan Huang {
534536f3b9SChiYuan Huang 	const struct regulator_desc *desc = rdev->desc;
544536f3b9SChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
554536f3b9SChiYuan Huang 	unsigned int mask, val;
564536f3b9SChiYuan Huang 
574536f3b9SChiYuan Huang 	if (desc->vsel_reg == RT5739_REG_NSEL0)
584536f3b9SChiYuan Huang 		mask = RT5739_MODEVSEL0_MASK;
594536f3b9SChiYuan Huang 	else
604536f3b9SChiYuan Huang 		mask = RT5739_MODEVSEL1_MASK;
614536f3b9SChiYuan Huang 
624536f3b9SChiYuan Huang 	switch (mode) {
634536f3b9SChiYuan Huang 	case REGULATOR_MODE_FAST:
644536f3b9SChiYuan Huang 		val = mask;
654536f3b9SChiYuan Huang 		break;
664536f3b9SChiYuan Huang 	case REGULATOR_MODE_NORMAL:
674536f3b9SChiYuan Huang 		val = 0;
684536f3b9SChiYuan Huang 		break;
694536f3b9SChiYuan Huang 	default:
704536f3b9SChiYuan Huang 		return -EINVAL;
714536f3b9SChiYuan Huang 	}
724536f3b9SChiYuan Huang 
734536f3b9SChiYuan Huang 	return regmap_update_bits(regmap, RT5739_REG_CNTL1, mask, val);
744536f3b9SChiYuan Huang }
754536f3b9SChiYuan Huang 
rt5739_get_mode(struct regulator_dev * rdev)764536f3b9SChiYuan Huang static unsigned int rt5739_get_mode(struct regulator_dev *rdev)
774536f3b9SChiYuan Huang {
784536f3b9SChiYuan Huang 	const struct regulator_desc *desc = rdev->desc;
794536f3b9SChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
804536f3b9SChiYuan Huang 	unsigned int mask, val;
814536f3b9SChiYuan Huang 	int ret;
824536f3b9SChiYuan Huang 
834536f3b9SChiYuan Huang 	if (desc->vsel_reg == RT5739_REG_NSEL0)
844536f3b9SChiYuan Huang 		mask = RT5739_MODEVSEL0_MASK;
854536f3b9SChiYuan Huang 	else
864536f3b9SChiYuan Huang 		mask = RT5739_MODEVSEL1_MASK;
874536f3b9SChiYuan Huang 
884536f3b9SChiYuan Huang 	ret = regmap_read(regmap, RT5739_REG_CNTL1, &val);
894536f3b9SChiYuan Huang 	if (ret)
904536f3b9SChiYuan Huang 		return REGULATOR_MODE_INVALID;
914536f3b9SChiYuan Huang 
924536f3b9SChiYuan Huang 	if (val & mask)
934536f3b9SChiYuan Huang 		return REGULATOR_MODE_FAST;
944536f3b9SChiYuan Huang 
954536f3b9SChiYuan Huang 	return REGULATOR_MODE_NORMAL;
964536f3b9SChiYuan Huang }
974536f3b9SChiYuan Huang 
rt5739_set_suspend_voltage(struct regulator_dev * rdev,int uV)984536f3b9SChiYuan Huang static int rt5739_set_suspend_voltage(struct regulator_dev *rdev, int uV)
994536f3b9SChiYuan Huang {
1004536f3b9SChiYuan Huang 	const struct regulator_desc *desc = rdev->desc;
1014536f3b9SChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
1024536f3b9SChiYuan Huang 	unsigned int reg, vsel;
103*6f5e2858SChiYuan Huang 	int max_uV;
1044536f3b9SChiYuan Huang 
105*6f5e2858SChiYuan Huang 	max_uV = desc->min_uV + desc->uV_step * (desc->n_voltages - 1);
106*6f5e2858SChiYuan Huang 
107*6f5e2858SChiYuan Huang 	if (uV < desc->min_uV || uV > max_uV)
1084536f3b9SChiYuan Huang 		return -EINVAL;
1094536f3b9SChiYuan Huang 
1104536f3b9SChiYuan Huang 	if (desc->vsel_reg == RT5739_REG_NSEL0)
1114536f3b9SChiYuan Huang 		reg = RT5739_REG_NSEL1;
1124536f3b9SChiYuan Huang 	else
1134536f3b9SChiYuan Huang 		reg = RT5739_REG_NSEL0;
1144536f3b9SChiYuan Huang 
115*6f5e2858SChiYuan Huang 	vsel = (uV - desc->min_uV) / desc->uV_step;
1164536f3b9SChiYuan Huang 	return regmap_write(regmap, reg, vsel);
1174536f3b9SChiYuan Huang }
1184536f3b9SChiYuan Huang 
rt5739_set_suspend_enable(struct regulator_dev * rdev)1194536f3b9SChiYuan Huang static int rt5739_set_suspend_enable(struct regulator_dev *rdev)
1204536f3b9SChiYuan Huang {
1214536f3b9SChiYuan Huang 	const struct regulator_desc *desc = rdev->desc;
1224536f3b9SChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
1234536f3b9SChiYuan Huang 	unsigned int mask;
1244536f3b9SChiYuan Huang 
1254536f3b9SChiYuan Huang 	if (desc->vsel_reg == RT5739_REG_NSEL0)
1264536f3b9SChiYuan Huang 		mask = RT5739_ENVSEL1_MASK;
1274536f3b9SChiYuan Huang 	else
1284536f3b9SChiYuan Huang 		mask = RT5739_ENVSEL0_MASK;
1294536f3b9SChiYuan Huang 
1304536f3b9SChiYuan Huang 	return regmap_update_bits(regmap, desc->enable_reg, mask, mask);
1314536f3b9SChiYuan Huang }
1324536f3b9SChiYuan Huang 
rt5739_set_suspend_disable(struct regulator_dev * rdev)1334536f3b9SChiYuan Huang static int rt5739_set_suspend_disable(struct regulator_dev *rdev)
1344536f3b9SChiYuan Huang {
1354536f3b9SChiYuan Huang 	const struct regulator_desc *desc = rdev->desc;
1364536f3b9SChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
1374536f3b9SChiYuan Huang 	unsigned int mask;
1384536f3b9SChiYuan Huang 
1394536f3b9SChiYuan Huang 	if (desc->vsel_reg == RT5739_REG_NSEL0)
1404536f3b9SChiYuan Huang 		mask = RT5739_ENVSEL1_MASK;
1414536f3b9SChiYuan Huang 	else
1424536f3b9SChiYuan Huang 		mask = RT5739_ENVSEL0_MASK;
1434536f3b9SChiYuan Huang 
1444536f3b9SChiYuan Huang 	return regmap_update_bits(regmap, desc->enable_reg, mask, 0);
1454536f3b9SChiYuan Huang }
1464536f3b9SChiYuan Huang 
rt5739_set_suspend_mode(struct regulator_dev * rdev,unsigned int mode)1474536f3b9SChiYuan Huang static int rt5739_set_suspend_mode(struct regulator_dev *rdev,
1484536f3b9SChiYuan Huang 				   unsigned int mode)
1494536f3b9SChiYuan Huang {
1504536f3b9SChiYuan Huang 	const struct regulator_desc *desc = rdev->desc;
1514536f3b9SChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
1524536f3b9SChiYuan Huang 	unsigned int mask, val;
1534536f3b9SChiYuan Huang 
1544536f3b9SChiYuan Huang 	if (desc->vsel_reg == RT5739_REG_NSEL0)
1554536f3b9SChiYuan Huang 		mask = RT5739_MODEVSEL1_MASK;
1564536f3b9SChiYuan Huang 	else
1574536f3b9SChiYuan Huang 		mask = RT5739_MODEVSEL0_MASK;
1584536f3b9SChiYuan Huang 
1594536f3b9SChiYuan Huang 	switch (mode) {
1604536f3b9SChiYuan Huang 	case REGULATOR_MODE_FAST:
1614536f3b9SChiYuan Huang 		val = mask;
1624536f3b9SChiYuan Huang 		break;
1634536f3b9SChiYuan Huang 	case REGULATOR_MODE_NORMAL:
1644536f3b9SChiYuan Huang 		val = 0;
1654536f3b9SChiYuan Huang 		break;
1664536f3b9SChiYuan Huang 	default:
1674536f3b9SChiYuan Huang 		return -EINVAL;
1684536f3b9SChiYuan Huang 	}
1694536f3b9SChiYuan Huang 
1704536f3b9SChiYuan Huang 	return regmap_update_bits(regmap, RT5739_REG_CNTL1, mask, val);
1714536f3b9SChiYuan Huang }
1724536f3b9SChiYuan Huang 
1734536f3b9SChiYuan Huang static const struct regulator_ops rt5739_regulator_ops = {
1744536f3b9SChiYuan Huang 	.list_voltage = regulator_list_voltage_linear,
1754536f3b9SChiYuan Huang 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
1764536f3b9SChiYuan Huang 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
1774536f3b9SChiYuan Huang 	.enable	= regulator_enable_regmap,
1784536f3b9SChiYuan Huang 	.disable = regulator_disable_regmap,
1794536f3b9SChiYuan Huang 	.is_enabled = regulator_is_enabled_regmap,
1804536f3b9SChiYuan Huang 	.set_active_discharge = regulator_set_active_discharge_regmap,
1814536f3b9SChiYuan Huang 	.set_mode = rt5739_set_mode,
1824536f3b9SChiYuan Huang 	.get_mode = rt5739_get_mode,
1834536f3b9SChiYuan Huang 	.set_suspend_voltage = rt5739_set_suspend_voltage,
1844536f3b9SChiYuan Huang 	.set_suspend_enable = rt5739_set_suspend_enable,
1854536f3b9SChiYuan Huang 	.set_suspend_disable = rt5739_set_suspend_disable,
1864536f3b9SChiYuan Huang 	.set_suspend_mode = rt5739_set_suspend_mode,
1874536f3b9SChiYuan Huang };
1884536f3b9SChiYuan Huang 
rt5739_of_map_mode(unsigned int mode)1894536f3b9SChiYuan Huang static unsigned int rt5739_of_map_mode(unsigned int mode)
1904536f3b9SChiYuan Huang {
1914536f3b9SChiYuan Huang 	switch (mode) {
1924536f3b9SChiYuan Huang 	case RT5739_AUTO_MODE:
1934536f3b9SChiYuan Huang 		return REGULATOR_MODE_NORMAL;
1944536f3b9SChiYuan Huang 	case RT5739_FPWM_MODE:
1954536f3b9SChiYuan Huang 		return REGULATOR_MODE_FAST;
1964536f3b9SChiYuan Huang 	default:
1974536f3b9SChiYuan Huang 		return REGULATOR_MODE_INVALID;
1984536f3b9SChiYuan Huang 	}
1994536f3b9SChiYuan Huang }
2004536f3b9SChiYuan Huang 
rt5739_init_regulator_desc(struct regulator_desc * desc,bool vsel_active_high,u8 did)2014536f3b9SChiYuan Huang static void rt5739_init_regulator_desc(struct regulator_desc *desc,
202*6f5e2858SChiYuan Huang 				       bool vsel_active_high, u8 did)
2034536f3b9SChiYuan Huang {
2044536f3b9SChiYuan Huang 	/* Fixed */
2054536f3b9SChiYuan Huang 	desc->name = "rt5739-regulator";
2064536f3b9SChiYuan Huang 	desc->owner = THIS_MODULE;
2074536f3b9SChiYuan Huang 	desc->ops = &rt5739_regulator_ops;
2084536f3b9SChiYuan Huang 	desc->vsel_mask = RT5739_VSEL_MASK;
2094536f3b9SChiYuan Huang 	desc->enable_reg = RT5739_REG_CNTL2;
2104536f3b9SChiYuan Huang 	desc->active_discharge_reg = RT5739_REG_CNTL1;
2114536f3b9SChiYuan Huang 	desc->active_discharge_mask = RT5739_ACTD_MASK;
2124536f3b9SChiYuan Huang 	desc->active_discharge_on = RT5739_ACTD_MASK;
2134536f3b9SChiYuan Huang 	desc->of_map_mode = rt5739_of_map_mode;
2144536f3b9SChiYuan Huang 
2154536f3b9SChiYuan Huang 	/* Assigned by vsel level */
2164536f3b9SChiYuan Huang 	if (vsel_active_high) {
2174536f3b9SChiYuan Huang 		desc->vsel_reg = RT5739_REG_NSEL1;
2184536f3b9SChiYuan Huang 		desc->enable_mask = RT5739_ENVSEL1_MASK;
2194536f3b9SChiYuan Huang 	} else {
2204536f3b9SChiYuan Huang 		desc->vsel_reg = RT5739_REG_NSEL0;
2214536f3b9SChiYuan Huang 		desc->enable_mask = RT5739_ENVSEL0_MASK;
2224536f3b9SChiYuan Huang 	}
223*6f5e2858SChiYuan Huang 
224*6f5e2858SChiYuan Huang 	/* Assigned by CHIPDIE ID */
225*6f5e2858SChiYuan Huang 	switch (did) {
226*6f5e2858SChiYuan Huang 	case RT5733_CHIPDIE_ID:
227*6f5e2858SChiYuan Huang 		desc->n_voltages = RT5733_N_VOLTS;
228*6f5e2858SChiYuan Huang 		desc->min_uV = RT5733_VOLT_MINUV;
229*6f5e2858SChiYuan Huang 		desc->uV_step = RT5733_VOLT_STPUV;
230*6f5e2858SChiYuan Huang 		break;
231*6f5e2858SChiYuan Huang 	default:
232*6f5e2858SChiYuan Huang 		desc->n_voltages = RT5739_N_VOLTS;
233*6f5e2858SChiYuan Huang 		desc->min_uV = RT5739_VOLT_MINUV;
234*6f5e2858SChiYuan Huang 		desc->uV_step = RT5739_VOLT_STPUV;
235*6f5e2858SChiYuan Huang 		break;
236*6f5e2858SChiYuan Huang 	}
2374536f3b9SChiYuan Huang }
2384536f3b9SChiYuan Huang 
2394536f3b9SChiYuan Huang static const struct regmap_config rt5739_regmap_config = {
2404536f3b9SChiYuan Huang 	.name = "rt5739",
2414536f3b9SChiYuan Huang 	.reg_bits = 8,
2424536f3b9SChiYuan Huang 	.val_bits = 8,
2434536f3b9SChiYuan Huang 	.max_register = RT5739_REG_CNTL4,
2444536f3b9SChiYuan Huang };
2454536f3b9SChiYuan Huang 
rt5739_probe(struct i2c_client * i2c)2464536f3b9SChiYuan Huang static int rt5739_probe(struct i2c_client *i2c)
2474536f3b9SChiYuan Huang {
2484536f3b9SChiYuan Huang 	struct device *dev = &i2c->dev;
2494536f3b9SChiYuan Huang 	struct regulator_desc *desc;
2504536f3b9SChiYuan Huang 	struct regmap *regmap;
2514536f3b9SChiYuan Huang 	struct gpio_desc *enable_gpio;
2524536f3b9SChiYuan Huang 	struct regulator_config cfg = {};
2534536f3b9SChiYuan Huang 	struct regulator_dev *rdev;
2544536f3b9SChiYuan Huang 	bool vsel_acth;
2554536f3b9SChiYuan Huang 	unsigned int vid;
2564536f3b9SChiYuan Huang 	int ret;
2574536f3b9SChiYuan Huang 
2584536f3b9SChiYuan Huang 	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
2594536f3b9SChiYuan Huang 	if (!desc)
2604536f3b9SChiYuan Huang 		return -ENOMEM;
2614536f3b9SChiYuan Huang 
2624536f3b9SChiYuan Huang 	enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
2634536f3b9SChiYuan Huang 	if (IS_ERR(enable_gpio))
2644536f3b9SChiYuan Huang 		return dev_err_probe(dev, PTR_ERR(enable_gpio), "Failed to get 'enable' gpio\n");
2654536f3b9SChiYuan Huang 	else if (enable_gpio)
2664536f3b9SChiYuan Huang 		usleep_range(RT5739_I2CRDY_TIMEUS, RT5739_I2CRDY_TIMEUS + 1000);
2674536f3b9SChiYuan Huang 
2684536f3b9SChiYuan Huang 	regmap = devm_regmap_init_i2c(i2c, &rt5739_regmap_config);
2694536f3b9SChiYuan Huang 	if (IS_ERR(regmap))
2704536f3b9SChiYuan Huang 		return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init regmap\n");
2714536f3b9SChiYuan Huang 
2724536f3b9SChiYuan Huang 	ret = regmap_read(regmap, RT5739_REG_ID1, &vid);
2734536f3b9SChiYuan Huang 	if (ret)
2744536f3b9SChiYuan Huang 		return dev_err_probe(dev, ret, "Failed to read VID\n");
2754536f3b9SChiYuan Huang 
2764536f3b9SChiYuan Huang 	/* RT5739: (VID & MASK) must be 0 */
2774536f3b9SChiYuan Huang 	if (vid & RT5739_VID_MASK)
2784536f3b9SChiYuan Huang 		return dev_err_probe(dev, -ENODEV, "Incorrect VID (0x%02x)\n", vid);
2794536f3b9SChiYuan Huang 
2804536f3b9SChiYuan Huang 	vsel_acth = device_property_read_bool(dev, "richtek,vsel-active-high");
2814536f3b9SChiYuan Huang 
282*6f5e2858SChiYuan Huang 	rt5739_init_regulator_desc(desc, vsel_acth, vid & RT5739_DID_MASK);
2834536f3b9SChiYuan Huang 
2844536f3b9SChiYuan Huang 	cfg.dev = dev;
2854536f3b9SChiYuan Huang 	cfg.of_node = dev_of_node(dev);
2864536f3b9SChiYuan Huang 	cfg.init_data = of_get_regulator_init_data(dev, dev_of_node(dev), desc);
2874536f3b9SChiYuan Huang 	rdev = devm_regulator_register(dev, desc, &cfg);
2884536f3b9SChiYuan Huang 	if (IS_ERR(rdev))
2894536f3b9SChiYuan Huang 		return dev_err_probe(dev, PTR_ERR(rdev), "Failed to register regulator\n");
2904536f3b9SChiYuan Huang 
2914536f3b9SChiYuan Huang 	return 0;
2924536f3b9SChiYuan Huang }
2934536f3b9SChiYuan Huang 
2944536f3b9SChiYuan Huang static const struct of_device_id rt5739_device_table[] = {
295*6f5e2858SChiYuan Huang 	{ .compatible = "richtek,rt5733" },
2964536f3b9SChiYuan Huang 	{ .compatible = "richtek,rt5739" },
2974536f3b9SChiYuan Huang 	{ /* sentinel */ }
2984536f3b9SChiYuan Huang };
2994536f3b9SChiYuan Huang MODULE_DEVICE_TABLE(of, rt5739_device_table);
3004536f3b9SChiYuan Huang 
3014536f3b9SChiYuan Huang static struct i2c_driver rt5739_driver = {
3024536f3b9SChiYuan Huang 	.driver = {
3034536f3b9SChiYuan Huang 		.name = "rt5739",
304bdce47bbSDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
3054536f3b9SChiYuan Huang 		.of_match_table = rt5739_device_table,
3064536f3b9SChiYuan Huang 	},
307d692cc61SUwe Kleine-König 	.probe = rt5739_probe,
3084536f3b9SChiYuan Huang };
3094536f3b9SChiYuan Huang module_i2c_driver(rt5739_driver);
3104536f3b9SChiYuan Huang 
3114536f3b9SChiYuan Huang MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
3124536f3b9SChiYuan Huang MODULE_DESCRIPTION("Richtek RT5739 regulator driver");
3134536f3b9SChiYuan Huang MODULE_LICENSE("GPL");
314