Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-only
  2
  3#include <linux/bitops.h>
  4#include <linux/kernel.h>
  5#include <linux/module.h>
  6#include <linux/of.h>
  7#include <linux/platform_device.h>
  8#include <linux/regmap.h>
  9#include <linux/regulator/consumer.h>
 10#include <linux/regulator/driver.h>
 11
 12enum {
 13	DSV_OUT_VLCM = 0,
 14	DSV_OUT_VPOS,
 15	DSV_OUT_VNEG,
 16	DSV_OUT_MAX
 17};
 18
 19#define RT4831_REG_DSVEN	0x09
 20#define RT4831_REG_VLCM		0x0c
 21#define RT4831_REG_VPOS		0x0d
 22#define RT4831_REG_VNEG		0x0e
 23#define RT4831_REG_FLAGS	0x0f
 24
 25#define RT4831_VOLT_MASK	GENMASK(5, 0)
 26#define RT4831_DSVMODE_SHIFT	5
 27#define RT4831_DSVMODE_MASK	GENMASK(7, 5)
 28#define RT4831_POSADEN_MASK	BIT(4)
 29#define RT4831_NEGADEN_MASK	BIT(3)
 30#define RT4831_POSEN_MASK	BIT(2)
 31#define RT4831_NEGEN_MASK	BIT(1)
 32
 33#define RT4831_OTP_MASK		BIT(6)
 34#define RT4831_LCMOVP_MASK	BIT(5)
 35#define RT4831_VPOSSCP_MASK	BIT(3)
 36#define RT4831_VNEGSCP_MASK	BIT(2)
 37
 38#define DSV_MODE_NORMAL		(0x4 << RT4831_DSVMODE_SHIFT)
 39#define DSV_MODE_BYPASS		(0x6 << RT4831_DSVMODE_SHIFT)
 40#define STEP_UV			50000
 41#define VLCM_MIN_UV		4000000
 42#define VLCM_MAX_UV		7150000
 43#define VLCM_N_VOLTAGES		((VLCM_MAX_UV - VLCM_MIN_UV) / STEP_UV + 1)
 44#define VPN_MIN_UV		4000000
 45#define VPN_MAX_UV		6500000
 46#define VPN_N_VOLTAGES		((VPN_MAX_UV - VPN_MIN_UV) / STEP_UV + 1)
 47
 48static int rt4831_get_error_flags(struct regulator_dev *rdev, unsigned int *flags)
 49{
 50	struct regmap *regmap = rdev_get_regmap(rdev);
 51	int rid = rdev_get_id(rdev);
 52	unsigned int val, events = 0;
 53	int ret;
 54
 55	ret = regmap_read(regmap, RT4831_REG_FLAGS, &val);
 56	if (ret)
 57		return ret;
 58
 59	if (val & RT4831_OTP_MASK)
 60		events |= REGULATOR_ERROR_OVER_TEMP;
 61
 62	if (rid == DSV_OUT_VLCM && (val & RT4831_LCMOVP_MASK))
 63		events |= REGULATOR_ERROR_OVER_CURRENT;
 64
 65	if (rid == DSV_OUT_VPOS && (val & RT4831_VPOSSCP_MASK))
 66		events |= REGULATOR_ERROR_OVER_CURRENT;
 67
 68	if (rid == DSV_OUT_VNEG && (val & RT4831_VNEGSCP_MASK))
 69		events |= REGULATOR_ERROR_OVER_CURRENT;
 70
 71	*flags = events;
 72	return 0;
 73}
 74
 75static const struct regulator_ops rt4831_dsvlcm_ops = {
 76	.list_voltage = regulator_list_voltage_linear,
 77	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 78	.get_voltage_sel = regulator_get_voltage_sel_regmap,
 79	.set_bypass = regulator_set_bypass_regmap,
 80	.get_bypass = regulator_get_bypass_regmap,
 81	.get_error_flags = rt4831_get_error_flags,
 82};
 83
 84static const struct regulator_ops rt4831_dsvpn_ops = {
 85	.list_voltage = regulator_list_voltage_linear,
 86	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 87	.get_voltage_sel = regulator_get_voltage_sel_regmap,
 88	.enable = regulator_enable_regmap,
 89	.disable = regulator_disable_regmap,
 90	.is_enabled = regulator_is_enabled_regmap,
 91	.set_active_discharge = regulator_set_active_discharge_regmap,
 92	.get_error_flags = rt4831_get_error_flags,
 93};
 94
 95static const struct regulator_desc rt4831_regulator_descs[] = {
 96	{
 97		.name = "DSVLCM",
 98		.ops = &rt4831_dsvlcm_ops,
 99		.of_match = of_match_ptr("DSVLCM"),
100		.regulators_node = of_match_ptr("regulators"),
101		.type = REGULATOR_VOLTAGE,
102		.id = DSV_OUT_VLCM,
103		.n_voltages = VLCM_N_VOLTAGES,
104		.min_uV = VLCM_MIN_UV,
105		.uV_step = STEP_UV,
106		.vsel_reg = RT4831_REG_VLCM,
107		.vsel_mask = RT4831_VOLT_MASK,
108		.bypass_reg = RT4831_REG_DSVEN,
109		.bypass_val_on = DSV_MODE_BYPASS,
110		.bypass_val_off = DSV_MODE_NORMAL,
111		.owner = THIS_MODULE,
112	},
113	{
114		.name = "DSVP",
115		.ops = &rt4831_dsvpn_ops,
116		.of_match = of_match_ptr("DSVP"),
117		.regulators_node = of_match_ptr("regulators"),
118		.type = REGULATOR_VOLTAGE,
119		.id = DSV_OUT_VPOS,
120		.n_voltages = VPN_N_VOLTAGES,
121		.min_uV = VPN_MIN_UV,
122		.uV_step = STEP_UV,
123		.vsel_reg = RT4831_REG_VPOS,
124		.vsel_mask = RT4831_VOLT_MASK,
125		.enable_reg = RT4831_REG_DSVEN,
126		.enable_mask = RT4831_POSEN_MASK,
127		.active_discharge_reg = RT4831_REG_DSVEN,
128		.active_discharge_mask = RT4831_POSADEN_MASK,
129		.owner = THIS_MODULE,
130	},
131	{
132		.name = "DSVN",
133		.ops = &rt4831_dsvpn_ops,
134		.of_match = of_match_ptr("DSVN"),
135		.regulators_node = of_match_ptr("regulators"),
136		.type = REGULATOR_VOLTAGE,
137		.id = DSV_OUT_VNEG,
138		.n_voltages = VPN_N_VOLTAGES,
139		.min_uV = VPN_MIN_UV,
140		.uV_step = STEP_UV,
141		.vsel_reg = RT4831_REG_VNEG,
142		.vsel_mask = RT4831_VOLT_MASK,
143		.enable_reg = RT4831_REG_DSVEN,
144		.enable_mask = RT4831_NEGEN_MASK,
145		.active_discharge_reg = RT4831_REG_DSVEN,
146		.active_discharge_mask = RT4831_NEGADEN_MASK,
147		.owner = THIS_MODULE,
148	}
149};
150
151static int rt4831_regulator_probe(struct platform_device *pdev)
152{
153	struct regmap *regmap;
154	struct regulator_dev *rdev;
155	struct regulator_config config = {};
156	int i, ret;
157
158	regmap = dev_get_regmap(pdev->dev.parent, NULL);
159	if (!regmap) {
160		dev_err(&pdev->dev, "Failed to init regmap\n");
161		return -ENODEV;
162	}
163
164	/* Configure DSV mode to normal by default */
165	ret = regmap_update_bits(regmap, RT4831_REG_DSVEN, RT4831_DSVMODE_MASK, DSV_MODE_NORMAL);
166	if (ret) {
167		dev_err(&pdev->dev, "Failed to configure dsv mode to normal\n");
168		return ret;
169	}
170
171	config.dev = pdev->dev.parent;
172	config.regmap = regmap;
173
174	for (i = 0; i < DSV_OUT_MAX; i++) {
175		rdev = devm_regulator_register(&pdev->dev, rt4831_regulator_descs + i, &config);
176		if (IS_ERR(rdev)) {
177			dev_err(&pdev->dev, "Failed to register %d regulator\n", i);
178			return PTR_ERR(rdev);
179		}
180	}
181
182	return 0;
183}
184
185static const struct platform_device_id rt4831_regulator_match[] = {
186	{ "rt4831-regulator", 0 },
187	{}
188};
189MODULE_DEVICE_TABLE(platform, rt4831_regulator_match);
190
191static struct platform_driver rt4831_regulator_driver = {
192	.driver = {
193		.name = "rt4831-regulator",
194	},
195	.id_table = rt4831_regulator_match,
196	.probe = rt4831_regulator_probe,
197};
198module_platform_driver(rt4831_regulator_driver);
199
200MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
201MODULE_LICENSE("GPL v2");