brintos

brintos / linux-shallow public Read only

0
0
Text · 15.5 KiB · 9fe539a Raw
548 lines · c
1// SPDX-License-Identifier: GPL-2.0+2//3// pv88080-regulator.c - Regulator device driver for PV880804// Copyright (C) 2016  Powerventure Semiconductor Ltd.5 6#include <linux/err.h>7#include <linux/i2c.h>8#include <linux/mod_devicetable.h>9#include <linux/module.h>10#include <linux/of.h>11#include <linux/init.h>12#include <linux/slab.h>13#include <linux/regulator/driver.h>14#include <linux/regulator/machine.h>15#include <linux/regmap.h>16#include <linux/irq.h>17#include <linux/interrupt.h>18#include <linux/regulator/of_regulator.h>19#include "pv88080-regulator.h"20 21#define PV88080_MAX_REGULATORS	422 23/* PV88080 REGULATOR IDs */24enum {25	/* BUCKs */26	PV88080_ID_BUCK1,27	PV88080_ID_BUCK2,28	PV88080_ID_BUCK3,29	PV88080_ID_HVBUCK,30};31 32struct pv88080_regulator {33	struct regulator_desc desc;34	unsigned int mode_reg;35	unsigned int conf2;36	unsigned int conf5;37};38 39struct pv88080 {40	struct device *dev;41	struct regmap *regmap;42	struct regulator_dev *rdev[PV88080_MAX_REGULATORS];43	unsigned long type;44	const struct pv88080_compatible_regmap *regmap_config;45};46 47struct pv88080_buck_voltage {48	int min_uV;49	int max_uV;50	int uV_step;51};52 53struct pv88080_buck_regmap {54	/* REGS */55	int buck_enable_reg;56	int buck_vsel_reg;57	int buck_mode_reg;58	int buck_limit_reg;59	int buck_vdac_range_reg;60	int buck_vrange_gain_reg;61	/* MASKS */62	int buck_enable_mask;63	int buck_vsel_mask;64	int buck_limit_mask;65};66 67struct pv88080_compatible_regmap {68	/* BUCK1, 2, 3 */69	struct pv88080_buck_regmap buck_regmap[PV88080_MAX_REGULATORS-1];70	/* HVBUCK */71	int hvbuck_enable_reg;72	int hvbuck_vsel_reg;73	int hvbuck_enable_mask;74	int hvbuck_vsel_mask;75};76 77static const struct regmap_config pv88080_regmap_config = {78	.reg_bits = 8,79	.val_bits = 8,80};81 82/* Current limits array (in uA) for BUCK1, BUCK2, BUCK3.83 * Entry indexes corresponds to register values.84 */85 86static const unsigned int pv88080_buck1_limits[] = {87	3230000, 5130000, 6960000, 879000088};89 90static const unsigned int pv88080_buck23_limits[] = {91	1496000, 2393000, 3291000, 418900092};93 94static const struct pv88080_buck_voltage pv88080_buck_vol[2] = {95	{96		.min_uV = 600000,97		.max_uV = 1393750,98		.uV_step = 6250,99	},100	{101		.min_uV = 1400000,102		.max_uV = 2193750,103		.uV_step = 6250,104	},105};106 107static const struct pv88080_compatible_regmap pv88080_aa_regs = {108	/* BUCK1 */109	.buck_regmap[0] = {110		.buck_enable_reg      = PV88080AA_REG_BUCK1_CONF0,111		.buck_vsel_reg        = PV88080AA_REG_BUCK1_CONF0,112		.buck_mode_reg        = PV88080AA_REG_BUCK1_CONF1,113		.buck_limit_reg       = PV88080AA_REG_BUCK1_CONF1,114		.buck_vdac_range_reg  = PV88080AA_REG_BUCK1_CONF2,115		.buck_vrange_gain_reg = PV88080AA_REG_BUCK1_CONF5,116		.buck_enable_mask     = PV88080_BUCK1_EN,117		.buck_vsel_mask       = PV88080_VBUCK1_MASK,118		.buck_limit_mask      = PV88080_BUCK1_ILIM_MASK,119	},120	/* BUCK2 */121	.buck_regmap[1] = {122		.buck_enable_reg      = PV88080AA_REG_BUCK2_CONF0,123		.buck_vsel_reg        = PV88080AA_REG_BUCK2_CONF0,124		.buck_mode_reg        = PV88080AA_REG_BUCK2_CONF1,125		.buck_limit_reg	      = PV88080AA_REG_BUCK2_CONF1,126		.buck_vdac_range_reg  = PV88080AA_REG_BUCK2_CONF2,127		.buck_vrange_gain_reg = PV88080AA_REG_BUCK2_CONF5,128		.buck_enable_mask	  = PV88080_BUCK2_EN,129		.buck_vsel_mask       = PV88080_VBUCK2_MASK,130		.buck_limit_mask      = PV88080_BUCK2_ILIM_MASK,131	},132	/* BUCK3 */133	.buck_regmap[2] = {134		.buck_enable_reg	  = PV88080AA_REG_BUCK3_CONF0,135		.buck_vsel_reg        = PV88080AA_REG_BUCK3_CONF0,136		.buck_mode_reg        = PV88080AA_REG_BUCK3_CONF1,137		.buck_limit_reg	      = PV88080AA_REG_BUCK3_CONF1,138		.buck_vdac_range_reg  = PV88080AA_REG_BUCK3_CONF2,139		.buck_vrange_gain_reg = PV88080AA_REG_BUCK3_CONF5,140		.buck_enable_mask	  = PV88080_BUCK3_EN,141		.buck_vsel_mask       = PV88080_VBUCK3_MASK,142		.buck_limit_mask      = PV88080_BUCK3_ILIM_MASK,143	},144	/* HVBUCK */145	.hvbuck_enable_reg	      = PV88080AA_REG_HVBUCK_CONF2,146	.hvbuck_vsel_reg          = PV88080AA_REG_HVBUCK_CONF1,147	.hvbuck_enable_mask       = PV88080_HVBUCK_EN,148	.hvbuck_vsel_mask         = PV88080_VHVBUCK_MASK,149};150 151static const struct pv88080_compatible_regmap pv88080_ba_regs = {152	/* BUCK1 */153	.buck_regmap[0] = {154		.buck_enable_reg	  = PV88080BA_REG_BUCK1_CONF0,155		.buck_vsel_reg        = PV88080BA_REG_BUCK1_CONF0,156		.buck_mode_reg        = PV88080BA_REG_BUCK1_CONF1,157		.buck_limit_reg       = PV88080BA_REG_BUCK1_CONF1,158		.buck_vdac_range_reg  = PV88080BA_REG_BUCK1_CONF2,159		.buck_vrange_gain_reg = PV88080BA_REG_BUCK1_CONF5,160		.buck_enable_mask     = PV88080_BUCK1_EN,161		.buck_vsel_mask       = PV88080_VBUCK1_MASK,162		.buck_limit_mask	  = PV88080_BUCK1_ILIM_MASK,163	},164	/* BUCK2 */165	.buck_regmap[1] = {166		.buck_enable_reg	  = PV88080BA_REG_BUCK2_CONF0,167		.buck_vsel_reg        = PV88080BA_REG_BUCK2_CONF0,168		.buck_mode_reg        = PV88080BA_REG_BUCK2_CONF1,169		.buck_limit_reg	      = PV88080BA_REG_BUCK2_CONF1,170		.buck_vdac_range_reg  = PV88080BA_REG_BUCK2_CONF2,171		.buck_vrange_gain_reg = PV88080BA_REG_BUCK2_CONF5,172		.buck_enable_mask	  = PV88080_BUCK2_EN,173		.buck_vsel_mask       = PV88080_VBUCK2_MASK,174		.buck_limit_mask	  = PV88080_BUCK2_ILIM_MASK,175	},176	/* BUCK3 */177	.buck_regmap[2] = {178		.buck_enable_reg	  = PV88080BA_REG_BUCK3_CONF0,179		.buck_vsel_reg        = PV88080BA_REG_BUCK3_CONF0,180		.buck_mode_reg        = PV88080BA_REG_BUCK3_CONF1,181		.buck_limit_reg	      = PV88080BA_REG_BUCK3_CONF1,182		.buck_vdac_range_reg  = PV88080BA_REG_BUCK3_CONF2,183		.buck_vrange_gain_reg = PV88080BA_REG_BUCK3_CONF5,184		.buck_enable_mask	  = PV88080_BUCK3_EN,185		.buck_vsel_mask       = PV88080_VBUCK3_MASK,186		.buck_limit_mask	  = PV88080_BUCK3_ILIM_MASK,187	},188	/* HVBUCK */189	.hvbuck_enable_reg	      = PV88080BA_REG_HVBUCK_CONF2,190	.hvbuck_vsel_reg          = PV88080BA_REG_HVBUCK_CONF1,191	.hvbuck_enable_mask       = PV88080_HVBUCK_EN,192	.hvbuck_vsel_mask		  = PV88080_VHVBUCK_MASK,193};194 195static unsigned int pv88080_buck_get_mode(struct regulator_dev *rdev)196{197	struct pv88080_regulator *info = rdev_get_drvdata(rdev);198	unsigned int data;199	int ret, mode = 0;200 201	ret = regmap_read(rdev->regmap, info->mode_reg, &data);202	if (ret < 0)203		return ret;204 205	switch (data & PV88080_BUCK1_MODE_MASK) {206	case PV88080_BUCK_MODE_SYNC:207		mode = REGULATOR_MODE_FAST;208		break;209	case PV88080_BUCK_MODE_AUTO:210		mode = REGULATOR_MODE_NORMAL;211		break;212	case PV88080_BUCK_MODE_SLEEP:213		mode = REGULATOR_MODE_STANDBY;214		break;215	default:216		return -EINVAL;217	}218 219	return mode;220}221 222static int pv88080_buck_set_mode(struct regulator_dev *rdev,223					unsigned int mode)224{225	struct pv88080_regulator *info = rdev_get_drvdata(rdev);226	int val = 0;227 228	switch (mode) {229	case REGULATOR_MODE_FAST:230		val = PV88080_BUCK_MODE_SYNC;231		break;232	case REGULATOR_MODE_NORMAL:233		val = PV88080_BUCK_MODE_AUTO;234		break;235	case REGULATOR_MODE_STANDBY:236		val = PV88080_BUCK_MODE_SLEEP;237		break;238	default:239		return -EINVAL;240	}241 242	return regmap_update_bits(rdev->regmap, info->mode_reg,243					PV88080_BUCK1_MODE_MASK, val);244}245 246static const struct regulator_ops pv88080_buck_ops = {247	.get_mode = pv88080_buck_get_mode,248	.set_mode = pv88080_buck_set_mode,249	.enable = regulator_enable_regmap,250	.disable = regulator_disable_regmap,251	.is_enabled = regulator_is_enabled_regmap,252	.set_voltage_sel = regulator_set_voltage_sel_regmap,253	.get_voltage_sel = regulator_get_voltage_sel_regmap,254	.list_voltage = regulator_list_voltage_linear,255	.set_current_limit = regulator_set_current_limit_regmap,256	.get_current_limit = regulator_get_current_limit_regmap,257};258 259static const struct regulator_ops pv88080_hvbuck_ops = {260	.enable = regulator_enable_regmap,261	.disable = regulator_disable_regmap,262	.is_enabled = regulator_is_enabled_regmap,263	.set_voltage_sel = regulator_set_voltage_sel_regmap,264	.get_voltage_sel = regulator_get_voltage_sel_regmap,265	.list_voltage = regulator_list_voltage_linear,266};267 268#define PV88080_BUCK(chip, regl_name, min, step, max, limits_array) \269{\270	.desc	=	{\271		.id = chip##_ID_##regl_name,\272		.name = __stringify(chip##_##regl_name),\273		.of_match = of_match_ptr(#regl_name),\274		.regulators_node = of_match_ptr("regulators"),\275		.type = REGULATOR_VOLTAGE,\276		.owner = THIS_MODULE,\277		.ops = &pv88080_buck_ops,\278		.min_uV = min, \279		.uV_step = step, \280		.n_voltages = ((max) - (min))/(step) + 1, \281		.curr_table = limits_array, \282		.n_current_limits = ARRAY_SIZE(limits_array), \283	},\284}285 286#define PV88080_HVBUCK(chip, regl_name, min, step, max) \287{\288	.desc	=	{\289		.id = chip##_ID_##regl_name,\290		.name = __stringify(chip##_##regl_name),\291		.of_match = of_match_ptr(#regl_name),\292		.regulators_node = of_match_ptr("regulators"),\293		.type = REGULATOR_VOLTAGE,\294		.owner = THIS_MODULE,\295		.ops = &pv88080_hvbuck_ops,\296		.min_uV = min, \297		.uV_step = step, \298		.n_voltages = ((max) - (min))/(step) + 1, \299	},\300}301 302static struct pv88080_regulator pv88080_regulator_info[] = {303	PV88080_BUCK(PV88080, BUCK1, 600000, 6250, 1393750,304		pv88080_buck1_limits),305	PV88080_BUCK(PV88080, BUCK2, 600000, 6250, 1393750,306		pv88080_buck23_limits),307	PV88080_BUCK(PV88080, BUCK3, 600000, 6250, 1393750,308		pv88080_buck23_limits),309	PV88080_HVBUCK(PV88080, HVBUCK, 0, 5000, 1275000),310};311 312static irqreturn_t pv88080_irq_handler(int irq, void *data)313{314	struct pv88080 *chip = data;315	int i, reg_val, err, ret = IRQ_NONE;316 317	err = regmap_read(chip->regmap, PV88080_REG_EVENT_A, &reg_val);318	if (err < 0)319		goto error_i2c;320 321	if (reg_val & PV88080_E_VDD_FLT) {322		for (i = 0; i < PV88080_MAX_REGULATORS; i++) {323			if (chip->rdev[i] != NULL)324				regulator_notifier_call_chain(chip->rdev[i],325					REGULATOR_EVENT_UNDER_VOLTAGE,326					NULL);327		}328 329		err = regmap_write(chip->regmap, PV88080_REG_EVENT_A,330			PV88080_E_VDD_FLT);331		if (err < 0)332			goto error_i2c;333 334		ret = IRQ_HANDLED;335	}336 337	if (reg_val & PV88080_E_OVER_TEMP) {338		for (i = 0; i < PV88080_MAX_REGULATORS; i++) {339			if (chip->rdev[i] != NULL)340				regulator_notifier_call_chain(chip->rdev[i],341					REGULATOR_EVENT_OVER_TEMP,342					NULL);343		}344 345		err = regmap_write(chip->regmap, PV88080_REG_EVENT_A,346			PV88080_E_OVER_TEMP);347		if (err < 0)348			goto error_i2c;349 350		ret = IRQ_HANDLED;351	}352 353	return ret;354 355error_i2c:356	dev_err(chip->dev, "I2C error : %d\n", err);357	return IRQ_NONE;358}359 360/*361 * I2C driver interface functions362 */363static int pv88080_i2c_probe(struct i2c_client *i2c)364{365	struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev);366	struct pv88080 *chip;367	const struct pv88080_compatible_regmap *regmap_config;368	struct regulator_config config = { };369	int i, error, ret;370	unsigned int conf2, conf5;371 372	chip = devm_kzalloc(&i2c->dev, sizeof(struct pv88080), GFP_KERNEL);373	if (!chip)374		return -ENOMEM;375 376	chip->dev = &i2c->dev;377	chip->regmap = devm_regmap_init_i2c(i2c, &pv88080_regmap_config);378	if (IS_ERR(chip->regmap)) {379		error = PTR_ERR(chip->regmap);380		dev_err(chip->dev, "Failed to allocate register map: %d\n",381			error);382		return error;383	}384 385	chip->regmap_config = i2c_get_match_data(i2c);386	if (!chip->regmap_config)387		return -ENODEV;388 389	i2c_set_clientdata(i2c, chip);390 391	if (i2c->irq != 0) {392		ret = regmap_write(chip->regmap, PV88080_REG_MASK_A, 0xFF);393		if (ret < 0) {394			dev_err(chip->dev,395				"Failed to mask A reg: %d\n", ret);396			return ret;397		}398		ret = regmap_write(chip->regmap, PV88080_REG_MASK_B, 0xFF);399		if (ret < 0) {400			dev_err(chip->dev,401				"Failed to mask B reg: %d\n", ret);402			return ret;403		}404		ret = regmap_write(chip->regmap, PV88080_REG_MASK_C, 0xFF);405		if (ret < 0) {406			dev_err(chip->dev,407				"Failed to mask C reg: %d\n", ret);408			return ret;409		}410 411		ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,412					pv88080_irq_handler,413					IRQF_TRIGGER_LOW|IRQF_ONESHOT,414					"pv88080", chip);415		if (ret != 0) {416			dev_err(chip->dev, "Failed to request IRQ: %d\n",417				i2c->irq);418			return ret;419		}420 421		ret = regmap_update_bits(chip->regmap, PV88080_REG_MASK_A,422			PV88080_M_VDD_FLT | PV88080_M_OVER_TEMP, 0);423		if (ret < 0) {424			dev_err(chip->dev,425				"Failed to update mask reg: %d\n", ret);426			return ret;427		}428	} else {429		dev_warn(chip->dev, "No IRQ configured\n");430	}431 432	regmap_config = chip->regmap_config;433	config.dev = chip->dev;434	config.regmap = chip->regmap;435 436	/* Registeration for BUCK1, 2, 3 */437	for (i = 0; i < PV88080_MAX_REGULATORS-1; i++) {438		if (init_data)439			config.init_data = &init_data[i];440 441		pv88080_regulator_info[i].desc.csel_reg442			= regmap_config->buck_regmap[i].buck_limit_reg;443		pv88080_regulator_info[i].desc.csel_mask444			= regmap_config->buck_regmap[i].buck_limit_mask;445		pv88080_regulator_info[i].mode_reg446			= regmap_config->buck_regmap[i].buck_mode_reg;447		pv88080_regulator_info[i].conf2448			= regmap_config->buck_regmap[i].buck_vdac_range_reg;449		pv88080_regulator_info[i].conf5450			= regmap_config->buck_regmap[i].buck_vrange_gain_reg;451		pv88080_regulator_info[i].desc.enable_reg452			= regmap_config->buck_regmap[i].buck_enable_reg;453		pv88080_regulator_info[i].desc.enable_mask454			= regmap_config->buck_regmap[i].buck_enable_mask;455		pv88080_regulator_info[i].desc.vsel_reg456			= regmap_config->buck_regmap[i].buck_vsel_reg;457		pv88080_regulator_info[i].desc.vsel_mask458			= regmap_config->buck_regmap[i].buck_vsel_mask;459 460		ret = regmap_read(chip->regmap,461				pv88080_regulator_info[i].conf2, &conf2);462		if (ret < 0)463			return ret;464		conf2 = ((conf2 >> PV88080_BUCK_VDAC_RANGE_SHIFT) &465			PV88080_BUCK_VDAC_RANGE_MASK);466 467		ret = regmap_read(chip->regmap,468				pv88080_regulator_info[i].conf5, &conf5);469		if (ret < 0)470			return ret;471		conf5 = ((conf5 >> PV88080_BUCK_VRANGE_GAIN_SHIFT) &472			PV88080_BUCK_VRANGE_GAIN_MASK);473 474		pv88080_regulator_info[i].desc.min_uV =475			pv88080_buck_vol[conf2].min_uV * (conf5+1);476		pv88080_regulator_info[i].desc.uV_step =477			pv88080_buck_vol[conf2].uV_step * (conf5+1);478		pv88080_regulator_info[i].desc.n_voltages =479			((pv88080_buck_vol[conf2].max_uV * (conf5+1))480			- (pv88080_regulator_info[i].desc.min_uV))481			/(pv88080_regulator_info[i].desc.uV_step) + 1;482 483		config.driver_data = (void *)&pv88080_regulator_info[i];484		chip->rdev[i] = devm_regulator_register(chip->dev,485			&pv88080_regulator_info[i].desc, &config);486		if (IS_ERR(chip->rdev[i])) {487			dev_err(chip->dev,488				"Failed to register PV88080 regulator\n");489			return PTR_ERR(chip->rdev[i]);490		}491	}492 493	pv88080_regulator_info[PV88080_ID_HVBUCK].desc.enable_reg494		= regmap_config->hvbuck_enable_reg;495	pv88080_regulator_info[PV88080_ID_HVBUCK].desc.enable_mask496		= regmap_config->hvbuck_enable_mask;497	pv88080_regulator_info[PV88080_ID_HVBUCK].desc.vsel_reg498		= regmap_config->hvbuck_vsel_reg;499	pv88080_regulator_info[PV88080_ID_HVBUCK].desc.vsel_mask500		= regmap_config->hvbuck_vsel_mask;501 502	/* Registeration for HVBUCK */503	if (init_data)504		config.init_data = &init_data[PV88080_ID_HVBUCK];505 506	config.driver_data = (void *)&pv88080_regulator_info[PV88080_ID_HVBUCK];507	chip->rdev[PV88080_ID_HVBUCK] = devm_regulator_register(chip->dev,508		&pv88080_regulator_info[PV88080_ID_HVBUCK].desc, &config);509	if (IS_ERR(chip->rdev[PV88080_ID_HVBUCK])) {510		dev_err(chip->dev, "Failed to register PV88080 regulator\n");511		return PTR_ERR(chip->rdev[PV88080_ID_HVBUCK]);512	}513 514	return 0;515}516 517static const struct of_device_id pv88080_dt_ids[] = {518	{ .compatible = "pvs,pv88080",    .data = &pv88080_aa_regs },519	{ .compatible = "pvs,pv88080-aa", .data = &pv88080_aa_regs },520	{ .compatible = "pvs,pv88080-ba", .data = &pv88080_ba_regs },521	{}522};523MODULE_DEVICE_TABLE(of, pv88080_dt_ids);524 525static const struct i2c_device_id pv88080_i2c_id[] = {526	{ "pv88080",    (kernel_ulong_t)&pv88080_aa_regs },527	{ "pv88080-aa", (kernel_ulong_t)&pv88080_aa_regs },528	{ "pv88080-ba", (kernel_ulong_t)&pv88080_ba_regs },529	{}530};531MODULE_DEVICE_TABLE(i2c, pv88080_i2c_id);532 533static struct i2c_driver pv88080_regulator_driver = {534	.driver = {535		.name = "pv88080",536		.probe_type = PROBE_PREFER_ASYNCHRONOUS,537		.of_match_table = pv88080_dt_ids,538	},539	.probe = pv88080_i2c_probe,540	.id_table = pv88080_i2c_id,541};542 543module_i2c_driver(pv88080_regulator_driver);544 545MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");546MODULE_DESCRIPTION("Regulator device driver for Powerventure PV88080");547MODULE_LICENSE("GPL");548