diff options
Diffstat (limited to 'drivers/regulator/max8649.c')
| -rw-r--r-- | drivers/regulator/max8649.c | 290 |
1 files changed, 78 insertions, 212 deletions
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index 30eb9e54f7e..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,167 +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, unsigned *selector) -{ - 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; - *selector = data & 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) @@ -230,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; @@ -246,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, @@ -273,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; @@ -383,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", }, @@ -406,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"); - |
