diff options
Diffstat (limited to 'drivers/regulator/max8649.c')
| -rw-r--r-- | drivers/regulator/max8649.c | 289 | 
1 files changed, 78 insertions, 211 deletions
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index 6b60a9c0366..c8bddcc8f91 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -16,6 +16,7 @@  #include <linux/regulator/driver.h>  #include <linux/slab.h>  #include <linux/regulator/max8649.h> +#include <linux/regmap.h>  #define MAX8649_DCDC_VMIN	750000		/* uV */  #define MAX8649_DCDC_VMAX	1380000		/* uV */ @@ -48,12 +49,9 @@  #define MAX8649_RAMP_DOWN	(1 << 1)  struct max8649_regulator_info { -	struct regulator_dev	*regulator; -	struct i2c_client	*i2c;  	struct device		*dev; -	struct mutex		io_lock; +	struct regmap		*regmap; -	int		vol_reg;  	unsigned	mode:2;	/* bit[1:0] = VID1, VID0 */  	unsigned	extclk_freq:2;  	unsigned	extclk:1; @@ -61,166 +59,27 @@ struct max8649_regulator_info {  	unsigned	ramp_down:1;  }; -/* I2C operations */ - -static inline int max8649_read_device(struct i2c_client *i2c, -				      int reg, int bytes, void *dest) -{ -	unsigned char data; -	int ret; - -	data = (unsigned char)reg; -	ret = i2c_master_send(i2c, &data, 1); -	if (ret < 0) -		return ret; -	ret = i2c_master_recv(i2c, dest, bytes); -	if (ret < 0) -		return ret; -	return 0; -} - -static inline int max8649_write_device(struct i2c_client *i2c, -				       int reg, int bytes, void *src) -{ -	unsigned char buf[bytes + 1]; -	int ret; - -	buf[0] = (unsigned char)reg; -	memcpy(&buf[1], src, bytes); - -	ret = i2c_master_send(i2c, buf, bytes + 1); -	if (ret < 0) -		return ret; -	return 0; -} - -static int max8649_reg_read(struct i2c_client *i2c, int reg) -{ -	struct max8649_regulator_info *info = i2c_get_clientdata(i2c); -	unsigned char data; -	int ret; - -	mutex_lock(&info->io_lock); -	ret = max8649_read_device(i2c, reg, 1, &data); -	mutex_unlock(&info->io_lock); - -	if (ret < 0) -		return ret; -	return (int)data; -} - -static int max8649_set_bits(struct i2c_client *i2c, int reg, -			    unsigned char mask, unsigned char data) -{ -	struct max8649_regulator_info *info = i2c_get_clientdata(i2c); -	unsigned char value; -	int ret; - -	mutex_lock(&info->io_lock); -	ret = max8649_read_device(i2c, reg, 1, &value); -	if (ret < 0) -		goto out; -	value &= ~mask; -	value |= data; -	ret = max8649_write_device(i2c, reg, 1, &value); -out: -	mutex_unlock(&info->io_lock); -	return ret; -} - -static inline int check_range(int min_uV, int max_uV) -{ -	if ((min_uV < MAX8649_DCDC_VMIN) || (max_uV > MAX8649_DCDC_VMAX) -		|| (min_uV > max_uV)) -		return -EINVAL; -	return 0; -} - -static int max8649_list_voltage(struct regulator_dev *rdev, unsigned index) -{ -	return (MAX8649_DCDC_VMIN + index * MAX8649_DCDC_STEP); -} - -static int max8649_get_voltage(struct regulator_dev *rdev) -{ -	struct max8649_regulator_info *info = rdev_get_drvdata(rdev); -	unsigned char data; -	int ret; - -	ret = max8649_reg_read(info->i2c, info->vol_reg); -	if (ret < 0) -		return ret; -	data = (unsigned char)ret & MAX8649_VOL_MASK; -	return max8649_list_voltage(rdev, data); -} - -static int max8649_set_voltage(struct regulator_dev *rdev, -			       int min_uV, int max_uV) -{ -	struct max8649_regulator_info *info = rdev_get_drvdata(rdev); -	unsigned char data, mask; - -	if (check_range(min_uV, max_uV)) { -		dev_err(info->dev, "invalid voltage range (%d, %d) uV\n", -			min_uV, max_uV); -		return -EINVAL; -	} -	data = (min_uV - MAX8649_DCDC_VMIN + MAX8649_DCDC_STEP - 1) -		/ MAX8649_DCDC_STEP; -	mask = MAX8649_VOL_MASK; - -	return max8649_set_bits(info->i2c, info->vol_reg, mask, data); -} - -/* EN_PD means pulldown on EN input */ -static int max8649_enable(struct regulator_dev *rdev) -{ -	struct max8649_regulator_info *info = rdev_get_drvdata(rdev); -	return max8649_set_bits(info->i2c, MAX8649_CONTROL, MAX8649_EN_PD, 0); -} - -/* - * Applied internal pulldown resistor on EN input pin. - * If pulldown EN pin outside, it would be better. - */ -static int max8649_disable(struct regulator_dev *rdev) -{ -	struct max8649_regulator_info *info = rdev_get_drvdata(rdev); -	return max8649_set_bits(info->i2c, MAX8649_CONTROL, MAX8649_EN_PD, -				MAX8649_EN_PD); -} - -static int max8649_is_enabled(struct regulator_dev *rdev) -{ -	struct max8649_regulator_info *info = rdev_get_drvdata(rdev); -	int ret; - -	ret = max8649_reg_read(info->i2c, MAX8649_CONTROL); -	if (ret < 0) -		return ret; -	return !((unsigned char)ret & MAX8649_EN_PD); -} -  static int max8649_enable_time(struct regulator_dev *rdev)  {  	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);  	int voltage, rate, ret; +	unsigned int val;  	/* get voltage */ -	ret = max8649_reg_read(info->i2c, info->vol_reg); -	if (ret < 0) +	ret = regmap_read(info->regmap, rdev->desc->vsel_reg, &val); +	if (ret != 0)  		return ret; -	ret &= MAX8649_VOL_MASK; -	voltage = max8649_list_voltage(rdev, (unsigned char)ret); /* uV */ +	val &= MAX8649_VOL_MASK; +	voltage = regulator_list_voltage_linear(rdev, (unsigned char)val);  	/* get rate */ -	ret = max8649_reg_read(info->i2c, MAX8649_RAMP); -	if (ret < 0) +	ret = regmap_read(info->regmap, MAX8649_RAMP, &val); +	if (ret != 0)  		return ret; -	ret = (ret & MAX8649_RAMP_MASK) >> 5; +	ret = (val & MAX8649_RAMP_MASK) >> 5;  	rate = (32 * 1000) >> ret;	/* uV/uS */ -	return (voltage / rate); +	return DIV_ROUND_UP(voltage, rate);  }  static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode) @@ -229,12 +88,12 @@ static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode)  	switch (mode) {  	case REGULATOR_MODE_FAST: -		max8649_set_bits(info->i2c, info->vol_reg, MAX8649_FORCE_PWM, -				 MAX8649_FORCE_PWM); +		regmap_update_bits(info->regmap, rdev->desc->vsel_reg, +				   MAX8649_FORCE_PWM, MAX8649_FORCE_PWM);  		break;  	case REGULATOR_MODE_NORMAL: -		max8649_set_bits(info->i2c, info->vol_reg, -				 MAX8649_FORCE_PWM, 0); +		regmap_update_bits(info->regmap, rdev->desc->vsel_reg, +				   MAX8649_FORCE_PWM, 0);  		break;  	default:  		return -EINVAL; @@ -245,21 +104,25 @@ static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode)  static unsigned int max8649_get_mode(struct regulator_dev *rdev)  {  	struct max8649_regulator_info *info = rdev_get_drvdata(rdev); +	unsigned int val;  	int ret; -	ret = max8649_reg_read(info->i2c, info->vol_reg); -	if (ret & MAX8649_FORCE_PWM) +	ret = regmap_read(info->regmap, rdev->desc->vsel_reg, &val); +	if (ret != 0) +		return ret; +	if (val & MAX8649_FORCE_PWM)  		return REGULATOR_MODE_FAST;  	return REGULATOR_MODE_NORMAL;  }  static struct regulator_ops max8649_dcdc_ops = { -	.set_voltage	= max8649_set_voltage, -	.get_voltage	= max8649_get_voltage, -	.list_voltage	= max8649_list_voltage, -	.enable		= max8649_enable, -	.disable	= max8649_disable, -	.is_enabled	= max8649_is_enabled, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.list_voltage	= regulator_list_voltage_linear, +	.map_voltage	= regulator_map_voltage_linear, +	.enable		= regulator_enable_regmap, +	.disable	= regulator_disable_regmap, +	.is_enabled	= regulator_is_enabled_regmap,  	.enable_time	= max8649_enable_time,  	.set_mode	= max8649_set_mode,  	.get_mode	= max8649_get_mode, @@ -272,103 +135,109 @@ static struct regulator_desc dcdc_desc = {  	.type		= REGULATOR_VOLTAGE,  	.n_voltages	= 1 << 6,  	.owner		= THIS_MODULE, +	.vsel_mask	= MAX8649_VOL_MASK, +	.min_uV		= MAX8649_DCDC_VMIN, +	.uV_step	= MAX8649_DCDC_STEP, +	.enable_reg	= MAX8649_CONTROL, +	.enable_mask	= MAX8649_EN_PD, +	.enable_is_inverted = true, +}; + +static struct regmap_config max8649_regmap_config = { +	.reg_bits = 8, +	.val_bits = 8,  }; -static int __devinit max8649_regulator_probe(struct i2c_client *client, +static int max8649_regulator_probe(struct i2c_client *client,  					     const struct i2c_device_id *id)  { -	struct max8649_platform_data *pdata = client->dev.platform_data; +	struct max8649_platform_data *pdata = dev_get_platdata(&client->dev);  	struct max8649_regulator_info *info = NULL; +	struct regulator_dev *regulator; +	struct regulator_config config = { }; +	unsigned int val;  	unsigned char data;  	int ret; -	info = kzalloc(sizeof(struct max8649_regulator_info), GFP_KERNEL); -	if (!info) { -		dev_err(&client->dev, "No enough memory\n"); +	info = devm_kzalloc(&client->dev, sizeof(struct max8649_regulator_info), +			    GFP_KERNEL); +	if (!info)  		return -ENOMEM; + +	info->regmap = devm_regmap_init_i2c(client, &max8649_regmap_config); +	if (IS_ERR(info->regmap)) { +		ret = PTR_ERR(info->regmap); +		dev_err(&client->dev, "Failed to allocate register map: %d\n", ret); +		return ret;  	} -	info->i2c = client;  	info->dev = &client->dev; -	mutex_init(&info->io_lock);  	i2c_set_clientdata(client, info);  	info->mode = pdata->mode;  	switch (info->mode) {  	case 0: -		info->vol_reg = MAX8649_MODE0; +		dcdc_desc.vsel_reg = MAX8649_MODE0;  		break;  	case 1: -		info->vol_reg = MAX8649_MODE1; +		dcdc_desc.vsel_reg = MAX8649_MODE1;  		break;  	case 2: -		info->vol_reg = MAX8649_MODE2; +		dcdc_desc.vsel_reg = MAX8649_MODE2;  		break;  	case 3: -		info->vol_reg = MAX8649_MODE3; +		dcdc_desc.vsel_reg = MAX8649_MODE3;  		break;  	default:  		break;  	} -	ret = max8649_reg_read(info->i2c, MAX8649_CHIP_ID1); -	if (ret < 0) { +	ret = regmap_read(info->regmap, MAX8649_CHIP_ID1, &val); +	if (ret != 0) {  		dev_err(info->dev, "Failed to detect ID of MAX8649:%d\n",  			ret); -		goto out; +		return ret;  	} -	dev_info(info->dev, "Detected MAX8649 (ID:%x)\n", ret); +	dev_info(info->dev, "Detected MAX8649 (ID:%x)\n", val);  	/* enable VID0 & VID1 */ -	max8649_set_bits(info->i2c, MAX8649_CONTROL, MAX8649_VID_MASK, 0); +	regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_VID_MASK, 0);  	/* enable/disable external clock synchronization */  	info->extclk = pdata->extclk;  	data = (info->extclk) ? MAX8649_SYNC_EXTCLK : 0; -	max8649_set_bits(info->i2c, info->vol_reg, MAX8649_SYNC_EXTCLK, data); +	regmap_update_bits(info->regmap, dcdc_desc.vsel_reg, +			   MAX8649_SYNC_EXTCLK, data);  	if (info->extclk) {  		/* set external clock frequency */  		info->extclk_freq = pdata->extclk_freq; -		max8649_set_bits(info->i2c, MAX8649_SYNC, MAX8649_EXT_MASK, -				 info->extclk_freq << 6); +		regmap_update_bits(info->regmap, MAX8649_SYNC, MAX8649_EXT_MASK, +				   info->extclk_freq << 6);  	}  	if (pdata->ramp_timing) {  		info->ramp_timing = pdata->ramp_timing; -		max8649_set_bits(info->i2c, MAX8649_RAMP, MAX8649_RAMP_MASK, -				 info->ramp_timing << 5); +		regmap_update_bits(info->regmap, MAX8649_RAMP, MAX8649_RAMP_MASK, +				   info->ramp_timing << 5);  	}  	info->ramp_down = pdata->ramp_down;  	if (info->ramp_down) { -		max8649_set_bits(info->i2c, MAX8649_RAMP, MAX8649_RAMP_DOWN, -				 MAX8649_RAMP_DOWN); +		regmap_update_bits(info->regmap, MAX8649_RAMP, MAX8649_RAMP_DOWN, +				   MAX8649_RAMP_DOWN);  	} -	info->regulator = regulator_register(&dcdc_desc, &client->dev, -					     pdata->regulator, info); -	if (IS_ERR(info->regulator)) { +	config.dev = &client->dev; +	config.init_data = pdata->regulator; +	config.driver_data = info; +	config.regmap = info->regmap; + +	regulator = devm_regulator_register(&client->dev, &dcdc_desc, +						  &config); +	if (IS_ERR(regulator)) {  		dev_err(info->dev, "failed to register regulator %s\n",  			dcdc_desc.name); -		ret = PTR_ERR(info->regulator); -		goto out; -	} - -	dev_info(info->dev, "Max8649 regulator device is detected.\n"); -	return 0; -out: -	kfree(info); -	return ret; -} - -static int __devexit max8649_regulator_remove(struct i2c_client *client) -{ -	struct max8649_regulator_info *info = i2c_get_clientdata(client); - -	if (info) { -		if (info->regulator) -			regulator_unregister(info->regulator); -		kfree(info); +		return PTR_ERR(regulator);  	}  	return 0; @@ -382,7 +251,6 @@ MODULE_DEVICE_TABLE(i2c, max8649_id);  static struct i2c_driver max8649_driver = {  	.probe		= max8649_regulator_probe, -	.remove		= __devexit_p(max8649_regulator_remove),  	.driver		= {  		.name	= "max8649",  	}, @@ -405,4 +273,3 @@ module_exit(max8649_exit);  MODULE_DESCRIPTION("MAXIM 8649 voltage regulator driver");  MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");  MODULE_LICENSE("GPL"); -  | 
