brintos

brintos / linux-shallow public Read only

0
0
Text · 12.8 KiB · fbebe53 Raw
461 lines · c
1// SPDX-License-Identifier: GPL-2.0+2//3// da9052-regulator.c: Regulator driver for DA90524//5// Copyright(c) 2011 Dialog Semiconductor Ltd.6//7// Author: David Dajun Chen <dchen@diasemi.com>8 9#include <linux/module.h>10#include <linux/moduleparam.h>11#include <linux/init.h>12#include <linux/err.h>13#include <linux/platform_device.h>14#include <linux/regulator/driver.h>15#include <linux/regulator/machine.h>16#include <linux/of.h>17#include <linux/regulator/of_regulator.h>18 19#include <linux/mfd/da9052/da9052.h>20#include <linux/mfd/da9052/reg.h>21#include <linux/mfd/da9052/pdata.h>22 23/* Buck step size */24#define DA9052_BUCK_PERI_3uV_STEP		10000025#define DA9052_BUCK_PERI_REG_MAP_UPTO_3uV	2426#define DA9052_CONST_3uV			300000027 28#define DA9052_MIN_UA		029#define DA9052_MAX_UA		330#define DA9052_CURRENT_RANGE	431 32/* Bit masks */33#define DA9052_BUCK_ILIM_MASK_EVEN	0x0c34#define DA9052_BUCK_ILIM_MASK_ODD	0xc035 36/* DA9052 REGULATOR IDs */37#define DA9052_ID_BUCK1		038#define DA9052_ID_BUCK2		139#define DA9052_ID_BUCK3		240#define DA9052_ID_BUCK4		341#define DA9052_ID_LDO1		442#define DA9052_ID_LDO2		543#define DA9052_ID_LDO3		644#define DA9052_ID_LDO4		745#define DA9052_ID_LDO5		846#define DA9052_ID_LDO6		947#define DA9052_ID_LDO7		1048#define DA9052_ID_LDO8		1149#define DA9052_ID_LDO9		1250#define DA9052_ID_LDO10		1351 52static const u32 da9052_current_limits[3][4] = {53	{700000, 800000, 1000000, 1200000},	/* DA9052-BC BUCKs */54	{1600000, 2000000, 2400000, 3000000},	/* DA9053-AA/Bx BUCK-CORE */55	{800000, 1000000, 1200000, 1500000},	/* DA9053-AA/Bx BUCK-PRO,56						 * BUCK-MEM and BUCK-PERI57						*/58};59 60struct da9052_regulator_info {61	struct regulator_desc reg_desc;62	int step_uV;63	int min_uV;64	int max_uV;65	unsigned char activate_bit;66};67 68struct da9052_regulator {69	struct da9052 *da9052;70	const struct da9052_regulator_info *info;71	struct regulator_dev *rdev;72};73 74static int verify_range(const struct da9052_regulator_info *info,75			 int min_uV, int max_uV)76{77	if (min_uV > info->max_uV || max_uV < info->min_uV)78		return -EINVAL;79 80	return 0;81}82 83static int da9052_dcdc_get_current_limit(struct regulator_dev *rdev)84{85	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);86	int offset = rdev_get_id(rdev);87	int ret, row = 2;88 89	ret = da9052_reg_read(regulator->da9052, DA9052_BUCKA_REG + offset/2);90	if (ret < 0)91		return ret;92 93	/* Determine the even or odd position of the buck current limit94	 * register field95	*/96	if (offset % 2 == 0)97		ret = (ret & DA9052_BUCK_ILIM_MASK_EVEN) >> 2;98	else99		ret = (ret & DA9052_BUCK_ILIM_MASK_ODD) >> 6;100 101	/* Select the appropriate current limit range */102	if (regulator->da9052->chip_id == DA9052)103		row = 0;104	else if (offset == 0)105		row = 1;106 107	return da9052_current_limits[row][ret];108}109 110static int da9052_dcdc_set_current_limit(struct regulator_dev *rdev, int min_uA,111					  int max_uA)112{113	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);114	int offset = rdev_get_id(rdev);115	int reg_val = 0;116	int i, row = 2;117 118	/* Select the appropriate current limit range */119	if (regulator->da9052->chip_id == DA9052)120		row = 0;121	else if (offset == 0)122		row = 1;123 124	for (i = DA9052_CURRENT_RANGE - 1; i >= 0; i--) {125		if ((min_uA <= da9052_current_limits[row][i]) &&126		    (da9052_current_limits[row][i] <= max_uA)) {127			reg_val = i;128			break;129		}130	}131 132	if (i < 0)133		return -EINVAL;134 135	/* Determine the even or odd position of the buck current limit136	 * register field137	*/138	if (offset % 2 == 0)139		return da9052_reg_update(regulator->da9052,140					 DA9052_BUCKA_REG + offset/2,141					 DA9052_BUCK_ILIM_MASK_EVEN,142					 reg_val << 2);143	else144		return da9052_reg_update(regulator->da9052,145					 DA9052_BUCKA_REG + offset/2,146					 DA9052_BUCK_ILIM_MASK_ODD,147					 reg_val << 6);148}149 150static int da9052_list_voltage(struct regulator_dev *rdev,151				unsigned int selector)152{153	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);154	const struct da9052_regulator_info *info = regulator->info;155	int id = rdev_get_id(rdev);156	int volt_uV;157 158	if ((id == DA9052_ID_BUCK4) && (regulator->da9052->chip_id == DA9052)159		&& (selector >= DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)) {160		volt_uV = ((DA9052_BUCK_PERI_REG_MAP_UPTO_3uV * info->step_uV)161			  + info->min_uV);162		volt_uV += (selector - DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)163				    * (DA9052_BUCK_PERI_3uV_STEP);164	} else {165		volt_uV = (selector * info->step_uV) + info->min_uV;166	}167 168	if (volt_uV > info->max_uV)169		return -EINVAL;170 171	return volt_uV;172}173 174static int da9052_map_voltage(struct regulator_dev *rdev,175			      int min_uV, int max_uV)176{177	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);178	const struct da9052_regulator_info *info = regulator->info;179	int id = rdev_get_id(rdev);180	int ret, sel;181 182	ret = verify_range(info, min_uV, max_uV);183	if (ret < 0)184		return ret;185 186	if (min_uV < info->min_uV)187		min_uV = info->min_uV;188 189	if ((id == DA9052_ID_BUCK4) && (regulator->da9052->chip_id == DA9052)190		&& (min_uV >= DA9052_CONST_3uV)) {191			sel = DA9052_BUCK_PERI_REG_MAP_UPTO_3uV +192			      DIV_ROUND_UP(min_uV - DA9052_CONST_3uV,193					   DA9052_BUCK_PERI_3uV_STEP);194	} else {195		sel = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);196	}197 198	ret = da9052_list_voltage(rdev, sel);199	if (ret < 0)200		return ret;201 202	return sel;203}204 205static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev,206					    unsigned int selector)207{208	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);209	const struct da9052_regulator_info *info = regulator->info;210	int id = rdev_get_id(rdev);211	int ret;212 213	ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg,214				rdev->desc->vsel_mask, selector);215	if (ret < 0)216		return ret;217 218	/* Some LDOs and DCDCs are DVC controlled which requires enabling of219	 * the activate bit to implment the changes on the output.220	 */221	switch (id) {222	case DA9052_ID_BUCK1:223	case DA9052_ID_BUCK2:224	case DA9052_ID_BUCK3:225	case DA9052_ID_LDO2:226	case DA9052_ID_LDO3:227		ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,228					info->activate_bit, info->activate_bit);229		break;230	}231 232	return ret;233}234 235static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev,236						 unsigned int old_sel,237						 unsigned int new_sel)238{239	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);240	const struct da9052_regulator_info *info = regulator->info;241	int id = rdev_get_id(rdev);242	int ret = 0;243 244	/* The DVC controlled LDOs and DCDCs ramp with 6.25mV/µs after enabling245	 * the activate bit.246	 */247	switch (id) {248	case DA9052_ID_BUCK1:249	case DA9052_ID_BUCK2:250	case DA9052_ID_BUCK3:251	case DA9052_ID_LDO2:252	case DA9052_ID_LDO3:253		ret = DIV_ROUND_UP(abs(new_sel - old_sel) * info->step_uV,254				   6250);255		break;256	}257 258	return ret;259}260 261static const struct regulator_ops da9052_dcdc_ops = {262	.get_current_limit = da9052_dcdc_get_current_limit,263	.set_current_limit = da9052_dcdc_set_current_limit,264 265	.list_voltage = da9052_list_voltage,266	.map_voltage = da9052_map_voltage,267	.get_voltage_sel = regulator_get_voltage_sel_regmap,268	.set_voltage_sel = da9052_regulator_set_voltage_sel,269	.set_voltage_time_sel = da9052_regulator_set_voltage_time_sel,270	.is_enabled = regulator_is_enabled_regmap,271	.enable = regulator_enable_regmap,272	.disable = regulator_disable_regmap,273};274 275static const struct regulator_ops da9052_ldo_ops = {276	.list_voltage = da9052_list_voltage,277	.map_voltage = da9052_map_voltage,278	.get_voltage_sel = regulator_get_voltage_sel_regmap,279	.set_voltage_sel = da9052_regulator_set_voltage_sel,280	.set_voltage_time_sel = da9052_regulator_set_voltage_time_sel,281	.is_enabled = regulator_is_enabled_regmap,282	.enable = regulator_enable_regmap,283	.disable = regulator_disable_regmap,284};285 286#define DA9052_LDO(_id, _name, step, min, max, sbits, ebits, abits) \287{\288	.reg_desc = {\289		.name = #_name,\290		.of_match = of_match_ptr(#_name),\291		.regulators_node = of_match_ptr("regulators"),\292		.ops = &da9052_ldo_ops,\293		.type = REGULATOR_VOLTAGE,\294		.id = DA9052_ID_##_id,\295		.n_voltages = (max - min) / step + 1, \296		.owner = THIS_MODULE,\297		.vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \298		.vsel_mask = (1 << (sbits)) - 1,\299		.enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \300		.enable_mask = 1 << (ebits),\301	},\302	.min_uV = (min) * 1000,\303	.max_uV = (max) * 1000,\304	.step_uV = (step) * 1000,\305	.activate_bit = (abits),\306}307 308#define DA9052_DCDC(_id, _name, step, min, max, sbits, ebits, abits) \309{\310	.reg_desc = {\311		.name = #_name,\312		.of_match = of_match_ptr(#_name),\313		.regulators_node = of_match_ptr("regulators"),\314		.ops = &da9052_dcdc_ops,\315		.type = REGULATOR_VOLTAGE,\316		.id = DA9052_ID_##_id,\317		.n_voltages = (max - min) / step + 1, \318		.owner = THIS_MODULE,\319		.vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \320		.vsel_mask = (1 << (sbits)) - 1,\321		.enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \322		.enable_mask = 1 << (ebits),\323	},\324	.min_uV = (min) * 1000,\325	.max_uV = (max) * 1000,\326	.step_uV = (step) * 1000,\327	.activate_bit = (abits),\328}329 330static const struct da9052_regulator_info da9052_regulator_info[] = {331	DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO),332	DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO),333	DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO),334	DA9052_DCDC(BUCK4, buck4, 50, 1800, 3600, 5, 6, 0),335	DA9052_LDO(LDO1, ldo1, 50, 600, 1800, 5, 6, 0),336	DA9052_LDO(LDO2, ldo2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO),337	DA9052_LDO(LDO3, ldo3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO),338	DA9052_LDO(LDO4, ldo4, 25, 1725, 3300, 6, 6, 0),339	DA9052_LDO(LDO5, ldo5, 50, 1200, 3600, 6, 6, 0),340	DA9052_LDO(LDO6, ldo6, 50, 1200, 3600, 6, 6, 0),341	DA9052_LDO(LDO7, ldo7, 50, 1200, 3600, 6, 6, 0),342	DA9052_LDO(LDO8, ldo8, 50, 1200, 3600, 6, 6, 0),343	DA9052_LDO(LDO9, ldo9, 50, 1250, 3650, 6, 6, 0),344	DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0),345};346 347static const struct da9052_regulator_info da9053_regulator_info[] = {348	DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO),349	DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO),350	DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO),351	DA9052_DCDC(BUCK4, buck4, 25, 950, 2525, 6, 6, 0),352	DA9052_LDO(LDO1, ldo1, 50, 600, 1800, 5, 6, 0),353	DA9052_LDO(LDO2, ldo2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO),354	DA9052_LDO(LDO3, ldo3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO),355	DA9052_LDO(LDO4, ldo4, 25, 1725, 3300, 6, 6, 0),356	DA9052_LDO(LDO5, ldo5, 50, 1200, 3600, 6, 6, 0),357	DA9052_LDO(LDO6, ldo6, 50, 1200, 3600, 6, 6, 0),358	DA9052_LDO(LDO7, ldo7, 50, 1200, 3600, 6, 6, 0),359	DA9052_LDO(LDO8, ldo8, 50, 1200, 3600, 6, 6, 0),360	DA9052_LDO(LDO9, ldo9, 50, 1250, 3650, 6, 6, 0),361	DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0),362};363 364static inline const struct da9052_regulator_info *find_regulator_info(u8 chip_id,365								      int id)366{367	const struct da9052_regulator_info *info;368	int i;369 370	switch (chip_id) {371	case DA9052:372		for (i = 0; i < ARRAY_SIZE(da9052_regulator_info); i++) {373			info = &da9052_regulator_info[i];374			if (info->reg_desc.id == id)375				return info;376		}377		break;378	case DA9053_AA:379	case DA9053_BA:380	case DA9053_BB:381	case DA9053_BC:382		for (i = 0; i < ARRAY_SIZE(da9053_regulator_info); i++) {383			info = &da9053_regulator_info[i];384			if (info->reg_desc.id == id)385				return info;386		}387		break;388	}389 390	return NULL;391}392 393static int da9052_regulator_probe(struct platform_device *pdev)394{395	const struct mfd_cell *cell = mfd_get_cell(pdev);396	struct regulator_config config = { };397	struct da9052_regulator *regulator;398	struct da9052 *da9052;399	struct da9052_pdata *pdata;400 401	regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9052_regulator),402				 GFP_KERNEL);403	if (!regulator)404		return -ENOMEM;405 406	da9052 = dev_get_drvdata(pdev->dev.parent);407	pdata = dev_get_platdata(da9052->dev);408	regulator->da9052 = da9052;409 410	regulator->info = find_regulator_info(regulator->da9052->chip_id,411					      cell->id);412	if (regulator->info == NULL) {413		dev_err(&pdev->dev, "invalid regulator ID specified\n");414		return -EINVAL;415	}416 417	config.dev = da9052->dev;418	config.driver_data = regulator;419	config.regmap = da9052->regmap;420	if (pdata)421		config.init_data = pdata->regulators[cell->id];422 423	regulator->rdev = devm_regulator_register(&pdev->dev,424						  &regulator->info->reg_desc,425						  &config);426	if (IS_ERR(regulator->rdev)) {427		dev_err(&pdev->dev, "failed to register regulator %s\n",428			regulator->info->reg_desc.name);429		return PTR_ERR(regulator->rdev);430	}431 432	platform_set_drvdata(pdev, regulator);433 434	return 0;435}436 437static struct platform_driver da9052_regulator_driver = {438	.probe = da9052_regulator_probe,439	.driver = {440		.name = "da9052-regulator",441		.probe_type = PROBE_PREFER_ASYNCHRONOUS,442	},443};444 445static int __init da9052_regulator_init(void)446{447	return platform_driver_register(&da9052_regulator_driver);448}449subsys_initcall(da9052_regulator_init);450 451static void __exit da9052_regulator_exit(void)452{453	platform_driver_unregister(&da9052_regulator_driver);454}455module_exit(da9052_regulator_exit);456 457MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");458MODULE_DESCRIPTION("Power Regulator driver for Dialog DA9052 PMIC");459MODULE_LICENSE("GPL");460MODULE_ALIAS("platform:da9052-regulator");461