brintos

brintos / linux-shallow public Read only

0
0
Text · 11.6 KiB · f0d3efd Raw
422 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3#include <linux/bits.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/driver.h>10#include <linux/regulator/machine.h>11#include <linux/regulator/of_regulator.h>12 13#define RT5120_REG_PGSTAT	0x0314#define RT5120_REG_CH1VID	0x0615#define RT5120_REG_CH1SLPVID	0x0716#define RT5120_REG_ENABLE	0x0817#define RT5120_REG_MODECTL	0x0918#define RT5120_REG_UVOVPROT	0x0A19#define RT5120_REG_SLPCTL	0x0C20#define RT5120_REG_INTSTAT	0x1E21#define RT5120_REG_DISCHG	0x1F22 23#define RT5120_OUTPG_MASK(rid)	BIT(rid + 1)24#define RT5120_OUTUV_MASK(rid)	BIT(rid + 9)25#define RT5120_OUTOV_MASK(rid)	BIT(rid + 16)26#define RT5120_CH1VID_MASK	GENMASK(6, 0)27#define RT5120_RIDEN_MASK(rid)	BIT(rid + 1)28#define RT5120_RADEN_MASK(rid)	BIT(rid)29#define RT5120_FPWM_MASK(rid)	BIT(rid + 1)30#define RT5120_UVHICCUP_MASK	BIT(1)31#define RT5120_OVHICCUP_MASK	BIT(0)32#define RT5120_HOTDIE_MASK	BIT(1)33 34#define RT5120_BUCK1_MINUV	60000035#define RT5120_BUCK1_MAXUV	139375036#define RT5120_BUCK1_STEPUV	625037#define RT5120_BUCK1_NUM_VOLT	0x8038 39#define RT5120_AUTO_MODE	040#define RT5120_FPWM_MODE	141 42enum {43	RT5120_REGULATOR_BUCK1 = 0,44	RT5120_REGULATOR_BUCK2,45	RT5120_REGULATOR_BUCK3,46	RT5120_REGULATOR_BUCK4,47	RT5120_REGULATOR_LDO,48	RT5120_REGULATOR_EXTEN,49	RT5120_MAX_REGULATOR50};51 52struct rt5120_priv {53	struct device *dev;54	struct regmap *regmap;55	struct regulator_desc rdesc[RT5120_MAX_REGULATOR];56};57 58static int rt5120_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)59{60	struct regmap *regmap = rdev_get_regmap(rdev);61	int rid = rdev_get_id(rdev);62	unsigned int mask = RT5120_FPWM_MASK(rid), val;63 64	switch (mode) {65	case REGULATOR_MODE_NORMAL:66		val = 0;67		break;68	case REGULATOR_MODE_FAST:69		val = RT5120_FPWM_MASK(rid);70		break;71	default:72		return -EINVAL;73	}74 75	return regmap_update_bits(regmap, RT5120_REG_MODECTL, mask, val);76}77 78static unsigned int rt5120_buck_get_mode(struct regulator_dev *rdev)79{80	struct regmap *regmap = rdev_get_regmap(rdev);81	int ret, rid = rdev_get_id(rdev);82	unsigned int val;83 84	ret = regmap_read(regmap, RT5120_REG_MODECTL, &val);85	if (ret)86		return REGULATOR_MODE_INVALID;87 88	if (val & RT5120_FPWM_MASK(rid))89		return REGULATOR_MODE_FAST;90 91	return REGULATOR_MODE_NORMAL;92}93 94static int rt5120_regulator_get_error_flags(struct regulator_dev *rdev,95					    unsigned int *flags)96{97	struct regmap *regmap = rdev_get_regmap(rdev);98	unsigned int stat, hd_stat, cur_flags = 0;99	int rid = rdev_get_id(rdev), ret;100 101	/*102	 * reg 0x03/0x04/0x05 to indicate PG/UV/OV103	 * use block read to descrease I/O xfer time104	 */105	ret = regmap_raw_read(regmap, RT5120_REG_PGSTAT, &stat, 3);106	if (ret)107		return ret;108 109	ret = regmap_read(regmap, RT5120_REG_INTSTAT, &hd_stat);110	if (ret)111		return ret;112 113	if (!(stat & RT5120_OUTPG_MASK(rid))) {114		if (stat & RT5120_OUTUV_MASK(rid))115			cur_flags |= REGULATOR_ERROR_UNDER_VOLTAGE;116 117		if (stat & RT5120_OUTOV_MASK(rid))118			cur_flags |= REGULATOR_ERROR_REGULATION_OUT;119	}120 121	if (hd_stat & RT5120_HOTDIE_MASK)122		cur_flags |= REGULATOR_ERROR_OVER_TEMP;123 124	*flags = cur_flags;125	return 0;126}127 128static int rt5120_buck1_set_suspend_voltage(struct regulator_dev *rdev, int uV)129{130	struct regmap *regmap = rdev_get_regmap(rdev);131	int sel;132 133	if (uV < RT5120_BUCK1_MINUV || uV > RT5120_BUCK1_MAXUV)134		return -EINVAL;135 136	sel = (uV - RT5120_BUCK1_MINUV) / RT5120_BUCK1_STEPUV;137	return regmap_write(regmap, RT5120_REG_CH1SLPVID, sel);138}139 140static int rt5120_regulator_set_suspend_enable(struct regulator_dev *rdev)141{142	struct regmap *regmap = rdev_get_regmap(rdev);143	int rid = rdev_get_id(rdev);144	unsigned int mask = RT5120_RIDEN_MASK(rid);145 146	return regmap_update_bits(regmap, RT5120_REG_SLPCTL, mask, mask);147}148 149static int rt5120_regulator_set_suspend_disable(struct regulator_dev *rdev)150{151	struct regmap *regmap = rdev_get_regmap(rdev);152	int rid = rdev_get_id(rdev);153	unsigned int mask = RT5120_RIDEN_MASK(rid);154 155	return regmap_update_bits(regmap, RT5120_REG_SLPCTL, mask, 0);156}157 158static const struct regulator_ops rt5120_buck1_ops = {159	.enable = regulator_enable_regmap,160	.disable = regulator_disable_regmap,161	.is_enabled = regulator_is_enabled_regmap,162	.list_voltage = regulator_list_voltage_linear,163	.set_voltage_sel = regulator_set_voltage_sel_regmap,164	.get_voltage_sel = regulator_get_voltage_sel_regmap,165	.set_active_discharge = regulator_set_active_discharge_regmap,166	.set_mode = rt5120_buck_set_mode,167	.get_mode = rt5120_buck_get_mode,168	.get_error_flags = rt5120_regulator_get_error_flags,169	.set_suspend_voltage = rt5120_buck1_set_suspend_voltage,170	.set_suspend_enable = rt5120_regulator_set_suspend_enable,171	.set_suspend_disable = rt5120_regulator_set_suspend_disable,172};173 174static const struct regulator_ops rt5120_buck234_ops = {175	.enable = regulator_enable_regmap,176	.disable = regulator_disable_regmap,177	.is_enabled = regulator_is_enabled_regmap,178	.set_active_discharge = regulator_set_active_discharge_regmap,179	.set_mode = rt5120_buck_set_mode,180	.get_mode = rt5120_buck_get_mode,181	.get_error_flags = rt5120_regulator_get_error_flags,182	.set_suspend_enable = rt5120_regulator_set_suspend_enable,183	.set_suspend_disable = rt5120_regulator_set_suspend_disable,184};185 186static const struct regulator_ops rt5120_ldo_ops = {187	.enable = regulator_enable_regmap,188	.disable = regulator_disable_regmap,189	.is_enabled = regulator_is_enabled_regmap,190	.set_active_discharge = regulator_set_active_discharge_regmap,191	.get_error_flags = rt5120_regulator_get_error_flags,192	.set_suspend_enable = rt5120_regulator_set_suspend_enable,193	.set_suspend_disable = rt5120_regulator_set_suspend_disable,194};195 196static const struct regulator_ops rt5120_exten_ops = {197	.enable = regulator_enable_regmap,198	.disable = regulator_disable_regmap,199	.is_enabled = regulator_is_enabled_regmap,200	.set_suspend_enable = rt5120_regulator_set_suspend_enable,201	.set_suspend_disable = rt5120_regulator_set_suspend_disable,202};203 204static unsigned int rt5120_buck_of_map_mode(unsigned int mode)205{206	switch (mode) {207	case RT5120_AUTO_MODE:208		return REGULATOR_MODE_NORMAL;209	case RT5120_FPWM_MODE:210		return REGULATOR_MODE_FAST;211	default:212		return REGULATOR_MODE_INVALID;213	}214}215 216static void rt5120_fillin_regulator_desc(struct regulator_desc *desc, int rid)217{218	static const char * const name[] = {219		"buck1", "buck2", "buck3", "buck4", "ldo", "exten" };220	static const char * const sname[] = {221		"vin1", "vin2", "vin3", "vin4", "vinldo", NULL };222 223	/* Common regulator property */224	desc->name = name[rid];225	desc->supply_name = sname[rid];226	desc->owner = THIS_MODULE;227	desc->type = REGULATOR_VOLTAGE;228	desc->id = rid;229	desc->enable_reg = RT5120_REG_ENABLE;230	desc->enable_mask = RT5120_RIDEN_MASK(rid);231	desc->active_discharge_reg = RT5120_REG_DISCHG;232	desc->active_discharge_mask = RT5120_RADEN_MASK(rid);233	desc->active_discharge_on = RT5120_RADEN_MASK(rid);234	/* Config n_voltages to 1 for all*/235	desc->n_voltages = 1;236 237	/* Only buck support mode change */238	if (rid >= RT5120_REGULATOR_BUCK1 && rid <= RT5120_REGULATOR_BUCK4)239		desc->of_map_mode = rt5120_buck_of_map_mode;240 241	/* RID specific property init */242	switch (rid) {243	case RT5120_REGULATOR_BUCK1:244		/* Only buck1 support voltage change by I2C */245		desc->n_voltages = RT5120_BUCK1_NUM_VOLT;246		desc->min_uV = RT5120_BUCK1_MINUV;247		desc->uV_step = RT5120_BUCK1_STEPUV;248		desc->vsel_reg = RT5120_REG_CH1VID;249		desc->vsel_mask = RT5120_CH1VID_MASK;250		desc->ops = &rt5120_buck1_ops;251		break;252	case RT5120_REGULATOR_BUCK2 ... RT5120_REGULATOR_BUCK4:253		desc->ops = &rt5120_buck234_ops;254		break;255	case RT5120_REGULATOR_LDO:256		desc->ops = &rt5120_ldo_ops;257		break;258	default:259		desc->ops = &rt5120_exten_ops;260	}261}262 263static int rt5120_of_parse_cb(struct rt5120_priv *priv, int rid,264			      struct of_regulator_match *match)265{266	struct regulator_desc *desc = priv->rdesc + rid;267	struct regulator_init_data *init_data = match->init_data;268 269	if (!init_data || rid == RT5120_REGULATOR_BUCK1)270		return 0;271 272	if (init_data->constraints.min_uV != init_data->constraints.max_uV) {273		dev_err(priv->dev, "Variable voltage for fixed regulator\n");274		return -EINVAL;275	}276 277	desc->fixed_uV = init_data->constraints.min_uV;278	return 0;279}280 281static struct of_regulator_match rt5120_regu_match[RT5120_MAX_REGULATOR] = {282	[RT5120_REGULATOR_BUCK1] = { .name = "buck1", },283	[RT5120_REGULATOR_BUCK2] = { .name = "buck2", },284	[RT5120_REGULATOR_BUCK3] = { .name = "buck3", },285	[RT5120_REGULATOR_BUCK4] = { .name = "buck4", },286	[RT5120_REGULATOR_LDO] = { .name = "ldo", },287	[RT5120_REGULATOR_EXTEN] = { .name = "exten", }288};289 290static int rt5120_parse_regulator_dt_data(struct rt5120_priv *priv)291{292	struct device *dev = priv->dev->parent;293	struct device_node *reg_node;294	int i, ret;295 296	for (i = 0; i < RT5120_MAX_REGULATOR; i++) {297		rt5120_fillin_regulator_desc(priv->rdesc + i, i);298 299		rt5120_regu_match[i].desc = priv->rdesc + i;300	}301 302	reg_node = of_get_child_by_name(dev->of_node, "regulators");303	if (!reg_node) {304		dev_err(priv->dev, "Couldn't find 'regulators' node\n");305		return -ENODEV;306	}307 308	ret = of_regulator_match(priv->dev, reg_node, rt5120_regu_match,309				 ARRAY_SIZE(rt5120_regu_match));310 311	of_node_put(reg_node);312 313	if (ret < 0) {314		dev_err(priv->dev,315			"Error parsing regulator init data (%d)\n", ret);316		return ret;317	}318 319	for (i = 0; i < RT5120_MAX_REGULATOR; i++) {320		ret = rt5120_of_parse_cb(priv, i, rt5120_regu_match + i);321		if (ret) {322			dev_err(priv->dev, "Failed in [%d] of_passe_cb\n", i);323			return ret;324		}325	}326 327	return 0;328}329 330static int rt5120_device_property_init(struct rt5120_priv *priv)331{332	struct device *dev = priv->dev->parent;333	struct device_node *np = dev->of_node;334	bool prot_enable;335	unsigned int prot_enable_val = 0;336 337	/* Assign UV/OV HW protection behavior */338	prot_enable = of_property_read_bool(np,339					    "richtek,enable-undervolt-hiccup");340	if (prot_enable)341		prot_enable_val |= RT5120_UVHICCUP_MASK;342 343	prot_enable = of_property_read_bool(np,344					    "richtek,enable-overvolt-hiccup");345	if (prot_enable)346		prot_enable_val |= RT5120_OVHICCUP_MASK;347 348	return regmap_update_bits(priv->regmap, RT5120_REG_UVOVPROT,349				  RT5120_UVHICCUP_MASK | RT5120_OVHICCUP_MASK,350				  prot_enable_val);351}352 353static int rt5120_regulator_probe(struct platform_device *pdev)354{355	struct rt5120_priv *priv;356	struct regulator_dev *rdev;357	struct regulator_config config = {};358	int i, ret;359 360	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);361	if (!priv)362		return -ENOMEM;363 364	priv->dev = &pdev->dev;365 366	priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);367	if (!priv->regmap) {368		dev_err(&pdev->dev, "Failed to init regmap\n");369		return -ENODEV;370	}371 372	ret = rt5120_device_property_init(priv);373	if (ret) {374		dev_err(&pdev->dev, "Failed to do property init\n");375		return ret;376	}377 378	ret = rt5120_parse_regulator_dt_data(priv);379	if (ret) {380		dev_err(&pdev->dev, "Failed to parse dt data\n");381		return ret;382	}383 384	config.dev = &pdev->dev;385	config.regmap = priv->regmap;386 387	for (i = 0; i < RT5120_MAX_REGULATOR; i++) {388		config.of_node = rt5120_regu_match[i].of_node;389		config.init_data = rt5120_regu_match[i].init_data;390 391		rdev = devm_regulator_register(&pdev->dev, priv->rdesc + i,392					       &config);393		if (IS_ERR(rdev)) {394			dev_err(&pdev->dev,395				"Failed to register regulator [%d]\n", i);396			return PTR_ERR(rdev);397		}398	}399 400	return 0;401}402 403static const struct platform_device_id rt5120_regulator_dev_table[] = {404	{ "rt5120-regulator", 0 },405	{}406};407MODULE_DEVICE_TABLE(platform, rt5120_regulator_dev_table);408 409static struct platform_driver rt5120_regulator_driver = {410	.driver = {411		.name = "rt5120-regulator",412		.probe_type = PROBE_PREFER_ASYNCHRONOUS,413	},414	.id_table = rt5120_regulator_dev_table,415	.probe = rt5120_regulator_probe,416};417module_platform_driver(rt5120_regulator_driver);418 419MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");420MODULE_DESCRIPTION("Richtek RT5120 regulator driver");421MODULE_LICENSE("GPL v2");422