diff options
author | Philippe Langlais <philippe.langlais@linaro.org> | 2011-07-06 14:03:21 +0200 |
---|---|---|
committer | Robert Marklund <robert.marklund@stericsson.com> | 2011-10-05 12:17:05 +0200 |
commit | e0403806afe9a03e0f3585820507234a72871bfc (patch) | |
tree | fe71d9c047c4a3117a6f0252753449de1e946ff3 | |
parent | fda2ad8cf563d623c8b987e3aab2d048d7a42c09 (diff) |
mach-ux500: move U5500 PRCMU regulator driver into regulator drivers and cleanup for 3.0
Signed-off-by: Philippe Langlais <philippe.langlais@linaro.org>
-rw-r--r-- | arch/arm/mach-ux500/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-ux500/Makefile | 6 | ||||
-rw-r--r-- | arch/arm/mach-ux500/board-u5500-regulators.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-ux500/include/mach/regulator.h | 74 | ||||
-rw-r--r-- | arch/arm/mach-ux500/regulator-u5500.c | 84 | ||||
-rw-r--r-- | arch/arm/mach-ux500/regulator-u5500.h | 20 | ||||
-rw-r--r-- | arch/arm/mach-ux500/regulator-ux500.c | 409 | ||||
-rw-r--r-- | drivers/regulator/Kconfig | 12 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 2 | ||||
-rw-r--r-- | drivers/regulator/db5500-prcmu.c | 344 | ||||
-rw-r--r-- | drivers/regulator/db8500-prcmu.c | 42 | ||||
-rw-r--r-- | drivers/regulator/dbx500-prcmu.c | 154 | ||||
-rw-r--r-- | include/linux/regulator/db5500-prcmu.h | 27 | ||||
-rw-r--r-- | include/linux/regulator/db8500-prcmu.h | 8 | ||||
-rw-r--r-- | include/linux/regulator/dbx500-prcmu.h | 96 |
15 files changed, 640 insertions, 641 deletions
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index 7dafc08e9ac..06254c7b14a 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -17,6 +17,7 @@ menu "Ux500 SoC" config UX500_SOC_DB5500 bool "DB5500" select MFD_DB5500_PRCMU + select REGULATOR_DB5500_PRCMU select UX500_SOC_DBX500 config UX500_SOC_DB8500 diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile index 05e491a5ad9..9fb6cca49f4 100644 --- a/arch/arm/mach-ux500/Makefile +++ b/arch/arm/mach-ux500/Makefile @@ -38,12 +38,6 @@ obj-$(CONFIG_TEE_SVP) += tee_ta_start_modem_svp.o obj-$(CONFIG_DB8500_MLOADER) += mloader-db8500.o obj-$(CONFIG_U5500_MLOADER) += mloader-db5500.o obj-$(CONFIG_UX500_PRCMU_TIMER) += timer-prcmu.o -obj-$(CONFIG_REGULATOR) += regulator-ux500.o - -ifeq ($(CONFIG_UX500_SOC_DB5500), y) -obj-$(CONFIG_REGULATOR) += regulator-u5500.o -endif - obj-$(CONFIG_U8500_REGULATOR_DEBUG) += virt-regulator-u8500.o obj-$(CONFIG_UX500_PRCMU_DEBUG) += prcmu-debug.o obj-$(CONFIG_UX500_PRCMU_QOS_POWER) += prcmu-qos-power.o diff --git a/arch/arm/mach-ux500/board-u5500-regulators.c b/arch/arm/mach-ux500/board-u5500-regulators.c index dd28f2f0ffa..b345a72038b 100644 --- a/arch/arm/mach-ux500/board-u5500-regulators.c +++ b/arch/arm/mach-ux500/board-u5500-regulators.c @@ -9,8 +9,8 @@ #include <linux/platform_device.h> #include <linux/regulator/machine.h> #include <linux/regulator/ab5500.h> +#include <linux/regulator/db5500-prcmu.h> -#include "regulator-u5500.h" #include "board-u5500.h" /* diff --git a/arch/arm/mach-ux500/include/mach/regulator.h b/arch/arm/mach-ux500/include/mach/regulator.h index 75ff3340359..cacb6bf5277 100644 --- a/arch/arm/mach-ux500/include/mach/regulator.h +++ b/arch/arm/mach-ux500/include/mach/regulator.h @@ -11,78 +11,6 @@ #ifndef MACH_UX500_REGULATOR_H #define MACH_UX500_REGULATOR_H -#include <linux/device.h> - -struct ux500_regulator; - -#ifdef CONFIG_REGULATOR -/* - * NOTE! The device will be connected to the correct regulator by this - * new framework. A list with connections will match up dev_name(dev) - * to the specific regulator. This follows the same principle as the - * normal regulator framework. - * - * This framework shall only be used in special cases when a regulator - * has to be enabled/disabled in atomic context. - */ - -/** - * ux500_regulator_get() - * - * @dev: Drivers device struct - * - * Returns a ux500_regulator struct. Shall be used as argument for - * ux500_regulator_atomic_enable/disable calls. - * Return ERR_PTR(-EINVAL) upon no matching regulator found. - */ -struct ux500_regulator *__must_check ux500_regulator_get(struct device *dev); - -/** - * ux500_regulator_atomic_enable() - * - * @regulator: Regulator handle, provided from ux500_regulator_get. - * - * The enable/disable functions keep an internal counter, so every - * enable must be paired with an disable in order to turn off regulator. - */ -int ux500_regulator_atomic_enable(struct ux500_regulator *regulator); - -/** - * ux500_regulator_atomic_disable() - * - * @regulator: Regulator handle, provided from ux500_regulator_get. - * - */ -int ux500_regulator_atomic_disable(struct ux500_regulator *regulator); - -/** - * ux500_regulator_put() - * - * @regulator: Regulator handle, provided from ux500_regulator_get. - */ -void ux500_regulator_put(struct ux500_regulator *regulator); -#else -static inline struct ux500_regulator *__must_check -ux500_regulator_get(struct device *dev) -{ - return ERR_PTR(-EINVAL); -} - -static inline int -ux500_regulator_atomic_enable(struct ux500_regulator *regulator) -{ - return -EINVAL; -} - -static inline int -ux500_regulator_atomic_disable(struct ux500_regulator *regulator) -{ - return -EINVAL; -} - -static inline void ux500_regulator_put(struct ux500_regulator *regulator) -{ -} -#endif +#include <linux/regulator/dbx500-prcmu.h> #endif diff --git a/arch/arm/mach-ux500/regulator-u5500.c b/arch/arm/mach-ux500/regulator-u5500.c deleted file mode 100644 index 4aca065d6e8..00000000000 --- a/arch/arm/mach-ux500/regulator-u5500.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2011 - * - * License Terms: GNU General Public License v2 - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/regulator/driver.h> -#include <linux/regulator/machine.h> - -#include <mach/prcmu.h> - -#include "regulator-ux500.h" -#include "regulator-u5500.h" - -#define U5500_REGULATOR_SWITCH(_name, reg) \ - [U5500_REGULATOR_SWITCH_##reg] = { \ - .desc = { \ - .name = _name, \ - .id = U5500_REGULATOR_SWITCH_##reg, \ - .ops = &ux500_regulator_switch_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - }, \ - .epod_id = DB5500_EPOD_ID_##reg, \ -} - -static struct u8500_regulator_info -u5500_regulator_info[U5500_NUM_REGULATORS] = { - [U5500_REGULATOR_VAPE] = { - .desc = { - .name = "u5500-vape", - .id = U5500_REGULATOR_VAPE, - .ops = &ux500_regulator_ops, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, - }, - }, - U5500_REGULATOR_SWITCH("u5500-sga", SGA), - U5500_REGULATOR_SWITCH("u5500-hva", HVA), - U5500_REGULATOR_SWITCH("u5500-sia", SIA), - U5500_REGULATOR_SWITCH("u5500-disp", DISP), - U5500_REGULATOR_SWITCH("u5500-esram12", ESRAM12), -}; - -static int __devinit u5500_regulator_probe(struct platform_device *pdev) -{ - return ux500_regulator_probe(pdev, u5500_regulator_info, - ARRAY_SIZE(u5500_regulator_info)); -} - -static int __devexit u5500_regulator_remove(struct platform_device *pdev) -{ - return ux500_regulator_remove(pdev, u5500_regulator_info, - ARRAY_SIZE(u5500_regulator_info)); -} - -static struct platform_driver u5500_regulator_driver = { - .driver = { - .name = "u5500-regulators", - .owner = THIS_MODULE, - }, - .probe = u5500_regulator_probe, - .remove = __devexit_p(u5500_regulator_remove), -}; - -static int __init u5500_regulator_init(void) -{ - return platform_driver_register(&u5500_regulator_driver); -} - -static void __exit u5500_regulator_exit(void) -{ - platform_driver_unregister(&u5500_regulator_driver); -} - -arch_initcall(u5500_regulator_init); -module_exit(u5500_regulator_exit); - -MODULE_DESCRIPTION("U5500 regulator driver"); -MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-ux500/regulator-u5500.h b/arch/arm/mach-ux500/regulator-u5500.h deleted file mode 100644 index cf3eeed9366..00000000000 --- a/arch/arm/mach-ux500/regulator-u5500.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2011 - * - * License Terms: GNU General Public License v2 - */ - -#ifndef __REGULATOR_U5500_H -#define __REGULATOR_U5500_H - -enum u5500_regulator_id { - U5500_REGULATOR_VAPE, - U5500_REGULATOR_SWITCH_SGA, - U5500_REGULATOR_SWITCH_HVA, - U5500_REGULATOR_SWITCH_SIA, - U5500_REGULATOR_SWITCH_DISP, - U5500_REGULATOR_SWITCH_ESRAM12, - U5500_NUM_REGULATORS -}; - -#endif diff --git a/arch/arm/mach-ux500/regulator-ux500.c b/arch/arm/mach-ux500/regulator-ux500.c deleted file mode 100644 index c76ea008ba0..00000000000 --- a/arch/arm/mach-ux500/regulator-ux500.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010 - * - * License Terms: GNU General Public License v2 - * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson - * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson - * - * Power domain regulators on UX500 - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/err.h> -#include <linux/spinlock.h> -#include <linux/platform_device.h> -#include <linux/regulator/driver.h> -#include <linux/regulator/machine.h> - -#include "regulator-ux500.h" - -#include <mach/prcmu.h> - -/* - * power state reference count - */ -static int power_state_active_cnt; /* will initialize to zero */ -static DEFINE_SPINLOCK(power_state_active_lock); - -static void power_state_active_enable(void) -{ - unsigned long flags; - - spin_lock_irqsave(&power_state_active_lock, flags); - power_state_active_cnt++; - spin_unlock_irqrestore(&power_state_active_lock, flags); -} - -static int power_state_active_disable(void) -{ - int ret = 0; - unsigned long flags; - - spin_lock_irqsave(&power_state_active_lock, flags); - if (power_state_active_cnt <= 0) { - pr_err("power state: unbalanced enable/disable calls\n"); - ret = -EINVAL; - goto out; - } - - power_state_active_cnt--; -out: - spin_unlock_irqrestore(&power_state_active_lock, flags); - return ret; -} - -/* FIXME: double definitions if U8500+U5500 enabled */ -#ifdef CONFIG_UX500_SOC_DB5500 -/* - * Exported interface for CPUIdle only. This function is called when interrupts - * are turned off. Hence, no locking. - */ -int power_state_active_is_enabled(void) -{ - return (power_state_active_cnt > 0); -} -#endif - -struct ux500_regulator { - char *name; - void (*enable)(void); - int (*disable)(void); -}; - -/* - * Don't add any clients to this struct without checking with regulator - * responsible! - */ -static struct ux500_regulator ux500_atomic_regulators[] = { - { - .name = "dma40.0", - .enable = power_state_active_enable, - .disable = power_state_active_disable, - }, - { - .name = "ssp0", - .enable = power_state_active_enable, - .disable = power_state_active_disable, - }, - { - .name = "ssp1", - .enable = power_state_active_enable, - .disable = power_state_active_disable, - }, - { - .name = "spi0", - .enable = power_state_active_enable, - .disable = power_state_active_disable, - }, - { - .name = "spi1", - .enable = power_state_active_enable, - .disable = power_state_active_disable, - }, - { - .name = "spi2", - .enable = power_state_active_enable, - .disable = power_state_active_disable, - }, - { - .name = "spi3", - .enable = power_state_active_enable, - .disable = power_state_active_disable, - }, - { - .name = "cryp1", - .enable = power_state_active_enable, - .disable = power_state_active_disable, - }, - { - .name = "hash1", - .enable = power_state_active_enable, - .disable = power_state_active_disable, - }, -}; - -struct ux500_regulator *__must_check ux500_regulator_get(struct device *dev) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ux500_atomic_regulators); i++) { - if (!strcmp(dev_name(dev), ux500_atomic_regulators[i].name)) - return &ux500_atomic_regulators[i]; - } - - return ERR_PTR(-EINVAL); -} -EXPORT_SYMBOL_GPL(ux500_regulator_get); - -int ux500_regulator_atomic_enable(struct ux500_regulator *regulator) -{ - if (regulator) { - regulator->enable(); - return 0; - } - return -EINVAL; -} -EXPORT_SYMBOL_GPL(ux500_regulator_atomic_enable); - -int ux500_regulator_atomic_disable(struct ux500_regulator *regulator) -{ - if (regulator) - return regulator->disable(); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(ux500_regulator_atomic_disable); - -void ux500_regulator_put(struct ux500_regulator *regulator) -{ - /* Here for symetric reasons and for possible future use */ -} -EXPORT_SYMBOL_GPL(ux500_regulator_put); - -#ifdef CONFIG_UX500_SOC_DB5500 -static int u8500_regulator_enable(struct regulator_dev *rdev) -{ - struct u8500_regulator_info *info = rdev_get_drvdata(rdev); - - if (info == NULL) - return -EINVAL; - - dev_vdbg(rdev_get_dev(rdev), "regulator-%s-enable\n", - info->desc.name); - - info->is_enabled = true; - if (!info->exclude_from_power_state) - power_state_active_enable(); - - return 0; -} - -static int u8500_regulator_disable(struct regulator_dev *rdev) -{ - struct u8500_regulator_info *info = rdev_get_drvdata(rdev); - int ret = 0; - - if (info == NULL) - return -EINVAL; - - dev_vdbg(rdev_get_dev(rdev), "regulator-%s-disable\n", - info->desc.name); - - info->is_enabled = false; - if (!info->exclude_from_power_state) - ret = power_state_active_disable(); - - return ret; -} - -static int u8500_regulator_is_enabled(struct regulator_dev *rdev) -{ - struct u8500_regulator_info *info = rdev_get_drvdata(rdev); - - if (info == NULL) - return -EINVAL; - - dev_vdbg(rdev_get_dev(rdev), "regulator-%s-is_enabled (is_enabled):" - " %i\n", info->desc.name, info->is_enabled); - - return info->is_enabled; -} - -/* u8500 regulator operations */ -struct regulator_ops ux500_regulator_ops = { - .enable = u8500_regulator_enable, - .disable = u8500_regulator_disable, - .is_enabled = u8500_regulator_is_enabled, -}; - -/* - * EPOD control - */ -static bool epod_on[NUM_EPOD_ID]; -static bool epod_ramret[NUM_EPOD_ID]; - -static int enable_epod(u16 epod_id, bool ramret) -{ - int ret; - - if (ramret) { - if (!epod_on[epod_id]) { - ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET); - if (ret < 0) - return ret; - } - epod_ramret[epod_id] = true; - } else { - ret = prcmu_set_epod(epod_id, EPOD_STATE_ON); - if (ret < 0) - return ret; - epod_on[epod_id] = true; - } - - return 0; -} - -static int disable_epod(u16 epod_id, bool ramret) -{ - int ret; - - if (ramret) { - if (!epod_on[epod_id]) { - ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF); - if (ret < 0) - return ret; - } - epod_ramret[epod_id] = false; - } else { - if (epod_ramret[epod_id]) { - ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET); - if (ret < 0) - return ret; - } else { - ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF); - if (ret < 0) - return ret; - } - epod_on[epod_id] = false; - } - - return 0; -} - -/* - * Regulator switch - */ -static int u8500_regulator_switch_enable(struct regulator_dev *rdev) -{ - struct u8500_regulator_info *info = rdev_get_drvdata(rdev); - int ret; - - if (info == NULL) - return -EINVAL; - - dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-enable\n", - info->desc.name); - - ret = enable_epod(info->epod_id, info->is_ramret); - if (ret < 0) { - dev_err(rdev_get_dev(rdev), - "regulator-switch-%s-enable: prcmu call failed\n", - info->desc.name); - goto out; - } - - info->is_enabled = true; -out: - return ret; -} - -static int u8500_regulator_switch_disable(struct regulator_dev *rdev) -{ - struct u8500_regulator_info *info = rdev_get_drvdata(rdev); - int ret; - - if (info == NULL) - return -EINVAL; - - dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-disable\n", - info->desc.name); - - ret = disable_epod(info->epod_id, info->is_ramret); - if (ret < 0) { - dev_err(rdev_get_dev(rdev), - "regulator_switch-%s-disable: prcmu call failed\n", - info->desc.name); - goto out; - } - - info->is_enabled = 0; -out: - return ret; -} - -static int u8500_regulator_switch_is_enabled(struct regulator_dev *rdev) -{ - struct u8500_regulator_info *info = rdev_get_drvdata(rdev); - - if (info == NULL) - return -EINVAL; - - dev_vdbg(rdev_get_dev(rdev), - "regulator-switch-%s-is_enabled (is_enabled): %i\n", - info->desc.name, info->is_enabled); - - return info->is_enabled; -} - -struct regulator_ops ux500_regulator_switch_ops = { - .enable = u8500_regulator_switch_enable, - .disable = u8500_regulator_switch_disable, - .is_enabled = u8500_regulator_switch_is_enabled, -}; - -int __devinit -ux500_regulator_probe(struct platform_device *pdev, - struct u8500_regulator_info *regulator_info, - int num_regulators) -{ - struct regulator_init_data *u8500_init_data = - dev_get_platdata(&pdev->dev); - int i, err; - - /* register all regulators */ - for (i = 0; i < num_regulators; i++) { - struct u8500_regulator_info *info; - struct regulator_init_data *init_data = &u8500_init_data[i]; - - /* assign per-regulator data */ - info = ®ulator_info[i]; - info->dev = &pdev->dev; - - /* register with the regulator framework */ - info->rdev = regulator_register(&info->desc, &pdev->dev, - init_data, info); - if (IS_ERR(info->rdev)) { - err = PTR_ERR(info->rdev); - dev_err(&pdev->dev, "failed to register %s: err %i\n", - info->desc.name, err); - - /* if failing, unregister all earlier regulators */ - i--; - while (i >= 0) { - info = ®ulator_info[i]; - regulator_unregister(info->rdev); - i--; - } - return err; - } - - dev_vdbg(rdev_get_dev(info->rdev), - "regulator-%s-probed\n", info->desc.name); - } - - return 0; -} - -int __devexit -ux500_regulator_remove(struct platform_device *pdev, - struct u8500_regulator_info *regulator_info, - int num_regulators) -{ - int i; - - for (i = 0; i < num_regulators; i++) { - struct u8500_regulator_info *info; - - info = ®ulator_info[i]; - - dev_vdbg(rdev_get_dev(info->rdev), - "regulator-%s-remove\n", info->desc.name); - - regulator_unregister(info->rdev); - } - - return 0; -} - -#endif diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 193cb09bbab..ec1cee88683 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -281,9 +281,21 @@ config REGULATOR_AB8500 This driver supports the regulators found on the ST-Ericsson mixed signal AB8500 PMIC +config REGULATOR_DBX500_PRCMU + bool + +config REGULATOR_DB5500_PRCMU + bool "ST-Ericsson DB5500 Voltage Domain Regulators" + depends on MFD_DB5500_PRCMU + select REGULATOR_DBX500_PRCMU + help + This driver supports the voltage domain regulators controlled by the + DB5500 PRCMU + config REGULATOR_DB8500_PRCMU bool "ST-Ericsson DB8500 Voltage Domain Regulators" depends on MFD_DB8500_PRCMU + select REGULATOR_DBX500_PRCMU help This driver supports the voltage domain regulators controlled by the DB8500 PRCMU diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index e3f9e83e316..aff7d7b213e 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -42,6 +42,8 @@ obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o obj-$(CONFIG_REGULATOR_AB5500) += ab5500.o obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o +obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o +obj-$(CONFIG_REGULATOR_DB5500_PRCMU) += db5500-prcmu.o obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o obj-$(CONFIG_REGULATOR_AB8500_DEBUG) += ab8500-debug.o diff --git a/drivers/regulator/db5500-prcmu.c b/drivers/regulator/db5500-prcmu.c new file mode 100644 index 00000000000..a6884ca8942 --- /dev/null +++ b/drivers/regulator/db5500-prcmu.c @@ -0,0 +1,344 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License Terms: GNU General Public License v2 + * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson + * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson + * + * Power domain regulators on DB5500 + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/db5500-prcmu.h> + +#include <mach/prcmu.h> + +/** + * struct db5500_regulator_info - db5500 regulator information + * @dev: device pointer + * @desc: regulator description + * @rdev: regulator device pointer + * @is_enabled: status of the regulator + * @epod_id: id for EPOD (power domain) + * @is_ramret: RAM retention switch for EPOD (power domain) + * @operating_point: operating point (only for vape, to be removed) + * + */ +struct db5500_regulator_info { + struct device *dev; + struct regulator_desc desc; + struct regulator_dev *rdev; + bool is_enabled; + u16 epod_id; + bool is_ramret; + bool exclude_from_power_state; + unsigned int operating_point; +}; + +static int db5500_regulator_enable(struct regulator_dev *rdev) +{ + struct db5500_regulator_info *info = rdev_get_drvdata(rdev); + + if (info == NULL) + return -EINVAL; + + dev_vdbg(rdev_get_dev(rdev), "regulator-%s-enable\n", + info->desc.name); + + info->is_enabled = true; + if (!info->exclude_from_power_state) + power_state_active_enable(); + + return 0; +} + +static int db5500_regulator_disable(struct regulator_dev *rdev) +{ + struct db5500_regulator_info *info = rdev_get_drvdata(rdev); + int ret = 0; + + if (info == NULL) + return -EINVAL; + + dev_vdbg(rdev_get_dev(rdev), "regulator-%s-disable\n", + info->desc.name); + + info->is_enabled = false; + if (!info->exclude_from_power_state) + ret = power_state_active_disable(); + + return ret; +} + +static int db5500_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct db5500_regulator_info *info = rdev_get_drvdata(rdev); + + if (info == NULL) + return -EINVAL; + + dev_vdbg(rdev_get_dev(rdev), "regulator-%s-is_enabled (is_enabled):" + " %i\n", info->desc.name, info->is_enabled); + + return info->is_enabled; +} + +/* db5500 regulator operations */ +static struct regulator_ops db5500_regulator_ops = { + .enable = db5500_regulator_enable, + .disable = db5500_regulator_disable, + .is_enabled = db5500_regulator_is_enabled, +}; + +/* + * EPOD control + */ +static bool epod_on[NUM_EPOD_ID]; +static bool epod_ramret[NUM_EPOD_ID]; + +static int enable_epod(u16 epod_id, bool ramret) +{ + int ret; + + if (ramret) { + if (!epod_on[epod_id]) { + ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET); + if (ret < 0) + return ret; + } + epod_ramret[epod_id] = true; + } else { + ret = prcmu_set_epod(epod_id, EPOD_STATE_ON); + if (ret < 0) + return ret; + epod_on[epod_id] = true; + } + + return 0; +} + +static int disable_epod(u16 epod_id, bool ramret) +{ + int ret; + + if (ramret) { + if (!epod_on[epod_id]) { + ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF); + if (ret < 0) + return ret; + } + epod_ramret[epod_id] = false; + } else { + if (epod_ramret[epod_id]) { + ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET); + if (ret < 0) + return ret; + } else { + ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF); + if (ret < 0) + return ret; + } + epod_on[epod_id] = false; + } + + return 0; +} + +/* + * Regulator switch + */ +static int db5500_regulator_switch_enable(struct regulator_dev *rdev) +{ + struct db5500_regulator_info *info = rdev_get_drvdata(rdev); + int ret; + + if (info == NULL) + return -EINVAL; + + dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-enable\n", + info->desc.name); + + ret = enable_epod(info->epod_id, info->is_ramret); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), + "regulator-switch-%s-enable: prcmu call failed\n", + info->desc.name); + goto out; + } + + info->is_enabled = true; +out: + return ret; +} + +static int db5500_regulator_switch_disable(struct regulator_dev *rdev) +{ + struct db5500_regulator_info *info = rdev_get_drvdata(rdev); + int ret; + + if (info == NULL) + return -EINVAL; + + dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-disable\n", + info->desc.name); + + ret = disable_epod(info->epod_id, info->is_ramret); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), + "regulator_switch-%s-disable: prcmu call failed\n", + info->desc.name); + goto out; + } + + info->is_enabled = 0; +out: + return ret; +} + +static int db5500_regulator_switch_is_enabled(struct regulator_dev *rdev) +{ + struct db5500_regulator_info *info = rdev_get_drvdata(rdev); + + if (info == NULL) + return -EINVAL; + + dev_vdbg(rdev_get_dev(rdev), + "regulator-switch-%s-is_enabled (is_enabled): %i\n", + info->desc.name, info->is_enabled); + + return info->is_enabled; +} + +static struct regulator_ops db5500_regulator_switch_ops = { + .enable = db5500_regulator_switch_enable, + .disable = db5500_regulator_switch_disable, + .is_enabled = db5500_regulator_switch_is_enabled, +}; + +/* + * Regulator information + */ +#define U5500_REGULATOR_SWITCH(_name, reg) \ + [U5500_REGULATOR_SWITCH_##reg] = { \ + .desc = { \ + .name = _name, \ + .id = U5500_REGULATOR_SWITCH_##reg, \ + .ops = &db5500_regulator_switch_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + }, \ + .epod_id = DB5500_EPOD_ID_##reg, \ +} + +static struct db5500_regulator_info + db5500_regulator_info[U5500_NUM_REGULATORS] = { + [U5500_REGULATOR_VAPE] = { + .desc = { + .name = "db5500-vape", + .id = U5500_REGULATOR_VAPE, + .ops = &db5500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + }, + U5500_REGULATOR_SWITCH("u5500-sga", SGA), + U5500_REGULATOR_SWITCH("u5500-hva", HVA), + U5500_REGULATOR_SWITCH("u5500-sia", SIA), + U5500_REGULATOR_SWITCH("u5500-disp", DISP), + U5500_REGULATOR_SWITCH("u5500-esram12", ESRAM12), +}; + +static int __devinit db5500_regulator_probe(struct platform_device *pdev) +{ + struct regulator_init_data *db5500_init_data = + dev_get_platdata(&pdev->dev); + int i, err; + + /* register all regulators */ + for (i = 0; i < ARRAY_SIZE(db5500_regulator_info); i++) { + struct db5500_regulator_info *info; + struct regulator_init_data *init_data = &db5500_init_data[i]; + + /* assign per-regulator data */ + info = &db5500_regulator_info[i]; + info->dev = &pdev->dev; + + /* register with the regulator framework */ + info->rdev = regulator_register(&info->desc, &pdev->dev, + init_data, info); + if (IS_ERR(info->rdev)) { + err = PTR_ERR(info->rdev); + dev_err(&pdev->dev, "failed to register %s: err %i\n", + info->desc.name, err); + + /* if failing, unregister all earlier regulators */ + i--; + while (i >= 0) { + info = &db5500_regulator_info[i]; + regulator_unregister(info->rdev); + i--; + } + return err; + } + + dev_dbg(rdev_get_dev(info->rdev), + "regulator-%s-probed\n", info->desc.name); + } + + return 0; +} + +static int __exit db5500_regulator_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(db5500_regulator_info); i++) { + struct db5500_regulator_info *info; + info = &db5500_regulator_info[i]; + + dev_vdbg(rdev_get_dev(info->rdev), + "regulator-%s-remove\n", info->desc.name); + + regulator_unregister(info->rdev); + } + + return 0; +} + +static struct platform_driver db5500_regulator_driver = { + .driver = { + .name = "db5500-prcmu-regulators", + .owner = THIS_MODULE, + }, + .probe = db5500_regulator_probe, + .remove = __exit_p(db5500_regulator_remove), +}; + +static int __init db5500_regulator_init(void) +{ + int ret; + + ret = platform_driver_register(&db5500_regulator_driver); + if (ret < 0) + return -ENODEV; + + return 0; +} + +static void __exit db5500_regulator_exit(void) +{ + platform_driver_unregister(&db5500_regulator_driver); +} + +arch_initcall(db5500_regulator_init); +module_exit(db5500_regulator_exit); + +MODULE_AUTHOR("STMicroelectronics/ST-Ericsson"); +MODULE_DESCRIPTION("DB5500 regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c index cc8fcc96b0a..99cd20514e2 100644 --- a/drivers/regulator/db8500-prcmu.c +++ b/drivers/regulator/db8500-prcmu.c @@ -19,48 +19,6 @@ #include <mach/prcmu.h> -/* - * power state reference count - */ -static int power_state_active_cnt; /* will initialize to zero */ -static DEFINE_SPINLOCK(power_state_active_lock); - -static void power_state_active_enable(void) -{ - unsigned long flags; - - spin_lock_irqsave(&power_state_active_lock, flags); - power_state_active_cnt++; - spin_unlock_irqrestore(&power_state_active_lock, flags); -} - -static int power_state_active_disable(void) -{ - int ret = 0; - unsigned long flags; - - spin_lock_irqsave(&power_state_active_lock, flags); - if (power_state_active_cnt <= 0) { - pr_err("power state: unbalanced enable/disable calls\n"); - ret = -EINVAL; - goto out; - } - - power_state_active_cnt--; -out: - spin_unlock_irqrestore(&power_state_active_lock, flags); - return ret; -} - -/* - * Exported interface for CPUIdle only. This function is called when interrupts - * are turned off. Hence, no locking. - */ -int power_state_active_is_enabled(void) -{ - return (power_state_active_cnt > 0); -} - /** * struct db8500_regulator_info - db8500 regulator information * @dev: device pointer diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c new file mode 100644 index 00000000000..3df5fcd454a --- /dev/null +++ b/drivers/regulator/dbx500-prcmu.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson + * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson + * + * UX500 common part of Power domain regulators (atomic regulators) + */ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/regulator/driver.h> + +/* + * power state reference count + */ +static int power_state_active_cnt; /* will initialize to zero */ +static DEFINE_SPINLOCK(power_state_active_lock); + +void power_state_active_enable(void) +{ + unsigned long flags; + + spin_lock_irqsave(&power_state_active_lock, flags); + power_state_active_cnt++; + spin_unlock_irqrestore(&power_state_active_lock, flags); +} +EXPORT_SYMBOL_GPL(power_state_active_enable); + +int power_state_active_disable(void) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&power_state_active_lock, flags); + if (power_state_active_cnt <= 0) { + pr_err("power state: unbalanced enable/disable calls\n"); + ret = -EINVAL; + goto out; + } + + power_state_active_cnt--; +out: + spin_unlock_irqrestore(&power_state_active_lock, flags); + return ret; +} +EXPORT_SYMBOL_GPL(power_state_active_disable); + +/* + * Exported interface for CPUIdle only. This function is called when interrupts + * are turned off. Hence, no locking. + */ +int power_state_active_is_enabled(void) +{ + return (power_state_active_cnt > 0); +} +EXPORT_SYMBOL_GPL(power_state_active_is_enabled); + +struct ux500_regulator { + char *name; + void (*enable)(void); + int (*disable)(void); +}; + +/* + * Don't add any clients to this struct without checking with regulator + * responsible! + */ +static struct ux500_regulator ux500_atomic_regulators[] = { + { + .name = "dma40.0", + .enable = power_state_active_enable, + .disable = power_state_active_disable, + }, + { + .name = "ssp0", + .enable = power_state_active_enable, + .disable = power_state_active_disable, + }, + { + .name = "ssp1", + .enable = power_state_active_enable, + .disable = power_state_active_disable, + }, + { + .name = "spi0", + .enable = power_state_active_enable, + .disable = power_state_active_disable, + }, + { + .name = "spi1", + .enable = power_state_active_enable, + .disable = power_state_active_disable, + }, + { + .name = "spi2", + .enable = power_state_active_enable, + .disable = power_state_active_disable, + }, + { + .name = "spi3", + .enable = power_state_active_enable, + .disable = power_state_active_disable, + }, + { + .name = "cryp1", + .enable = power_state_active_enable, + .disable = power_state_active_disable, + }, + { + .name = "hash1", + .enable = power_state_active_enable, + .disable = power_state_active_disable, + }, +}; + +struct ux500_regulator *__must_check ux500_regulator_get(struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ux500_atomic_regulators); i++) { + if (!strcmp(dev_name(dev), ux500_atomic_regulators[i].name)) + return &ux500_atomic_regulators[i]; + } + + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL_GPL(ux500_regulator_get); + +int ux500_regulator_atomic_enable(struct ux500_regulator *regulator) +{ + if (regulator) { + regulator->enable(); + return 0; + } + return -EINVAL; +} +EXPORT_SYMBOL_GPL(ux500_regulator_atomic_enable); + +int ux500_regulator_atomic_disable(struct ux500_regulator *regulator) +{ + if (regulator) + return regulator->disable(); + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(ux500_regulator_atomic_disable); + +void ux500_regulator_put(struct ux500_regulator *regulator) +{ + /* Here for symetric reasons and for possible future use */ +} +EXPORT_SYMBOL_GPL(ux500_regulator_put); diff --git a/include/linux/regulator/db5500-prcmu.h b/include/linux/regulator/db5500-prcmu.h new file mode 100644 index 00000000000..52950287c09 --- /dev/null +++ b/include/linux/regulator/db5500-prcmu.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * + * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson + * + * Interface to power domain regulators on DB5500 + */ + +#ifndef __DB5500_REGULATOR_H__ +#define __DB5500_REGULATOR_H__ + +#include <linux/regulator/dbx500-prcmu.h> + +/* Number of DB5500 regulators and regulator enumeration */ +enum db5500_regulator_id { + U5500_REGULATOR_VAPE, + U5500_REGULATOR_SWITCH_SGA, + U5500_REGULATOR_SWITCH_HVA, + U5500_REGULATOR_SWITCH_SIA, + U5500_REGULATOR_SWITCH_DISP, + U5500_REGULATOR_SWITCH_ESRAM12, + U5500_NUM_REGULATORS +}; + +#endif diff --git a/include/linux/regulator/db8500-prcmu.h b/include/linux/regulator/db8500-prcmu.h index 612062313b6..a3138ea2177 100644 --- a/include/linux/regulator/db8500-prcmu.h +++ b/include/linux/regulator/db8500-prcmu.h @@ -11,6 +11,8 @@ #ifndef __REGULATOR_H__ #define __REGULATOR_H__ +#include <linux/regulator/dbx500-prcmu.h> + /* Number of DB8500 regulators and regulator enumeration */ enum db8500_regulator_id { DB8500_REGULATOR_VAPE, @@ -36,10 +38,4 @@ enum db8500_regulator_id { DB8500_NUM_REGULATORS }; -/* - * Exported interface for CPUIdle only. This function is called with all - * interrupts turned off. - */ -int power_state_active_is_enabled(void); - #endif diff --git a/include/linux/regulator/dbx500-prcmu.h b/include/linux/regulator/dbx500-prcmu.h new file mode 100644 index 00000000000..a18cf6c4107 --- /dev/null +++ b/include/linux/regulator/dbx500-prcmu.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Bengt Jonsson <bengt.jonsson@stericsson.com> for ST-Ericsson, + * Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson + * + * License Terms: GNU General Public License v2 + * + */ + +#ifndef DBX500_REGULATOR_H +#define DBX500_REGULATOR_H + +#include <linux/device.h> + +struct ux500_regulator; + +#ifdef CONFIG_REGULATOR +/* + * NOTE! The device will be connected to the correct regulator by this + * new framework. A list with connections will match up dev_name(dev) + * to the specific regulator. This follows the same principle as the + * normal regulator framework. + * + * This framework shall only be used in special cases when a regulator + * has to be enabled/disabled in atomic context. + */ + +void power_state_active_enable(void); +int power_state_active_disable(void); +/* + * Exported interface for CPUIdle only. This function is called with all + * interrupts turned off. + */ +int power_state_active_is_enabled(void); + +/** + * ux500_regulator_get() + * + * @dev: Drivers device struct + * + * Returns a ux500_regulator struct. Shall be used as argument for + * ux500_regulator_atomic_enable/disable calls. + * Return ERR_PTR(-EINVAL) upon no matching regulator found. + */ +struct ux500_regulator *__must_check ux500_regulator_get(struct device *dev); + +/** + * ux500_regulator_atomic_enable() + * + * @regulator: Regulator handle, provided from ux500_regulator_get. + * + * The enable/disable functions keep an internal counter, so every + * enable must be paired with an disable in order to turn off regulator. + */ +int ux500_regulator_atomic_enable(struct ux500_regulator *regulator); + +/** + * ux500_regulator_atomic_disable() + * + * @regulator: Regulator handle, provided from ux500_regulator_get. + * + */ +int ux500_regulator_atomic_disable(struct ux500_regulator *regulator); + +/** + * ux500_regulator_put() + * + * @regulator: Regulator handle, provided from ux500_regulator_get. + */ +void ux500_regulator_put(struct ux500_regulator *regulator); +#else +static inline struct ux500_regulator *__must_check +ux500_regulator_get(struct device *dev) +{ + return ERR_PTR(-EINVAL); +} + +static inline int +ux500_regulator_atomic_enable(struct ux500_regulator *regulator) +{ + return -EINVAL; +} + +static inline int +ux500_regulator_atomic_disable(struct ux500_regulator *regulator) +{ + return -EINVAL; +} + +static inline void ux500_regulator_put(struct ux500_regulator *regulator) +{ +} +#endif + +#endif |