brintos

brintos / linux-shallow public Read only

0
0
Text · 10.3 KiB · 7531b2c Raw
368 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * TI LM363X Regulator Driver4 *5 * Copyright 2015 Texas Instruments6 *7 * Author: Milo Kim <milo.kim@ti.com>8 */9 10#include <linux/err.h>11#include <linux/kernel.h>12#include <linux/mfd/ti-lmu.h>13#include <linux/mfd/ti-lmu-register.h>14#include <linux/module.h>15#include <linux/of.h>16#include <linux/gpio/consumer.h>17#include <linux/platform_device.h>18#include <linux/regulator/driver.h>19#include <linux/regulator/of_regulator.h>20#include <linux/slab.h>21 22/* LM3631 */23#define LM3631_BOOST_VSEL_MAX		0x2524#define LM3631_LDO_VSEL_MAX		0x2825#define LM3631_CONT_VSEL_MAX		0x0326#define LM3631_VBOOST_MIN		450000027#define LM3631_VCONT_MIN		180000028#define LM3631_VLDO_MIN			400000029#define ENABLE_TIME_USEC		100030 31/* LM3632 */32#define LM3632_BOOST_VSEL_MAX		0x2633#define LM3632_LDO_VSEL_MAX		0x2834#define LM3632_VBOOST_MIN		450000035#define LM3632_VLDO_MIN			400000036 37/* LM36274 */38#define LM36274_BOOST_VSEL_MAX		0x3f39#define LM36274_LDO_VSEL_MAX		0x3240#define LM36274_VOLTAGE_MIN		400000041 42/* Common */43#define LM363X_STEP_50mV		5000044#define LM363X_STEP_500mV		50000045 46static const int ldo_cont_enable_time[] = {47	0, 2000, 5000, 10000, 20000, 50000, 100000, 200000,48};49 50static int lm363x_regulator_enable_time(struct regulator_dev *rdev)51{52	enum lm363x_regulator_id id = rdev_get_id(rdev);53	unsigned int val, addr, mask;54 55	switch (id) {56	case LM3631_LDO_CONT:57		addr = LM3631_REG_ENTIME_VCONT;58		mask = LM3631_ENTIME_CONT_MASK;59		break;60	case LM3631_LDO_OREF:61		addr = LM3631_REG_ENTIME_VOREF;62		mask = LM3631_ENTIME_MASK;63		break;64	case LM3631_LDO_POS:65		addr = LM3631_REG_ENTIME_VPOS;66		mask = LM3631_ENTIME_MASK;67		break;68	case LM3631_LDO_NEG:69		addr = LM3631_REG_ENTIME_VNEG;70		mask = LM3631_ENTIME_MASK;71		break;72	default:73		return 0;74	}75 76	if (regmap_read(rdev->regmap, addr, &val))77		return -EINVAL;78 79	val = (val & mask) >> LM3631_ENTIME_SHIFT;80 81	if (id == LM3631_LDO_CONT)82		return ldo_cont_enable_time[val];83	else84		return ENABLE_TIME_USEC * val;85}86 87static const struct regulator_ops lm363x_boost_voltage_table_ops = {88	.list_voltage     = regulator_list_voltage_linear,89	.set_voltage_sel  = regulator_set_voltage_sel_regmap,90	.get_voltage_sel  = regulator_get_voltage_sel_regmap,91};92 93static const struct regulator_ops lm363x_regulator_voltage_table_ops = {94	.list_voltage     = regulator_list_voltage_linear,95	.set_voltage_sel  = regulator_set_voltage_sel_regmap,96	.get_voltage_sel  = regulator_get_voltage_sel_regmap,97	.enable           = regulator_enable_regmap,98	.disable          = regulator_disable_regmap,99	.is_enabled       = regulator_is_enabled_regmap,100	.enable_time      = lm363x_regulator_enable_time,101};102 103static const struct regulator_desc lm363x_regulator_desc[] = {104	/* LM3631 */105	{106		.name           = "vboost",107		.of_match	= "vboost",108		.id             = LM3631_BOOST,109		.ops            = &lm363x_boost_voltage_table_ops,110		.n_voltages     = LM3631_BOOST_VSEL_MAX + 1,111		.min_uV         = LM3631_VBOOST_MIN,112		.uV_step        = LM363X_STEP_50mV,113		.type           = REGULATOR_VOLTAGE,114		.owner          = THIS_MODULE,115		.vsel_reg       = LM3631_REG_VOUT_BOOST,116		.vsel_mask      = LM3631_VOUT_MASK,117	},118	{119		.name           = "ldo_cont",120		.of_match	= "vcont",121		.id             = LM3631_LDO_CONT,122		.ops            = &lm363x_regulator_voltage_table_ops,123		.n_voltages     = LM3631_CONT_VSEL_MAX + 1,124		.min_uV         = LM3631_VCONT_MIN,125		.uV_step        = LM363X_STEP_500mV,126		.type           = REGULATOR_VOLTAGE,127		.owner          = THIS_MODULE,128		.vsel_reg       = LM3631_REG_VOUT_CONT,129		.vsel_mask      = LM3631_VOUT_CONT_MASK,130		.enable_reg     = LM3631_REG_LDO_CTRL2,131		.enable_mask    = LM3631_EN_CONT_MASK,132	},133	{134		.name           = "ldo_oref",135		.of_match	= "voref",136		.id             = LM3631_LDO_OREF,137		.ops            = &lm363x_regulator_voltage_table_ops,138		.n_voltages     = LM3631_LDO_VSEL_MAX + 1,139		.min_uV         = LM3631_VLDO_MIN,140		.uV_step        = LM363X_STEP_50mV,141		.type           = REGULATOR_VOLTAGE,142		.owner          = THIS_MODULE,143		.vsel_reg       = LM3631_REG_VOUT_OREF,144		.vsel_mask      = LM3631_VOUT_MASK,145		.enable_reg     = LM3631_REG_LDO_CTRL1,146		.enable_mask    = LM3631_EN_OREF_MASK,147	},148	{149		.name           = "ldo_vpos",150		.of_match	= "vpos",151		.id             = LM3631_LDO_POS,152		.ops            = &lm363x_regulator_voltage_table_ops,153		.n_voltages     = LM3631_LDO_VSEL_MAX + 1,154		.min_uV         = LM3631_VLDO_MIN,155		.uV_step        = LM363X_STEP_50mV,156		.type           = REGULATOR_VOLTAGE,157		.owner          = THIS_MODULE,158		.vsel_reg       = LM3631_REG_VOUT_POS,159		.vsel_mask      = LM3631_VOUT_MASK,160		.enable_reg     = LM3631_REG_LDO_CTRL1,161		.enable_mask    = LM3631_EN_VPOS_MASK,162	},163	{164		.name           = "ldo_vneg",165		.of_match	= "vneg",166		.id             = LM3631_LDO_NEG,167		.ops            = &lm363x_regulator_voltage_table_ops,168		.n_voltages     = LM3631_LDO_VSEL_MAX + 1,169		.min_uV         = LM3631_VLDO_MIN,170		.uV_step        = LM363X_STEP_50mV,171		.type           = REGULATOR_VOLTAGE,172		.owner          = THIS_MODULE,173		.vsel_reg       = LM3631_REG_VOUT_NEG,174		.vsel_mask      = LM3631_VOUT_MASK,175		.enable_reg     = LM3631_REG_LDO_CTRL1,176		.enable_mask    = LM3631_EN_VNEG_MASK,177	},178	/* LM3632 */179	{180		.name           = "vboost",181		.of_match	= "vboost",182		.id             = LM3632_BOOST,183		.ops            = &lm363x_boost_voltage_table_ops,184		.n_voltages     = LM3632_BOOST_VSEL_MAX + 1,185		.min_uV         = LM3632_VBOOST_MIN,186		.uV_step        = LM363X_STEP_50mV,187		.type           = REGULATOR_VOLTAGE,188		.owner          = THIS_MODULE,189		.vsel_reg       = LM3632_REG_VOUT_BOOST,190		.vsel_mask      = LM3632_VOUT_MASK,191	},192	{193		.name           = "ldo_vpos",194		.of_match	= "vpos",195		.id             = LM3632_LDO_POS,196		.ops            = &lm363x_regulator_voltage_table_ops,197		.n_voltages     = LM3632_LDO_VSEL_MAX + 1,198		.min_uV         = LM3632_VLDO_MIN,199		.uV_step        = LM363X_STEP_50mV,200		.type           = REGULATOR_VOLTAGE,201		.owner          = THIS_MODULE,202		.vsel_reg       = LM3632_REG_VOUT_POS,203		.vsel_mask      = LM3632_VOUT_MASK,204		.enable_reg     = LM3632_REG_BIAS_CONFIG,205		.enable_mask    = LM3632_EN_VPOS_MASK,206	},207	{208		.name           = "ldo_vneg",209		.of_match	= "vneg",210		.id             = LM3632_LDO_NEG,211		.ops            = &lm363x_regulator_voltage_table_ops,212		.n_voltages     = LM3632_LDO_VSEL_MAX + 1,213		.min_uV         = LM3632_VLDO_MIN,214		.uV_step        = LM363X_STEP_50mV,215		.type           = REGULATOR_VOLTAGE,216		.owner          = THIS_MODULE,217		.vsel_reg       = LM3632_REG_VOUT_NEG,218		.vsel_mask      = LM3632_VOUT_MASK,219		.enable_reg     = LM3632_REG_BIAS_CONFIG,220		.enable_mask    = LM3632_EN_VNEG_MASK,221	},222 223	/* LM36274 */224	{225		.name           = "vboost",226		.of_match	= "vboost",227		.id             = LM36274_BOOST,228		.ops            = &lm363x_boost_voltage_table_ops,229		.n_voltages     = LM36274_BOOST_VSEL_MAX + 1,230		.min_uV         = LM36274_VOLTAGE_MIN,231		.uV_step        = LM363X_STEP_50mV,232		.type           = REGULATOR_VOLTAGE,233		.owner          = THIS_MODULE,234		.vsel_reg       = LM36274_REG_VOUT_BOOST,235		.vsel_mask      = LM36274_VOUT_MASK,236	},237	{238		.name           = "ldo_vpos",239		.of_match	= "vpos",240		.id             = LM36274_LDO_POS,241		.ops            = &lm363x_regulator_voltage_table_ops,242		.n_voltages     = LM36274_LDO_VSEL_MAX + 1,243		.min_uV         = LM36274_VOLTAGE_MIN,244		.uV_step        = LM363X_STEP_50mV,245		.type           = REGULATOR_VOLTAGE,246		.owner          = THIS_MODULE,247		.vsel_reg       = LM36274_REG_VOUT_POS,248		.vsel_mask      = LM36274_VOUT_MASK,249		.enable_reg     = LM36274_REG_BIAS_CONFIG_1,250		.enable_mask    = LM36274_EN_VPOS_MASK,251	},252	{253		.name           = "ldo_vneg",254		.of_match	= "vneg",255		.id             = LM36274_LDO_NEG,256		.ops            = &lm363x_regulator_voltage_table_ops,257		.n_voltages     = LM36274_LDO_VSEL_MAX + 1,258		.min_uV         = LM36274_VOLTAGE_MIN,259		.uV_step        = LM363X_STEP_50mV,260		.type           = REGULATOR_VOLTAGE,261		.owner          = THIS_MODULE,262		.vsel_reg       = LM36274_REG_VOUT_NEG,263		.vsel_mask      = LM36274_VOUT_MASK,264		.enable_reg     = LM36274_REG_BIAS_CONFIG_1,265		.enable_mask    = LM36274_EN_VNEG_MASK,266	},267};268 269static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev, int id)270{271	/*272	 * Check LCM_EN1/2_GPIO is configured.273	 * Those pins are used for enabling VPOS/VNEG LDOs.274	 * Do not use devm* here: the regulator core takes over the275	 * lifecycle management of the GPIO descriptor.276	 */277	switch (id) {278	case LM3632_LDO_POS:279	case LM36274_LDO_POS:280		return gpiod_get_index_optional(dev, "enable", 0,281				GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);282	case LM3632_LDO_NEG:283	case LM36274_LDO_NEG:284		return gpiod_get_index_optional(dev, "enable", 1,285				GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);286	default:287		return NULL;288	}289}290 291static int lm363x_regulator_set_ext_en(struct regmap *regmap, int id)292{293	int ext_en_mask = 0;294 295	switch (id) {296	case LM3632_LDO_POS:297	case LM3632_LDO_NEG:298		ext_en_mask = LM3632_EXT_EN_MASK;299		break;300	case LM36274_LDO_POS:301	case LM36274_LDO_NEG:302		ext_en_mask = LM36274_EXT_EN_MASK;303		break;304	default:305		return -ENODEV;306	}307 308	return regmap_update_bits(regmap, lm363x_regulator_desc[id].enable_reg,309				 ext_en_mask, ext_en_mask);310}311 312static int lm363x_regulator_probe(struct platform_device *pdev)313{314	struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);315	struct regmap *regmap = lmu->regmap;316	struct regulator_config cfg = { };317	struct regulator_dev *rdev;318	struct device *dev = &pdev->dev;319	int id = pdev->id;320	struct gpio_desc *gpiod;321	int ret;322 323	cfg.dev = dev;324	cfg.regmap = regmap;325 326	/*327	 * LM3632 LDOs can be controlled by external pin.328	 * Register update is required if the pin is used.329	 */330	gpiod = lm363x_regulator_of_get_enable_gpio(dev, id);331	if (IS_ERR(gpiod))332		return PTR_ERR(gpiod);333 334	if (gpiod) {335		cfg.ena_gpiod = gpiod;336		ret = lm363x_regulator_set_ext_en(regmap, id);337		if (ret) {338			gpiod_put(gpiod);339			dev_err(dev, "External pin err: %d\n", ret);340			return ret;341		}342	}343 344	rdev = devm_regulator_register(dev, &lm363x_regulator_desc[id], &cfg);345	if (IS_ERR(rdev)) {346		ret = PTR_ERR(rdev);347		dev_err(dev, "[%d] regulator register err: %d\n", id, ret);348		return ret;349	}350 351	return 0;352}353 354static struct platform_driver lm363x_regulator_driver = {355	.probe = lm363x_regulator_probe,356	.driver = {357		.name = "lm363x-regulator",358		.probe_type = PROBE_PREFER_ASYNCHRONOUS,359	},360};361 362module_platform_driver(lm363x_regulator_driver);363 364MODULE_DESCRIPTION("TI LM363X Regulator Driver");365MODULE_AUTHOR("Milo Kim");366MODULE_LICENSE("GPL v2");367MODULE_ALIAS("platform:lm363x-regulator");368