brintos

brintos / linux-shallow public Read only

0
0
Text · 8.6 KiB · 48dcee5 Raw
370 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// MP8867/MP8869 regulator driver4//5// Copyright (C) 2020 Synaptics Incorporated6//7// Author: Jisheng Zhang <jszhang@kernel.org>8 9#include <linux/gpio/consumer.h>10#include <linux/i2c.h>11#include <linux/module.h>12#include <linux/of.h>13#include <linux/regmap.h>14#include <linux/regulator/driver.h>15#include <linux/regulator/of_regulator.h>16 17#define MP886X_VSEL		0x0018#define  MP886X_V_BOOT		(1 << 7)19#define MP886X_SYSCNTLREG1	0x0120#define  MP886X_MODE		(1 << 0)21#define  MP886X_SLEW_SHIFT	322#define  MP886X_SLEW_MASK	(0x7 << MP886X_SLEW_SHIFT)23#define  MP886X_GO		(1 << 6)24#define  MP886X_EN		(1 << 7)25#define MP8869_SYSCNTLREG2	0x0226 27struct mp886x_cfg_info {28	const struct regulator_ops *rops;29	const unsigned int slew_rates[8];30	const int switch_freq[4];31	const u8 fs_reg;32	const u8 fs_shift;33};34 35struct mp886x_device_info {36	struct device *dev;37	struct regulator_desc desc;38	struct regulator_init_data *regulator;39	struct gpio_desc *en_gpio;40	const struct mp886x_cfg_info *ci;41	u32 r[2];42	unsigned int sel;43};44 45static void mp886x_set_switch_freq(struct mp886x_device_info *di,46				   struct regmap *regmap,47				   u32 freq)48{49	const struct mp886x_cfg_info *ci = di->ci;50	int i;51 52	for (i = 0; i < ARRAY_SIZE(ci->switch_freq); i++) {53		if (freq == ci->switch_freq[i]) {54			regmap_update_bits(regmap, ci->fs_reg,55				  0x3 << ci->fs_shift, i << ci->fs_shift);56			return;57		}58	}59 60	dev_err(di->dev, "invalid frequency %d\n", freq);61}62 63static int mp886x_set_mode(struct regulator_dev *rdev, unsigned int mode)64{65	switch (mode) {66	case REGULATOR_MODE_FAST:67		regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,68				   MP886X_MODE, MP886X_MODE);69		break;70	case REGULATOR_MODE_NORMAL:71		regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,72				   MP886X_MODE, 0);73		break;74	default:75		return -EINVAL;76	}77	return 0;78}79 80static unsigned int mp886x_get_mode(struct regulator_dev *rdev)81{82	u32 val;83	int ret;84 85	ret = regmap_read(rdev->regmap, MP886X_SYSCNTLREG1, &val);86	if (ret < 0)87		return ret;88	if (val & MP886X_MODE)89		return REGULATOR_MODE_FAST;90	else91		return REGULATOR_MODE_NORMAL;92}93 94static int mp8869_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)95{96	int ret;97 98	ret = regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,99				 MP886X_GO, MP886X_GO);100	if (ret < 0)101		return ret;102 103	sel <<= ffs(rdev->desc->vsel_mask) - 1;104	return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,105				  MP886X_V_BOOT | rdev->desc->vsel_mask, sel);106}107 108static inline unsigned int mp8869_scale(unsigned int uv, u32 r1, u32 r2)109{110	u32 tmp = uv * r1 / r2;111 112	return uv + tmp;113}114 115static int mp8869_get_voltage_sel(struct regulator_dev *rdev)116{117	struct mp886x_device_info *di = rdev_get_drvdata(rdev);118	int ret, uv;119	unsigned int val;120	bool fbloop;121 122	ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);123	if (ret)124		return ret;125 126	fbloop = val & MP886X_V_BOOT;127	if (fbloop) {128		uv = rdev->desc->min_uV;129		uv = mp8869_scale(uv, di->r[0], di->r[1]);130		return regulator_map_voltage_linear(rdev, uv, uv);131	}132 133	val &= rdev->desc->vsel_mask;134	val >>= ffs(rdev->desc->vsel_mask) - 1;135 136	return val;137}138 139static const struct regulator_ops mp8869_regulator_ops = {140	.set_voltage_sel = mp8869_set_voltage_sel,141	.get_voltage_sel = mp8869_get_voltage_sel,142	.set_voltage_time_sel = regulator_set_voltage_time_sel,143	.map_voltage = regulator_map_voltage_linear,144	.list_voltage = regulator_list_voltage_linear,145	.enable = regulator_enable_regmap,146	.disable = regulator_disable_regmap,147	.is_enabled = regulator_is_enabled_regmap,148	.set_mode = mp886x_set_mode,149	.get_mode = mp886x_get_mode,150	.set_ramp_delay = regulator_set_ramp_delay_regmap,151};152 153static const struct mp886x_cfg_info mp8869_ci = {154	.rops = &mp8869_regulator_ops,155	.slew_rates = {156		40000,157		30000,158		20000,159		10000,160		5000,161		2500,162		1250,163		625,164	},165	.switch_freq = {166		500000,167		750000,168		1000000,169		1250000,170	},171	.fs_reg = MP8869_SYSCNTLREG2,172	.fs_shift = 4,173};174 175static int mp8867_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)176{177	struct mp886x_device_info *di = rdev_get_drvdata(rdev);178	int ret, delta;179 180	ret = mp8869_set_voltage_sel(rdev, sel);181	if (ret < 0)182		return ret;183 184	delta = di->sel - sel;185	if (abs(delta) <= 5)186		ret = regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,187					 MP886X_GO, 0);188	di->sel = sel;189 190	return ret;191}192 193static int mp8867_get_voltage_sel(struct regulator_dev *rdev)194{195	struct mp886x_device_info *di = rdev_get_drvdata(rdev);196	int ret, uv;197	unsigned int val;198	bool fbloop;199 200	ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);201	if (ret)202		return ret;203 204	fbloop = val & MP886X_V_BOOT;205 206	val &= rdev->desc->vsel_mask;207	val >>= ffs(rdev->desc->vsel_mask) - 1;208 209	if (fbloop) {210		uv = regulator_list_voltage_linear(rdev, val);211		uv = mp8869_scale(uv, di->r[0], di->r[1]);212		return regulator_map_voltage_linear(rdev, uv, uv);213	}214 215	return val;216}217 218static const struct regulator_ops mp8867_regulator_ops = {219	.set_voltage_sel = mp8867_set_voltage_sel,220	.get_voltage_sel = mp8867_get_voltage_sel,221	.set_voltage_time_sel = regulator_set_voltage_time_sel,222	.map_voltage = regulator_map_voltage_linear,223	.list_voltage = regulator_list_voltage_linear,224	.enable = regulator_enable_regmap,225	.disable = regulator_disable_regmap,226	.is_enabled = regulator_is_enabled_regmap,227	.set_mode = mp886x_set_mode,228	.get_mode = mp886x_get_mode,229	.set_ramp_delay = regulator_set_ramp_delay_regmap,230};231 232static const struct mp886x_cfg_info mp8867_ci = {233	.rops = &mp8867_regulator_ops,234	.slew_rates = {235		64000,236		32000,237		16000,238		8000,239		4000,240		2000,241		1000,242		500,243	},244	.switch_freq = {245		500000,246		750000,247		1000000,248		1500000,249	},250	.fs_reg = MP886X_SYSCNTLREG1,251	.fs_shift = 1,252};253 254static int mp886x_regulator_register(struct mp886x_device_info *di,255				     struct regulator_config *config)256{257	struct regulator_desc *rdesc = &di->desc;258	struct regulator_dev *rdev;259 260	rdesc->name = "mp886x-reg";261	rdesc->supply_name = "vin";262	rdesc->ops = di->ci->rops;263	rdesc->type = REGULATOR_VOLTAGE;264	rdesc->n_voltages = 128;265	rdesc->enable_reg = MP886X_SYSCNTLREG1;266	rdesc->enable_mask = MP886X_EN;267	rdesc->min_uV = 600000;268	rdesc->uV_step = 10000;269	rdesc->vsel_reg = MP886X_VSEL;270	rdesc->vsel_mask = 0x3f;271	rdesc->ramp_reg = MP886X_SYSCNTLREG1;272	rdesc->ramp_mask = MP886X_SLEW_MASK;273	rdesc->ramp_delay_table = di->ci->slew_rates;274	rdesc->n_ramp_values = ARRAY_SIZE(di->ci->slew_rates);275	rdesc->owner = THIS_MODULE;276 277	rdev = devm_regulator_register(di->dev, &di->desc, config);278	if (IS_ERR(rdev))279		return PTR_ERR(rdev);280	di->sel = rdesc->ops->get_voltage_sel(rdev);281	return 0;282}283 284static const struct regmap_config mp886x_regmap_config = {285	.reg_bits = 8,286	.val_bits = 8,287};288 289static int mp886x_i2c_probe(struct i2c_client *client)290{291	struct device *dev = &client->dev;292	struct device_node *np = dev->of_node;293	struct mp886x_device_info *di;294	struct regulator_config config = { };295	struct regmap *regmap;296	u32 freq;297	int ret;298 299	di = devm_kzalloc(dev, sizeof(struct mp886x_device_info), GFP_KERNEL);300	if (!di)301		return -ENOMEM;302 303	di->regulator = of_get_regulator_init_data(dev, np, &di->desc);304	if (!di->regulator) {305		dev_err(dev, "Platform data not found!\n");306		return -EINVAL;307	}308 309	ret = of_property_read_u32_array(np, "mps,fb-voltage-divider",310					 di->r, 2);311	if (ret)312		return ret;313 314	di->en_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);315	if (IS_ERR(di->en_gpio))316		return PTR_ERR(di->en_gpio);317 318	di->ci = i2c_get_match_data(client);319	di->dev = dev;320 321	regmap = devm_regmap_init_i2c(client, &mp886x_regmap_config);322	if (IS_ERR(regmap)) {323		dev_err(dev, "Failed to allocate regmap!\n");324		return PTR_ERR(regmap);325	}326	i2c_set_clientdata(client, di);327 328	config.dev = di->dev;329	config.init_data = di->regulator;330	config.regmap = regmap;331	config.driver_data = di;332	config.of_node = np;333 334	if (!of_property_read_u32(np, "mps,switch-frequency-hz", &freq))335		mp886x_set_switch_freq(di, regmap, freq);336 337	ret = mp886x_regulator_register(di, &config);338	if (ret < 0)339		dev_err(dev, "Failed to register regulator!\n");340	return ret;341}342 343static const struct of_device_id mp886x_dt_ids[] = {344	{ .compatible = "mps,mp8867", .data = &mp8867_ci },345	{ .compatible = "mps,mp8869", .data = &mp8869_ci },346	{ }347};348MODULE_DEVICE_TABLE(of, mp886x_dt_ids);349 350static const struct i2c_device_id mp886x_id[] = {351	{ "mp886x", (kernel_ulong_t)&mp8869_ci },352	{ },353};354MODULE_DEVICE_TABLE(i2c, mp886x_id);355 356static struct i2c_driver mp886x_regulator_driver = {357	.driver = {358		.name = "mp886x-regulator",359		.probe_type = PROBE_PREFER_ASYNCHRONOUS,360		.of_match_table = mp886x_dt_ids,361	},362	.probe = mp886x_i2c_probe,363	.id_table = mp886x_id,364};365module_i2c_driver(mp886x_regulator_driver);366 367MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");368MODULE_DESCRIPTION("MP886x regulator driver");369MODULE_LICENSE("GPL v2");370