brintos

brintos / linux-shallow public Read only

0
0
Text · 7.9 KiB · c1532db Raw
287 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Regulators driver for Maxim max89254 *5 * Copyright (C) 2009 Marvell International Ltd.6 *      Haojian Zhuang <haojian.zhuang@marvell.com>7 */8#include <linux/kernel.h>9#include <linux/module.h>10#include <linux/init.h>11#include <linux/err.h>12#include <linux/i2c.h>13#include <linux/platform_device.h>14#include <linux/regulator/driver.h>15#include <linux/regulator/machine.h>16#include <linux/mfd/max8925.h>17#include <linux/of.h>18#include <linux/regulator/of_regulator.h>19 20#define SD1_DVM_VMIN		85000021#define SD1_DVM_VMAX		100000022#define SD1_DVM_STEP		5000023#define SD1_DVM_SHIFT		5		/* SDCTL1 bit5 */24#define SD1_DVM_EN		6		/* SDV1 bit 6 */25 26/* bit definitions in LDO control registers */27#define LDO_SEQ_I2C		0x7		/* Power U/D by i2c */28#define LDO_SEQ_MASK		0x7		/* Power U/D sequence mask */29#define LDO_SEQ_SHIFT		2		/* Power U/D sequence offset */30#define LDO_I2C_EN		0x1		/* Enable by i2c */31#define LDO_I2C_EN_MASK		0x1		/* Enable mask by i2c */32#define LDO_I2C_EN_SHIFT	0		/* Enable offset by i2c */33 34struct max8925_regulator_info {35	struct regulator_desc	desc;36	struct i2c_client	*i2c;37 38	int	vol_reg;39	int	enable_reg;40};41 42static int max8925_set_voltage_sel(struct regulator_dev *rdev,43				   unsigned int selector)44{45	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);46	unsigned char mask = rdev->desc->n_voltages - 1;47 48	return max8925_set_bits(info->i2c, info->vol_reg, mask, selector);49}50 51static int max8925_get_voltage_sel(struct regulator_dev *rdev)52{53	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);54	unsigned char data, mask;55	int ret;56 57	ret = max8925_reg_read(info->i2c, info->vol_reg);58	if (ret < 0)59		return ret;60	mask = rdev->desc->n_voltages - 1;61	data = ret & mask;62 63	return data;64}65 66static int max8925_enable(struct regulator_dev *rdev)67{68	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);69 70	return max8925_set_bits(info->i2c, info->enable_reg,71				LDO_SEQ_MASK << LDO_SEQ_SHIFT |72				LDO_I2C_EN_MASK << LDO_I2C_EN_SHIFT,73				LDO_SEQ_I2C << LDO_SEQ_SHIFT |74				LDO_I2C_EN << LDO_I2C_EN_SHIFT);75}76 77static int max8925_disable(struct regulator_dev *rdev)78{79	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);80 81	return max8925_set_bits(info->i2c, info->enable_reg,82				LDO_SEQ_MASK << LDO_SEQ_SHIFT |83				LDO_I2C_EN_MASK << LDO_I2C_EN_SHIFT,84				LDO_SEQ_I2C << LDO_SEQ_SHIFT);85}86 87static int max8925_is_enabled(struct regulator_dev *rdev)88{89	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);90	int ldo_seq, ret;91 92	ret = max8925_reg_read(info->i2c, info->enable_reg);93	if (ret < 0)94		return ret;95	ldo_seq = (ret >> LDO_SEQ_SHIFT) & LDO_SEQ_MASK;96	if (ldo_seq != LDO_SEQ_I2C)97		return 1;98	else99		return ret & (LDO_I2C_EN_MASK << LDO_I2C_EN_SHIFT);100}101 102static int max8925_set_dvm_voltage(struct regulator_dev *rdev, int uV)103{104	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);105	unsigned char data, mask;106 107	if (uV < SD1_DVM_VMIN || uV > SD1_DVM_VMAX)108		return -EINVAL;109 110	data = DIV_ROUND_UP(uV - SD1_DVM_VMIN, SD1_DVM_STEP);111	data <<= SD1_DVM_SHIFT;112	mask = 3 << SD1_DVM_SHIFT;113 114	return max8925_set_bits(info->i2c, info->enable_reg, mask, data);115}116 117static int max8925_set_dvm_enable(struct regulator_dev *rdev)118{119	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);120 121	return max8925_set_bits(info->i2c, info->vol_reg, 1 << SD1_DVM_EN,122				1 << SD1_DVM_EN);123}124 125static int max8925_set_dvm_disable(struct regulator_dev *rdev)126{127	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);128 129	return max8925_set_bits(info->i2c, info->vol_reg, 1 << SD1_DVM_EN, 0);130}131 132static const struct regulator_ops max8925_regulator_sdv_ops = {133	.map_voltage		= regulator_map_voltage_linear,134	.list_voltage		= regulator_list_voltage_linear,135	.set_voltage_sel	= max8925_set_voltage_sel,136	.get_voltage_sel	= max8925_get_voltage_sel,137	.enable			= max8925_enable,138	.disable		= max8925_disable,139	.is_enabled		= max8925_is_enabled,140	.set_suspend_voltage	= max8925_set_dvm_voltage,141	.set_suspend_enable	= max8925_set_dvm_enable,142	.set_suspend_disable	= max8925_set_dvm_disable,143};144 145static const struct regulator_ops max8925_regulator_ldo_ops = {146	.map_voltage		= regulator_map_voltage_linear,147	.list_voltage		= regulator_list_voltage_linear,148	.set_voltage_sel	= max8925_set_voltage_sel,149	.get_voltage_sel	= max8925_get_voltage_sel,150	.enable			= max8925_enable,151	.disable		= max8925_disable,152	.is_enabled		= max8925_is_enabled,153};154 155#define MAX8925_SDV(_id, min, max, step)			\156{								\157	.desc	= {						\158		.name	= "SDV" #_id,				\159		.of_match = of_match_ptr("SDV" #_id),		\160		.regulators_node = of_match_ptr("regulators"),	\161		.ops	= &max8925_regulator_sdv_ops,		\162		.type	= REGULATOR_VOLTAGE,			\163		.id	= MAX8925_ID_SD##_id,			\164		.owner	= THIS_MODULE,				\165		.n_voltages = 64,				\166		.min_uV = min * 1000,				\167		.uV_step = step * 1000,				\168	},							\169	.vol_reg	= MAX8925_SDV##_id,			\170	.enable_reg	= MAX8925_SDCTL##_id,			\171}172 173#define MAX8925_LDO(_id, min, max, step)			\174{								\175	.desc	= {						\176		.name	= "LDO" #_id,				\177		.of_match = of_match_ptr("LDO" #_id),		\178		.regulators_node = of_match_ptr("regulators"),	\179		.ops	= &max8925_regulator_ldo_ops,		\180		.type	= REGULATOR_VOLTAGE,			\181		.id	= MAX8925_ID_LDO##_id,			\182		.owner	= THIS_MODULE,				\183		.n_voltages = 64,				\184		.min_uV = min * 1000,				\185		.uV_step = step * 1000,				\186	},							\187	.vol_reg	= MAX8925_LDOVOUT##_id,			\188	.enable_reg	= MAX8925_LDOCTL##_id,			\189}190 191static struct max8925_regulator_info max8925_regulator_info[] = {192	MAX8925_SDV(1, 637.5, 1425, 12.5),193	MAX8925_SDV(2,   650, 2225,   25),194	MAX8925_SDV(3,   750, 3900,   50),195 196	MAX8925_LDO(1,  750, 3900, 50),197	MAX8925_LDO(2,  650, 2250, 25),198	MAX8925_LDO(3,  650, 2250, 25),199	MAX8925_LDO(4,  750, 3900, 50),200	MAX8925_LDO(5,  750, 3900, 50),201	MAX8925_LDO(6,  750, 3900, 50),202	MAX8925_LDO(7,  750, 3900, 50),203	MAX8925_LDO(8,  750, 3900, 50),204	MAX8925_LDO(9,  750, 3900, 50),205	MAX8925_LDO(10, 750, 3900, 50),206	MAX8925_LDO(11, 750, 3900, 50),207	MAX8925_LDO(12, 750, 3900, 50),208	MAX8925_LDO(13, 750, 3900, 50),209	MAX8925_LDO(14, 750, 3900, 50),210	MAX8925_LDO(15, 750, 3900, 50),211	MAX8925_LDO(16, 750, 3900, 50),212	MAX8925_LDO(17, 650, 2250, 25),213	MAX8925_LDO(18, 650, 2250, 25),214	MAX8925_LDO(19, 750, 3900, 50),215	MAX8925_LDO(20, 750, 3900, 50),216};217 218static int max8925_regulator_probe(struct platform_device *pdev)219{220	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);221	struct regulator_init_data *pdata = dev_get_platdata(&pdev->dev);222	struct regulator_config config = { };223	struct max8925_regulator_info *ri;224	struct resource *res;225	struct regulator_dev *rdev;226	int i;227 228	res = platform_get_resource(pdev, IORESOURCE_REG, 0);229	if (!res) {230		dev_err(&pdev->dev, "No REG resource!\n");231		return -EINVAL;232	}233	for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) {234		ri = &max8925_regulator_info[i];235		if (ri->vol_reg == res->start)236			break;237	}238 239	if (i == ARRAY_SIZE(max8925_regulator_info)) {240		dev_err(&pdev->dev, "Failed to find regulator %llu\n",241			(unsigned long long)res->start);242		return -EINVAL;243	}244	ri->i2c = chip->i2c;245 246	config.dev = chip->dev;247	config.driver_data = ri;248 249	if (pdata)250		config.init_data = pdata;251 252	rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config);253	if (IS_ERR(rdev)) {254		dev_err(&pdev->dev, "failed to register regulator %s\n",255				ri->desc.name);256		return PTR_ERR(rdev);257	}258 259	platform_set_drvdata(pdev, rdev);260	return 0;261}262 263static struct platform_driver max8925_regulator_driver = {264	.driver		= {265		.name	= "max8925-regulator",266		.probe_type = PROBE_PREFER_ASYNCHRONOUS,267	},268	.probe		= max8925_regulator_probe,269};270 271static int __init max8925_regulator_init(void)272{273	return platform_driver_register(&max8925_regulator_driver);274}275subsys_initcall(max8925_regulator_init);276 277static void __exit max8925_regulator_exit(void)278{279	platform_driver_unregister(&max8925_regulator_driver);280}281module_exit(max8925_regulator_exit);282 283MODULE_LICENSE("GPL");284MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");285MODULE_DESCRIPTION("Regulator Driver for Maxim 8925 PMIC");286MODULE_ALIAS("platform:max8925-regulator");287