diff options
author | Venkat Moganty <vmoganty@nvidia.com> | 2010-02-23 19:43:46 +0530 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-03-01 18:34:09 -0800 |
commit | 5db8fe51ef51627b751fe2c71c6b0a8ab2f49df3 (patch) | |
tree | 2667fc823f116ca9e3e03c4035c308af2a9f165c /drivers | |
parent | f1d2c093ffdcc37a0ade002752644eaada63bef3 (diff) |
tegra regulator: Add regulator driver
Adding regulator driver to set the pmu charging current limit for
drawing the current through the USB charger/USB host.
Bug 631316
Change-Id: I65581af883fd8b86c9ddd2ddf93aac9cc88d3f56
Reviewed-on: http://git-master/r/692
Reviewed-by: John Davis <jodavis@nvidia.com>
Reviewed-by: Gary King <gking@nvidia.com>
Tested-by: Gary King <gking@nvidia.com>
Diffstat (limited to 'drivers')
-rwxr-xr-x[-rw-r--r--] | drivers/regulator/Kconfig | 5 | ||||
-rwxr-xr-x[-rw-r--r--] | drivers/regulator/Makefile | 2 | ||||
-rwxr-xr-x | drivers/regulator/tegra_regulator.c | 170 |
3 files changed, 176 insertions, 1 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index e7e0cf102d6d..76111f44154c 100644..100755 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -80,4 +80,9 @@ config REGULATOR_PCF50633 Say Y here to support the voltage regulators and convertors on PCF50633 +config REGULATOR_TEGRA + boolean "Regulator support on Nvidia Tegra SoCs" + depends on ARCH_TEGRA + help + This enables the regulator interfaces in Nvidia Tegra SoCs. endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 61b30c6ddecc..2ed054853092 100644..100755 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -12,5 +12,5 @@ obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o - +obj-$(CONFIG_REGULATOR_TEGRA) += tegra_regulator.o ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/tegra_regulator.c b/drivers/regulator/tegra_regulator.c new file mode 100755 index 000000000000..179c62b89171 --- /dev/null +++ b/drivers/regulator/tegra_regulator.c @@ -0,0 +1,170 @@ +/* + * tegra-regulator.c + * + * Regulator driver for setting the vbus charging current for NVIDIA Tegra SoCs + * + * Copyright (C) 2010 NVIDIA Corporation + * + * 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/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/err.h> +#include <linux/regulator/machine.h> +#include <linux/mutex.h> +#include "mach/nvrm_linux.h" +#include "nvassert.h" +#include "nvrm_pmu.h" +#include "nvrm_power.h" + +/* + * Tegra regulator data structure. + */ +struct tegra_regulator_data { + struct regulator_init_data vbus_data; /* vbus data for current limit */ + struct regulator_consumer_supply vbus_supply; /* vbus supply info */ + int current_limit_uA; /* current limit in uA */ + struct mutex lock; /* mutex for gaurding current_limit_uA */ + struct work_struct work; /* work thread for setting the current limit */ +}; + +/* + * Work thread function for setting the charging current limit. + * + * This work thread is created to avoid the pre-emption from the ISR context. + * If any driver calls the tegra_regulator_set_current_limit() api this will + * schedule the work thread for setting the current limit. + * NvRmPmuSetChargingCurrentLimit() uses I2C driver, that waits on semaphore + * during the I2C transaction this will cause the pre-emption if called in ISR. + */ +static void tegra_regulator_set_current_limit_work(struct work_struct* work) +{ + struct tegra_regulator_data *reg_data = + container_of(work, struct tegra_regulator_data, work); + + mutex_lock(®_data->lock); + NvRmPmuSetChargingCurrentLimit( + s_hRmGlobal, + NvRmPmuChargingPath_UsbBus, + (reg_data->current_limit_uA/1000), + NvOdmUsbChargerType_SE0); + mutex_unlock(®_data->lock); +} + +/* + * Stores the current limit and starts the work thread for setting the limit + */ +static int tegra_regulator_set_current_limit(struct regulator_dev * rdev, + int min_uA, int max_uA) +{ + struct tegra_regulator_data *reg_data = rdev_get_drvdata(rdev); + + mutex_lock(®_data->lock); + reg_data->current_limit_uA = max_uA; + mutex_unlock(®_data->lock); + schedule_work(®_data->work); + + return 0; +} + +static int tegra_regulator_initialize(void *drv_data) +{ + struct tegra_regulator_data *reg_data = + (struct tegra_regulator_data *)drv_data; + + mutex_init(®_data->lock); + reg_data->current_limit_uA = 0; + INIT_WORK(®_data->work, tegra_regulator_set_current_limit_work); + + return 0; +} + +static struct regulator_ops tegra_regulator_ops = { + .set_current_limit = tegra_regulator_set_current_limit, +}; + +static struct regulator_desc tegra_vbus_regulator = { + .name = "vbus_draw", + .id = 0, + .ops = &tegra_regulator_ops, + .type = REGULATOR_CURRENT, + .owner = THIS_MODULE, +}; + +static int __devinit tegra_regulator_probe(struct platform_device *pdev) +{ + struct regulator_dev *rdev; + struct tegra_regulator_data *reg_data; + + reg_data = kzalloc(sizeof(struct tegra_regulator_data),GFP_KERNEL); + if (!reg_data) + return -ENOMEM; + + reg_data->vbus_supply.dev = &pdev->dev; + reg_data->vbus_supply.supply = "vbus_draw"; + reg_data->vbus_data.constraints.min_uA = 0; + reg_data->vbus_data.constraints.max_uA = 1800000; + reg_data->vbus_data.constraints.valid_ops_mask = REGULATOR_CHANGE_CURRENT; + reg_data->vbus_data.num_consumer_supplies = 1; + reg_data->vbus_data.consumer_supplies = ®_data->vbus_supply; + reg_data->vbus_data.regulator_init = tegra_regulator_initialize; + pdev->dev.platform_data = ®_data->vbus_data; + + rdev = regulator_register(&tegra_vbus_regulator, &pdev->dev, reg_data); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s\n", + tegra_vbus_regulator.name); + return PTR_ERR(rdev); + } + + return 0; +} + +static int __devexit tegra_regulator_remove(struct platform_device *pdev) +{ + struct regulator_dev *rdev = platform_get_drvdata(pdev); + struct tegra_regulator_data *reg_data = rdev_get_drvdata(rdev); + + regulator_unregister(rdev); + kfree(reg_data); + + return 0; +} + +static struct platform_driver tegra_regulator_driver = { + .driver = { + .name = "tegra_regulator", + }, + .probe = tegra_regulator_probe, + .remove = __devexit_p(tegra_regulator_remove), +}; + + +static int __init tegra_regulator_init(void) +{ + return platform_driver_register(&tegra_regulator_driver); +} +module_init(tegra_regulator_init); + +static void __exit tegra_regulator_exit(void) +{ + platform_driver_unregister(&tegra_regulator_driver); +} +module_exit(tegra_regulator_exit); + +MODULE_DESCRIPTION("Tegra regulator driver"); +MODULE_LICENSE("GPL"); |