diff options
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/Kconfig | 37 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 13 | ||||
-rw-r--r-- | drivers/regulator/core.c | 5 | ||||
-rw-r--r-- | drivers/regulator/da9052-regulator.c | 547 | ||||
-rw-r--r-- | drivers/regulator/ltc3589-regulator.c | 1052 | ||||
-rw-r--r-- | drivers/regulator/max17135-regulator.c | 640 | ||||
-rw-r--r-- | drivers/regulator/mxs-regulator.c | 302 | ||||
-rw-r--r-- | drivers/regulator/reg-mc13783.c | 2662 | ||||
-rw-r--r-- | drivers/regulator/reg-mc13892.c | 1956 | ||||
-rw-r--r-- | drivers/regulator/reg-mc34704.c | 289 | ||||
-rw-r--r-- | drivers/regulator/reg-mc9s08dz60.c | 236 |
11 files changed, 7738 insertions, 1 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 04f2e085116a..694c2e6e539d 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -201,5 +201,42 @@ config REGULATOR_88PM8607 help This driver supports 88PM8607 voltage regulator chips. +config REGULATOR_MC13892 + tristate "MC13892 Regulator Support" + depends on MXC_PMIC_MC13892 + default y + +config REGULATOR_MC34704 + tristate "MC34704 Regulator Support" + depends on MXC_PMIC_MC34704 + default y + +config REGULATOR_LTC3589 + tristate "LTC3589 Regulator Support" + depends on MFD_LTC3589_I2C + depends on REGULATOR + default n + +config REGULATOR_MXS + tristate "MXS Regulator Support" + depends on ARCH_MXS + default y + +config REGULATOR_MC9S08DZ60 + tristate "mc9s08dz60 Regulator Support" + depends on MXC_PMIC_MC9S08DZ60 + default y + +config REGULATOR_MAX17135 + tristate "Maxim MAX17135 Regulator Support" + depends on MFD_MAX17135 + default n + +config REGULATOR_DA9052 + tristate "Dialog DA9052 regulators" + depends on PMIC_DA9052 + help + Say y here to support the BUCKs and LDOs regulators found on + Dialog Semiconductor DA9052 PMIC. endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 4e7feece22d5..850fdd8d45fa 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -2,7 +2,6 @@ # Makefile for regulator drivers. # - obj-$(CONFIG_REGULATOR) += core.o obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o @@ -32,4 +31,16 @@ obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o +obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o + +obj-$(CONFIG_REGULATOR_MAX17135) += max17135-regulator.o + +obj-$(CONFIG_REGULATOR_MC13892) += reg-mc13892.o +obj-$(CONFIG_REGULATOR_MC34704) += reg-mc34704.o +obj-$(CONFIG_REGULATOR_STMP3XXX) += stmp3xxx.o +obj-$(CONFIG_REGULATOR_MXS) += mxs-regulator.o +obj-$(CONFIG_REGULATOR_LTC3589) += ltc3589-regulator.o + +obj-$(CONFIG_REGULATOR_MC9S08DZ60) += reg-mc9s08dz60.o + ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 2248087b9be2..af6ebc027884 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1108,6 +1108,11 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, goto found; } } + list_for_each_entry(rdev, ®ulator_list, list) { + if (strcmp(rdev->desc->name, id) == 0) { + goto found; + } + } #ifdef CONFIG_REGULATOR_DUMMY if (!devname) diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c new file mode 100644 index 000000000000..34452839570c --- /dev/null +++ b/drivers/regulator/da9052-regulator.c @@ -0,0 +1,547 @@ +/* + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * da9052-regulator.c: Regulator driver for DA9052 + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> + +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/reg.h> +#include <linux/mfd/da9052/pm.h> + +static struct regulator_ops da9052_ldo_buck_ops; + + +struct regulator { + struct device *dev; + struct list_head list; + int uA_load; + int min_uV; + int max_uV; + int enabled; /* client has called enabled */ + char *supply_name; + struct device_attribute dev_attr; + struct regulator_dev *rdev; +}; + + + + +#define DA9052_LDO(_id, max, min, step_v, reg, mbits, cbits) \ +{\ + .reg_desc = {\ + .name = #_id,\ + .ops = &da9052_ldo_buck_ops,\ + .type = REGULATOR_VOLTAGE,\ + .id = _id,\ + .owner = THIS_MODULE,\ + },\ + .reg_const = {\ + .max_uV = (max) * 1000,\ + .min_uV = (min) * 1000,\ + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE\ + | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE,\ + .valid_modes_mask = REGULATOR_MODE_NORMAL,\ + },\ + .step_uV = (step_v) * 1000,\ + .reg_add = (reg),\ + .mask_bits = (mbits),\ + .en_bit_mask = (cbits),\ +} + +struct regulator_info { + struct regulator_desc reg_desc; + struct regulation_constraints reg_const; + int step_uV; + unsigned char reg_add; + unsigned char mask_bits; + unsigned char en_bit_mask; +}; + +struct da9052_regulator_priv { + struct da9052 *da9052; + struct regulator_dev *regulators[]; +}; + +struct regulator_info da9052_regulators[] = { + /* LD01 - LDO10*/ + DA9052_LDO(DA9052_LDO1, DA9052_LDO1_VOLT_UPPER, DA9052_LDO1_VOLT_LOWER, + DA9052_LDO1_VOLT_STEP, DA9052_LDO1_REG, + DA9052_LDO1_VLDO1, DA9052_LDO1_LDO1EN), + + DA9052_LDO(DA9052_LDO2, + DA9052_LDO2_VOLT_UPPER, DA9052_LDO2_VOLT_LOWER, + DA9052_LDO2_VOLT_STEP, DA9052_LDO2_REG, + DA9052_LDO2_VLDO2, + DA9052_LDO2_LDO2EN), + + DA9052_LDO(DA9052_LDO3, DA9052_LDO34_VOLT_UPPER, + DA9052_LDO34_VOLT_LOWER, + DA9052_LDO34_VOLT_STEP, DA9052_LDO3_REG, + DA9052_LDO3_VLDO3, DA9052_LDO3_LDO3EN), + + DA9052_LDO(DA9052_LDO4, DA9052_LDO34_VOLT_UPPER, + DA9052_LDO34_VOLT_LOWER, + DA9052_LDO34_VOLT_STEP, DA9052_LDO4_REG, + DA9052_LDO4_VLDO4, DA9052_LDO4_LDO4EN), + + DA9052_LDO(DA9052_LDO5, DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, + DA9052_LDO567810_VOLT_STEP, DA9052_LDO5_REG, + DA9052_LDO5_VLDO5, DA9052_LDO5_LDO5EN), + + DA9052_LDO(DA9052_LDO6, DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, + DA9052_LDO567810_VOLT_STEP, DA9052_LDO6_REG, + DA9052_LDO6_VLDO6, DA9052_LDO6_LDO6EN), + + DA9052_LDO(DA9052_LDO7, DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, + DA9052_LDO567810_VOLT_STEP, DA9052_LDO7_REG, + DA9052_LDO7_VLDO7, DA9052_LDO7_LDO7EN), + + DA9052_LDO(DA9052_LDO8, DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, + DA9052_LDO567810_VOLT_STEP, DA9052_LDO8_REG, + DA9052_LDO8_VLDO8, DA9052_LDO8_LDO8EN), + + DA9052_LDO(DA9052_LDO9, DA9052_LDO9_VOLT_UPPER, + DA9052_LDO9_VOLT_LOWER, + DA9052_LDO9_VOLT_STEP, + DA9052_LDO9_REG, DA9052_LDO9_VLDO9, + DA9052_LDO9_LDO9EN), + + DA9052_LDO(DA9052_LDO10, DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, + DA9052_LDO567810_VOLT_STEP, DA9052_LDO10_REG, + DA9052_LDO10_VLDO10, DA9052_LDO10_LDO10EN), + + /* BUCKS */ + DA9052_LDO(DA9052_BUCK_CORE, DA9052_BUCK_CORE_PRO_VOLT_UPPER, + DA9052_BUCK_CORE_PRO_VOLT_LOWER, + DA9052_BUCK_CORE_PRO_STEP, DA9052_BUCKCORE_REG, + DA9052_BUCKCORE_VBCORE, DA9052_BUCKCORE_BCOREEN), + + DA9052_LDO(DA9052_BUCK_PRO, DA9052_BUCK_CORE_PRO_VOLT_UPPER, + DA9052_BUCK_CORE_PRO_VOLT_LOWER, + DA9052_BUCK_CORE_PRO_STEP, DA9052_BUCKPRO_REG, + DA9052_BUCKPRO_VBPRO, DA9052_BUCKPRO_BPROEN), + + DA9052_LDO(DA9052_BUCK_MEM, DA9052_BUCK_MEM_VOLT_UPPER, + DA9052_BUCK_MEM_VOLT_LOWER, + DA9052_BUCK_MEM_STEP, DA9052_BUCKMEM_REG, + DA9052_BUCKMEM_VBMEM, DA9052_BUCKMEM_BMEMEN), + + DA9052_LDO(DA9052_BUCK_PERI, DA9052_BUCK_PERI_VOLT_UPPER, + DA9052_BUCK_PERI_VOLT_LOWER, + DA9052_BUCK_PERI_STEP_BELOW_3000, DA9052_BUCKPERI_REG, + DA9052_BUCKPERI_VBPERI, DA9052_BUCKPERI_BPERIEN), +}; + +int da9052_ldo_buck_enable(struct regulator_dev *rdev) +{ + struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int ret = 0; + struct da9052_ssc_msg ssc_msg; + + ssc_msg.addr = da9052_regulators[id].reg_add; + ssc_msg.data = 0; + + da9052_lock(priv->da9052); + ret = priv->da9052->read(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + + ssc_msg.data = (ssc_msg.data | da9052_regulators[id].en_bit_mask); + + ret = priv->da9052->write(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + da9052_unlock(priv->da9052); + + return 0; +} +EXPORT_SYMBOL_GPL(da9052_ldo_buck_enable); +/* Code added by KPIT to support additional attribure in sysfs - changestate */ + + + +int da9052_ldo_buck_disable(struct regulator_dev *rdev) +{ + struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int ret; + struct da9052_ssc_msg ssc_msg; + + ssc_msg.addr = da9052_regulators[id].reg_add; + ssc_msg.data = 0; + + da9052_lock(priv->da9052); + ret = priv->da9052->read(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + + ssc_msg.data = (ssc_msg.data & ~(da9052_regulators[id].en_bit_mask)); + + ret = priv->da9052->write(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + da9052_unlock(priv->da9052); + + return 0; +} +EXPORT_SYMBOL_GPL(da9052_ldo_buck_disable); +/* Code added by KPIT to support additional attribure in sysfs - changestate */ + +static int da9052_ldo_buck_is_enabled(struct regulator_dev *rdev) +{ + struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int ret; + struct da9052_ssc_msg ssc_msg; + ssc_msg.addr = da9052_regulators[id].reg_add; + ssc_msg.data = 0; + + da9052_lock(priv->da9052); + ret = priv->da9052->read(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + da9052_unlock(priv->da9052); + return (ssc_msg.data & da9052_regulators[id].en_bit_mask) != 0; +} + +int da9052_ldo_buck_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev); + struct da9052_ssc_msg ssc_msg; + int id = rdev_get_id(rdev); + int ret; + int ldo_volt = 0; + + /* KPIT - Below if condition is there for added setvoltage attribute + in sysfs */ + if (0 == max_uV) + max_uV = da9052_regulators[id].reg_const.max_uV; + + /* Compare voltage range */ + if (min_uV > max_uV) + return -EINVAL; + + /* Check Minimum/ Maximum voltage range */ + if (min_uV < da9052_regulators[id].reg_const.min_uV || + min_uV > da9052_regulators[id].reg_const.max_uV) + return -EINVAL; + if (max_uV < da9052_regulators[id].reg_const.min_uV || + max_uV > da9052_regulators[id].reg_const.max_uV) + return -EINVAL; + + /* Get the ldo register value */ + /* Varying step size for BUCK PERI */ + if ((da9052_regulators[id].reg_desc.id == DA9052_BUCK_PERI) && + (min_uV >= DA9052_BUCK_PERI_VALUES_3000)) { + ldo_volt = (DA9052_BUCK_PERI_VALUES_3000 - + da9052_regulators[id].reg_const.min_uV)/ + (da9052_regulators[id].step_uV); + ldo_volt += (min_uV - DA9052_BUCK_PERI_VALUES_3000)/ + (DA9052_BUCK_PERI_STEP_ABOVE_3000); + } else{ + ldo_volt = (min_uV - da9052_regulators[id].reg_const.min_uV)/ + (da9052_regulators[id].step_uV); + /* Check for maximum value */ + if ((ldo_volt * da9052_regulators[id].step_uV) + + da9052_regulators[id].reg_const.min_uV > max_uV) + return -EINVAL; + } + + /* Configure LDO Voltage, CONF bits */ + ssc_msg.addr = da9052_regulators[id].reg_add; + ssc_msg.data = 0; + + /* Read register */ + da9052_lock(priv->da9052); + ret = priv->da9052->read(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + + ssc_msg.data = (ssc_msg.data & ~(da9052_regulators[id].mask_bits)); + ssc_msg.data |= ldo_volt; + + ret = priv->da9052->write(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + + /* Set the GO LDO/BUCk bits so that the voltage changes */ + ssc_msg.addr = DA9052_SUPPLY_REG; + ssc_msg.data = 0; + + ret = priv->da9052->read(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + + switch (id) { + case DA9052_LDO2: + ssc_msg.data = (ssc_msg.data | DA9052_SUPPLY_VLDO2GO); + break; + case DA9052_LDO3: + ssc_msg.data = (ssc_msg.data | DA9052_SUPPLY_VLDO3GO); + break; + case DA9052_BUCK_CORE: + ssc_msg.data = (ssc_msg.data | DA9052_SUPPLY_VBCOREGO); + break; + case DA9052_BUCK_PRO: + ssc_msg.data = (ssc_msg.data | DA9052_SUPPLY_VBPROGO); + break; + case DA9052_BUCK_MEM: + ssc_msg.data = (ssc_msg.data | DA9052_SUPPLY_VBMEMGO); + break; + default: + da9052_unlock(priv->da9052); + return -EINVAL; + } + + ret = priv->da9052->write(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + + da9052_unlock(priv->da9052); + + return 0; +} +EXPORT_SYMBOL_GPL(da9052_ldo_buck_set_voltage); +/* Code added by KPIT to support additional attributes in sysfs - setvoltage */ + + +int da9052_ldo_buck_get_voltage(struct regulator_dev *rdev) +{ + struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev); + struct da9052_ssc_msg ssc_msg; + int id = rdev_get_id(rdev); + int ldo_volt = 0; + int ldo_volt_uV = 0; + int ret; + + ssc_msg.addr = da9052_regulators[id].reg_add; + ssc_msg.data = 0; + /* Read register */ + da9052_lock(priv->da9052); + ret = priv->da9052->read(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + da9052_unlock(priv->da9052); + + ldo_volt = ssc_msg.data & da9052_regulators[id].mask_bits; + if (da9052_regulators[id].reg_desc.id == DA9052_BUCK_PERI) { + if (ldo_volt >= DA9052_BUCK_PERI_VALUES_UPTO_3000) { + ldo_volt_uV = ((DA9052_BUCK_PERI_VALUES_UPTO_3000 * + da9052_regulators[id].step_uV) + + da9052_regulators[id].reg_const.min_uV); + ldo_volt_uV = (ldo_volt_uV + + (ldo_volt - DA9052_BUCK_PERI_VALUES_UPTO_3000) + * (DA9052_BUCK_PERI_STEP_ABOVE_3000)); + } else { + ldo_volt_uV = + (ldo_volt * da9052_regulators[id].step_uV) + + da9052_regulators[id].reg_const.min_uV; + } + } else { + ldo_volt_uV = (ldo_volt * da9052_regulators[id].step_uV) + + da9052_regulators[id].reg_const.min_uV; + } + return ldo_volt_uV; +} +EXPORT_SYMBOL_GPL(da9052_ldo_buck_get_voltage); +/* Code added by KPIT to support additional attributes in sysfs - setvoltage */ + +static int da9052_set_suspend_voltage(struct regulator_dev *rdev, int uV) +{ + struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev); + struct da9052_ssc_msg ssc_msg; + int id = rdev_get_id(rdev); + int ret; + int ldo_volt = 0; + + + /* Check Minimum/ Maximum voltage range */ + if (uV < da9052_regulators[id].reg_const.min_uV || + uV > da9052_regulators[id].reg_const.max_uV) + return -EINVAL; + + /* Get the ldo register value */ + /* Varying step size for BUCK PERI */ + if ((da9052_regulators[id].reg_desc.id == DA9052_BUCK_PERI) && + (uV >= DA9052_BUCK_PERI_VALUES_3000)) { + ldo_volt = (DA9052_BUCK_PERI_VALUES_3000 - + da9052_regulators[id].reg_const.min_uV)/ + (da9052_regulators[id].step_uV); + ldo_volt += (uV - DA9052_BUCK_PERI_VALUES_3000)/ + (DA9052_BUCK_PERI_STEP_ABOVE_3000); + } else{ + ldo_volt = (uV - da9052_regulators[id].reg_const.min_uV)/ + (da9052_regulators[id].step_uV); + } + ldo_volt |= 0x80; + dev_info(&rdev->dev, "preset to %d %x\n", uV, ldo_volt); + + /* Configure LDO Voltage, CONF bits */ + ssc_msg.addr = da9052_regulators[id].reg_add; + ssc_msg.data = 0; + + /* Read register */ + da9052_lock(priv->da9052); + ret = priv->da9052->read(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + + ssc_msg.data = (ssc_msg.data & ~(da9052_regulators[id].mask_bits)); + ssc_msg.data |= ldo_volt; + + ret = priv->da9052->write(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + + da9052_unlock(priv->da9052); + + return 0; +} + +static int da9052_ldo_buck_stby_enable(struct regulator_dev *reg) +{ + return 0; +} + +static int da9052_ldo_buck_stby_disable(struct regulator_dev *reg) +{ + return 0; +} + +static int da9052_ldo_buck_stby_set_mode(struct regulator_dev *reg, + unsigned int mode) +{ + return 0; +} + + +static struct regulator_ops da9052_ldo_buck_ops = { + .is_enabled = da9052_ldo_buck_is_enabled, + .enable = da9052_ldo_buck_enable, + .disable = da9052_ldo_buck_disable, + .get_voltage = da9052_ldo_buck_get_voltage, + .set_voltage = da9052_ldo_buck_set_voltage, + .set_suspend_voltage = da9052_set_suspend_voltage, + .set_suspend_enable = da9052_ldo_buck_stby_enable, + .set_suspend_disable = da9052_ldo_buck_stby_disable, + .set_suspend_mode = da9052_ldo_buck_stby_set_mode, +}; + + +static int __devinit da9052_regulator_probe(struct platform_device *pdev) +{ + struct da9052_regulator_priv *priv; + struct da9052_regulator_platform_data *pdata = + (pdev->dev.platform_data); + struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent); + struct regulator_init_data *init_data; + int i, ret = 0; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + + priv->da9052 = da9052; + for (i = 0; i < 14; i++) { + + init_data = &pdata->regulators[i]; + init_data->driver_data = da9052; + pdev->dev.platform_data = init_data; + priv->regulators[i] = regulator_register( + &da9052_regulators[i].reg_desc, + &pdev->dev, init_data, + priv); + if (IS_ERR(priv->regulators[i])) { + ret = PTR_ERR(priv->regulators[i]); + goto err; + } + } + platform_set_drvdata(pdev, priv); + return 0; +err: + while (--i >= 0) + regulator_unregister(priv->regulators[i]); + kfree(priv); + return ret; +} + +static int __devexit da9052_regulator_remove(struct platform_device *pdev) +{ + struct da9052_regulator_priv *priv = platform_get_drvdata(pdev); + struct da9052_platform_data *pdata = pdev->dev.platform_data; + int i; + + for (i = 0; i < pdata->num_regulators; i++) + regulator_unregister(priv->regulators[i]); + + return 0; +} + +static struct platform_driver da9052_regulator_driver = { + .probe = da9052_regulator_probe, + .remove = __devexit_p(da9052_regulator_remove), + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init da9052_regulator_init(void) +{ + return platform_driver_register(&da9052_regulator_driver); +} +subsys_initcall(da9052_regulator_init); + +static void __exit da9052_regulator_exit(void) +{ + platform_driver_unregister(&da9052_regulator_driver); +} +module_exit(da9052_regulator_exit); + +MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); +MODULE_DESCRIPTION("Power Regulator driver for Dialog DA9052 PMIC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/regulator/ltc3589-regulator.c b/drivers/regulator/ltc3589-regulator.c new file mode 100644 index 000000000000..b81552e94316 --- /dev/null +++ b/drivers/regulator/ltc3589-regulator.c @@ -0,0 +1,1052 @@ + /* + * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/*! + * @file ltc3589-regulator.c + * @brief This is the main file for the Linear PMIC regulator driver. i2c + * should be providing the interface between the PMIC and the MCU. + * + * @ingroup PMIC_CORE + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/ltc3589.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/mfd/ltc3589/core.h> +#include <mach/hardware.h> + +/* Register definitions */ +#define LTC3589_REG_IRSTAT 0x02 +#define LTC3589_REG_SCR1 0x07 +#define LTC3589_REG_OVEN 0x10 +#define LTC3589_REG_SCR2 0x12 +#define LTC3589_REG_PGSTAT 0x13 +#define LTC3589_REG_VCCR 0x20 +#define LTC3589_REG_CLIRQ 0x21 +#define LTC3589_REG_B1DTV1 0x23 +#define LTC3589_REG_B1DTV2 0x24 +#define LTC3589_REG_VRRCR 0x25 +#define LTC3589_REG_B2DTV1 0x26 +#define LTC3589_REG_B2DTV2 0x27 +#define LTC3589_REG_B3DTV1 0x29 +#define LTC3589_REG_B3DTV2 0x2A +#define LTC3589_REG_L2DTV1 0x32 +#define LTC3589_REG_L2DTV2 0x33 + +/* SCR1 bitfields */ +#define LTC3589_SCR1_ BIT(7) +#define LTC3589_PGOODZ_LOWBATTZ BIT(6) +#define LTC3589_PGOODZ_VDCDC1 BIT(5) +#define LTC3589_PGOODZ_VDCDC2 BIT(4) +#define LTC3589_PGOODZ_VDCDC3 BIT(3) +#define LTC3589_PGOODZ_LDO2 BIT(2) +#define LTC3589_PGOODZ_LDO1 BIT(1) + +/* MASK bitfields */ +#define LTC3589_MASK_PWRFAILZ BIT(7) +#define LTC3589_MASK_LOWBATTZ BIT(6) +#define LTC3589_MASK_VDCDC1 BIT(5) +#define LTC3589_MASK_VDCDC2 BIT(4) +#define LTC3589_MASK_VDCDC3 BIT(3) +#define LTC3589_MASK_LDO2 BIT(2) +#define LTC3589_MASK_LDO1 BIT(1) + +/* REG_CTRL bitfields */ +#define LTC3589_REG_CTRL_VDCDC1_EN BIT(5) +#define LTC3589_REG_CTRL_VDCDC2_EN BIT(4) +#define LTC3589_REG_CTRL_VDCDC3_EN BIT(3) +#define LTC3589_REG_CTRL_LDO2_EN BIT(2) +#define LTC3589_REG_CTRL_LDO1_EN BIT(1) + +/* LDO_CTRL bitfields */ +#define LTC3589_LDO_CTRL_LDOx_SHIFT(ldo_id) ((ldo_id)*4) +#define LTC3589_LDO_CTRL_LDOx_MASK(ldo_id) (0xF0 >> ((ldo_id)*4)) + +/* Number of step-down converters available */ +#define LTC3589_NUM_DCDC 4 +/* Number of LDO voltage regulators available */ +#define LTC3589_NUM_LDO 4 +/* Number of total regulators available */ +#define LTC3589_NUM_REGULATOR (LTC3589_NUM_DCDC + LTC3589_NUM_LDO) + +/* DCDCs */ +#define LTC3589_DCDC_1 0 +#define LTC3589_DCDC_2 1 +#define LTC3589_DCDC_3 2 +#define LTC3589_DCDC_4 3 +/* LDOs */ +#define LTC3589_LDO_1 4 +#define LTC3589_LDO_2 5 +#define LTC3589_LDO_3 6 +#define LTC3589_LDO_4 7 +/* Resistorss */ +#define LTC3589_LDO2_R1 180 +#define LTC3589_LDO2_R2_TO1 232 +#define LTC3589_LDO2_R2_TO2 191 +#define LTC3589_SW1_R1 100 +#define LTC3589_SW1_R2 180 +#define LTC3589_SW2_R1 180 +#define LTC3589_SW2_R2_TO1 232 +#define LTC3589_SW2_R2_TO2 191 +#define LTC3589_SW3_R1 270 +#define LTC3589_SW3_R2 100 + +#define LTC3589_MAX_REG_ID LTC3589_LDO_4 + +/* Supported voltage values for regulators */ +static const u16 LDO4_VSEL_table[] = { + 2800, 2500, 1800, 3300, +}; + +struct i2c_client *ltc3589_client; + +/* Regulator specific details */ +struct ltc_info { + const char *name; + unsigned min_uV; + unsigned max_uV; + bool fixed; + u8 table_len; + const u16 *table; +}; + +/* PMIC details */ +struct ltc_pmic { + struct regulator_desc desc[LTC3589_NUM_REGULATOR]; + struct i2c_client *client; + struct regulator_dev *rdev[LTC3589_NUM_REGULATOR]; + const struct ltc_info *info[LTC3589_NUM_REGULATOR]; + struct mutex io_lock; +}; + +static int ltc3589_ldo2_r2; +static int ltc3589_sw2_r2; + +/* + * LTC3589 Device IO + */ +static DEFINE_MUTEX(io_mutex); + +static int ltc_3589_set_bits(struct ltc3589 *ltc, u8 reg, u8 mask) +{ + int err, data; + + mutex_lock(&io_mutex); + + data = ltc->read_dev(ltc, reg); + if (data < 0) { + dev_err(<c->i2c_client->dev, + "Read from reg 0x%x failed\n", reg); + err = data; + goto out; + } + + data |= mask; + err = ltc->write_dev(ltc, reg, data); + if (err) + dev_err(<c->i2c_client->dev, + "Write for reg 0x%x failed\n", reg); + +out: + mutex_unlock(&io_mutex); + return err; +} + +static int ltc_3589_clear_bits(struct ltc3589 *ltc, u8 reg, u8 mask) +{ + int err, data; + + mutex_lock(&io_mutex); + + data = ltc->read_dev(ltc, reg); + if (data < 0) { + dev_err(<c->i2c_client->dev, + "Read from reg 0x%x failed\n", reg); + err = data; + goto out; + } + + data &= ~mask; + + err = ltc->write_dev(ltc, reg, data); + if (err) + dev_err(<c->i2c_client->dev, + "Write for reg 0x%x failed\n", reg); + +out: + mutex_unlock(&io_mutex); + return err; + +} + +static int ltc_3589_reg_read(struct ltc3589 *ltc, u8 reg) +{ + int data; + + mutex_lock(&io_mutex); + + data = ltc->read_dev(ltc, reg); + if (data < 0) + dev_err(<c->i2c_client->dev, + "Read from reg 0x%x failed\n", reg); + + mutex_unlock(&io_mutex); + return data; +} + +static int ltc_3589_reg_write(struct ltc3589 *ltc, u8 reg, u8 val) +{ + int err; + + mutex_lock(&io_mutex); + + err = ltc->write_dev(ltc, reg, val); + if (err < 0) + dev_err(<c->i2c_client->dev, + "Write for reg 0x%x failed\n", reg); + + mutex_unlock(&io_mutex); + return err; +} + +int ltc3589_set_slew_rate(struct regulator_dev *dev, int rate) +{ + struct ltc3589 *ltc = rdev_get_drvdata(dev); + int data, dcdc = rdev_get_id(dev); + + if (dcdc == LTC3589_DCDC_4 || dcdc == LTC3589_LDO_1 || + dcdc == LTC3589_LDO_3 || dcdc == LTC3589_LDO_4) + return 0; + + if (rate > 0x3) + return -EINVAL; + + data = ltc_3589_reg_read(ltc, LTC3589_REG_VRRCR); + if (data < 0) + return data; + + if (dcdc == LTC3589_LDO_2) + dcdc = 3; + + data &= ~(3 << (2 * dcdc)); + data |= (3 << (2 * dcdc)); + + ltc_3589_reg_write(ltc, LTC3589_REG_VRRCR, data); + + return 0; +} + +static int ltc3589_dcdc_is_enabled(struct regulator_dev *dev) +{ + struct ltc3589 *ltc = rdev_get_drvdata(dev); + int data, dcdc = rdev_get_id(dev); + u8 shift; + + if (dcdc < LTC3589_DCDC_1 || dcdc > LTC3589_DCDC_4) + return -EINVAL; + + shift = dcdc; + data = ltc_3589_reg_read(ltc, LTC3589_REG_OVEN); + + if (data < 0) + return data; + else + return (data & 1<<shift) ? 1 : 0; +} + +static int ltc3589_ldo_is_enabled(struct regulator_dev *dev) +{ + struct ltc3589 *ltc = rdev_get_drvdata(dev); + int data, ldo = rdev_get_id(dev); + u8 shift; + + if (ldo < LTC3589_LDO_1 || ldo > LTC3589_LDO_4) + return -EINVAL; + + if (ldo == LTC3589_LDO_1) + return 1; + + shift = ldo - 1; + data = ltc_3589_reg_read(ltc, LTC3589_REG_OVEN); + + if (data < 0) + return data; + else + return (data & 1<<shift) ? 1 : 0; +} + +static int ltc3589_dcdc_enable(struct regulator_dev *dev) +{ + struct ltc3589 *ltc = rdev_get_drvdata(dev); + int dcdc = rdev_get_id(dev); + u8 shift; + + if (dcdc < LTC3589_DCDC_1 || dcdc > LTC3589_DCDC_4) + return -EINVAL; + + shift = dcdc; + return ltc_3589_set_bits(ltc, LTC3589_REG_OVEN, 1 << shift); +} + +static int ltc3589_dcdc_disable(struct regulator_dev *dev) +{ + struct ltc3589 *ltc = rdev_get_drvdata(dev); + int dcdc = rdev_get_id(dev); + u8 shift; + + if (dcdc < LTC3589_DCDC_1 || dcdc > LTC3589_DCDC_4) + return -EINVAL; + + shift = dcdc; + return ltc_3589_clear_bits(ltc, LTC3589_REG_OVEN, 1 << shift); +} + +static int ltc3589_ldo_enable(struct regulator_dev *dev) +{ + struct ltc3589 *ltc = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev); + u8 shift; + + if (ldo < LTC3589_LDO_1 || ldo > LTC3589_LDO_4) + return -EINVAL; + + if (ldo == LTC3589_LDO_1) { + printk(KERN_ERR "LDO1 is always enabled\n"); + return 0; + } + + shift = (ldo - 1); + return ltc_3589_set_bits(ltc, LTC3589_REG_OVEN, 1 << shift); +} + +static int ltc3589_ldo_disable(struct regulator_dev *dev) +{ + struct ltc3589 *ltc = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev); + u8 shift; + + if (ldo < LTC3589_LDO_1 || ldo > LTC3589_LDO_4) + return -EINVAL; + + if (ldo == LTC3589_LDO_1) { + printk(KERN_ERR "LDO1 can not be disabled\n"); + return 0; + } + + shift = (ldo - 1); + return ltc_3589_clear_bits(ltc, LTC3589_REG_OVEN, 1 << shift); +} + +static int ltc3589_dcdc_set_mode(struct regulator_dev *dev, + unsigned int mode) +{ + struct ltc3589 *ltc = rdev_get_drvdata(dev); + int dcdc = rdev_get_id(dev); + u16 val; + int data; + + if (dcdc < LTC3589_DCDC_1 || dcdc > LTC3589_DCDC_4) + return -EINVAL; + + val = 1 << (dcdc - LTC3589_DCDC_1); + data = ltc_3589_reg_read(ltc, LTC3589_REG_SCR1); + if (data < 0) + return data; + + data &= ~(3 << (2 * dcdc)); + + switch (mode) { + case REGULATOR_MODE_FAST: + /* burst mode */ + data |= (1 << (2 * dcdc)); + break; + case REGULATOR_MODE_NORMAL: + /* active / pulse skipping */ + data |= (0 << (2 * dcdc)); + break; + case REGULATOR_MODE_IDLE: + case REGULATOR_MODE_STANDBY: + /* force continuous mode */ + data |= (2 << (2 * dcdc)); + } + + return ltc_3589_reg_write(ltc, LTC3589_REG_SCR1, data);; +} + +static unsigned int ltc3589_dcdc_get_mode(struct regulator_dev *dev) +{ + struct ltc3589 *ltc = rdev_get_drvdata(dev); + int dcdc = rdev_get_id(dev); + int data; + + data = ltc_3589_reg_read(ltc, LTC3589_REG_VCCR); + if (data < 0) + return data; + + if (dcdc == LTC3589_DCDC_4) { + data >>= (2 * dcdc); + data &= 0x01; + + if (data == 1) + return REGULATOR_MODE_FAST; + else + return REGULATOR_MODE_NORMAL; + } else { + data >>= (2 * dcdc); + data &= 0x03; + + switch (data) { + case 0: + return REGULATOR_MODE_NORMAL; + case 1: + return REGULATOR_MODE_FAST; + case 2: + return REGULATOR_MODE_IDLE; + } + } + + return 0; +} + +static int ltc3589_dcdc_get_voltage(struct regulator_dev *dev) +{ + struct ltc3589 *ltc = rdev_get_drvdata(dev); + int volt_reg, data, dcdc = rdev_get_id(dev); + int shift, mask, r1, r2; + int uV; + + r1 = 0; + r2 = 1; + + if (dcdc < LTC3589_DCDC_1 || dcdc > LTC3589_DCDC_3) + return -EINVAL; + + data = ltc_3589_reg_read(ltc, LTC3589_REG_VCCR); + if (data < 0) + return data; + + switch (dcdc) { + case LTC3589_DCDC_1: + r1 = LTC3589_SW1_R1; + r2 = LTC3589_SW1_R2; + shift = LTC3589_B1DTV2_REG1_REF_INPUT_V2_SHIFT; + mask = LTC3589_B1DTV2_REG1_REF_INPUT_V2_MASK; + if (data & LTC3589_VCCR_REG1_REF_SELECT) + volt_reg = LTC3589_REG_B1DTV2; + else + volt_reg = LTC3589_REG_B1DTV1; + break; + case LTC3589_DCDC_2: + r1 = LTC3589_SW2_R1; + r2 = ltc3589_sw2_r2; + shift = LTC3589_B2DTV2_REG2_REF_INPUT_V2_SHIFT; + mask = LTC3589_B2DTV2_REG2_REF_INPUT_V2_MASK; + if (data & LTC3589_VCCR_REG2_REF_SELECT) + volt_reg = LTC3589_REG_B2DTV2; + else + volt_reg = LTC3589_REG_B2DTV1; + break; + case LTC3589_DCDC_3: + r1 = LTC3589_SW3_R1; + r2 = LTC3589_SW3_R2; + shift = LTC3589_B3DTV2_REG3_REF_INPUT_V2_SHIFT; + mask = LTC3589_B3DTV2_REG3_REF_INPUT_V2_MASK; + if (data & LTC3589_VCCR_REG3_REF_SELECT) + volt_reg = LTC3589_REG_B3DTV2; + else + volt_reg = LTC3589_REG_B3DTV1; + break; + default: + return -EINVAL; + } + + data = ltc_3589_reg_read(ltc, volt_reg); + if (data < 0) + return data; + + data >>= shift; + data &= mask; + uV = (((r1 + r2) * (362500 + data * 12500)) / r2); + return uV; +} + +static int ltc3589_dcdc_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) +{ + struct ltc3589 *ltc = rdev_get_drvdata(dev); + int dcdc = rdev_get_id(dev); + int volt_reg1; + int volt_reg2; + int shift, mask; + int r1, r2; + int dac_vol, data, slew_val; + + r1 = 0; + r2 = 1; + if (dcdc < LTC3589_DCDC_1 || dcdc > LTC3589_DCDC_3) + return -EINVAL; + + switch (dcdc) { + case LTC3589_DCDC_1: + r1 = LTC3589_SW1_R1; + r2 = LTC3589_SW1_R2; + volt_reg1 = 0; + volt_reg2 = LTC3589_REG_B1DTV1; + slew_val = 1; + shift = LTC3589_B1DTV2_REG1_REF_INPUT_V2_SHIFT; + mask = LTC3589_B1DTV2_REG1_REF_INPUT_V2_MASK; + break; + case LTC3589_DCDC_2: + r1 = LTC3589_SW2_R1; + r2 = ltc3589_sw2_r2; + volt_reg1 = 0; + volt_reg2 = LTC3589_REG_B2DTV1; + slew_val = 1; + shift = LTC3589_B2DTV2_REG2_REF_INPUT_V2_SHIFT; + mask = LTC3589_B2DTV2_REG2_REF_INPUT_V2_MASK; + break; + case LTC3589_DCDC_3: + r1 = LTC3589_SW3_R1; + r2 = LTC3589_SW3_R2; + volt_reg1 = 0; + volt_reg2 = LTC3589_REG_B3DTV1; + slew_val = 1; + shift = LTC3589_B3DTV2_REG3_REF_INPUT_V2_SHIFT; + mask = LTC3589_B3DTV2_REG3_REF_INPUT_V2_MASK; + break; + default: + return -EINVAL; + } + + dac_vol = ((min_uV * r2 - 362500 * (r1 + r2)) / (12500 * (r1 + r2))); + if ((dac_vol > 0x1F) || (dac_vol < 0)) + return -EINVAL; + + /* Set voltage */ + if (volt_reg1 != 0) { + data = ltc_3589_reg_read(ltc, volt_reg1); + if (data < 0) + return data; + + data >>= shift; + data &= ~mask; + data |= dac_vol; + ltc_3589_reg_write(ltc, volt_reg1, data); + } + + if (volt_reg2 != 0) { + data = ltc_3589_reg_read(ltc, volt_reg2); + if (data < 0) + return data; + + data >>= shift; + data &= ~mask; + data |= dac_vol; + ltc_3589_reg_write(ltc, volt_reg2, data); + } + + /* Set slew config */ + data = ltc_3589_reg_read(ltc, LTC3589_REG_VCCR); + if (data < 0) + return data; + + data &= ~(3 << (2 * dcdc)); + data |= (slew_val << (2 * dcdc)); + + ltc_3589_reg_write(ltc, LTC3589_REG_VCCR, data); + + data = ltc_3589_reg_read(ltc, LTC3589_REG_SCR2); + if (data < 0) + return data; + + data &= ~(1 << dcdc); + data |= (1 << dcdc); + + ltc_3589_reg_write(ltc, LTC3589_REG_SCR2, data); + + data = ltc_3589_reg_read(ltc, LTC3589_REG_OVEN); + if (data < 0) + return data; + + data &= ~(1 << dcdc); + data |= (1 << dcdc); + + ltc_3589_reg_write(ltc, LTC3589_REG_OVEN, data); + + mdelay(10); + + return 0; +} + +static int ltc3589_set_suspend_voltage(struct regulator_dev *dev, + int uV) +{ + struct ltc3589 *ltc = rdev_get_drvdata(dev); + int dcdc = rdev_get_id(dev); + int volt_reg1; + int shift, mask; + int r1, r2; + int dac_vol, data; + + r1 = 0; + r2 = 1; + if (dcdc < LTC3589_DCDC_1 || dcdc > LTC3589_DCDC_3) + return -EINVAL; + + switch (dcdc) { + case LTC3589_DCDC_1: + r1 = LTC3589_SW1_R1; + r2 = LTC3589_SW1_R2; + volt_reg1 = LTC3589_REG_B1DTV2; + shift = LTC3589_B1DTV2_REG1_REF_INPUT_V2_SHIFT; + mask = LTC3589_B1DTV2_REG1_REF_INPUT_V2_MASK; + break; + case LTC3589_DCDC_2: + r1 = LTC3589_SW2_R1; + r2 = ltc3589_sw2_r2; + volt_reg1 = LTC3589_REG_B2DTV2; + shift = LTC3589_B2DTV2_REG2_REF_INPUT_V2_SHIFT; + mask = LTC3589_B2DTV2_REG2_REF_INPUT_V2_MASK; + break; + default: + return 0; + } + + dac_vol = ((uV * r2 - 362500 * (r1 + r2)) / (12500 * (r1 + r2))); + if ((dac_vol > 0x1F) || (dac_vol < 0)) + return -EINVAL; + + data = ltc_3589_reg_read(ltc, volt_reg1); + if (data < 0) + return data; + + data >>= shift; + data &= ~mask; + data |= dac_vol; + ltc_3589_reg_write(ltc, volt_reg1, data); + return 0; +} + +static int ltc3589_set_suspend_enable(struct regulator_dev *rdev) +{ + return 0; +} + +static int ltc3589_set_suspend_disable(struct regulator_dev *rdev) +{ + return 0; +} + +static int ltc3589_set_suspend_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + return 0; +} + +static int ltc3589_ldo_get_voltage(struct regulator_dev *dev) +{ + struct ltc3589 *ltc = rdev_get_drvdata(dev); + int data, ldo = rdev_get_id(dev); + int uV; + + if (ldo < LTC3589_LDO_1 || ldo > LTC3589_LDO_4) + return -EINVAL; + + if (ldo == LTC3589_LDO_1 || ldo == LTC3589_LDO_3) + return -EINVAL; + + if (ldo == LTC3589_LDO_4) { + data = ltc_3589_reg_read(ltc, LTC3589_REG_L2DTV2); + if (data < 0) + return data; + + data >>= LTC3589_L2DTV2_LDO4_OUTPUT_VOLTAGE_SHIFT; + data &= LTC3589_L2DTV2_LDO4_OUTPUT_VOLTAGE_MASK; + switch (data) { + case 0: + return 1800000; + case 1: + return 2500000; + case 2: + return 3000000; + case 3: + return 3300000; + default: + return -EINVAL; + } + } else { + data = ltc_3589_reg_read(ltc, LTC3589_REG_VCCR); + if (data < 0) + return data; + + if (data & LTC3589_VCCR_LDO2_REF_SELECT) + data = ltc_3589_reg_read(ltc, LTC3589_REG_L2DTV2); + else + data = ltc_3589_reg_read(ltc, LTC3589_REG_L2DTV1); + + if (data < 0) + return data; + + data >>= LTC3589_L2DTV2_LDO2_REF_INPUT_V2_SHIFT; + data &= LTC3589_L2DTV2_LDO2_REF_INPUT_V2_MASK; + uV = (((LTC3589_LDO2_R1 + ltc3589_ldo2_r2) + * (362500 + data * 12500)) / ltc3589_ldo2_r2); + return uV; + } + + return -EINVAL; +} + +static int ltc3589_ldo_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) +{ + struct ltc3589 *ltc = rdev_get_drvdata(dev); + int data, vsel, ldo = rdev_get_id(dev); + + if (ldo < LTC3589_LDO_1 || ldo > LTC3589_LDO_4) + return -EINVAL; + + if (ldo == LTC3589_LDO_1 || ldo == LTC3589_LDO_3) + return -EINVAL; + + if (ldo == LTC3589_LDO_4) { + for (vsel = 0; vsel < 4; vsel++) { + int mV = LDO4_VSEL_table[vsel]; + int uV = mV * 1000; + + /* Break at the first in-range value */ + if (min_uV <= uV && uV <= max_uV) + break; + } + + if (vsel == 4) + return -EINVAL; + + data = ltc_3589_reg_read(ltc, LTC3589_REG_L2DTV2); + if (data < 0) + return data; + + data &= ~(0x3 << LTC3589_L2DTV2_LDO4_OUTPUT_VOLTAGE_SHIFT); + data |= (vsel << LTC3589_L2DTV2_LDO4_OUTPUT_VOLTAGE_SHIFT); + data &= ~(1 << LTC3589_L2DTV2_LDO4_CONTROL_MODE_SHIFT); + data |= (1 << LTC3589_L2DTV2_LDO4_CONTROL_MODE_SHIFT); + ltc_3589_reg_write(ltc, LTC3589_REG_L2DTV2, data); + + + data = ltc_3589_reg_read(ltc, LTC3589_REG_SCR2); + if (data < 0) + return data; + + data &= ~(1 << LTC3589_SCR2_LDO4_STARTUP_SHIFT); + data |= (1 << LTC3589_SCR2_LDO4_STARTUP_SHIFT); + + ltc_3589_reg_write(ltc, LTC3589_REG_SCR2, data); + + data = ltc_3589_reg_read(ltc, LTC3589_REG_OVEN); + if (data < 0) + return data; + + data &= ~(LTC3589_OVEN_EN_LDO4); + data |= LTC3589_OVEN_EN_LDO4; + + ltc_3589_reg_write(ltc, LTC3589_REG_OVEN, data); + + mdelay(10); + } else { + int dac_vol; + + dac_vol = ((min_uV * ltc3589_ldo2_r2 - + 362500 * (LTC3589_LDO2_R1 + ltc3589_ldo2_r2)) + / (12500 * (LTC3589_LDO2_R1 + ltc3589_ldo2_r2))); + if ((dac_vol > 0x1F) || (dac_vol < 0)) + return -EINVAL; + + data = ltc_3589_reg_read(ltc, LTC3589_REG_L2DTV1); + if (data < 0) + return data; + + data &= ~LTC3589_L2DTV2_LDO2_REF_INPUT_V2_MASK; + data |= dac_vol; + ltc_3589_reg_write(ltc, LTC3589_REG_L2DTV1, data); + + /* Set slew config */ + data = ltc_3589_reg_read(ltc, LTC3589_REG_VCCR); + if (data < 0) + return data; + + data &= ~(LTC3589_VCCR_LDO2_SLEW | + LTC3589_VCCR_LDO2_REF_SELECT); + data |= LTC3589_VCCR_LDO2_SLEW; + + ltc_3589_reg_write(ltc, LTC3589_REG_VCCR, data); + + data = ltc_3589_reg_read(ltc, LTC3589_REG_SCR2); + if (data < 0) + return data; + + data &= ~(1 << LTC3589_SCR2_LDO2_STARTUP_SHIFT); + data |= (1 << LTC3589_SCR2_LDO2_STARTUP_SHIFT); + + ltc_3589_reg_write(ltc, LTC3589_REG_SCR2, data); + + data = ltc_3589_reg_read(ltc, LTC3589_REG_OVEN); + if (data < 0) + return data; + + data &= ~(LTC3589_OVEN_EN_LDO2); + data |= (LTC3589_OVEN_EN_LDO2); + + ltc_3589_reg_write(ltc, LTC3589_REG_OVEN, data); + + mdelay(10); + } + return 0; +} + +static int ltc3589_ldo4_list_voltage(struct regulator_dev *dev, + unsigned selector) +{ + int ldo = rdev_get_id(dev); + + if (ldo != LTC3589_LDO_4) + return -EINVAL; + + if (selector >= 4) + return -EINVAL; + else + return LDO4_VSEL_table[selector] * 1000; +} + +/* Operations permitted on SWx */ +static struct regulator_ops ltc3589_sw_ops = { + .is_enabled = ltc3589_dcdc_is_enabled, + .enable = ltc3589_dcdc_enable, + .disable = ltc3589_dcdc_disable, + .get_mode = ltc3589_dcdc_get_mode, + .set_mode = ltc3589_dcdc_set_mode, + .get_voltage = ltc3589_dcdc_get_voltage, + .set_voltage = ltc3589_dcdc_set_voltage, + .set_suspend_voltage = ltc3589_set_suspend_voltage, + .set_suspend_enable = ltc3589_set_suspend_enable, + .set_suspend_disable = ltc3589_set_suspend_disable, + .set_suspend_mode = ltc3589_set_suspend_mode, +}; + +/* Operations permitted on SW4 Buck-Boost */ +static struct regulator_ops ltc3589_sw4_ops = { + .is_enabled = ltc3589_dcdc_is_enabled, + .enable = ltc3589_dcdc_enable, + .disable = ltc3589_dcdc_disable, + .get_mode = ltc3589_dcdc_get_mode, + .set_mode = ltc3589_dcdc_set_mode, +}; + +/* Operations permitted on LDO1_STBY, LDO3 */ +static struct regulator_ops ltc3589_ldo13_ops = { + .is_enabled = ltc3589_ldo_is_enabled, + .enable = ltc3589_ldo_enable, + .disable = ltc3589_ldo_disable, +}; + +/* Operations permitted on LDO2 */ +static struct regulator_ops ltc3589_ldo2_ops = { + .is_enabled = ltc3589_ldo_is_enabled, + .enable = ltc3589_ldo_enable, + .disable = ltc3589_ldo_disable, + .get_voltage = ltc3589_ldo_get_voltage, + .set_voltage = ltc3589_ldo_set_voltage, +}; + +/* Operations permitted on LDO4 */ +static struct regulator_ops ltc3589_ldo4_ops = { + .is_enabled = ltc3589_ldo_is_enabled, + .enable = ltc3589_ldo_enable, + .disable = ltc3589_ldo_disable, + .get_voltage = ltc3589_ldo_get_voltage, + .set_voltage = ltc3589_ldo_set_voltage, + .list_voltage = ltc3589_ldo4_list_voltage, +}; + +static struct regulator_desc ltc3589_reg[] = { + { + .name = "SW1", + .id = LTC3589_SW1, + .ops = <c3589_sw_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 0x1F + 1, + .owner = THIS_MODULE, + }, + { + .name = "SW2", + .id = LTC3589_SW2, + .ops = <c3589_sw_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 0x1F + 1, + .owner = THIS_MODULE, + }, + { + .name = "SW3", + .id = LTC3589_SW3, + .ops = <c3589_sw_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 0x1F + 1, + .owner = THIS_MODULE, + }, + { + .name = "SW4", + .id = LTC3589_SW4, + .ops = <c3589_sw4_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO1_STBY", + .id = LTC3589_LDO1, + .ops = <c3589_ldo13_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO2", + .id = LTC3589_LDO2, + .ops = <c3589_ldo2_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 0x1F + 1, + .owner = THIS_MODULE, + }, + { + .name = "LDO3", + .id = LTC3589_LDO3, + .ops = <c3589_ldo13_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO4", + .id = LTC3589_LDO4, + .ops = <c3589_ldo4_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = ARRAY_SIZE(LDO4_VSEL_table), + .owner = THIS_MODULE, + }, +}; + +static int ltc3589_regulator_probe(struct platform_device *pdev) +{ + struct regulator_dev *rdev; + + if (pdev->id < LTC3589_DCDC_1 || pdev->id > LTC3589_LDO4) + return -ENODEV; + + if (cpu_is_mx53_rev(CHIP_REV_2_0) >= 1) { + ltc3589_ldo2_r2 = LTC3589_LDO2_R2_TO2; + ltc3589_sw2_r2 = LTC3589_SW2_R2_TO2; + } else { + ltc3589_ldo2_r2 = LTC3589_LDO2_R2_TO1; + ltc3589_sw2_r2 = LTC3589_SW2_R2_TO1; + } + + /* register regulator */ + rdev = regulator_register(<c3589_reg[pdev->id], &pdev->dev, + pdev->dev.platform_data, + dev_get_drvdata(&pdev->dev)); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s\n", + ltc3589_reg[pdev->id].name); + return PTR_ERR(rdev); + } + + ltc3589_set_slew_rate(rdev, LTC3589_VRRCR_SLEW_RATE_7P00MV_US); + + return 0; +} + +static int ltc3589_regulator_remove(struct platform_device *pdev) +{ + struct regulator_dev *rdev = platform_get_drvdata(pdev); + + regulator_unregister(rdev); + + return 0; +} + +int ltc3589_register_regulator(struct ltc3589 *ltc3589, int reg, + struct regulator_init_data *initdata) +{ + struct platform_device *pdev; + int ret; + + if (ltc3589->pmic.pdev[reg]) + return -EBUSY; + if (reg < LTC3589_DCDC_1 || reg > LTC3589_LDO_4) + return -ENODEV; + pdev = platform_device_alloc("ltc3589-regulator", reg); + if (!pdev) + return -ENOMEM; + ltc3589->pmic.pdev[reg] = pdev; + + initdata->driver_data = ltc3589; + + pdev->dev.platform_data = initdata; + pdev->dev.parent = ltc3589->dev; + platform_set_drvdata(pdev, ltc3589); + + ret = platform_device_add(pdev); + + if (ret != 0) { + dev_err(ltc3589->dev, "Failed to register regulator %d: %d\n", + reg, ret); + platform_device_del(pdev); + ltc3589->pmic.pdev[reg] = NULL; + } + + return ret; +} +EXPORT_SYMBOL_GPL(ltc3589_register_regulator); + +static struct platform_driver ltc3589_regulator_driver = { + .driver = { + .name = "ltc3589-regulator", + }, + .probe = ltc3589_regulator_probe, + .remove = ltc3589_regulator_remove, +}; + +static int __init ltc3589_regulator_init(void) +{ + return platform_driver_register(<c3589_regulator_driver); + +} +subsys_initcall_sync(ltc3589_regulator_init); + +static void __exit ltc3589_regulator_exit(void) +{ + platform_driver_unregister(<c3589_regulator_driver); +} +module_exit(ltc3589_regulator_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("LTC3589 Regulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max17135-regulator.c b/drivers/regulator/max17135-regulator.c new file mode 100644 index 000000000000..2d4cbcc1667c --- /dev/null +++ b/drivers/regulator/max17135-regulator.c @@ -0,0 +1,640 @@ +/* + * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/driver.h> +#include <linux/mfd/max17135.h> +#include <linux/gpio.h> + +/* + * Regulator definitions + * *_MIN_uV - minimum microvolt for regulator + * *_MAX_uV - maximum microvolt for regulator + * *_STEP_uV - microvolts between regulator output levels + * *_MIN_VAL - minimum register field value for regulator + * *_MAX_VAL - maximum register field value for regulator + */ +#define MAX17135_HVINP_MIN_uV 5000000 +#define MAX17135_HVINP_MAX_uV 20000000 +#define MAX17135_HVINP_STEP_uV 1000000 +#define MAX17135_HVINP_MIN_VAL 0 +#define MAX17135_HVINP_MAX_VAL 1 + +#define MAX17135_HVINN_MIN_uV 5000000 +#define MAX17135_HVINN_MAX_uV 20000000 +#define MAX17135_HVINN_STEP_uV 1000000 +#define MAX17135_HVINN_MIN_VAL 0 +#define MAX17135_HVINN_MAX_VAL 1 + +#define MAX17135_GVDD_MIN_uV 5000000 +#define MAX17135_GVDD_MAX_uV 20000000 +#define MAX17135_GVDD_STEP_uV 1000000 +#define MAX17135_GVDD_MIN_VAL 0 +#define MAX17135_GVDD_MAX_VAL 1 + +#define MAX17135_GVEE_MIN_uV 5000000 +#define MAX17135_GVEE_MAX_uV 20000000 +#define MAX17135_GVEE_STEP_uV 1000000 +#define MAX17135_GVEE_MIN_VAL 0 +#define MAX17135_GVEE_MAX_VAL 1 + +#define MAX17135_VCOM_MIN_VAL 0 +#define MAX17135_VCOM_MAX_VAL 255 + +#define MAX17135_VNEG_MIN_uV 5000000 +#define MAX17135_VNEG_MAX_uV 20000000 +#define MAX17135_VNEG_STEP_uV 1000000 +#define MAX17135_VNEG_MIN_VAL 0 +#define MAX17135_VNEG_MAX_VAL 1 + +#define MAX17135_VPOS_MIN_uV 5000000 +#define MAX17135_VPOS_MAX_uV 20000000 +#define MAX17135_VPOS_STEP_uV 1000000 +#define MAX17135_VPOS_MIN_VAL 0 +#define MAX17135_VPOS_MAX_VAL 1 + +struct max17135_vcom_programming_data { + int vcom_min_uV; + int vcom_max_uV; + int vcom_step_uV; +}; + +static int max17135_pass_num = { 1 }; +static int max17135_vcom = { -1250000 }; + +struct max17135_vcom_programming_data vcom_data[2] = { + { + -4325000, + -500000, + 15000, + }, + { + -3050000, + -500000, + 10000, + }, +}; + +static int max17135_is_power_good(struct max17135 *max17135); + +/* + * Regulator operations + */ +static int max17135_hvinp_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int reg_val; + unsigned int fld_val; + + if ((uV >= MAX17135_HVINP_MIN_uV) && + (uV <= MAX17135_HVINP_MAX_uV)) + fld_val = (uV - MAX17135_HVINP_MIN_uV) / + MAX17135_HVINP_STEP_uV; + else + return -EINVAL; + + max17135_reg_read(REG_MAX17135_HVINP, ®_val); + + reg_val &= ~BITFMASK(HVINP); + reg_val |= BITFVAL(HVINP, fld_val); /* shift to correct bit */ + + return max17135_reg_write(REG_MAX17135_HVINP, reg_val); +} + +static int max17135_hvinp_get_voltage(struct regulator_dev *reg) +{ + unsigned int reg_val; + unsigned int fld_val; + int volt; + + max17135_reg_read(REG_MAX17135_HVINP, ®_val); + + fld_val = (reg_val & BITFMASK(HVINP)) >> HVINP_LSH; + + if ((fld_val >= MAX17135_HVINP_MIN_VAL) && + (fld_val <= MAX17135_HVINP_MAX_VAL)) { + volt = (fld_val * MAX17135_HVINP_STEP_uV) + + MAX17135_HVINP_MIN_uV; + } else { + printk(KERN_ERR "MAX17135: HVINP voltage is out of range\n"); + volt = 0; + } + return volt; +} + +static int max17135_hvinp_enable(struct regulator_dev *reg) +{ + return 0; +} + +static int max17135_hvinp_disable(struct regulator_dev *reg) +{ + return 0; +} + +/* Convert uV to the VCOM register bitfield setting */ +static inline int vcom_uV_to_rs(int uV, int pass_num) +{ + return (vcom_data[pass_num].vcom_max_uV - uV) + / vcom_data[pass_num].vcom_step_uV; +} + +/* Convert the VCOM register bitfield setting to uV */ +static inline int vcom_rs_to_uV(int rs, int pass_num) +{ + return vcom_data[pass_num].vcom_max_uV + - (vcom_data[pass_num].vcom_step_uV * rs); +} + +static int max17135_vcom_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + struct max17135 *max17135 = rdev_get_drvdata(reg); + unsigned int reg_val; + int vcom_read; + + if ((uV < vcom_data[max17135->pass_num-1].vcom_min_uV) + || (uV > vcom_data[max17135->pass_num-1].vcom_max_uV)) + return -EINVAL; + + max17135_reg_read(REG_MAX17135_DVR, ®_val); + + /* + * Only program VCOM if it is not set to the desired value. + * Programming VCOM excessively degrades ability to keep + * DVR register value persistent. + */ + vcom_read = vcom_rs_to_uV(reg_val, max17135->pass_num-1); + if (vcom_read != max17135->vcom_uV) { + reg_val &= ~BITFMASK(DVR); + reg_val |= BITFVAL(DVR, vcom_uV_to_rs(uV, + max17135->pass_num-1)); + max17135_reg_write(REG_MAX17135_DVR, reg_val); + + reg_val = BITFVAL(CTRL_DVR, true); /* shift to correct bit */ + return max17135_reg_write(REG_MAX17135_PRGM_CTRL, reg_val); + } + + return 0; +} + +static int max17135_vcom_get_voltage(struct regulator_dev *reg) +{ + struct max17135 *max17135 = rdev_get_drvdata(reg); + unsigned int reg_val; + + max17135_reg_read(REG_MAX17135_DVR, ®_val); + return vcom_rs_to_uV(BITFEXT(reg_val, DVR), max17135->pass_num-1); +} + +static int max17135_vcom_enable(struct regulator_dev *reg) +{ + struct max17135 *max17135 = rdev_get_drvdata(reg); + + /* + * Check to see if we need to set the VCOM voltage. + * Should only be done one time. And, we can + * only change vcom voltage if we have been enabled. + */ + if (!max17135->vcom_setup && max17135_is_power_good(max17135)) { + max17135_vcom_set_voltage(reg, + max17135->vcom_uV, + max17135->vcom_uV); + max17135->vcom_setup = true; + } + + /* enable VCOM regulator output */ + if (max17135->pass_num == 1) + gpio_set_value(max17135->gpio_pmic_vcom_ctrl, 1); + else { + unsigned int reg_val; + + max17135_reg_read(REG_MAX17135_ENABLE, ®_val); + reg_val &= ~BITFMASK(VCOM_ENABLE); + reg_val |= BITFVAL(VCOM_ENABLE, 1); /* shift to correct bit */ + max17135_reg_write(REG_MAX17135_ENABLE, reg_val); + } + + return 0; +} + +static int max17135_vcom_disable(struct regulator_dev *reg) +{ + struct max17135 *max17135 = rdev_get_drvdata(reg); + + if (max17135->pass_num == 1) + gpio_set_value(max17135->gpio_pmic_vcom_ctrl, 0); + else { + unsigned int reg_val; + + max17135_reg_read(REG_MAX17135_ENABLE, ®_val); + reg_val &= ~BITFMASK(VCOM_ENABLE); + max17135_reg_write(REG_MAX17135_ENABLE, reg_val); + } + + return 0; +} + +static int max17135_vcom_is_enabled(struct regulator_dev *reg) +{ + struct max17135 *max17135 = rdev_get_drvdata(reg); + + /* read VCOM regulator enable setting */ + if (max17135->pass_num == 1) { + int gpio = gpio_get_value(max17135->gpio_pmic_vcom_ctrl); + if (gpio == 0) + return 0; + else + return 1; + } else { + unsigned int reg_val; + + max17135_reg_read(REG_MAX17135_ENABLE, ®_val); + reg_val &= BITFMASK(VCOM_ENABLE); + if (reg_val != 0) + return 1; + else + return 0; + } +} + +static int max17135_is_power_good(struct max17135 *max17135) +{ + /* + * XOR of polarity (starting value) and current + * value yields whether power is good. + */ + return gpio_get_value(max17135->gpio_pmic_pwrgood) ^ + max17135->pwrgood_polarity; +} + +static int max17135_wait_power_good(struct max17135 *max17135) +{ + int i; + + for (i = 0; i < max17135->max_wait * 3; i++) { + if (max17135_is_power_good(max17135)) + return 0; + + msleep(1); + } + return -ETIMEDOUT; +} + +static int max17135_display_enable(struct regulator_dev *reg) +{ + struct max17135 *max17135 = rdev_get_drvdata(reg); + + /* The Pass 1 parts cannot turn on the PMIC via I2C. */ + if (max17135->pass_num == 1) + gpio_set_value(max17135->gpio_pmic_wakeup, 1); + else { + unsigned int reg_val; + + max17135_reg_read(REG_MAX17135_ENABLE, ®_val); + reg_val &= ~BITFMASK(ENABLE); + reg_val |= BITFVAL(ENABLE, 1); + max17135_reg_write(REG_MAX17135_ENABLE, reg_val); + } + + return max17135_wait_power_good(max17135); +} + +static int max17135_display_disable(struct regulator_dev *reg) +{ + struct max17135 *max17135 = rdev_get_drvdata(reg); + + if (max17135->pass_num == 1) + gpio_set_value(max17135->gpio_pmic_wakeup, 0); + else { + unsigned int reg_val; + + max17135_reg_read(REG_MAX17135_ENABLE, ®_val); + reg_val &= ~BITFMASK(ENABLE); + max17135_reg_write(REG_MAX17135_ENABLE, reg_val); + } + + msleep(max17135->max_wait); + + return 0; +} + +static int max17135_display_is_enabled(struct regulator_dev *reg) +{ + struct max17135 *max17135 = rdev_get_drvdata(reg); + int gpio = gpio_get_value(max17135->gpio_pmic_wakeup); + + if (gpio == 0) + return 0; + else + return 1; +} + +/* + * Regulator operations + */ + +static struct regulator_ops max17135_display_ops = { + .enable = max17135_display_enable, + .disable = max17135_display_disable, + .is_enabled = max17135_display_is_enabled, +}; + +static struct regulator_ops max17135_gvdd_ops = { +}; + +static struct regulator_ops max17135_gvee_ops = { +}; + +static struct regulator_ops max17135_hvinn_ops = { +}; + +static struct regulator_ops max17135_hvinp_ops = { + .enable = max17135_hvinp_enable, + .disable = max17135_hvinp_disable, + .get_voltage = max17135_hvinp_get_voltage, + .set_voltage = max17135_hvinp_set_voltage, +}; + +static struct regulator_ops max17135_vcom_ops = { + .enable = max17135_vcom_enable, + .disable = max17135_vcom_disable, + .get_voltage = max17135_vcom_get_voltage, + .set_voltage = max17135_vcom_set_voltage, + .is_enabled = max17135_vcom_is_enabled, +}; + +static struct regulator_ops max17135_vneg_ops = { +}; + +static struct regulator_ops max17135_vpos_ops = { +}; + +/* + * Regulator descriptors + */ +static struct regulator_desc max17135_reg[MAX17135_NUM_REGULATORS] = { +{ + .name = "DISPLAY", + .id = MAX17135_DISPLAY, + .ops = &max17135_display_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}, +{ + .name = "GVDD", + .id = MAX17135_GVDD, + .ops = &max17135_gvdd_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}, +{ + .name = "GVEE", + .id = MAX17135_GVEE, + .ops = &max17135_gvee_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}, +{ + .name = "HVINN", + .id = MAX17135_HVINN, + .ops = &max17135_hvinn_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}, +{ + .name = "HVINP", + .id = MAX17135_HVINP, + .ops = &max17135_hvinp_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}, +{ + .name = "VCOM", + .id = MAX17135_VCOM, + .ops = &max17135_vcom_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}, +{ + .name = "VNEG", + .id = MAX17135_VNEG, + .ops = &max17135_vneg_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}, +{ + .name = "VPOS", + .id = MAX17135_VPOS, + .ops = &max17135_vpos_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}, +}; + +static void max17135_setup_timings(struct max17135 *max17135) +{ + unsigned int reg_val; + + int timing1, timing2, timing3, timing4, + timing5, timing6, timing7, timing8; + + max17135_reg_read(REG_MAX17135_TIMING1, &timing1); + max17135_reg_read(REG_MAX17135_TIMING2, &timing2); + max17135_reg_read(REG_MAX17135_TIMING3, &timing3); + max17135_reg_read(REG_MAX17135_TIMING4, &timing4); + max17135_reg_read(REG_MAX17135_TIMING5, &timing5); + max17135_reg_read(REG_MAX17135_TIMING6, &timing6); + max17135_reg_read(REG_MAX17135_TIMING7, &timing7); + max17135_reg_read(REG_MAX17135_TIMING8, &timing8); + + if ((timing1 != max17135->gvee_pwrup) || + (timing2 != max17135->vneg_pwrup) || + (timing3 != max17135->vpos_pwrup) || + (timing4 != max17135->gvdd_pwrup) || + (timing5 != max17135->gvdd_pwrdn) || + (timing6 != max17135->vpos_pwrdn) || + (timing7 != max17135->vneg_pwrdn) || + (timing8 != max17135->gvee_pwrdn)) { + max17135_reg_write(REG_MAX17135_TIMING1, max17135->gvee_pwrup); + max17135_reg_write(REG_MAX17135_TIMING2, max17135->vneg_pwrup); + max17135_reg_write(REG_MAX17135_TIMING3, max17135->vpos_pwrup); + max17135_reg_write(REG_MAX17135_TIMING4, max17135->gvdd_pwrup); + max17135_reg_write(REG_MAX17135_TIMING5, max17135->gvdd_pwrdn); + max17135_reg_write(REG_MAX17135_TIMING6, max17135->vpos_pwrdn); + max17135_reg_write(REG_MAX17135_TIMING7, max17135->vneg_pwrdn); + max17135_reg_write(REG_MAX17135_TIMING8, max17135->gvee_pwrdn); + + reg_val = BITFVAL(CTRL_TIMING, true); /* shift to correct bit */ + max17135_reg_write(REG_MAX17135_PRGM_CTRL, reg_val); + } +} + + +/* + * Regulator init/probing/exit functions + */ +static int max17135_regulator_probe(struct platform_device *pdev) +{ + struct regulator_dev *rdev; + + rdev = regulator_register(&max17135_reg[pdev->id], &pdev->dev, + pdev->dev.platform_data, + dev_get_drvdata(&pdev->dev)); + + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s\n", + max17135_reg[pdev->id].name); + return PTR_ERR(rdev); + } + + return 0; +} + +static int max17135_regulator_remove(struct platform_device *pdev) +{ + struct regulator_dev *rdev = platform_get_drvdata(pdev); + regulator_unregister(rdev); + return 0; +} + +static struct platform_driver max17135_regulator_driver = { + .probe = max17135_regulator_probe, + .remove = max17135_regulator_remove, + .driver = { + .name = "max17135-reg", + }, +}; + +int max17135_register_regulator(struct max17135 *max17135, int reg, + struct regulator_init_data *initdata) +{ + struct platform_device *pdev; + int ret; + + struct i2c_client *client = max17135->i2c_client; + /* If we can't find PMIC via I2C, we should not register regulators */ + if (i2c_smbus_read_byte_data(client, + REG_MAX17135_PRODUCT_REV) != 0) { + dev_err(max17135->dev, + "Max17135 PMIC not found!\n"); + return -ENXIO; + } + + if (max17135->pdev[reg]) + return -EBUSY; + + pdev = platform_device_alloc("max17135-reg", reg); + if (!pdev) + return -ENOMEM; + + max17135->pdev[reg] = pdev; + + initdata->driver_data = max17135; + + pdev->dev.platform_data = initdata; + pdev->dev.parent = max17135->dev; + platform_set_drvdata(pdev, max17135); + + ret = platform_device_add(pdev); + + if (ret != 0) { + dev_err(max17135->dev, + "Failed to register regulator %d: %d\n", + reg, ret); + platform_device_del(pdev); + max17135->pdev[reg] = NULL; + } + + if (!max17135->init_done) { + max17135->pass_num = max17135_pass_num; + max17135->vcom_uV = max17135_vcom; + + /* + * Set up PMIC timing values. + * Should only be done one time! Timing values may only be + * changed a limited number of times according to spec. + */ + max17135_setup_timings(max17135); + + max17135->pwrgood_polarity = + gpio_get_value(max17135->gpio_pmic_pwrgood); + + max17135->init_done = true; + } + + return ret; +} + +static int __init max17135_regulator_init(void) +{ + return platform_driver_register(&max17135_regulator_driver); +} +subsys_initcall(max17135_regulator_init); + +static void __exit max17135_regulator_exit(void) +{ + platform_driver_unregister(&max17135_regulator_driver); +} +module_exit(max17135_regulator_exit); + + +/* + * Parse user specified options (`max17135:') + * example: + * max17135:pass=2,vcom=-1250000 + */ +static int __init max17135_setup(char *options) +{ + int ret; + char *opt; + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + if (!strncmp(opt, "pass=", 5)) { + ret = strict_strtoul(opt + 5, 0, &max17135_pass_num); + if (ret < 0) + return ret; + } + if (!strncmp(opt, "vcom=", 5)) { + int offs = 5; + if (opt[5] == '-') + offs = 6; + ret = strict_strtoul(opt + offs, 0, &max17135_vcom); + if (ret < 0) + return ret; + max17135_vcom = -max17135_vcom; + } + } + + return 1; +} + +__setup("max17135:", max17135_setup); + +/* Module information */ +MODULE_DESCRIPTION("MAX17135 regulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/mxs-regulator.c b/drivers/regulator/mxs-regulator.c new file mode 100644 index 000000000000..34930776a90c --- /dev/null +++ b/drivers/regulator/mxs-regulator.c @@ -0,0 +1,302 @@ +/* + * Freescale STMP378X voltage regulators + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/driver.h> +#include <mach/power.h> +#include <mach/regulator.h> + +static int mxs_set_voltage(struct regulator_dev *reg, int MiniV, int uv) +{ + struct mxs_regulator *mxs_reg = rdev_get_drvdata(reg); + + if (mxs_reg->rdata->set_voltage) + return mxs_reg->rdata->set_voltage(mxs_reg, uv); + else + return -ENOTSUPP; +} + + +static int mxs_get_voltage(struct regulator_dev *reg) +{ + struct mxs_regulator *mxs_reg = rdev_get_drvdata(reg); + + if (mxs_reg->rdata->get_voltage) + return mxs_reg->rdata->get_voltage(mxs_reg); + else + return -ENOTSUPP; +} + +static int mxs_set_current(struct regulator_dev *reg, int min_uA, int uA) +{ + struct mxs_regulator *mxs_reg = rdev_get_drvdata(reg); + + if (mxs_reg->rdata->set_current) + return mxs_reg->rdata->set_current(mxs_reg, uA); + else + return -ENOTSUPP; +} + +static int mxs_get_current(struct regulator_dev *reg) +{ + struct mxs_regulator *mxs_reg = rdev_get_drvdata(reg); + + if (mxs_reg->rdata->get_current) + return mxs_reg->rdata->get_current(mxs_reg); + else + return -ENOTSUPP; +} + +static int mxs_enable(struct regulator_dev *reg) +{ + struct mxs_regulator *mxs_reg = rdev_get_drvdata(reg); + + return mxs_reg->rdata->enable(mxs_reg); +} + +static int mxs_disable(struct regulator_dev *reg) +{ + struct mxs_regulator *mxs_reg = rdev_get_drvdata(reg); + + return mxs_reg->rdata->disable(mxs_reg); +} + +static int mxs_is_enabled(struct regulator_dev *reg) +{ + struct mxs_regulator *mxs_reg = rdev_get_drvdata(reg); + + return mxs_reg->rdata->is_enabled(mxs_reg); +} + +static int mxs_set_mode(struct regulator_dev *reg, unsigned int mode) +{ + struct mxs_regulator *mxs_reg = rdev_get_drvdata(reg); + + return mxs_reg->rdata->set_mode(mxs_reg, mode); +} + +static unsigned int mxs_get_mode(struct regulator_dev *reg) +{ + struct mxs_regulator *mxs_reg = rdev_get_drvdata(reg); + + return mxs_reg->rdata->get_mode(mxs_reg); +} + +static unsigned int mxs_get_optimum_mode(struct regulator_dev *reg, + int input_uV, int output_uV, int load_uA) +{ + struct mxs_regulator *mxs_reg = rdev_get_drvdata(reg); + + if (mxs_reg->rdata->get_optimum_mode) + return mxs_reg->rdata->get_optimum_mode(mxs_reg, input_uV, + output_uV, load_uA); + else + return -ENOTSUPP; +} + +static struct regulator_ops mxs_rops = { + .set_voltage = mxs_set_voltage, + .get_voltage = mxs_get_voltage, + .set_current_limit = mxs_set_current, + .get_current_limit = mxs_get_current, + .enable = mxs_enable, + .disable = mxs_disable, + .is_enabled = mxs_is_enabled, + .set_mode = mxs_set_mode, + .get_mode = mxs_get_mode, + .get_optimum_mode = mxs_get_optimum_mode, +}; + +static struct regulator_desc mxs_reg_desc[] = { + { + .name = "vddd", + .id = MXS_VDDD, + .ops = &mxs_rops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "vdda", + .id = MXS_VDDA, + .ops = &mxs_rops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "vddio", + .id = MXS_VDDIO, + .ops = &mxs_rops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "vddd_bo", + .id = MXS_VDDDBO, + .ops = &mxs_rops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "overall_current", + .id = MXS_OVERALL_CUR, + .ops = &mxs_rops, + .irq = 0, + .type = REGULATOR_CURRENT, + .owner = THIS_MODULE + }, +}; + +static int reg_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + unsigned long flags; + struct mxs_regulator *sreg = + container_of(self, struct mxs_regulator , nb); + + switch (event) { + case MXS_REG5V_IS_USB: + spin_lock_irqsave(&sreg->lock, flags); + sreg->rdata->max_current = 500000; + spin_unlock_irqrestore(&sreg->lock, flags); + break; + case MXS_REG5V_NOT_USB: + spin_lock_irqsave(&sreg->lock, flags); + sreg->rdata->max_current = 0x7fffffff; + spin_unlock_irqrestore(&sreg->lock, flags); + break; + } + + return 0; +} + +int mxs_regulator_probe(struct platform_device *pdev) +{ + struct regulator_desc *rdesc; + struct regulator_dev *rdev; + struct mxs_regulator *sreg; + struct regulator_init_data *initdata; + + sreg = platform_get_drvdata(pdev); + initdata = pdev->dev.platform_data; + sreg->cur_current = 0; + sreg->next_current = 0; + sreg->cur_voltage = 0; + + init_waitqueue_head(&sreg->wait_q); + spin_lock_init(&sreg->lock); + + if (pdev->id > MXS_OVERALL_CUR) { + rdesc = kzalloc(sizeof(struct regulator_desc), GFP_KERNEL); + memcpy(rdesc, &mxs_reg_desc[MXS_OVERALL_CUR], + sizeof(struct regulator_desc)); + rdesc->name = kstrdup(sreg->rdata->name, GFP_KERNEL); + } else + rdesc = &mxs_reg_desc[pdev->id]; + + pr_debug("probing regulator %s %s %d\n", + sreg->rdata->name, + rdesc->name, + pdev->id); + + /* register regulator */ + rdev = regulator_register(rdesc, &pdev->dev, + initdata, sreg); + + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s\n", + rdesc->name); + return PTR_ERR(rdev); + } + + if (sreg->rdata->max_current) { + struct regulator *regu; + regu = regulator_get(NULL, sreg->rdata->name); + sreg->nb.notifier_call = reg_callback; + regulator_register_notifier(regu, &sreg->nb); + } + + return 0; +} + + +int mxs_regulator_remove(struct platform_device *pdev) +{ + struct regulator_dev *rdev = platform_get_drvdata(pdev); + + regulator_unregister(rdev); + + return 0; + +} + +int mxs_register_regulator( + struct mxs_regulator *reg_data, int reg, + struct regulator_init_data *initdata) +{ + struct platform_device *pdev; + int ret; + + pdev = platform_device_alloc("mxs_reg", reg); + if (!pdev) + return -ENOMEM; + + pdev->dev.platform_data = initdata; + + platform_set_drvdata(pdev, reg_data); + ret = platform_device_add(pdev); + + if (ret != 0) { + pr_debug("Failed to register regulator %d: %d\n", + reg, ret); + platform_device_del(pdev); + } + pr_debug("register regulator %s, %d: %d\n", + reg_data->rdata->name, reg, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(mxs_register_regulator); + +struct platform_driver mxs_reg = { + .driver = { + .name = "mxs_reg", + }, + .probe = mxs_regulator_probe, + .remove = mxs_regulator_remove, +}; + +int mxs_regulator_init(void) +{ + return platform_driver_register(&mxs_reg); +} + +void mxs_regulator_exit(void) +{ + platform_driver_unregister(&mxs_reg); +} + +postcore_initcall(mxs_regulator_init); +module_exit(mxs_regulator_exit); diff --git a/drivers/regulator/reg-mc13783.c b/drivers/regulator/reg-mc13783.c new file mode 100644 index 000000000000..da20907ba087 --- /dev/null +++ b/drivers/regulator/reg-mc13783.c @@ -0,0 +1,2662 @@ +/* + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/driver.h> +#include <linux/mfd/mc13783/core.h> +#include <linux/platform_device.h> +#include <linux/pmic_status.h> +#include <linux/pmic_external.h> + +/* + * Convenience conversion. + * Here atm, maybe there is somewhere better for this. + */ +#define mV_to_uV(mV) (mV * 1000) +#define uV_to_mV(uV) (uV / 1000) +#define V_to_uV(V) (mV_to_uV(V * 1000)) +#define uV_to_V(uV) (uV_to_mV(uV) / 1000) + +/*! + * @enum regulator_voltage_sw + * @brief PMIC regulator SW output voltage. + */ +enum { + SW_0_9V = 0, /*!< 0.900 V */ + SW_0_925V, /*!< 0.925 V */ + SW_0_95V, /*!< 0.950 V */ + SW_0_975V, /*!< 0.975 V */ + SW_1V, /*!< 1.000 V */ + SW_1_025V, /*!< 1.025 V */ + SW_1_05V, /*!< 1.050 V */ + SW_1_075V, /*!< 1.075 V */ + SW_1_1V, /*!< 1.100 V */ + SW_1_125V, /*!< 1.125 V */ + SW_1_15V, /*!< 1.150 V */ + SW_1_175V, /*!< 1.175 V */ + SW_1_2V, /*!< 1.200 V */ + SW_1_225V, /*!< 1.225 V */ + SW_1_25V, /*!< 1.250 V */ + SW_1_275V, /*!< 1.275 V */ + SW_1_3V, /*!< 1.300 V */ + SW_1_325V, /*!< 1.325 V */ + SW_1_35V, /*!< 1.350 V */ + SW_1_375V, /*!< 1.375 V */ + SW_1_4V, /*!< 1.400 V */ + SW_1_425V, /*!< 1.425 V */ + SW_1_45V, /*!< 1.450 V */ + SW_1_475V, /*!< 1.475 V */ + SW_1_5V, /*!< 1.500 V */ + SW_1_525V, /*!< 1.525 V */ + SW_1_55V, /*!< 1.550 V */ + SW_1_575V, /*!< 1.575 V */ + SW_1_6V, /*!< 1.600 V */ + SW_1_625V, /*!< 1.625 V */ + SW_1_65V, /*!< 1.650 V */ + SW_1_675V, /*!< 1.675 V */ + SW_1_7V, /*!< 1.700 V */ + SW_1_8V = 36, /*!< 1.800 V */ + SW_1_85V = 40, /*!< 1.850 V */ + SW_2V = 44, /*!< 2_000 V */ + SW_2_1V = 48, /*!< 2_100 V */ + SW_2_2V = 52, /*!< 2_200 V */ +} regulator_voltage_sw; + +/*! + * @enum regulator_voltage_violo + * @brief PMIC regulator VIOLO output voltage. + */ +enum { + VIOLO_1_2V = 0, /*!< 1.2 V */ + VIOLO_1_3V, /*!< 1.3 V */ + VIOLO_1_5V, /*!< 1.5 V */ + VIOLO_1_8V, /*!< 1.8 V */ +} regulator_voltage_violo; + +/*! + * @enum regulator_voltage_vdig + * @brief PMIC regulator VDIG output voltage. + */ +enum { + VDIG_1_2V = 0, /*!< 1.2 V */ + VDIG_1_3V, /*!< 1.3 V */ + VDIG_1_5V, /*!< 1.5 V */ + VDIG_1_8V, /*!< 1.8 V */ +} regulator_voltage_vdig; + +/*! + * @enum regulator_voltage_vgen + * @brief PMIC regulator VGEN output voltage. + */ +enum { + VGEN_1_2V = 0, /*!< 1.2 V */ + VGEN_1_3V, /*!< 1.3 V */ + VGEN_1_5V, /*!< 1.5 V */ + VGEN_1_8V, /*!< 1.8 V */ + VGEN_1_1V, /*!< 1.1 V */ + VGEN_2V, /*!< 2 V */ + VGEN_2_775V, /*!< 2.775 V */ + VGEN_2_4V, /*!< 2.4 V */ +} regulator_voltage_vgen; + +/*! + * @enum regulator_voltage_vrfdig + * @brief PMIC regulator VRFDIG output voltage. + */ +enum { + VRFDIG_1_2V = 0, /*!< 1.2 V */ + VRFDIG_1_5V, /*!< 1.5 V */ + VRFDIG_1_8V, /*!< 1.8 V */ + VRFDIG_1_875V, /*!< 1.875 V */ +} regulator_voltage_vrfdig; + +/*! + * @enum regulator_voltage_vrfref + * @brief PMIC regulator VRFREF output voltage. + */ +enum { + VRFREF_2_475V = 0, /*!< 2.475 V */ + VRFREF_2_6V, /*!< 2.600 V */ + VRFREF_2_7V, /*!< 2.700 V */ + VRFREF_2_775V, /*!< 2.775 V */ +} regulator_voltage_vrfref; + +/*! + * @enum regulator_voltage_vrfcp + * @brief PMIC regulator VRFCP output voltage. + */ +enum { + VRFCP_2_7V = 0, /*!< 2.700 V */ + VRFCP_2_775V, /*!< 2.775 V */ +} regulator_voltage_vrfcp; + +/*! + * @enum regulator_voltage_vsim + * @brief PMIC linear regulator VSIM output voltage. + */ +enum { + VSIM_1_8V = 0, /*!< 1.8 V */ + VSIM_2_9V, /*!< 2.90 V */ + VSIM_3V = 1, /*!< 3 V */ +} regulator_voltage_vsim; + +/*! + * @enum regulator_voltage_vesim + * @brief PMIC regulator VESIM output voltage. + */ +enum { + VESIM_1_8V = 0, /*!< 1.80 V */ + VESIM_2_9V, /*!< 2.90 V */ +} regulator_voltage_vesim; + +/*! + * @enum regulator_voltage_vcam + * @brief PMIC regulator VCAM output voltage. + */ +enum { + VCAM_1_5V = 0, /*!< 1.50 V */ + VCAM_1_8V, /*!< 1.80 V */ + VCAM_2_5V, /*!< 2.50 V */ + VCAM_2_55V, /*!< 2.55 V */ + VCAM_2_6V, /*!< 2.60 V */ + VCAM_2_75V, /*!< 2.75 V */ + VCAM_2_8V, /*!< 2.80 V */ + VCAM_3V, /*!< 3.00 V */ +} regulator_voltage_vcam; + +/*! + * @enum regulator_voltage_vvib + * @brief PMIC linear regulator V_VIB output voltage. + */ +enum { + VVIB_1_3V = 0, /*!< 1.30 V */ + VVIB_1_8V, /*!< 1.80 V */ + VVIB_2V, /*!< 2 V */ + VVIB_3V, /*!< 3 V */ +} regulator_voltage_vvib; + +/*! + * @enum regulator_voltage_vmmc + * @brief MC13783 PMIC regulator VMMC output voltage. + */ +enum { + VMMC_1_6V = 0, /*!< 1.60 V */ + VMMC_1_8V, /*!< 1.80 V */ + VMMC_2V, /*!< 2.00 V */ + VMMC_2_6V, /*!< 2.60 V */ + VMMC_2_7V, /*!< 2.70 V */ + VMMC_2_8V, /*!< 2.80 V */ + VMMC_2_9V, /*!< 2.90 V */ + VMMC_3V, /*!< 3.00 V */ +} regulator_voltage_vmmc; + +/*! + * @enum regulator_voltage_vrf + * @brief PMIC regulator VRF output voltage. + */ +enum { + VRF_1_5V = 0, /*!< 1.500 V */ + VRF_1_875V, /*!< 1.875 V */ + VRF_2_7V, /*!< 2.700 V */ + VRF_2_775V, /*!< 2.775 V */ +} regulator_voltage_vrf; + +/*! + * @enum regulator_voltage_sw3 + * @brief PMIC Switch mode regulator SW3 output voltages. + */ +enum { + SW3_5V = 0, /*!< 5.0 V */ + SW3_5_5V = 3, /*!< 5.5 V */ +} regulator_voltage_sw3; + +/*! + * The \b TPmicDVSTransitionSpeed enum defines the rate with which the + * voltage transition occurs. + */ +enum { + ESysDependent, + E25mVEach4us, + E25mVEach8us, + E25mvEach16us +} DVS_transition_speed; + +/* + * Reg Regulator Mode 0 + */ +#define VAUDIO_EN_LSH 0 +#define VAUDIO_EN_WID 1 +#define VAUDIO_EN_ENABLE 1 +#define VAUDIO_EN_DISABLE 0 +#define VIOHI_EN_LSH 3 +#define VIOHI_EN_WID 1 +#define VIOHI_EN_ENABLE 1 +#define VIOHI_EN_DISABLE 0 +#define VIOLO_EN_LSH 6 +#define VIOLO_EN_WID 1 +#define VIOLO_EN_ENABLE 1 +#define VIOLO_EN_DISABLE 0 +#define VDIG_EN_LSH 9 +#define VDIG_EN_WID 1 +#define VDIG_EN_ENABLE 1 +#define VDIG_EN_DISABLE 0 +#define VGEN_EN_LSH 12 +#define VGEN_EN_WID 1 +#define VGEN_EN_ENABLE 1 +#define VGEN_EN_DISABLE 0 +#define VRFDIG_EN_LSH 15 +#define VRFDIG_EN_WID 1 +#define VRFDIG_EN_ENABLE 1 +#define VRFDIG_EN_DISABLE 0 +#define VRFREF_EN_LSH 18 +#define VRFREF_EN_WID 1 +#define VRFREF_EN_ENABLE 1 +#define VRFREF_EN_DISABLE 0 +#define VRFCP_EN_LSH 21 +#define VRFCP_EN_WID 1 +#define VRFCP_EN_ENABLE 1 +#define VRFCP_EN_DISABLE 0 + +/* + * Reg Regulator Mode 1 + */ +#define VSIM_EN_LSH 0 +#define VSIM_EN_WID 1 +#define VSIM_EN_ENABLE 1 +#define VSIM_EN_DISABLE 0 +#define VESIM_EN_LSH 3 +#define VESIM_EN_WID 1 +#define VESIM_EN_ENABLE 1 +#define VESIM_EN_DISABLE 0 +#define VCAM_EN_LSH 6 +#define VCAM_EN_WID 1 +#define VCAM_EN_ENABLE 1 +#define VCAM_EN_DISABLE 0 +#define VRFBG_EN_LSH 9 +#define VRFBG_EN_WID 1 +#define VRFBG_EN_ENABLE 1 +#define VRFBG_EN_DISABLE 0 +#define VVIB_EN_LSH 11 +#define VVIB_EN_WID 1 +#define VVIB_EN_ENABLE 1 +#define VVIB_EN_DISABLE 0 +#define VRF1_EN_LSH 12 +#define VRF1_EN_WID 1 +#define VRF1_EN_ENABLE 1 +#define VRF1_EN_DISABLE 0 +#define VRF2_EN_LSH 15 +#define VRF2_EN_WID 1 +#define VRF2_EN_ENABLE 1 +#define VRF2_EN_DISABLE 0 +#define VMMC1_EN_LSH 18 +#define VMMC1_EN_WID 1 +#define VMMC1_EN_ENABLE 1 +#define VMMC1_EN_DISABLE 0 +#define VMMC2_EN_LSH 21 +#define VMMC2_EN_WID 1 +#define VMMC2_EN_ENABLE 1 +#define VMMC2_EN_DISABLE 0 + +/* + * Reg Regulator Setting 0 + */ +#define VIOLO_LSH 2 +#define VIOLO_WID 2 +#define VDIG_LSH 4 +#define VDIG_WID 2 +#define VGEN_LSH 6 +#define VGEN_WID 3 +#define VRFDIG_LSH 9 +#define VRFDIG_WID 2 +#define VRFREF_LSH 11 +#define VRFREF_WID 2 +#define VRFCP_LSH 13 +#define VRFCP_WID 1 +#define VSIM_LSH 14 +#define VSIM_WID 1 +#define VESIM_LSH 15 +#define VESIM_WID 1 +#define VCAM_LSH 16 +#define VCAM_WID 3 + +/* + * Reg Regulator Setting 1 + */ +#define VVIB_LSH 0 +#define VVIB_WID 2 +#define VRF1_LSH 2 +#define VRF1_WID 2 +#define VRF2_LSH 4 +#define VRF2_WID 2 +#define VMMC1_LSH 6 +#define VMMC1_WID 3 +#define VMMC2_LSH 9 +#define VMMC2_WID 3 + +/* + * Reg Switcher 0 + */ +#define SW1A_LSH 0 +#define SW1A_WID 6 +#define SW1A_DVS_LSH 6 +#define SW1A_DVS_WID 6 +#define SW1A_STDBY_LSH 12 +#define SW1A_STDBY_WID 6 + +/* + * Reg Switcher 1 + */ +#define SW1B_LSH 0 +#define SW1B_WID 6 +#define SW1B_DVS_LSH 6 +#define SW1B_DVS_WID 6 +#define SW1B_STDBY_LSH 12 +#define SW1B_STDBY_WID 6 + +/* + * Reg Switcher 2 + */ +#define SW2A_LSH 0 +#define SW2A_WID 6 +#define SW2A_DVS_LSH 6 +#define SW2A_DVS_WID 6 +#define SW2A_STDBY_LSH 12 +#define SW2A_STDBY_WID 6 + +/* + * Reg Switcher 3 + */ +#define SW2B_LSH 0 +#define SW2B_WID 6 +#define SW2B_DVS_LSH 6 +#define SW2B_DVS_WID 6 +#define SW2B_STDBY_LSH 12 +#define SW2B_STDBY_WID 6 + +/* + * Reg Switcher 4 + */ +#define SW1A_MODE_LSH 0 +#define SW1A_MODE_WID 2 +#define SW1A_STBY_MODE_LSH 2 +#define SW1A_STBY_MODE_WID 2 +#define SW1A_DVS_SPEED_LSH 6 +#define SW1A_DVS_SPEED_WID 2 +#define SW1B_MODE_LSH 10 +#define SW1B_MODE_WID 2 +#define SW1B_STBY_MODE_LSH 12 +#define SW1B_STBY_MODE_WID 2 +#define SW1B_DVS_SPEED_LSH 14 +#define SW1B_DVS_SPEED_WID 2 + +/* + * Reg Switcher 5 + */ +#define SW2A_MODE_LSH 0 +#define SW2A_MODE_WID 2 +#define SW2A_STBY_MODE_LSH 2 +#define SW2A_STBY_MODE_WID 2 +#define SW2A_DVS_SPEED_LSH 6 +#define SW2A_DVS_SPEED_WID 2 +#define SW2B_MODE_LSH 10 +#define SW2B_MODE_WID 2 +#define SW2B_STBY_MODE_LSH 12 +#define SW2B_STBY_MODE_WID 2 +#define SW2B_DVS_SPEED_LSH 14 +#define SW2B_DVS_SPEED_WID 2 +#define SW3_LSH 18 +#define SW3_WID 2 +#define SW3_EN_LSH 20 +#define SW3_EN_WID 2 +#define SW3_EN_ENABLE 1 +#define SW3_EN_DISABLE 0 + +/* + * Reg Regulator Misc. + */ +#define GPO1_EN_LSH 6 +#define GPO1_EN_WID 1 +#define GPO1_EN_ENABLE 1 +#define GPO1_EN_DISABLE 0 +#define GPO2_EN_LSH 8 +#define GPO2_EN_WID 1 +#define GPO2_EN_ENABLE 1 +#define GPO2_EN_DISABLE 0 +#define GPO3_EN_LSH 10 +#define GPO3_EN_WID 1 +#define GPO3_EN_ENABLE 1 +#define GPO3_EN_DISABLE 0 +#define GPO4_EN_LSH 12 +#define GPO4_EN_WID 1 +#define GPO4_EN_ENABLE 1 +#define GPO4_EN_DISABLE 0 + +/* + * Switcher mode configuration + */ +#define SW_MODE_SYNC_RECT_EN 0 +#define SW_MODE_PULSE_NO_SKIP_EN 1 +#define SW_MODE_PULSE_SKIP_EN 2 +#define SW_MODE_LOW_POWER_EN 3 + +#define dvs_speed E25mvEach16us + +static int mc13783_vaudio_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VAUDIO_EN, VAUDIO_EN_ENABLE); + register_mask = BITFMASK(VAUDIO_EN); + register1 = REG_REGULATOR_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vaudio_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VAUDIO_EN, VAUDIO_EN_DISABLE); + register_mask = BITFMASK(VAUDIO_EN); + register1 = REG_REGULATOR_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_viohi_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VIOHI_EN, VIOHI_EN_ENABLE); + register_mask = BITFMASK(VIOHI_EN); + register1 = REG_REGULATOR_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_viohi_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VIOHI_EN, VIOHI_EN_DISABLE); + register_mask = BITFMASK(VIOHI_EN); + register1 = REG_REGULATOR_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_violo_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0, register1 = 0; + int voltage, mV = uV / 1000; + + if ((mV >= 1200) && (mV < 1300)) + voltage = VIOLO_1_2V; + else if ((mV >= 1300) && (mV < 1500)) + voltage = VIOLO_1_3V; + else if ((mV >= 1500) && (mV < 1800)) + voltage = VIOLO_1_5V; + else + voltage = VIOLO_1_8V; + + register_val = BITFVAL(VIOLO, voltage); + register_mask = BITFMASK(VIOLO); + register1 = REG_REGULATOR_SETTING_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_violo_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_REGULATOR_SETTING_0, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VIOLO); + + switch (voltage) { + case VIOLO_1_2V: + mV = 1200; + break; + case VIOLO_1_3V: + mV = 1300; + break; + case VIOLO_1_5V: + mV = 1500; + break; + case VIOLO_1_8V: + mV = 1800; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13783_violo_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VIOLO_EN, VIOLO_EN_ENABLE); + register_mask = BITFMASK(VIOLO_EN); + register1 = REG_REGULATOR_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_violo_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VIOLO_EN, VIOLO_EN_DISABLE); + register_mask = BITFMASK(VIOLO_EN); + register1 = REG_REGULATOR_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vdig_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 1200) && (mV < 1300)) + voltage = VDIG_1_2V; + else if ((mV >= 1300) && (mV < 1500)) + voltage = VDIG_1_3V; + else if ((mV >= 1500) && (mV < 1800)) + voltage = VDIG_1_5V; + else + voltage = VDIG_1_8V; + + register_val = BITFVAL(VDIG, voltage); + register_mask = BITFMASK(VDIG); + register1 = REG_REGULATOR_SETTING_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vdig_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_REGULATOR_SETTING_0, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VDIG); + + switch (voltage) { + case VDIG_1_2V: + mV = 1200; + break; + case VDIG_1_3V: + mV = 1300; + break; + case VDIG_1_5V: + mV = 1500; + break; + case VDIG_1_8V: + mV = 1800; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13783_vdig_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VDIG_EN, VDIG_EN_ENABLE); + register_mask = BITFMASK(VDIG_EN); + register1 = REG_REGULATOR_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vdig_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VDIG_EN, VDIG_EN_DISABLE); + register_mask = BITFMASK(VDIG_EN); + register1 = REG_REGULATOR_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vgen_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + int vgenid = rdev_get_id(reg); + + printk(KERN_INFO "VGEN ID is %d\n", vgenid); + + if ((mV >= 1100) && (mV < 1200)) + voltage = VGEN_1_1V; + else if ((mV >= 1200) && (mV < 1300)) + voltage = VGEN_1_2V; + else if ((mV >= 1300) && (mV < 1500)) + voltage = VGEN_1_3V; + else if ((mV >= 1500) && (mV < 1800)) + voltage = VGEN_1_5V; + else if ((mV >= 1800) && (mV < 2000)) + voltage = VGEN_1_8V; + else if ((mV >= 2000) && (mV < 2400)) + voltage = VGEN_2V; + else if ((mV >= 2400) && (mV < 2775)) + voltage = VGEN_2_4V; + else + voltage = VGEN_2_775V; + + register_val = BITFVAL(VGEN, voltage); + register_mask = BITFMASK(VGEN); + register1 = REG_REGULATOR_SETTING_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vgen_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_REGULATOR_SETTING_0, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VGEN); + + switch (voltage) { + case VGEN_1_2V: + mV = 1200; + break; + case VGEN_1_3V: + mV = 1300; + break; + case VGEN_1_5V: + mV = 1500; + break; + case VGEN_1_8V: + mV = 1800; + break; + case VGEN_1_1V: + mV = 1100; + break; + case VGEN_2V: + mV = 2000; + break; + case VGEN_2_775V: + mV = 2775; + break; + case VGEN_2_4V: + mV = 2400; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13783_vgen_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VGEN_EN, VGEN_EN_ENABLE); + register_mask = BITFMASK(VGEN_EN); + register1 = REG_REGULATOR_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vgen_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VGEN_EN, VGEN_EN_DISABLE); + register_mask = BITFMASK(VGEN_EN); + register1 = REG_REGULATOR_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vrfdig_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 1200) && (mV < 1500)) + voltage = VRFDIG_1_2V; + else if ((mV >= 1500) && (mV < 1300)) + voltage = VRFDIG_1_5V; + else if ((mV >= 1800) && (mV < 1875)) + voltage = VRFDIG_1_8V; + else + voltage = VRFDIG_1_875V; + + register_val = BITFVAL(VRFDIG, voltage); + register_mask = BITFMASK(VRFDIG); + register1 = REG_REGULATOR_SETTING_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vrfdig_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_REGULATOR_SETTING_0, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VRFDIG); + + switch (voltage) { + case VRFDIG_1_2V: + mV = 1200; + break; + case VRFDIG_1_5V: + mV = 1500; + break; + case VRFDIG_1_8V: + mV = 1800; + break; + case VRFDIG_1_875V: + mV = 1875; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13783_vrfdig_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VRFDIG_EN, VRFDIG_EN_ENABLE); + register_mask = BITFMASK(VRFDIG_EN); + register1 = REG_REGULATOR_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vrfdig_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VRFDIG_EN, VRFDIG_EN_DISABLE); + register_mask = BITFMASK(VRFDIG_EN); + register1 = REG_REGULATOR_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vrfref_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 2475) && (mV < 2600)) + voltage = VRFREF_2_475V; + else if ((mV >= 2600) && (mV < 2700)) + voltage = VRFREF_2_6V; + else if ((mV >= 2700) && (mV < 2775)) + voltage = VRFREF_2_7V; + else + voltage = VRFREF_2_775V; + + register_val = BITFVAL(VRFREF, voltage); + register_mask = BITFMASK(VRFREF); + register1 = REG_REGULATOR_SETTING_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vrfref_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_REGULATOR_SETTING_0, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VRFREF); + + switch (voltage) { + case VRFREF_2_475V: + mV = 2475; + break; + case VRFREF_2_6V: + mV = 2600; + break; + case VRFREF_2_7V: + mV = 2700; + break; + case VRFREF_2_775V: + mV = 2775; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13783_vrfref_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VRFREF_EN, VRFREF_EN_ENABLE); + register_mask = BITFMASK(VRFREF_EN); + register1 = REG_REGULATOR_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vrfref_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VRFREF_EN, VRFREF_EN_DISABLE); + register_mask = BITFMASK(VRFREF_EN); + register1 = REG_REGULATOR_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vrfcp_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 2700) && (mV < 2775)) + voltage = VRFCP_2_7V; + else + voltage = VRFCP_2_775V; + + register_val = BITFVAL(VRFCP, voltage); + register_mask = BITFMASK(VRFCP); + register1 = REG_REGULATOR_SETTING_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vrfcp_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_REGULATOR_SETTING_0, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VRFCP); + + switch (voltage) { + case VRFCP_2_7V: + mV = 2700; + break; + case VRFCP_2_775V: + mV = 2775; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13783_vrfcp_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VRFCP_EN, VRFCP_EN_ENABLE); + register_mask = BITFMASK(VRFCP_EN); + register1 = REG_REGULATOR_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vrfcp_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VRFCP_EN, VRFCP_EN_DISABLE); + register_mask = BITFMASK(VRFCP_EN); + register1 = REG_REGULATOR_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vsim_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 1800) && (mV < 2900)) + voltage = VSIM_1_8V; + else + voltage = VSIM_2_9V; + + register_val = BITFVAL(VSIM, voltage); + register_mask = BITFMASK(VSIM); + register1 = REG_REGULATOR_SETTING_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vsim_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_REGULATOR_SETTING_0, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VSIM); + + switch (voltage) { + case VSIM_1_8V: + mV = 1800; + break; + case VSIM_2_9V: + mV = 1900; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13783_vsim_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VSIM_EN, VSIM_EN_ENABLE); + register_mask = BITFMASK(VSIM_EN); + register1 = REG_REGULATOR_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vsim_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VSIM_EN, VSIM_EN_DISABLE); + register_mask = BITFMASK(VSIM_EN); + register1 = REG_REGULATOR_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vesim_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 1800) && (mV < 2900)) + voltage = VESIM_1_8V; + else + voltage = VESIM_2_9V; + + register_val = BITFVAL(VESIM, voltage); + register_mask = BITFMASK(VESIM); + register1 = REG_REGULATOR_SETTING_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vesim_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_REGULATOR_SETTING_0, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VESIM); + + switch (voltage) { + case VESIM_1_8V: + mV = 1800; + break; + case VESIM_2_9V: + mV = 1900; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13783_vesim_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VESIM_EN, VESIM_EN_ENABLE); + register_mask = BITFMASK(VESIM_EN); + register1 = REG_REGULATOR_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vesim_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VESIM_EN, VESIM_EN_DISABLE); + register_mask = BITFMASK(VESIM_EN); + register1 = REG_REGULATOR_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vcam_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 1500) && (mV < 1800)) + voltage = VCAM_1_5V; + else if ((mV >= 1800) && (mV < 2500)) + voltage = VCAM_1_8V; + else if ((mV >= 2500) && (mV < 2550)) + voltage = VCAM_2_5V; + else if ((mV >= 2550) && (mV < 2600)) + voltage = VCAM_2_55V; + if ((mV >= 2600) && (mV < 2750)) + voltage = VCAM_2_6V; + else if ((mV >= 2750) && (mV < 2800)) + voltage = VCAM_2_75V; + else if ((mV >= 2800) && (mV < 3000)) + voltage = VCAM_2_8V; + else + voltage = VCAM_3V; + + register_val = BITFVAL(VCAM, voltage); + register_mask = BITFMASK(VCAM); + register1 = REG_REGULATOR_SETTING_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vcam_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_REGULATOR_SETTING_0, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VCAM); + + switch (voltage) { + case VCAM_1_5V: + mV = 1500; + break; + case VCAM_1_8V: + mV = 1800; + break; + case VCAM_2_5V: + mV = 2500; + break; + case VCAM_2_55V: + mV = 2550; + break; + case VCAM_2_6V: + mV = 2600; + break; + case VCAM_2_75V: + mV = 2750; + break; + case VCAM_2_8V: + mV = 2800; + break; + case VCAM_3V: + mV = 3000; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13783_vcam_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VCAM_EN, VCAM_EN_ENABLE); + register_mask = BITFMASK(VCAM_EN); + register1 = REG_REGULATOR_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vcam_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VCAM_EN, VCAM_EN_DISABLE); + register_mask = BITFMASK(VCAM_EN); + register1 = REG_REGULATOR_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vvib_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 1300) && (mV < 1800)) + voltage = VVIB_1_3V; + else if ((mV >= 1800) && (mV < 2000)) + voltage = VVIB_1_8V; + else if ((mV >= 2000) && (mV < 3000)) + voltage = VVIB_2V; + else + voltage = VVIB_3V; + + register_val = BITFVAL(VVIB, voltage); + register_mask = BITFMASK(VVIB); + register1 = REG_REGULATOR_SETTING_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vvib_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_REGULATOR_SETTING_1, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VVIB); + + switch (voltage) { + case VVIB_1_3V: + mV = 1300; + break; + case VVIB_1_8V: + mV = 1800; + break; + case VVIB_2V: + mV = 2000; + break; + case VVIB_3V: + mV = 3000; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13783_vvib_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VVIB_EN, VVIB_EN_ENABLE); + register_mask = BITFMASK(VVIB_EN); + register1 = REG_REGULATOR_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vvib_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VVIB_EN, VVIB_EN_DISABLE); + register_mask = BITFMASK(VVIB_EN); + register1 = REG_REGULATOR_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vrf_set_voltage(struct regulator_dev *reg, int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, rf = rdev_get_id(reg), mV = uV / 1000; + + if ((mV >= 1500) && (mV < 1875)) + voltage = VRF_1_5V; + else if ((mV >= 1875) && (mV < 2700)) + voltage = VRF_1_875V; + else if ((mV >= 2700) && (mV < 2775)) + voltage = VRF_2_7V; + else + voltage = VRF_2_775V; + + switch (rf) { + case MC13783_VRF1: + register_val = BITFVAL(VRF1, voltage); + register_mask = BITFMASK(VRF1); + break; + case MC13783_VRF2: + register_val = BITFVAL(VRF2, voltage); + register_mask = BITFMASK(VRF2); + break; + default: + return -EINVAL; + } + + register1 = REG_REGULATOR_SETTING_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vrf_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, rf = rdev_get_id(reg), mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_REGULATOR_SETTING_1, + ®ister_val, PMIC_ALL_BITS)); + + switch (rf) { + case MC13783_VRF1: + voltage = BITFEXT(register_val, VRF1); + break; + case MC13783_VRF2: + voltage = BITFEXT(register_val, VRF2); + break; + default: + return -EINVAL; + }; + + switch (voltage) { + case VRF_1_5V: + mV = 1500; + break; + case VRF_1_875V: + mV = 1875; + break; + case VRF_2_7V: + mV = 2700; + break; + case VRF_2_775V: + mV = 2775; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13783_vrf_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int vrf = rdev_get_id(reg); + + switch (vrf) { + case MC13783_VRF1: + register_val = BITFVAL(VRF1_EN, VRF1_EN_ENABLE); + register_mask = BITFMASK(VRF1_EN); + break; + case MC13783_VRF2: + register_val = BITFVAL(VRF2_EN, VRF2_EN_ENABLE); + register_mask = BITFMASK(VRF2_EN); + break; + default: + return -EINVAL; + }; + + register1 = REG_REGULATOR_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vrf_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int vrf = rdev_get_id(reg); + + switch (vrf) { + case MC13783_VRF1: + register_val = BITFVAL(VRF1_EN, VRF1_EN_DISABLE); + register_mask = BITFMASK(VRF1_EN); + break; + case MC13783_VRF2: + register_val = BITFVAL(VRF2_EN, VRF2_EN_DISABLE); + register_mask = BITFMASK(VRF2_EN); + break; + default: + return -EINVAL; + }; + + register1 = REG_REGULATOR_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vmmc_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mmc = rdev_get_id(reg), mV = uV / 1000; + + printk(KERN_INFO "VMMC ID is %d\n", mmc); + + if ((mV >= 1600) && (mV < 1800)) + voltage = VMMC_1_6V; + else if ((mV >= 1800) && (mV < 2000)) + voltage = VMMC_1_8V; + else if ((mV >= 2000) && (mV < 2600)) + voltage = VMMC_2V; + else if ((mV >= 2600) && (mV < 2700)) + voltage = VMMC_2_6V; + else if ((mV >= 2700) && (mV < 2800)) + voltage = VMMC_2_7V; + else if ((mV >= 2800) && (mV < 2900)) + voltage = VMMC_2_8V; + else if ((mV >= 2900) && (mV < 3000)) + voltage = VMMC_2_9V; + else + voltage = VMMC_3V; + + switch (mmc) { + case MC13783_VMMC1: + register_val = BITFVAL(VMMC1, voltage); + register_mask = BITFMASK(VMMC1); + break; + case MC13783_VMMC2: + register_val = BITFVAL(VMMC2, voltage); + register_mask = BITFMASK(VMMC2); + break; + default: + return -EINVAL; + } + + register1 = REG_REGULATOR_SETTING_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vmmc_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mmc = rdev_get_id(reg), mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_REGULATOR_SETTING_1, + ®ister_val, PMIC_ALL_BITS)); + + switch (mmc) { + case MC13783_VMMC1: + voltage = BITFEXT(register_val, VMMC1); + break; + case MC13783_VMMC2: + voltage = BITFEXT(register_val, VMMC2); + break; + default: + return -EINVAL; + } + + switch (voltage) { + case VMMC_1_6V: + mV = 1600; + break; + case VMMC_1_8V: + mV = 1800; + break; + case VMMC_2V: + mV = 2000; + break; + case VMMC_2_6V: + mV = 2600; + break; + case VMMC_2_7V: + mV = 2700; + break; + case VMMC_2_8V: + mV = 2800; + break; + case VMMC_2_9V: + mV = 2900; + break; + case VMMC_3V: + mV = 3000; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13783_vmmc_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int vmmc = rdev_get_id(reg); + + switch (vmmc) { + case MC13783_VMMC1: + register_val = BITFVAL(VMMC1_EN, VMMC1_EN_ENABLE); + register_mask = BITFMASK(VMMC1_EN); + break; + case MC13783_VMMC2: + register_val = BITFVAL(VMMC2_EN, VMMC2_EN_ENABLE); + register_mask = BITFMASK(VMMC2_EN); + break; + default: + return -EINVAL; + }; + + register1 = REG_REGULATOR_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_vmmc_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int vmmc = rdev_get_id(reg); + + switch (vmmc) { + case MC13783_VMMC1: + register_val = BITFVAL(VMMC1_EN, VMMC1_EN_DISABLE); + register_mask = BITFMASK(VMMC1_EN); + break; + case MC13783_VMMC2: + register_val = BITFVAL(VMMC2_EN, VMMC2_EN_DISABLE); + register_mask = BITFMASK(VMMC2_EN); + break; + default: + return -EINVAL; + }; + + register1 = REG_REGULATOR_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_gpo_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int gpo = rdev_get_id(reg); + + switch (gpo) { + case MC13783_GPO1: + register_val = BITFVAL(GPO1_EN, GPO1_EN_ENABLE); + register_mask = BITFMASK(GPO1_EN); + break; + case MC13783_GPO2: + register_val = BITFVAL(GPO2_EN, GPO2_EN_ENABLE); + register_mask = BITFMASK(GPO2_EN); + break; + case MC13783_GPO3: + register_val = BITFVAL(GPO3_EN, GPO3_EN_ENABLE); + register_mask = BITFMASK(GPO3_EN); + break; + case MC13783_GPO4: + register_val = BITFVAL(GPO4_EN, GPO4_EN_ENABLE); + register_mask = BITFMASK(GPO4_EN); + break; + default: + return -EINVAL; + }; + + register1 = REG_POWER_MISCELLANEOUS; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_gpo_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int gpo = rdev_get_id(reg); + + switch (gpo) { + case MC13783_GPO1: + register_val = BITFVAL(GPO1_EN, GPO1_EN_DISABLE); + register_mask = BITFMASK(GPO1_EN); + break; + case MC13783_GPO2: + register_val = BITFVAL(GPO2_EN, GPO2_EN_DISABLE); + register_mask = BITFMASK(GPO2_EN); + break; + case MC13783_GPO3: + register_val = BITFVAL(GPO3_EN, GPO3_EN_DISABLE); + register_mask = BITFMASK(GPO3_EN); + break; + case MC13783_GPO4: + register_val = BITFVAL(GPO4_EN, GPO4_EN_DISABLE); + register_mask = BITFMASK(GPO4_EN); + break; + default: + return -EINVAL; + }; + + register1 = REG_POWER_MISCELLANEOUS; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_sw3_set_voltage(struct regulator_dev *reg, int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0, register1 = 0; + int voltage, mV = uV / 1000; + + if ((mV >= 5000) && (mV < 5500)) + voltage = SW3_5V; + else + voltage = SW3_5_5V; + + register_val = BITFVAL(SW3, voltage); + register_mask = BITFMASK(SW3); + register1 = REG_SWITCHERS_5; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_sw3_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_SWITCHERS_5, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, SW3); + + if (voltage == SW3_5_5V) + mV = 5500; + else + mV = 5000; + + return mV * 1000; +} + +static int mc13783_sw3_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(SW3_EN, SW3_EN_ENABLE); + register_mask = BITFMASK(SW3_EN); + register1 = REG_SWITCHERS_5; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_sw3_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(SW3_EN, SW3_EN_DISABLE); + register_mask = BITFMASK(SW3_EN); + register1 = REG_SWITCHERS_5; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_sw_set_normal_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1 = 0; + int voltage, sw = rdev_get_id(reg), mV = uV / 1000; + + if ((mV >= 900) && (mV < 925)) + voltage = SW_0_9V; + else if ((mV >= 925) && (mV < 950)) + voltage = SW_0_925V; + else if ((mV >= 950) && (mV < 975)) + voltage = SW_0_95V; + else if ((mV >= 975) && (mV < 1000)) + voltage = SW_0_975V; + else if ((mV >= 1000) && (mV < 1025)) + voltage = SW_1V; + else if ((mV >= 1025) && (mV < 1050)) + voltage = SW_1_025V; + else if ((mV >= 1050) && (mV < 1075)) + voltage = SW_1_05V; + else if ((mV >= 1075) && (mV < 1100)) + voltage = SW_1_075V; + else if ((mV >= 1100) && (mV < 1125)) + voltage = SW_1_1V; + else if ((mV >= 1125) && (mV < 1150)) + voltage = SW_1_125V; + else if ((mV >= 1150) && (mV < 1175)) + voltage = SW_1_15V; + else if ((mV >= 1175) && (mV < 1200)) + voltage = SW_1_175V; + else if ((mV >= 1200) && (mV < 1225)) + voltage = SW_1_2V; + else if ((mV >= 1225) && (mV < 1250)) + voltage = SW_1_225V; + else if ((mV >= 1250) && (mV < 1275)) + voltage = SW_1_25V; + else if ((mV >= 1275) && (mV < 1300)) + voltage = SW_1_275V; + else if ((mV >= 1300) && (mV < 1325)) + voltage = SW_1_3V; + else if ((mV >= 1325) && (mV < 1350)) + voltage = SW_1_325V; + else if ((mV >= 1350) && (mV < 1375)) + voltage = SW_1_35V; + else if ((mV >= 1375) && (mV < 1400)) + voltage = SW_1_375V; + else if ((mV >= 1400) && (mV < 1425)) + voltage = SW_1_4V; + else if ((mV >= 1425) && (mV < 1450)) + voltage = SW_1_425V; + else if ((mV >= 1450) && (mV < 1475)) + voltage = SW_1_45V; + else if ((mV >= 1475) && (mV < 1500)) + voltage = SW_1_475V; + else if ((mV >= 1500) && (mV < 1525)) + voltage = SW_1_5V; + else if ((mV >= 1525) && (mV < 1550)) + voltage = SW_1_525V; + else if ((mV >= 1550) && (mV < 1575)) + voltage = SW_1_55V; + else if ((mV >= 1575) && (mV < 1600)) + voltage = SW_1_575V; + else if ((mV >= 1600) && (mV < 1625)) + voltage = SW_1_6V; + else if ((mV >= 1625) && (mV < 1650)) + voltage = SW_1_625V; + else if ((mV >= 1650) && (mV < 1675)) + voltage = SW_1_65V; + else if ((mV >= 1675) && (mV < 1700)) + voltage = SW_1_675V; + else if ((mV >= 1700) && (mV < 1800)) + voltage = SW_1_7V; + else if ((mV >= 1800) && (mV < 1850)) + voltage = SW_1_8V; + else if ((mV >= 1850) && (mV < 2000)) + voltage = SW_1_85V; + else if ((mV >= 2000) && (mV < 2100)) + voltage = SW_2V; + else if ((mV >= 2100) && (mV < 2200)) + voltage = SW_2_1V; + else + voltage = SW_2_2V; + + switch (sw) { + case MC13783_SW1A: + register1 = REG_SWITCHERS_0; + register_val = BITFVAL(SW1A, voltage); + register_mask = BITFMASK(SW1A); + break; + case MC13783_SW1B: + register1 = REG_SWITCHERS_1; + register_val = BITFVAL(SW1B, voltage); + register_mask = BITFMASK(SW1B); + break; + case MC13783_SW2A: + register1 = REG_SWITCHERS_2; + register_val = BITFVAL(SW2A, voltage); + register_mask = BITFMASK(SW2A); + break; + case MC13783_SW2B: + register1 = REG_SWITCHERS_3; + register_val = BITFVAL(SW2B, voltage); + register_mask = BITFMASK(SW2B); + break; + default: + return -EINVAL; + } + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_sw_get_normal_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0, sw = rdev_get_id(reg); + + switch (sw) { + case MC13783_SW1A: + CHECK_ERROR(pmic_read_reg(REG_SWITCHERS_0, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, SW1A); + break; + case MC13783_SW1B: + CHECK_ERROR(pmic_read_reg(REG_SWITCHERS_1, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, SW1B); + break; + case MC13783_SW2A: + CHECK_ERROR(pmic_read_reg(REG_SWITCHERS_2, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, SW2A); + break; + case MC13783_SW2B: + CHECK_ERROR(pmic_read_reg(REG_SWITCHERS_3, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, SW2B); + break; + default: + return -EINVAL; + } + + switch (voltage) { + case SW_0_9V: + mV = 900; + break; + case SW_0_925V: + mV = 925; + break; + case SW_0_95V: + mV = 950; + break; + case SW_0_975V: + mV = 975; + break; + case SW_1V: + mV = 1000; + break; + case SW_1_025V: + mV = 1025; + break; + case SW_1_05V: + mV = 1050; + break; + case SW_1_075V: + mV = 1075; + break; + case SW_1_1V: + mV = 1100; + break; + case SW_1_125V: + mV = 1125; + break; + case SW_1_15V: + mV = 1150; + break; + case SW_1_175V: + mV = 1175; + break; + case SW_1_2V: + mV = 1200; + break; + case SW_1_225V: + mV = 1225; + break; + case SW_1_25V: + mV = 1250; + break; + case SW_1_275V: + mV = 1275; + break; + case SW_1_3V: + mV = 1300; + break; + case SW_1_325V: + mV = 1325; + break; + case SW_1_35V: + mV = 1350; + break; + case SW_1_375V: + mV = 1375; + break; + case SW_1_4V: + mV = 1400; + break; + case SW_1_425V: + mV = 1425; + break; + case SW_1_45V: + mV = 1450; + break; + case SW_1_475V: + mV = 1475; + break; + case SW_1_5V: + mV = 1500; + break; + case SW_1_525V: + mV = 1525; + break; + case SW_1_55V: + mV = 1550; + break; + case SW_1_575V: + mV = 1575; + break; + case SW_1_6V: + mV = 1600; + break; + case SW_1_625V: + mV = 1625; + break; + case SW_1_65V: + mV = 1650; + break; + case SW_1_675V: + mV = 1675; + break; + case SW_1_7V: + mV = 1700; + break; + case SW_1_8V: + mV = 1800; + break; + case SW_1_85V: + mV = 1850; + break; + case SW_2V: + mV = 2000; + break; + case SW_2_1V: + mV = 2100; + break; + case SW_2_2V: + mV = 2200; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13783_sw_normal_enable(struct regulator_dev *reg) +{ + return 0; +} + +static int mc13783_sw_normal_disable(struct regulator_dev *reg) +{ + return 0; +} + +static int mc13783_sw_stby_enable(struct regulator_dev *reg) +{ + return 0; +} + +static int mc13783_sw_stby_disable(struct regulator_dev *reg) +{ + return 0; +} + +static int mc13783_sw_set_stby_voltage(struct regulator_dev *reg, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1 = 0; + int voltage, sw = rdev_get_id(reg), mV = uV / 1000; + + if ((mV >= 900) && (mV < 925)) + voltage = SW_0_9V; + else if ((mV >= 925) && (mV < 950)) + voltage = SW_0_925V; + else if ((mV >= 950) && (mV < 975)) + voltage = SW_0_95V; + else if ((mV >= 975) && (mV < 1000)) + voltage = SW_0_975V; + else if ((mV >= 1000) && (mV < 1025)) + voltage = SW_1V; + else if ((mV >= 1025) && (mV < 1050)) + voltage = SW_1_025V; + else if ((mV >= 1050) && (mV < 1075)) + voltage = SW_1_05V; + else if ((mV >= 1075) && (mV < 1100)) + voltage = SW_1_075V; + else if ((mV >= 1100) && (mV < 1125)) + voltage = SW_1_1V; + else if ((mV >= 1125) && (mV < 1150)) + voltage = SW_1_125V; + else if ((mV >= 1150) && (mV < 1175)) + voltage = SW_1_15V; + else if ((mV >= 1175) && (mV < 1200)) + voltage = SW_1_175V; + else if ((mV >= 1200) && (mV < 1225)) + voltage = SW_1_2V; + else if ((mV >= 1225) && (mV < 1250)) + voltage = SW_1_225V; + else if ((mV >= 1250) && (mV < 1275)) + voltage = SW_1_25V; + else if ((mV >= 1275) && (mV < 1300)) + voltage = SW_1_275V; + else if ((mV >= 1300) && (mV < 1325)) + voltage = SW_1_3V; + else if ((mV >= 1325) && (mV < 1350)) + voltage = SW_1_325V; + else if ((mV >= 1350) && (mV < 1375)) + voltage = SW_1_35V; + else if ((mV >= 1375) && (mV < 1400)) + voltage = SW_1_375V; + else if ((mV >= 1400) && (mV < 1425)) + voltage = SW_1_4V; + else if ((mV >= 1425) && (mV < 1450)) + voltage = SW_1_425V; + else if ((mV >= 1450) && (mV < 1475)) + voltage = SW_1_45V; + else if ((mV >= 1475) && (mV < 1500)) + voltage = SW_1_475V; + else if ((mV >= 1500) && (mV < 1525)) + voltage = SW_1_5V; + else if ((mV >= 1525) && (mV < 1550)) + voltage = SW_1_525V; + else if ((mV >= 1550) && (mV < 1575)) + voltage = SW_1_55V; + else if ((mV >= 1575) && (mV < 1600)) + voltage = SW_1_575V; + else if ((mV >= 1600) && (mV < 1625)) + voltage = SW_1_6V; + else if ((mV >= 1625) && (mV < 1650)) + voltage = SW_1_625V; + else if ((mV >= 1650) && (mV < 1675)) + voltage = SW_1_65V; + else if ((mV >= 1675) && (mV < 1700)) + voltage = SW_1_675V; + else if ((mV >= 1700) && (mV < 1800)) + voltage = SW_1_7V; + else if ((mV >= 1800) && (mV < 1850)) + voltage = SW_1_8V; + else if ((mV >= 1850) && (mV < 2000)) + voltage = SW_1_85V; + else if ((mV >= 2000) && (mV < 2100)) + voltage = SW_2V; + else if ((mV >= 2100) && (mV < 2200)) + voltage = SW_2_1V; + else + voltage = SW_2_2V; + + switch (sw) { + case MC13783_SW1A: + register1 = REG_SWITCHERS_0; + register_val = BITFVAL(SW1A_STDBY, voltage); + register_mask = BITFMASK(SW1A_STDBY); + break; + case MC13783_SW1B: + register1 = REG_SWITCHERS_1; + register_val = BITFVAL(SW1B_STDBY, voltage); + register_mask = BITFMASK(SW1B_STDBY); + break; + case MC13783_SW2A: + register1 = REG_SWITCHERS_2; + register_val = BITFVAL(SW2A_STDBY, voltage); + register_mask = BITFMASK(SW2A_STDBY); + break; + case MC13783_SW2B: + register1 = REG_SWITCHERS_3; + register_val = BITFVAL(SW2B_STDBY, voltage); + register_mask = BITFMASK(SW2B_STDBY); + break; + default: + return -EINVAL; + } + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13783_sw_set_normal_mode(struct regulator_dev *reg, + unsigned int mode) +{ + unsigned int reg_val = 0, reg_mask = 0; + unsigned int register1 = 0; + unsigned int l_mode; + int sw = rdev_get_id(reg); + + switch (mode) { + case REGULATOR_MODE_FAST: + /* SYNC RECT mode */ + l_mode = SW_MODE_SYNC_RECT_EN; + break; + case REGULATOR_MODE_NORMAL: + /* PULSE SKIP mode */ + l_mode = SW_MODE_PULSE_SKIP_EN; + break; + case REGULATOR_MODE_IDLE: + /* LOW POWER mode */ + l_mode = SW_MODE_LOW_POWER_EN; + break; + case REGULATOR_MODE_STANDBY: + /* NO PULSE SKIP mode */ + l_mode = SW_MODE_PULSE_NO_SKIP_EN; + break; + default: + return -EINVAL; + } + + switch (sw) { + case MC13783_SW1A: + reg_val = BITFVAL(SW1A_MODE, l_mode); + reg_mask = BITFMASK(SW1A_MODE); + register1 = REG_SWITCHERS_4; + break; + case MC13783_SW1B: + reg_val = BITFVAL(SW1B_MODE, l_mode); + reg_mask = BITFMASK(SW1B_MODE); + register1 = REG_SWITCHERS_4; + break; + case MC13783_SW2A: + reg_val = BITFVAL(SW2A_MODE, l_mode); + reg_mask = BITFMASK(SW2A_MODE); + register1 = REG_SWITCHERS_5; + break; + case MC13783_SW2B: + reg_val = BITFVAL(SW2B_MODE, l_mode); + reg_mask = BITFMASK(SW2B_MODE); + register1 = REG_SWITCHERS_5; + break; + default: + return -EINVAL; + } + + return pmic_write_reg(register1, reg_val, reg_mask); +} + +static unsigned int mc13783_sw_get_normal_mode(struct regulator_dev *reg) +{ + unsigned int reg_val = 0, reg_mask = 0; + unsigned int register1 = 0; + unsigned int l_mode = 0; + int sw = rdev_get_id(reg); + int ret = 0; + + switch (sw) { + case MC13783_SW1A: + reg_mask = BITFMASK(SW1A_MODE); + register1 = REG_SWITCHERS_4; + break; + case MC13783_SW1B: + reg_mask = BITFMASK(SW1B_MODE); + register1 = REG_SWITCHERS_4; + break; + case MC13783_SW2A: + reg_mask = BITFMASK(SW2A_MODE); + register1 = REG_SWITCHERS_5; + break; + case MC13783_SW2B: + reg_mask = BITFMASK(SW2B_MODE); + register1 = REG_SWITCHERS_5; + break; + default: + return -EINVAL; + } + + ret = pmic_read_reg(register1, ®_val, reg_mask); + if (ret != 0) + return ret; + + switch (sw) { + case MC13783_SW1A: + l_mode = BITFEXT(reg_val, SW1A_MODE); + break; + case MC13783_SW1B: + l_mode = BITFEXT(reg_val, SW1B_MODE); + break; + case MC13783_SW2A: + l_mode = BITFEXT(reg_val, SW2A_MODE); + break; + case MC13783_SW2B: + l_mode = BITFEXT(reg_val, SW2B_MODE); + break; + default: + return -EINVAL; + } + + if (l_mode == SW_MODE_SYNC_RECT_EN) { + return REGULATOR_MODE_FAST; + } else if (l_mode == SW_MODE_PULSE_NO_SKIP_EN) { + return REGULATOR_MODE_STANDBY; + } else if (l_mode == SW_MODE_PULSE_SKIP_EN) { + return REGULATOR_MODE_NORMAL; + } else if (l_mode == SW_MODE_LOW_POWER_EN) { + return REGULATOR_MODE_IDLE; + } else { + return -EINVAL; + } +} + +static int mc13783_sw_set_stby_mode(struct regulator_dev *reg, + unsigned int mode) +{ + unsigned int reg_val = 0, reg_mask = 0; + unsigned int register1 = 0; + unsigned int l_mode; + int sw = rdev_get_id(reg); + + switch (mode) { + case REGULATOR_MODE_FAST: + /* SYNC RECT mode */ + l_mode = SW_MODE_SYNC_RECT_EN; + break; + case REGULATOR_MODE_NORMAL: + /* PULSE SKIP mode */ + l_mode = SW_MODE_PULSE_SKIP_EN; + break; + case REGULATOR_MODE_IDLE: + /* LOW POWER mode */ + l_mode = SW_MODE_LOW_POWER_EN; + break; + case REGULATOR_MODE_STANDBY: + /* NO PULSE SKIP mode */ + l_mode = SW_MODE_PULSE_NO_SKIP_EN; + break; + default: + return -EINVAL; + } + + switch (sw) { + case MC13783_SW1A: + reg_val = BITFVAL(SW1A_STBY_MODE, l_mode); + reg_mask = BITFMASK(SW1A_STBY_MODE); + register1 = REG_SWITCHERS_4; + break; + case MC13783_SW1B: + reg_val = BITFVAL(SW1B_STBY_MODE, l_mode); + reg_mask = BITFMASK(SW1B_STBY_MODE); + register1 = REG_SWITCHERS_4; + break; + case MC13783_SW2A: + reg_val = BITFVAL(SW2A_STBY_MODE, l_mode); + reg_mask = BITFMASK(SW2A_STBY_MODE); + register1 = REG_SWITCHERS_5; + break; + case MC13783_SW2B: + reg_val = BITFVAL(SW2B_STBY_MODE, l_mode); + reg_mask = BITFMASK(SW2B_STBY_MODE); + register1 = REG_SWITCHERS_5; + break; + default: + return -EINVAL; + } + + return pmic_write_reg(register1, reg_val, reg_mask); +} + +static struct regulator_ops mc13783_vaudio_ops = { + .enable = mc13783_vaudio_enable, + .disable = mc13783_vaudio_disable, +}; + +static struct regulator_ops mc13783_viohi_ops = { + .enable = mc13783_viohi_enable, + .disable = mc13783_viohi_disable, +}; + +static struct regulator_ops mc13783_violo_ops = { + .set_voltage = mc13783_violo_set_voltage, + .get_voltage = mc13783_violo_get_voltage, + .enable = mc13783_violo_enable, + .disable = mc13783_violo_disable, +}; + +static struct regulator_ops mc13783_vdig_ops = { + .set_voltage = mc13783_vdig_set_voltage, + .get_voltage = mc13783_vdig_get_voltage, + .enable = mc13783_vdig_enable, + .disable = mc13783_vdig_disable, +}; + +static struct regulator_ops mc13783_vgen_ops = { + .set_voltage = mc13783_vgen_set_voltage, + .get_voltage = mc13783_vgen_get_voltage, + .enable = mc13783_vgen_enable, + .disable = mc13783_vgen_disable, +}; + +static struct regulator_ops mc13783_vrfdig_ops = { + .set_voltage = mc13783_vrfdig_set_voltage, + .get_voltage = mc13783_vrfdig_get_voltage, + .enable = mc13783_vrfdig_enable, + .disable = mc13783_vrfdig_disable, +}; + +static struct regulator_ops mc13783_vrfref_ops = { + .set_voltage = mc13783_vrfref_set_voltage, + .get_voltage = mc13783_vrfref_get_voltage, + .enable = mc13783_vrfref_enable, + .disable = mc13783_vrfref_disable, +}; + +static struct regulator_ops mc13783_vrfcp_ops = { + .set_voltage = mc13783_vrfcp_set_voltage, + .get_voltage = mc13783_vrfcp_get_voltage, + .enable = mc13783_vrfcp_enable, + .disable = mc13783_vrfcp_disable, +}; + +static struct regulator_ops mc13783_vsim_ops = { + .set_voltage = mc13783_vsim_set_voltage, + .get_voltage = mc13783_vsim_get_voltage, + .enable = mc13783_vsim_enable, + .disable = mc13783_vsim_disable, +}; + +static struct regulator_ops mc13783_vesim_ops = { + .set_voltage = mc13783_vesim_set_voltage, + .get_voltage = mc13783_vesim_get_voltage, + .enable = mc13783_vesim_enable, + .disable = mc13783_vesim_disable, +}; + +static struct regulator_ops mc13783_vcam_ops = { + .set_voltage = mc13783_vcam_set_voltage, + .get_voltage = mc13783_vcam_get_voltage, + .enable = mc13783_vcam_enable, + .disable = mc13783_vcam_disable, +}; + +static struct regulator_ops mc13783_vvib_ops = { + .set_voltage = mc13783_vvib_set_voltage, + .get_voltage = mc13783_vvib_get_voltage, + .enable = mc13783_vvib_enable, + .disable = mc13783_vvib_disable, +}; + +static struct regulator_ops mc13783_vrf_ops = { + .set_voltage = mc13783_vrf_set_voltage, + .get_voltage = mc13783_vrf_get_voltage, + .enable = mc13783_vrf_enable, + .disable = mc13783_vrf_disable, +}; + +static struct regulator_ops mc13783_vmmc_ops = { + .set_voltage = mc13783_vmmc_set_voltage, + .get_voltage = mc13783_vmmc_get_voltage, + .enable = mc13783_vmmc_enable, + .disable = mc13783_vmmc_disable, +}; + +static struct regulator_ops mc13783_gpo_ops = { + .enable = mc13783_gpo_enable, + .disable = mc13783_gpo_disable, +}; + +static struct regulator_ops mc13783_sw3_ops = { + .set_voltage = mc13783_sw3_set_voltage, + .get_voltage = mc13783_sw3_get_voltage, + .enable = mc13783_sw3_enable, + .disable = mc13783_sw3_disable, +}; + +static struct regulator_ops mc13783_sw1_ops = { + .set_voltage = mc13783_sw_set_normal_voltage, + .get_voltage = mc13783_sw_get_normal_voltage, + .get_mode = mc13783_sw_get_normal_mode, + .set_mode = mc13783_sw_set_normal_mode, + .set_suspend_voltage = mc13783_sw_set_stby_voltage, + .set_suspend_enable = mc13783_sw_stby_enable, + .set_suspend_disable = mc13783_sw_stby_disable, + .set_suspend_mode = mc13783_sw_set_stby_mode, +}; + +static struct regulator_ops mc13783_sw_normal_ops = { + .set_voltage = mc13783_sw_set_normal_voltage, + .get_voltage = mc13783_sw_get_normal_voltage, + .get_mode = mc13783_sw_get_normal_mode, + .set_mode = mc13783_sw_set_normal_mode, + .enable = mc13783_sw_normal_enable, + .disable = mc13783_sw_normal_disable, +}; + +static struct regulator_desc reg_mc13783[] = { + { + .name = "SW1A", + .id = MC13783_SW1A, + .ops = &mc13783_sw1_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "SW1B", + .id = MC13783_SW1B, + .ops = &mc13783_sw_normal_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "SW2A", + .id = MC13783_SW2A, + .ops = &mc13783_sw_normal_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "SW2B", + .id = MC13783_SW2B, + .ops = &mc13783_sw_normal_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "SW3", + .id = MC13783_SW3, + .ops = &mc13783_sw3_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VAUDIO", + .id = MC13783_VAUDIO, + .ops = &mc13783_vaudio_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VIOHI", + .id = MC13783_VIOHI, + .ops = &mc13783_viohi_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VIOLO", + .id = MC13783_VIOLO, + .ops = &mc13783_violo_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VDIG", + .id = MC13783_VDIG, + .ops = &mc13783_vdig_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VGEN", + .id = MC13783_VGEN, + .ops = &mc13783_vgen_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VRFDIG", + .id = MC13783_VRFDIG, + .ops = &mc13783_vrfdig_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VRFREF", + .id = MC13783_VRFREF, + .ops = &mc13783_vrfref_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VRFCP", + .id = MC13783_VRFCP, + .ops = &mc13783_vrfcp_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VSIM", + .id = MC13783_VSIM, + .ops = &mc13783_vsim_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VESIM", + .id = MC13783_VESIM, + .ops = &mc13783_vesim_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VCAM", + .id = MC13783_VCAM, + .ops = &mc13783_vcam_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VRFBG", + .id = MC13783_VRFBG, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VVIB", + .id = MC13783_VVIB, + .ops = &mc13783_vvib_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VRF1", + .id = MC13783_VRF1, + .ops = &mc13783_vrf_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VRF2", + .id = MC13783_VRF2, + .ops = &mc13783_vrf_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VMMC1", + .id = MC13783_VMMC1, + .ops = &mc13783_vmmc_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VMMC2", + .id = MC13783_VMMC2, + .ops = &mc13783_vmmc_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "GPO1", + .id = MC13783_GPO1, + .ops = &mc13783_gpo_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "GPO2", + .id = MC13783_GPO2, + .ops = &mc13783_gpo_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "GPO3", + .id = MC13783_GPO3, + .ops = &mc13783_gpo_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "GPO4", + .id = MC13783_GPO4, + .ops = &mc13783_gpo_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, +}; + +/* + * Init and Exit + */ + +static int reg_mc13783_probe(struct platform_device *pdev) +{ + struct regulator_dev *rdev; + + /* register regulator */ + rdev = regulator_register(®_mc13783[pdev->id], &pdev->dev, + pdev->dev.platform_data, + dev_get_drvdata(&pdev->dev)); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s\n", + reg_mc13783[pdev->id].name); + return PTR_ERR(rdev); + } + platform_set_drvdata(pdev, rdev); + + return 0; +} + +static int mc13783_regulator_remove(struct platform_device *pdev) +{ + struct regulator_dev *rdev = platform_get_drvdata(pdev); + + regulator_unregister(rdev); + + return 0; +} + +int mc13783_register_regulator(struct mc13783 *mc13783, int reg, + struct regulator_init_data *initdata) +{ + struct platform_device *pdev; + int ret; + + if (mc13783->pmic.pdev[reg]) + return -EBUSY; + + pdev = platform_device_alloc("mc13783-regulatr", reg); + if (!pdev) + return -ENOMEM; + + mc13783->pmic.pdev[reg] = pdev; + + initdata->driver_data = mc13783; + + pdev->dev.platform_data = initdata; + pdev->dev.parent = mc13783->dev; + ret = platform_device_add(pdev); + + if (ret != 0) { + dev_err(mc13783->dev, "Failed to register regulator %d: %d\n", + reg, ret); + platform_device_del(pdev); + mc13783->pmic.pdev[reg] = NULL; + } + + return ret; +} +EXPORT_SYMBOL_GPL(mc13783_register_regulator); + +static struct platform_driver mc13783_regulator_driver = { + .probe = reg_mc13783_probe, + .remove = mc13783_regulator_remove, + .driver = { + .name = "mc13783-regulatr", + /* o left out due to string length */ + }, +}; + +static int __init mc13783_regulator_subsys_init(void) +{ + return platform_driver_register(&mc13783_regulator_driver); +} +subsys_initcall(mc13783_regulator_subsys_init); + +static void __exit mc13783_regulator_exit(void) +{ + platform_driver_unregister(&mc13783_regulator_driver); +} +module_exit(mc13783_regulator_exit); + + +/* Module information */ +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MC13783 Regulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/reg-mc13892.c b/drivers/regulator/reg-mc13892.c new file mode 100644 index 000000000000..e3c6ab36426d --- /dev/null +++ b/drivers/regulator/reg-mc13892.c @@ -0,0 +1,1956 @@ +/* + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/driver.h> +#include <linux/mfd/mc13892/core.h> +#include <linux/platform_device.h> +#include <linux/pmic_status.h> +#include <linux/pmic_external.h> + +/* + * Convenience conversion. + * Here atm, maybe there is somewhere better for this. + */ +#define mV_to_uV(mV) (mV * 1000) +#define uV_to_mV(uV) (uV / 1000) +#define V_to_uV(V) (mV_to_uV(V * 1000)) +#define uV_to_V(uV) (uV_to_mV(uV) / 1000) + +enum { + VDIG_1_05V = 0, + VDIG_1_25V, + VDIG_1_65V, + VDIG_1_80V, +} regulator_voltage_vdig; + +enum { + VPLL_1_05V = 0, + VPLL_1_25V, + VPLL_1_65V, + VPLL_1_80V, +} regulator_voltage_vpll; + +enum { + VGEN1_1_2V = 0, + VGEN1_1_5V, + VGEN1_2_775V, + VGEN1_3_15V, +} regulator_voltage_vgen1; + +enum { + VGEN2_1_2V = 0, + VGEN2_1_5V, + VGEN2_1_6V, + VGEN2_1_8V, + VGEN2_2_7V, + VGEN2_2_8V, + VGEN2_3_0V, + VGEN2_3_15V, +} regulator_voltage_vgen2; + +enum { + VGEN3_1_8V = 0, + VGEN3_2_9V, +} regulator_voltage_vgen3; + +enum { + VSD_1_8V = 0, + VSD_2_0V, + VSD_2_6V, + VSD_2_7V, + VSD_2_8V, + VSD_2_9V, + VSD_3_0V, + VSD_3_15V, +} regulator_voltage_vsd; + +enum { + VCAM_2_5V, + VCAM_2_6V, + VCAM_2_75V, + VCAM_3_0V, +} regulator_voltage_vcam; + +enum { + VAUDIO_2_3V, + VAUDIO_2_5V, + VAUDIO_2_775V, + VAUDIO_3V, +} regulator_voltage_vaudio; + +enum { + VUSB2_2_4V, + VUSB2_2_6V, + VUSB2_2_7V, + VUSB2_2_775V, +} regulator_voltage_vusb2; + +enum { + VVIDEO_2_7V, + VVIDEO_2_775V, + VVIDEO_2_5V, + VVIDEO_2_6V, +} regulator_voltage_vvideo; + +#define VAUDIO_LSH 4 +#define VAUDIO_WID 2 +#define VAUDIO_EN_LSH 15 +#define VAUDIO_EN_WID 1 +#define VAUDIO_EN_ENABLE 1 +#define VAUDIO_EN_DISABLE 0 + +#define VUSB2_LSH 11 +#define VUSB2_WID 2 +#define VUSB2_EN_LSH 18 +#define VUSB2_EN_WID 1 +#define VUSB2_EN_ENABLE 1 +#define VUSB2_EN_DISABLE 0 + +#define VVIDEO_LSH 2 +#define VVIDEO_WID 2 +#define VVIDEO_EN_LSH 12 +#define VVIDEO_EN_WID 1 +#define VVIDEO_EN_ENABLE 1 +#define VVIDEO_EN_DISABLE 0 + +#define SWBST_EN_LSH 20 +#define SWBST_EN_WID 1 +#define SWBST_EN_ENABLE 1 +#define SWBST_EN_DISABLE 0 + +#define VIOHI_EN_LSH 3 +#define VIOHI_EN_WID 1 +#define VIOHI_EN_ENABLE 1 +#define VIOHI_EN_DISABLE 0 + +#define VDIG_LSH 4 +#define VDIG_WID 2 +#define VDIG_EN_LSH 9 +#define VDIG_EN_WID 1 +#define VDIG_EN_ENABLE 1 +#define VDIG_EN_DISABLE 0 + +#define VPLL_LSH 9 +#define VPLL_WID 2 +#define VPLL_EN_LSH 15 +#define VPLL_EN_WID 1 +#define VPLL_EN_ENABLE 1 +#define VPLL_EN_DISABLE 0 + +#define VGEN1_LSH 0 +#define VGEN1_WID 2 +#define VGEN1_EN_LSH 0 +#define VGEN1_EN_WID 1 +#define VGEN1_EN_ENABLE 1 +#define VGEN1_EN_DISABLE 0 + +#define VGEN2_LSH 6 +#define VGEN2_WID 3 +#define VGEN2_EN_LSH 12 +#define VGEN2_EN_WID 1 +#define VGEN2_EN_ENABLE 1 +#define VGEN2_EN_DISABLE 0 + +#define VGEN3_LSH 14 +#define VGEN3_WID 1 +#define VGEN3_EN_LSH 0 +#define VGEN3_EN_WID 1 +#define VGEN3_EN_ENABLE 1 +#define VGEN3_EN_DISABLE 0 + +#define VSD_LSH 6 +#define VSD_WID 3 +#define VSD_EN_LSH 18 +#define VSD_EN_WID 1 +#define VSD_EN_ENABLE 1 +#define VSD_EN_DISABLE 0 + +#define VCAM_LSH 16 +#define VCAM_WID 2 +#define VCAM_EN_LSH 6 +#define VCAM_EN_WID 1 +#define VCAM_EN_ENABLE 1 +#define VCAM_EN_DISABLE 0 +#define VCAM_CONFIG_LSH 9 +#define VCAM_CONFIG_WID 1 +#define VCAM_CONFIG_EXT 1 +#define VCAM_CONFIG_INT 0 + +#define SW1_LSH 0 +#define SW1_WID 5 +#define SW1_DVS_LSH 5 +#define SW1_DVS_WID 5 +#define SW1_STDBY_LSH 10 +#define SW1_STDBY_WID 5 + +#define SW2_LSH 0 +#define SW2_WID 5 +#define SW2_DVS_LSH 5 +#define SW2_DVS_WID 5 +#define SW2_STDBY_LSH 10 +#define SW2_STDBY_WID 5 + +#define SW3_LSH 0 +#define SW3_WID 5 +#define SW3_STDBY_LSH 10 +#define SW3_STDBY_WID 5 + +#define SW4_LSH 0 +#define SW4_WID 5 +#define SW4_STDBY_LSH 10 +#define SW4_STDBY_WID 5 + +#define VUSB_EN_LSH 3 +#define VUSB_EN_WID 1 +#define VUSB_EN_ENABLE 1 +#define VUSB_EN_DISABLE 0 + +#define GPO1_EN_LSH 6 +#define GPO1_EN_WID 1 +#define GPO1_EN_ENABLE 1 +#define GPO1_EN_DISABLE 0 + +#define GPO2_EN_LSH 8 +#define GPO2_EN_WID 1 +#define GPO2_EN_ENABLE 1 +#define GPO2_EN_DISABLE 0 + +#define GPO3_EN_LSH 10 +#define GPO3_EN_WID 1 +#define GPO3_EN_ENABLE 1 +#define GPO3_EN_DISABLE 0 + +#define GPO4_EN_LSH 12 +#define GPO4_EN_WID 1 +#define GPO4_EN_ENABLE 1 +#define GPO4_EN_DISABLE 0 + +#define GPO4_ADIN_LSH 21 +#define GPO4_ADIN_WID 1 +#define GPO4_ADIN_ENABLE 1 +#define GPO4_ADIN_DISABLE 0 + +#define PWGT1SPI_EN_LSH 15 +#define PWGT1SPI_EN_WID 1 +#define PWGT1SPI_EN_ENABLE 0 +#define PWGT1SPI_EN_DISABLE 1 + +#define PWGT2SPI_EN_LSH 16 +#define PWGT2SPI_EN_WID 1 +#define PWGT2SPI_EN_ENABLE 0 +#define PWGT2SPI_EN_DISABLE 1 + +#define SWXHI_LSH 23 +#define SWXHI_WID 1 +#define SWXHI_ON 1 +#define SWXHI_OFF 0 + +static int mc13892_get_sw_hi_bit(int sw) +{ + unsigned int register_val = 0; + unsigned int reg = 0; + + switch (sw) { + case MC13892_SW1: + reg = REG_SW_0; + break; + case MC13892_SW2: + reg = REG_SW_1; + break; + case MC13892_SW3: + reg = REG_SW_2; + break; + case MC13892_SW4: + reg = REG_SW_3; + break; + default: + return -EINVAL; + } + + CHECK_ERROR(pmic_read_reg(reg, ®ister_val, PMIC_ALL_BITS)); + return (register_val & 0x800000) >> SWXHI_LSH; +} + +static int mc13892_get_voltage_value(int *hi, int mV) +{ + int voltage; + + if (mV < 600) + mV = 600; + if (mV > 1850) + mV = 1850; + + if (mV > 1375) + *hi = 1; + if (mV < 1100) + *hi = 0; + + if (*hi == 0) + voltage = (mV - 600) / 25; + else + voltage = (mV - 1100) / 25; + + return voltage; +} + +static int mc13892_get_voltage_mV(int hi, int voltage) +{ + int mV; + + if (hi == 0) + mV = voltage * 25 + 600; + else + mV = voltage * 25 + 1100; + + return mV; +} + +static int mc13892_sw_set_voltage(struct regulator_dev *reg, int MiniV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1 = 0; + int voltage; + int sw = rdev_get_id(reg); + int mV = uV / 1000; + int hi; + + hi = mc13892_get_sw_hi_bit(sw); + voltage = mc13892_get_voltage_value(&hi, mV); + + switch (sw) { + case MC13892_SW1: + register1 = REG_SW_0; + register_val = BITFVAL(SW1, voltage); + register_mask = BITFMASK(SW1); + break; + case MC13892_SW2: + register1 = REG_SW_1; + register_val = BITFVAL(SW2, voltage); + register_mask = BITFMASK(SW2); + break; + case MC13892_SW3: + register1 = REG_SW_2; + register_val = BITFVAL(SW3, voltage); + register_mask = BITFMASK(SW3); + break; + case MC13892_SW4: + register1 = REG_SW_3; + register_val = BITFVAL(SW4, voltage); + register_mask = BITFMASK(SW4); + break; + default: + return -EINVAL; + } + + register_val |= (hi << SWXHI_LSH); + register_mask |= (1 << SWXHI_LSH); + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_sw_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0; + int mV = 0; + int sw = rdev_get_id(reg); + int hi; + + switch (sw) { + case MC13892_SW1: + CHECK_ERROR(pmic_read_reg(REG_SW_0, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, SW1); + break; + case MC13892_SW2: + CHECK_ERROR(pmic_read_reg(REG_SW_1, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, SW2); + break; + case MC13892_SW3: + CHECK_ERROR(pmic_read_reg(REG_SW_2, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, SW3); + break; + case MC13892_SW4: + CHECK_ERROR(pmic_read_reg(REG_SW_3, + ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, SW4); + break; + default: + return -EINVAL; + } + + hi = mc13892_get_sw_hi_bit(sw); + mV = mc13892_get_voltage_mV(hi, voltage); + + return mV * 1000; +} + +static int mc13892_sw_stby_enable(struct regulator_dev *reg) +{ + return 0; +} + +static int mc13892_sw_stby_disable(struct regulator_dev *reg) +{ + return 0; +} + +static int mc13892_sw_stby_set_mode(struct regulator_dev *reg, unsigned int mode) +{ + return 0; +} + +static int mc13892_sw_stby_set_voltage(struct regulator_dev *reg, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1 = 0; + int voltage, mV = uV / 1000, hi; + int sw = rdev_get_id(reg); + + hi = mc13892_get_sw_hi_bit(sw); + voltage = mc13892_get_voltage_value(&hi, mV); + + switch (sw) { + case MC13892_SW1: + register1 = REG_SW_0; + register_val = BITFVAL(SW1_STDBY, voltage); + register_mask = BITFMASK(SW1_STDBY); + break; + case MC13892_SW2: + register1 = REG_SW_1; + register_val = BITFVAL(SW2_STDBY, voltage); + register_mask = BITFMASK(SW2_STDBY); + break; + case MC13892_SW3: + register1 = REG_SW_2; + register_val = BITFVAL(SW3_STDBY, voltage); + register_mask = BITFMASK(SW3_STDBY); + break; + case MC13892_SW4: + register1 = REG_SW_3; + register_val = BITFVAL(SW4_STDBY, voltage); + register_mask = BITFMASK(SW4_STDBY); + break; + default: + return -EINVAL; + } + + register_val |= (hi << SWXHI_LSH); + register_mask |= (1 << SWXHI_LSH); + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_swbst_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(SWBST_EN, SWBST_EN_ENABLE); + register_mask = BITFMASK(SWBST_EN); + register1 = REG_SW_5; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_swbst_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(SWBST_EN, SWBST_EN_DISABLE); + register_mask = BITFMASK(SWBST_EN); + register1 = REG_SW_5; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_viohi_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VIOHI_EN, VIOHI_EN_ENABLE); + register_mask = BITFMASK(VIOHI_EN); + register1 = REG_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_viohi_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VIOHI_EN, VIOHI_EN_DISABLE); + register_mask = BITFMASK(VIOHI_EN); + register1 = REG_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vusb_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VUSB_EN, VUSB_EN_ENABLE); + register_mask = BITFMASK(VUSB_EN); + register1 = REG_USB1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vusb_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VUSB_EN, VUSB_EN_DISABLE); + register_mask = BITFMASK(VUSB_EN); + register1 = REG_USB1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vdig_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 1050) && (mV < 1250)) + voltage = VDIG_1_05V; + else if ((mV >= 1250) && (mV < 1650)) + voltage = VDIG_1_25V; + else if ((mV >= 1650) && (mV < 1800)) + voltage = VDIG_1_65V; + else + voltage = VDIG_1_80V; + + register_val = BITFVAL(VDIG, voltage); + register_mask = BITFMASK(VDIG); + register1 = REG_SETTING_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vdig_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_SETTING_0, ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VDIG); + + switch (voltage) { + case VDIG_1_05V: + mV = 1050; + break; + case VDIG_1_25V: + mV = 1250; + break; + case VDIG_1_65V: + mV = 1650; + break; + case VDIG_1_80V: + mV = 1800; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13892_vdig_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VDIG_EN, VDIG_EN_ENABLE); + register_mask = BITFMASK(VDIG_EN); + register1 = REG_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vdig_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VDIG_EN, VDIG_EN_DISABLE); + register_mask = BITFMASK(VDIG_EN); + register1 = REG_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vpll_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 1050) && (mV < 1250)) + voltage = VPLL_1_05V; + else if ((mV >= 1250) && (mV < 1650)) + voltage = VPLL_1_25V; + else if ((mV >= 1650) && (mV < 1800)) + voltage = VPLL_1_65V; + else + voltage = VPLL_1_80V; + + register_val = BITFVAL(VPLL, voltage); + register_mask = BITFMASK(VPLL); + register1 = REG_SETTING_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vpll_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_SETTING_0, ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VPLL); + + switch (voltage) { + case VPLL_1_05V: + mV = 1050; + break; + case VPLL_1_25V: + mV = 1250; + break; + case VPLL_1_65V: + mV = 1650; + break; + case VPLL_1_80V: + mV = 1800; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13892_vpll_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VPLL_EN, VPLL_EN_ENABLE); + register_mask = BITFMASK(VPLL_EN); + register1 = REG_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vpll_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VPLL_EN, VPLL_EN_DISABLE); + register_mask = BITFMASK(VPLL_EN); + register1 = REG_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vaudio_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 2300) && (mV < 2500)) + voltage = VAUDIO_2_3V; + else if ((mV >= 2500) && (mV < 2775)) + voltage = VAUDIO_2_5V; + else if ((mV >= 2775) && (mV < 3000)) + voltage = VAUDIO_2_775V; + else + voltage = VAUDIO_3V; + + register_val = BITFVAL(VAUDIO, voltage); + register_mask = BITFMASK(VAUDIO); + register1 = REG_SETTING_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vaudio_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_SETTING_1, ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VAUDIO); + + switch (voltage) { + case VAUDIO_2_3V: + mV = 2300; + break; + case VAUDIO_2_5V: + mV = 2500; + break; + case VAUDIO_2_775V: + mV = 2775; + break; + case VAUDIO_3V: + mV = 3000; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13892_vaudio_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VAUDIO_EN, VAUDIO_EN_ENABLE); + register_mask = BITFMASK(VAUDIO_EN); + register1 = REG_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vaudio_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VAUDIO_EN, VAUDIO_EN_DISABLE); + register_mask = BITFMASK(VAUDIO_EN); + register1 = REG_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vusb2_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 2400) && (mV < 2600)) + voltage = VUSB2_2_4V; + else if ((mV >= 2600) && (mV < 2700)) + voltage = VUSB2_2_6V; + else if ((mV >= 2700) && (mV < 2775)) + voltage = VUSB2_2_7V; + else + voltage = VUSB2_2_775V; + + register_val = BITFVAL(VUSB2, voltage); + register_mask = BITFMASK(VUSB2); + register1 = REG_SETTING_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vusb2_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_SETTING_0, ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VUSB2); + + switch (voltage) { + case VUSB2_2_4V: + mV = 2400; + break; + case VUSB2_2_6V: + mV = 2600; + break; + case VUSB2_2_7V: + mV = 2700; + break; + case VUSB2_2_775V: + mV = 2775; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13892_vusb2_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VUSB2_EN, VUSB2_EN_ENABLE); + register_mask = BITFMASK(VUSB2_EN); + register1 = REG_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vusb2_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VUSB2_EN, VUSB2_EN_DISABLE); + register_mask = BITFMASK(VUSB2_EN); + register1 = REG_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vvideo_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 2500) && (mV < 2600)) + voltage = VVIDEO_2_5V; + else if ((mV >= 2600) && (mV < 2700)) + voltage = VVIDEO_2_6V; + else if ((mV >= 2700) && (mV < 2775)) + voltage = VVIDEO_2_7V; + else + voltage = VVIDEO_2_775V; + + register_val = BITFVAL(VVIDEO, voltage); + register_mask = BITFMASK(VVIDEO); + register1 = REG_SETTING_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vvideo_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_SETTING_1, ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VVIDEO); + + switch (voltage) { + case VVIDEO_2_5V: + mV = 2500; + break; + case VVIDEO_2_6V: + mV = 2600; + break; + case VVIDEO_2_7V: + mV = 2700; + break; + case VVIDEO_2_775V: + mV = 2775; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13892_vvideo_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VVIDEO_EN, VVIDEO_EN_ENABLE); + register_mask = BITFMASK(VVIDEO_EN); + register1 = REG_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vvideo_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VVIDEO_EN, VVIDEO_EN_DISABLE); + register_mask = BITFMASK(VVIDEO_EN); + register1 = REG_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vsd_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 1800) && (mV < 2000)) + voltage = VSD_1_8V; + else if ((mV >= 2000) && (mV < 2600)) + voltage = VSD_2_0V; + else if ((mV >= 2600) && (mV < 2700)) + voltage = VSD_2_6V; + else if ((mV >= 2700) && (mV < 2800)) + voltage = VSD_2_7V; + else if ((mV >= 2800) && (mV < 2900)) + voltage = VSD_2_8V; + else if ((mV >= 2900) && (mV < 3000)) + voltage = VSD_2_9V; + else if ((mV >= 3000) && (mV < 3150)) + voltage = VSD_3_0V; + else + voltage = VSD_3_15V; + + register_val = BITFVAL(VSD, voltage); + register_mask = BITFMASK(VSD); + register1 = REG_SETTING_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vsd_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_SETTING_1, ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VSD); + + switch (voltage) { + case VSD_1_8V: + mV = 1800; + break; + case VSD_2_0V: + mV = 2000; + break; + case VSD_2_6V: + mV = 2600; + break; + case VSD_2_7V: + mV = 2700; + break; + case VSD_2_8V: + mV = 2800; + break; + case VSD_2_9V: + mV = 2900; + break; + case VSD_3_0V: + mV = 3000; + break; + case VSD_3_15V: + mV = 3150; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13892_vsd_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VSD_EN, VSD_EN_ENABLE); + register_mask = BITFMASK(VSD_EN); + register1 = REG_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vsd_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VSD_EN, VSD_EN_DISABLE); + register_mask = BITFMASK(VSD_EN); + register1 = REG_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vcam_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 2500) && (mV < 2600)) + voltage = VCAM_2_5V; + else if ((mV >= 2600) && (mV < 2750)) + voltage = VCAM_2_6V; + else if ((mV >= 2750) && (mV < 3000)) + voltage = VCAM_2_75V; + else + voltage = VCAM_3_0V; + + register_val = BITFVAL(VCAM, voltage); + register_mask = BITFMASK(VCAM); + register1 = REG_SETTING_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vcam_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_SETTING_0, ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VCAM); + + switch (voltage) { + case VCAM_2_5V: + mV = 2500; + break; + case VCAM_2_6V: + mV = 2600; + break; + case VCAM_2_75V: + mV = 2750; + break; + case VCAM_3_0V: + mV = 3000; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13892_vcam_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VCAM_EN, VCAM_EN_ENABLE); + register_mask = BITFMASK(VCAM_EN); + register1 = REG_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vcam_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VCAM_EN, VCAM_EN_DISABLE); + register_mask = BITFMASK(VCAM_EN); + register1 = REG_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vcam_set_mode(struct regulator_dev *reg, unsigned int mode) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + switch (mode) { + case REGULATOR_MODE_FAST: + register_val = BITFVAL(VCAM_CONFIG, VCAM_CONFIG_EXT); + break; + case REGULATOR_MODE_NORMAL: + register_val = BITFVAL(VCAM_CONFIG, VCAM_CONFIG_INT); + break; + default: + return -EINVAL; + } + register_mask = BITFMASK(VCAM_CONFIG); + register1 = REG_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +unsigned int mc13892_vcam_get_mode(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int config = 0, mode = VCAM_CONFIG_INT; + + CHECK_ERROR(pmic_read_reg(REG_MODE_1, ®ister_val, PMIC_ALL_BITS)); + config = BITFEXT(register_val, VCAM_CONFIG); + + switch (config) { + case VCAM_CONFIG_EXT: + mode = REGULATOR_MODE_FAST; + break; + case VCAM_CONFIG_INT: + mode = REGULATOR_MODE_NORMAL; + break; + default: + return -EINVAL; + } + return mode; +} + +static int mc13892_vgen1_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 1200) && (mV < 1500)) + voltage = VGEN1_1_2V; + else if ((mV >= 1500) && (mV < 2775)) + voltage = VGEN1_1_5V; + else if ((mV >= 2775) && (mV < 3150)) + voltage = VGEN1_2_775V; + else + voltage = VGEN1_3_15V; + + register_val = BITFVAL(VGEN1, voltage); + register_mask = BITFMASK(VGEN1); + register1 = REG_SETTING_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vgen1_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_SETTING_0, ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VGEN1); + + switch (voltage) { + case VGEN1_1_2V: + mV = 1200; + break; + case VGEN1_1_5V: + mV = 1500; + break; + case VGEN1_2_775V: + mV = 2775; + break; + case VGEN1_3_15V: + mV = 3150; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13892_vgen1_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VGEN1_EN, VGEN1_EN_ENABLE); + register_mask = BITFMASK(VGEN1_EN); + register1 = REG_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vgen1_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VGEN1_EN, VGEN1_EN_DISABLE); + register_mask = BITFMASK(VGEN1_EN); + register1 = REG_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vgen2_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 1200) && (mV < 1500)) + voltage = VGEN2_1_2V; + else if ((mV >= 1500) && (mV < 1600)) + voltage = VGEN2_1_5V; + else if ((mV >= 1600) && (mV < 1800)) + voltage = VGEN2_1_6V; + else if ((mV >= 1800) && (mV < 2700)) + voltage = VGEN2_1_8V; + else if ((mV >= 2700) && (mV < 2800)) + voltage = VGEN2_2_7V; + else if ((mV >= 2800) && (mV < 3000)) + voltage = VGEN2_2_8V; + else if ((mV >= 3000) && (mV < 3150)) + voltage = VGEN2_3_0V; + else + voltage = VGEN2_3_15V; + + register_val = BITFVAL(VGEN2, voltage); + register_mask = BITFMASK(VGEN2); + register1 = REG_SETTING_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vgen2_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_SETTING_0, ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VGEN2); + + switch (voltage) { + case VGEN2_1_2V: + mV = 1200; + break; + case VGEN2_1_5V: + mV = 1500; + break; + case VGEN2_1_6V: + mV = 1600; + break; + case VGEN2_1_8V: + mV = 1800; + break; + case VGEN2_2_7V: + mV = 2700; + break; + case VGEN2_2_8V: + mV = 2800; + break; + case VGEN2_3_0V: + mV = 3000; + break; + case VGEN2_3_15V: + mV = 3150; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13892_vgen2_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VGEN2_EN, VGEN2_EN_ENABLE); + register_mask = BITFMASK(VGEN2_EN); + register1 = REG_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vgen2_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VGEN2_EN, VGEN2_EN_DISABLE); + register_mask = BITFMASK(VGEN2_EN); + register1 = REG_MODE_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vgen3_set_voltage(struct regulator_dev *reg, + int minuV, int uV) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int voltage, mV = uV / 1000; + + if ((mV >= 1800) && (mV < 2900)) + voltage = VGEN3_1_8V; + else + voltage = VGEN3_2_9V; + + register_val = BITFVAL(VGEN3, voltage); + register_mask = BITFMASK(VGEN3); + register1 = REG_SETTING_0; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vgen3_get_voltage(struct regulator_dev *reg) +{ + unsigned int register_val = 0; + int voltage = 0, mV = 0; + + CHECK_ERROR(pmic_read_reg(REG_SETTING_0, ®ister_val, PMIC_ALL_BITS)); + voltage = BITFEXT(register_val, VGEN3); + + switch (voltage) { + case VGEN3_1_8V: + mV = 1800; + break; + case VGEN3_2_9V: + mV = 2900; + break; + default: + return -EINVAL; + } + + return mV * 1000; +} + +static int mc13892_vgen3_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VGEN3_EN, VGEN3_EN_ENABLE); + register_mask = BITFMASK(VGEN3_EN); + register1 = REG_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_vgen3_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + + register_val = BITFVAL(VGEN3_EN, VGEN3_EN_DISABLE); + register_mask = BITFMASK(VGEN3_EN); + register1 = REG_MODE_1; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_gpo_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int gpo = rdev_get_id(reg); + + switch (gpo) { + case MC13892_GPO1: + register_val = BITFVAL(GPO1_EN, GPO1_EN_ENABLE); + register_mask = BITFMASK(GPO1_EN); + break; + case MC13892_GPO2: + register_val = BITFVAL(GPO2_EN, GPO2_EN_ENABLE); + register_mask = BITFMASK(GPO2_EN); + break; + case MC13892_GPO3: + register_val = BITFVAL(GPO3_EN, GPO3_EN_ENABLE); + register_mask = BITFMASK(GPO3_EN); + break; + case MC13892_GPO4: + register_val = BITFVAL(GPO4_EN, GPO4_EN_ENABLE) + + BITFVAL(GPO4_ADIN, GPO4_ADIN_DISABLE); + register_mask = BITFMASK(GPO4_EN) + BITFMASK(GPO4_ADIN); + break; + default: + return -EINVAL; + }; + + register1 = REG_POWER_MISC; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_gpo_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int gpo = rdev_get_id(reg); + + switch (gpo) { + case MC13892_GPO1: + register_val = BITFVAL(GPO1_EN, GPO1_EN_DISABLE); + register_mask = BITFMASK(GPO1_EN); + break; + case MC13892_GPO2: + register_val = BITFVAL(GPO2_EN, GPO2_EN_DISABLE); + register_mask = BITFMASK(GPO2_EN); + break; + case MC13892_GPO3: + register_val = BITFVAL(GPO3_EN, GPO3_EN_DISABLE); + register_mask = BITFMASK(GPO3_EN); + break; + case MC13892_GPO4: + register_val = BITFVAL(GPO4_EN, GPO4_EN_DISABLE); + register_mask = BITFMASK(GPO4_EN); + break; + default: + return -EINVAL; + }; + + register1 = REG_POWER_MISC; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_power_gating_enable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int gpo = rdev_get_id(reg); + + switch (gpo) { + case MC13892_PWGT1: + register_val = BITFVAL(PWGT1SPI_EN, PWGT1SPI_EN_ENABLE); + register_mask = BITFMASK(PWGT1SPI_EN); + break; + case MC13892_PWGT2: + register_val = BITFVAL(PWGT2SPI_EN, PWGT2SPI_EN_ENABLE); + register_mask = BITFMASK(PWGT2SPI_EN); + break; + default: + return -EINVAL; + }; + + register1 = REG_POWER_MISC; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_power_gating_disable(struct regulator_dev *reg) +{ + unsigned int register_val = 0, register_mask = 0; + unsigned int register1; + int gpo = rdev_get_id(reg); + + switch (gpo) { + case MC13892_PWGT1: + register_val = BITFVAL(PWGT1SPI_EN, PWGT1SPI_EN_DISABLE); + register_mask = BITFMASK(PWGT1SPI_EN); + break; + case MC13892_PWGT2: + register_val = BITFVAL(PWGT2SPI_EN, PWGT2SPI_EN_DISABLE); + register_mask = BITFMASK(PWGT2SPI_EN); + break; + default: + return -EINVAL; + }; + + register1 = REG_POWER_MISC; + + return pmic_write_reg(register1, register_val, register_mask); +} + +static int mc13892_regulator_is_enabled(struct regulator_dev *rdev) +{ + unsigned int register1; + unsigned int register_mask; + int id = rdev_get_id(rdev); + unsigned int register_val = 0; + + switch (id) { + case MC13892_SWBST: + register_mask = BITFMASK(SWBST_EN); + register1 = REG_SW_5; + break; + case MC13892_VIOHI: + register_mask = BITFMASK(VIOHI_EN); + register1 = REG_MODE_0; + break; + case MC13892_VPLL: + register_mask = BITFMASK(VPLL_EN); + register1 = REG_MODE_0; + break; + case MC13892_VDIG: + register_mask = BITFMASK(VDIG_EN); + register1 = REG_MODE_0; + break; + case MC13892_VSD: + register_mask = BITFMASK(VSD_EN); + register1 = REG_MODE_1; + break; + case MC13892_VUSB2: + register_mask = BITFMASK(VUSB2_EN); + register1 = REG_MODE_0; + break; + case MC13892_VVIDEO: + register_mask = BITFMASK(VVIDEO_EN); + register1 = REG_MODE_1; + break; + case MC13892_VAUDIO: + register_mask = BITFMASK(VAUDIO_EN); + register1 = REG_MODE_1; + break; + case MC13892_VCAM: + register_mask = BITFMASK(VCAM_EN); + register1 = REG_MODE_1; + break; + case MC13892_VGEN1: + register_mask = BITFMASK(VGEN1_EN); + register1 = REG_MODE_0; + break; + case MC13892_VGEN2: + register_mask = BITFMASK(VGEN2_EN); + register1 = REG_MODE_0; + break; + case MC13892_VGEN3: + register_mask = BITFMASK(VGEN3_EN); + register1 = REG_MODE_1; + break; + case MC13892_VUSB: + register_mask = BITFMASK(VUSB_EN); + register1 = REG_USB1; + break; + case MC13892_GPO1: + register_mask = BITFMASK(GPO1_EN); + register1 = REG_POWER_MISC; + break; + case MC13892_GPO2: + register_mask = BITFMASK(GPO2_EN); + register1 = REG_POWER_MISC; + break; + case MC13892_GPO3: + register_mask = BITFMASK(GPO3_EN); + register1 = REG_POWER_MISC; + break; + case MC13892_GPO4: + register_mask = BITFMASK(GPO4_EN); + register1 = REG_POWER_MISC; + break; + case MC13892_PWGT1: + register_mask = BITFMASK(PWGT1SPI_EN); + register1 = REG_POWER_MISC; + break; + case MC13892_PWGT2: + register_mask = BITFMASK(PWGT2SPI_EN); + register1 = REG_POWER_MISC; + break; + default: + return 1; + } + CHECK_ERROR(pmic_read_reg(register1, ®ister_val, register_mask)); + return (register_val != 0); +} + +static struct regulator_ops mc13892_sw_ops = { + .enable = mc13892_sw_stby_enable, + .disable = mc13892_sw_stby_disable, + .set_voltage = mc13892_sw_set_voltage, + .get_voltage = mc13892_sw_get_voltage, + .set_suspend_voltage = mc13892_sw_stby_set_voltage, + .set_suspend_enable = mc13892_sw_stby_enable, + .set_suspend_disable = mc13892_sw_stby_disable, + .set_suspend_mode = mc13892_sw_stby_set_mode, +}; + +static struct regulator_ops mc13892_swbst_ops = { + .enable = mc13892_swbst_enable, + .disable = mc13892_swbst_disable, + .is_enabled = mc13892_regulator_is_enabled, +}; + +static struct regulator_ops mc13892_viohi_ops = { + .enable = mc13892_viohi_enable, + .disable = mc13892_viohi_disable, + .is_enabled = mc13892_regulator_is_enabled, +}; + +static struct regulator_ops mc13892_vusb_ops = { + .enable = mc13892_vusb_enable, + .disable = mc13892_vusb_disable, + .is_enabled = mc13892_regulator_is_enabled, +}; + +static struct regulator_ops mc13892_vdig_ops = { + .set_voltage = mc13892_vdig_set_voltage, + .get_voltage = mc13892_vdig_get_voltage, + .enable = mc13892_vdig_enable, + .disable = mc13892_vdig_disable, + .is_enabled = mc13892_regulator_is_enabled, +}; + +static struct regulator_ops mc13892_vpll_ops = { + .set_voltage = mc13892_vpll_set_voltage, + .get_voltage = mc13892_vpll_get_voltage, + .enable = mc13892_vpll_enable, + .disable = mc13892_vpll_disable, + .is_enabled = mc13892_regulator_is_enabled, +}; + +static struct regulator_ops mc13892_vusb2_ops = { + .set_voltage = mc13892_vusb2_set_voltage, + .get_voltage = mc13892_vusb2_get_voltage, + .enable = mc13892_vusb2_enable, + .disable = mc13892_vusb2_disable, + .is_enabled = mc13892_regulator_is_enabled, +}; + +static struct regulator_ops mc13892_vvideo_ops = { + .set_voltage = mc13892_vvideo_set_voltage, + .get_voltage = mc13892_vvideo_get_voltage, + .enable = mc13892_vvideo_enable, + .disable = mc13892_vvideo_disable, + .is_enabled = mc13892_regulator_is_enabled, +}; + +static struct regulator_ops mc13892_vaudio_ops = { + .set_voltage = mc13892_vaudio_set_voltage, + .get_voltage = mc13892_vaudio_get_voltage, + .enable = mc13892_vaudio_enable, + .disable = mc13892_vaudio_disable, + .is_enabled = mc13892_regulator_is_enabled, +}; + +static struct regulator_ops mc13892_vsd_ops = { + .set_voltage = mc13892_vsd_set_voltage, + .get_voltage = mc13892_vsd_get_voltage, + .enable = mc13892_vsd_enable, + .disable = mc13892_vsd_disable, + .is_enabled = mc13892_regulator_is_enabled, +}; + +static struct regulator_ops mc13892_vcam_ops = { + .set_voltage = mc13892_vcam_set_voltage, + .get_voltage = mc13892_vcam_get_voltage, + .enable = mc13892_vcam_enable, + .disable = mc13892_vcam_disable, + .is_enabled = mc13892_regulator_is_enabled, + .set_mode = mc13892_vcam_set_mode, + .get_mode = mc13892_vcam_get_mode, +}; + +static struct regulator_ops mc13892_vgen1_ops = { + .set_voltage = mc13892_vgen1_set_voltage, + .get_voltage = mc13892_vgen1_get_voltage, + .enable = mc13892_vgen1_enable, + .disable = mc13892_vgen1_disable, + .is_enabled = mc13892_regulator_is_enabled, +}; + +static struct regulator_ops mc13892_vgen2_ops = { + .set_voltage = mc13892_vgen2_set_voltage, + .get_voltage = mc13892_vgen2_get_voltage, + .enable = mc13892_vgen2_enable, + .disable = mc13892_vgen2_disable, + .is_enabled = mc13892_regulator_is_enabled, +}; + +static struct regulator_ops mc13892_vgen3_ops = { + .set_voltage = mc13892_vgen3_set_voltage, + .get_voltage = mc13892_vgen3_get_voltage, + .enable = mc13892_vgen3_enable, + .disable = mc13892_vgen3_disable, + .is_enabled = mc13892_regulator_is_enabled, +}; + +static struct regulator_ops mc13892_gpo_ops = { + .enable = mc13892_gpo_enable, + .disable = mc13892_gpo_disable, + .is_enabled = mc13892_regulator_is_enabled, +}; + +static struct regulator_ops mc13892_power_gating_ops = { + .enable = mc13892_power_gating_enable, + .disable = mc13892_power_gating_disable, + .is_enabled = mc13892_regulator_is_enabled, + +}; + +static struct regulator_desc mc13892_reg[] = { + { + .name = "SW1", + .id = MC13892_SW1, + .ops = &mc13892_sw_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "SW2", + .id = MC13892_SW2, + .ops = &mc13892_sw_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "SW3", + .id = MC13892_SW3, + .ops = &mc13892_sw_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "SW4", + .id = MC13892_SW4, + .ops = &mc13892_sw_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "SWBST", + .id = MC13892_SWBST, + .ops = &mc13892_swbst_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VIOHI", + .id = MC13892_VIOHI, + .ops = &mc13892_viohi_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VPLL", + .id = MC13892_VPLL, + .ops = &mc13892_vpll_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VDIG", + .id = MC13892_VDIG, + .ops = &mc13892_vdig_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VSD", + .id = MC13892_VSD, + .ops = &mc13892_vsd_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VUSB2", + .id = MC13892_VUSB2, + .ops = &mc13892_vusb2_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VVIDEO", + .id = MC13892_VVIDEO, + .ops = &mc13892_vvideo_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VAUDIO", + .id = MC13892_VAUDIO, + .ops = &mc13892_vaudio_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VCAM", + .id = MC13892_VCAM, + .ops = &mc13892_vcam_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VGEN1", + .id = MC13892_VGEN1, + .ops = &mc13892_vgen1_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VGEN2", + .id = MC13892_VGEN2, + .ops = &mc13892_vgen2_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VGEN3", + .id = MC13892_VGEN3, + .ops = &mc13892_vgen3_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "VUSB", + .id = MC13892_VUSB, + .ops = &mc13892_vusb_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "GPO1", + .id = MC13892_GPO1, + .ops = &mc13892_gpo_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "GPO2", + .id = MC13892_GPO2, + .ops = &mc13892_gpo_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "GPO3", + .id = MC13892_GPO3, + .ops = &mc13892_gpo_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "GPO4", + .id = MC13892_GPO4, + .ops = &mc13892_gpo_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "PWGT1", + .id = MC13892_PWGT1, + .ops = &mc13892_power_gating_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "PWGT2", + .id = MC13892_PWGT2, + .ops = &mc13892_power_gating_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, +}; + +static int mc13892_regulator_probe(struct platform_device *pdev) +{ + struct regulator_dev *rdev; + + /* register regulator */ + rdev = regulator_register(&mc13892_reg[pdev->id], &pdev->dev, + pdev->dev.platform_data, + dev_get_drvdata(&pdev->dev)); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s\n", + mc13892_reg[pdev->id].name); + return PTR_ERR(rdev); + } + + return 0; +} + + +static int mc13892_regulator_remove(struct platform_device *pdev) +{ + struct regulator_dev *rdev = platform_get_drvdata(pdev); + + regulator_unregister(rdev); + + return 0; +} + +int mc13892_register_regulator(struct mc13892 *mc13892, int reg, + struct regulator_init_data *initdata) +{ + struct platform_device *pdev; + int ret; + + if (mc13892->pmic.pdev[reg]) + return -EBUSY; + + pdev = platform_device_alloc("mc13892-regulatr", reg); + if (!pdev) + return -ENOMEM; + + mc13892->pmic.pdev[reg] = pdev; + + initdata->driver_data = mc13892; + + pdev->dev.platform_data = initdata; + pdev->dev.parent = mc13892->dev; + platform_set_drvdata(pdev, mc13892); + ret = platform_device_add(pdev); + + if (ret != 0) { + dev_err(mc13892->dev, "Failed to register regulator %d: %d\n", + reg, ret); + platform_device_del(pdev); + mc13892->pmic.pdev[reg] = NULL; + } + + return ret; +} +EXPORT_SYMBOL_GPL(mc13892_register_regulator); + +static struct platform_driver mc13892_regulator_driver = { + .probe = mc13892_regulator_probe, + .remove = mc13892_regulator_remove, + .driver = { + .name = "mc13892-regulatr", + }, +}; + +static int __init mc13892_regulator_init(void) +{ + return platform_driver_register(&mc13892_regulator_driver); +} +subsys_initcall(mc13892_regulator_init); + +static void __exit mc13892_regulator_exit(void) +{ + platform_driver_unregister(&mc13892_regulator_driver); +} +module_exit(mc13892_regulator_exit); + + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MC13892 Regulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/reg-mc34704.c b/drivers/regulator/reg-mc34704.c new file mode 100644 index 000000000000..7fb3732b9e03 --- /dev/null +++ b/drivers/regulator/reg-mc34704.c @@ -0,0 +1,289 @@ +/* + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/ioctl.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/driver.h> +#include <linux/mfd/mc34704/core.h> +#include <linux/platform_device.h> +#include <linux/pmic_status.h> +#include <linux/pmic_external.h> + +#define MC34704_ONOFFA 0x8 +#define MC34704_ONOFFC 0x4 +#define MC34704_ONOFFD 0x2 +#define MC34704_ONOFFE 0x1 + +/* Private data for MC34704 regulators */ + +struct reg_mc34704_priv { + short enable; /* enable bit, if available */ + short v_default; /* default regulator voltage in mV */ + int dvs_min; /* minimum voltage change in units of 2.5% */ + int dvs_max; /* maximum voltage change in units of 2.5% */ + char i2c_dvs; /* i2c DVS register number */ + char i2c_stat; /* i2c status register number */ +}; +struct reg_mc34704_priv mc34704_reg_priv[] = { + { + .v_default = REG1_V_MV, + .dvs_min = REG1_DVS_MIN_PCT / 2.5, + .dvs_max = REG1_DVS_MAX_PCT / 2.5, + .i2c_dvs = 0x4, + .i2c_stat = 0x5, + .enable = MC34704_ONOFFA, + }, + { + .v_default = REG2_V_MV, + .dvs_min = REG2_DVS_MIN_PCT / 2.5, + .dvs_max = REG2_DVS_MAX_PCT / 2.5, + .i2c_dvs = 0x6, + .i2c_stat = 0x7, + }, + { + .v_default = REG3_V_MV, + .dvs_min = REG3_DVS_MIN_PCT / 2.5, + .dvs_max = REG3_DVS_MAX_PCT / 2.5, + .i2c_dvs = 0x8, + .i2c_stat = 0x9, + }, + { + .v_default = REG4_V_MV, + .dvs_min = REG4_DVS_MIN_PCT / 2.5, + .dvs_max = REG4_DVS_MAX_PCT / 2.5, + .i2c_dvs = 0xA, + .i2c_stat = 0xB, + }, + { + .v_default = REG5_V_MV, + .dvs_min = REG5_DVS_MIN_PCT / 2.5, + .dvs_max = REG5_DVS_MAX_PCT / 2.5, + .i2c_dvs = 0xC, + .i2c_stat = 0xE, + .enable = MC34704_ONOFFE, + }, +}; + +static int mc34704_set_voltage(struct regulator_dev *reg, int MiniV, int uV) +{ + struct reg_mc34704_priv *priv = rdev_get_drvdata(reg); + int mV = uV / 1000; + int dV = mV - priv->v_default; + + /* compute dynamic voltage scaling value */ + int dvs = 1000 * dV / priv->v_default / 25; + + /* clip to regulator limits */ + if (dvs > priv->dvs_max) + dvs = priv->dvs_max; + if (dvs < priv->dvs_min) + dvs = priv->dvs_min; + + return pmic_write_reg(priv->i2c_dvs, dvs << 1, 0x1E); +} + +static int mc34704_get_voltage(struct regulator_dev *reg) +{ + int mV; + struct reg_mc34704_priv *priv = rdev_get_drvdata(reg); + int val, dvs; + + CHECK_ERROR(pmic_read_reg(priv->i2c_dvs, &val, 0xF)); + + dvs = (val >> 1) & 0xF; + + /* dvs is 4-bit 2's complement; sign-extend it */ + if (dvs & 8) + dvs |= -1 & ~0xF; + + /* Regulator voltage is adjusted by (dvs * 2.5%) */ + mV = priv->v_default * (1000 + 25 * dvs) / 1000; + + return 1000 * mV; +} + +static int mc34704_enable_reg(struct regulator_dev *reg) +{ + struct reg_mc34704_priv *priv = rdev_get_drvdata(reg); + + if (priv->enable) + return pmic_write_reg(REG_MC34704_GENERAL2, -1, priv->enable); + + return PMIC_ERROR; +} + +static int mc34704_disable_reg(struct regulator_dev *reg) +{ + struct reg_mc34704_priv *priv = rdev_get_drvdata(reg); + + if (priv->enable) + return pmic_write_reg(REG_MC34704_GENERAL2, 0, priv->enable); + + return PMIC_ERROR; +} + +static int mc34704_is_reg_enabled(struct regulator_dev *reg) +{ + struct reg_mc34704_priv *priv = rdev_get_drvdata(reg); + int val; + + if (priv->enable) { + CHECK_ERROR(pmic_read_reg(REG_MC34704_GENERAL2, &val, + priv->enable)); + return val ? 1 : 0; + } else { + return PMIC_ERROR; + } +} + +static struct regulator_ops mc34704_full_ops = { + .set_voltage = mc34704_set_voltage, + .get_voltage = mc34704_get_voltage, + .enable = mc34704_enable_reg, + .disable = mc34704_disable_reg, + .is_enabled = mc34704_is_reg_enabled, +}; + +static struct regulator_ops mc34704_partial_ops = { + .set_voltage = mc34704_set_voltage, + .get_voltage = mc34704_get_voltage, +}; + +static struct regulator_desc reg_mc34704[] = { + { + .name = "REG1_BKLT", + .id = MC34704_BKLT, + .ops = &mc34704_full_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE}, + { + .name = "REG2_CPU", + .id = MC34704_CPU, + .ops = &mc34704_partial_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE}, + { + .name = "REG3_CORE", + .id = MC34704_CORE, + .ops = &mc34704_partial_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE}, + { + .name = "REG4_DDR", + .id = MC34704_DDR, + .ops = &mc34704_partial_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE}, + { + .name = "REG5_PERS", + .id = MC34704_PERS, + .ops = &mc34704_full_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE}, +}; + +static int mc34704_regulator_probe(struct platform_device *pdev) +{ + struct regulator_dev *rdev; + + /* register regulator */ + rdev = regulator_register(®_mc34704[pdev->id], &pdev->dev, + pdev->dev.platform_data, + (void *)&mc34704_reg_priv[pdev->id]); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s\n", + reg_mc34704[pdev->id].name); + return PTR_ERR(rdev); + } + + return 0; +} + +static int mc34704_regulator_remove(struct platform_device *pdev) +{ + struct regulator_dev *rdev = platform_get_drvdata(pdev); + + regulator_unregister(rdev); + + return 0; +} + +int mc34704_register_regulator(struct mc34704 *mc34704, int reg, + struct regulator_init_data *initdata) +{ + struct platform_device *pdev; + int ret; + + if (mc34704->pmic.pdev[reg]) + return -EBUSY; + + pdev = platform_device_alloc("mc34704-regulatr", reg); + if (!pdev) + return -ENOMEM; + + mc34704->pmic.pdev[reg] = pdev; + + initdata->driver_data = mc34704; + + pdev->dev.platform_data = initdata; + + pdev->dev.parent = mc34704->dev; + platform_set_drvdata(pdev, mc34704); + ret = platform_device_add(pdev); + + if (ret != 0) { + dev_err(mc34704->dev, "Failed to register regulator %d: %d\n", + reg, ret); + platform_device_del(pdev); + mc34704->pmic.pdev[reg] = NULL; + } + + return ret; +} +EXPORT_SYMBOL_GPL(mc34704_register_regulator); + +static struct platform_driver mc34704_regulator_driver = { + .probe = mc34704_regulator_probe, + .remove = mc34704_regulator_remove, + .driver = { + .name = "mc34704-regulatr", + }, +}; + +static int __init mc34704_regulator_init(void) +{ + return platform_driver_register(&mc34704_regulator_driver); +} +subsys_initcall(mc34704_regulator_init); + +static void __exit mc34704_regulator_exit(void) +{ + platform_driver_unregister(&mc34704_regulator_driver); +} +module_exit(mc34704_regulator_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MC34704 Regulator Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/reg-mc9s08dz60.c b/drivers/regulator/reg-mc9s08dz60.c new file mode 100644 index 000000000000..f2748e99fd80 --- /dev/null +++ b/drivers/regulator/reg-mc9s08dz60.c @@ -0,0 +1,236 @@ +/* + * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/driver.h> +#include <linux/mfd/mc9s08dz60/core.h> +#include <linux/mfd/mc9s08dz60/pmic.h> +#include <linux/platform_device.h> +#include <linux/pmic_status.h> + +/* lcd */ +static int mc9s08dz60_lcd_enable(struct regulator_dev *reg) +{ + return pmic_gpio_set_bit_val(MCU_GPIO_REG_GPIO_CONTROL_1, 6, 1); +} + +static int mc9s08dz60_lcd_disable(struct regulator_dev *reg) +{ + return pmic_gpio_set_bit_val(MCU_GPIO_REG_GPIO_CONTROL_1, 6, 0); +} + +static struct regulator_ops mc9s08dz60_lcd_ops = { + .enable = mc9s08dz60_lcd_enable, + .disable = mc9s08dz60_lcd_disable, +}; + +/* wifi */ +static int mc9s08dz60_wifi_enable(struct regulator_dev *reg) +{ + return pmic_gpio_set_bit_val(MCU_GPIO_REG_GPIO_CONTROL_1, 5, 1); +} + +static int mc9s08dz60_wifi_disable(struct regulator_dev *reg) +{ + return pmic_gpio_set_bit_val(MCU_GPIO_REG_GPIO_CONTROL_1, 5, 0); +} + +static struct regulator_ops mc9s08dz60_wifi_ops = { + .enable = mc9s08dz60_wifi_enable, + .disable = mc9s08dz60_wifi_disable, +}; + +/* hdd */ +static int mc9s08dz60_hdd_enable(struct regulator_dev *reg) +{ + return pmic_gpio_set_bit_val(MCU_GPIO_REG_GPIO_CONTROL_1, 4, 1); +} + +static int mc9s08dz60_hdd_disable(struct regulator_dev *reg) +{ + return pmic_gpio_set_bit_val(MCU_GPIO_REG_GPIO_CONTROL_1, 4, 0); +} + +static struct regulator_ops mc9s08dz60_hdd_ops = { + .enable = mc9s08dz60_hdd_enable, + .disable = mc9s08dz60_hdd_disable, +}; + +/* gps */ +static int mc9s08dz60_gps_enable(struct regulator_dev *reg) +{ + return pmic_gpio_set_bit_val(MCU_GPIO_REG_GPIO_CONTROL_2, 0, 1); +} + +static int mc9s08dz60_gps_disable(struct regulator_dev *reg) +{ + return pmic_gpio_set_bit_val(MCU_GPIO_REG_GPIO_CONTROL_2, 0, 0); +} + +static struct regulator_ops mc9s08dz60_gps_ops = { + .enable = mc9s08dz60_gps_enable, + .disable = mc9s08dz60_gps_disable, +}; + +/* speaker */ +static int mc9s08dz60_speaker_enable(struct regulator_dev *reg) +{ + return pmic_gpio_set_bit_val(MCU_GPIO_REG_GPIO_CONTROL_1, 0, 1); +} + +static int mc9s08dz60_speaker_disable(struct regulator_dev *reg) +{ + return pmic_gpio_set_bit_val(MCU_GPIO_REG_GPIO_CONTROL_1, 0, 0); +} + +static struct regulator_ops mc9s08dz60_speaker_ops = { + .enable = mc9s08dz60_speaker_enable, + .disable = mc9s08dz60_speaker_disable, +}; + +static struct regulator_desc mc9s08dz60_reg[] = { + { + .name = "LCD", + .id = MC9S08DZ60_LCD, + .ops = &mc9s08dz60_lcd_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "WIFI", + .id = MC9S08DZ60_WIFI, + .ops = &mc9s08dz60_wifi_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "HDD", + .id = MC9S08DZ60_HDD, + .ops = &mc9s08dz60_hdd_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "GPS", + .id = MC9S08DZ60_GPS, + .ops = &mc9s08dz60_gps_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + { + .name = "SPKR", + .id = MC9S08DZ60_SPKR, + .ops = &mc9s08dz60_speaker_ops, + .irq = 0, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE + }, + +}; + +static int mc9s08dz60_regulator_probe(struct platform_device *pdev) +{ + struct regulator_dev *rdev; + + /* register regulator */ + rdev = regulator_register(&mc9s08dz60_reg[pdev->id], &pdev->dev, + pdev->dev.platform_data, + dev_get_drvdata(&pdev->dev)); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s\n", + mc9s08dz60_reg[pdev->id].name); + return PTR_ERR(rdev); + } + + return 0; +} + + +static int mc9s08dz60_regulator_remove(struct platform_device *pdev) +{ + struct regulator_dev *rdev = platform_get_drvdata(pdev); + + regulator_unregister(rdev); + + return 0; +} + +int mc9s08dz60_register_regulator(struct mc9s08dz60 *mc9s08dz60, int reg, + struct regulator_init_data *initdata) +{ + struct platform_device *pdev; + int ret; + + if (mc9s08dz60->pmic.pdev[reg]) + return -EBUSY; + + pdev = platform_device_alloc("mc9s08dz60-regu", reg); + if (!pdev) + return -ENOMEM; + + mc9s08dz60->pmic.pdev[reg] = pdev; + + initdata->driver_data = mc9s08dz60; + + pdev->dev.platform_data = initdata; + pdev->dev.parent = mc9s08dz60->dev; + platform_set_drvdata(pdev, mc9s08dz60); + ret = platform_device_add(pdev); + + if (ret != 0) { + dev_err(mc9s08dz60->dev, + "Failed to register regulator %d: %d\n", + reg, ret); + platform_device_del(pdev); + mc9s08dz60->pmic.pdev[reg] = NULL; + } + + return ret; +} +EXPORT_SYMBOL_GPL(mc9s08dz60_register_regulator); + +static struct platform_driver mc9s08dz60_regulator_driver = { + .probe = mc9s08dz60_regulator_probe, + .remove = mc9s08dz60_regulator_remove, + .driver = { + .name = "mc9s08dz60-regu", + }, +}; + +static int __init mc9s08dz60_regulator_init(void) +{ + return platform_driver_register(&mc9s08dz60_regulator_driver); +} +subsys_initcall(mc9s08dz60_regulator_init); + +static void __exit mc9s08dz60_regulator_exit(void) +{ + platform_driver_unregister(&mc9s08dz60_regulator_driver); +} +module_exit(mc9s08dz60_regulator_exit); + + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MC9S08DZ60 Regulator driver"); +MODULE_LICENSE("GPL"); |