diff options
author | Bitan Biswas <bbiswas@nvidia.com> | 2011-12-30 18:10:36 +0530 |
---|---|---|
committer | Varun Wadekar <vwadekar@nvidia.com> | 2012-01-04 11:44:36 +0530 |
commit | 8de2ce3de0a3463516c30a6d6891d6716218e819 (patch) | |
tree | 03d161e5630f07be16caf98b358de789e018e185 /arch | |
parent | d42874773d71b8f71225adba714f6d12ccacd31f (diff) |
arm: tegra: power: io dpd APIs defined
Defined IO deep power down(DPD) APIs for tegra drivers -
tegra_io_dpd_get - returns dpd handle
tegra_io_dpd_enable - enable driver dpd
tegra_io_dpd_disable - disables driver dpd
bug 919993
Change-Id: I45976b41dca0e3e9266ace86393ef4db8b20c97b
Signed-off-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-on: http://git-master/r/72737
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-tegra/include/mach/io_dpd.h | 25 | ||||
-rw-r--r-- | arch/arm/mach-tegra/pm-t2.c | 21 | ||||
-rw-r--r-- | arch/arm/mach-tegra/pm-t3.c | 99 | ||||
-rw-r--r-- | arch/arm/mach-tegra/pm.h | 7 |
4 files changed, 152 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/include/mach/io_dpd.h b/arch/arm/mach-tegra/include/mach/io_dpd.h new file mode 100644 index 000000000000..16385b463d77 --- /dev/null +++ b/arch/arm/mach-tegra/include/mach/io_dpd.h @@ -0,0 +1,25 @@ +/* + * arch/arm/mach-tegra/include/mach/io_dpd.h + * + * Copyright (C) 2012 NVIDIA Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __MACH_TEGRA_IO_DPD_H +#define __MACH_TEGRA_IO_DPD_H + +/* Tegra io dpd APIs */ +struct tegra_io_dpd *tegra_io_dpd_get(struct device *dev); /* get handle */ +void tegra_io_dpd_enable(struct tegra_io_dpd *hnd); /* enable dpd */ +void tegra_io_dpd_disable(struct tegra_io_dpd *hnd); /* disable dpd */ + +#endif /* end __MACH_TEGRA_IO_DPD_H */ diff --git a/arch/arm/mach-tegra/pm-t2.c b/arch/arm/mach-tegra/pm-t2.c index 0fbc433c2773..7ddbb2125595 100644 --- a/arch/arm/mach-tegra/pm-t2.c +++ b/arch/arm/mach-tegra/pm-t2.c @@ -24,10 +24,13 @@ #include <linux/gpio.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/module.h> #include <mach/iomap.h> #include <mach/irqs.h> +#include "pm.h" + #define PMC_SCRATCH3 0x5c #define PMC_SCRATCH5 0x64 #define PMC_SCRATCH6 0x68 @@ -353,3 +356,21 @@ void __init tegra2_lp0_suspend_init(void) } wmb(); } + +struct tegra_io_dpd *tegra_io_dpd_get(struct device *dev) +{ + return NULL; +} +EXPORT_SYMBOL(tegra_io_dpd_get); + +void tegra_io_dpd_enable(struct tegra_io_dpd *hnd) +{ + return; +} +EXPORT_SYMBOL(tegra_io_dpd_enable); + +void tegra_io_dpd_disable(struct tegra_io_dpd *hnd) +{ + return; +} +EXPORT_SYMBOL(tegra_io_dpd_disable); diff --git a/arch/arm/mach-tegra/pm-t3.c b/arch/arm/mach-tegra/pm-t3.c index 6e7bc03cdc34..2de6f8770ba8 100644 --- a/arch/arm/mach-tegra/pm-t3.c +++ b/arch/arm/mach-tegra/pm-t3.c @@ -24,6 +24,8 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/irq.h> +#include <linux/device.h> +#include <linux/module.h> #include <mach/gpio.h> #include <mach/iomap.h> @@ -421,3 +423,100 @@ void tegra_lp0_cpu_mode(bool enter) } } #endif + +#define IO_DPD_INFO(_name, _index, _bit) \ + { \ + .name = _name, \ + .io_dpd_reg_index = _index, \ + .io_dpd_bit = _bit, \ + } + +/* PMC IO DPD register offsets */ +#define APBDEV_PMC_IO_DPD_REQ_0 0x1b8 +#define APBDEV_PMC_IO_DPD_STATUS_0 0x1bc +#define APBDEV_PMC_SEL_DPD_TIM_0 0x1c8 +#define APBDEV_DPD_ENABLE_LSB 30 +#define APBDEV_DPD2_ENABLE_LSB 5 +#define PMC_DPD_SAMPLE 0x20 + +struct tegra_io_dpd tegra_list_io_dpd[] = { + /* sd dpd bits in dpd2 register */ + IO_DPD_INFO("sdhci-tegra.0", 1, 1), /* SDMMC1 */ + IO_DPD_INFO("sdhci-tegra.2", 1, 2), /* SDMMC3 */ + IO_DPD_INFO("sdhci-tegra.3", 1, 3), /* SDMMC4 */ +}; + +struct tegra_io_dpd *tegra_io_dpd_get(struct device *dev) +{ + int i; + const char *name = dev ? dev_name(dev) : NULL; + if (name) { + for (i = 0; i < (sizeof(tegra_list_io_dpd) / + sizeof(struct tegra_io_dpd)); i++) { + if (!(strncmp(tegra_list_io_dpd[i].name, name, + strlen(name)))) { + return &tegra_list_io_dpd[i]; + } + } + } + dev_info(dev, "Error: tegra3 io dpd not supported for %s\n", + ((name) ? name : "NULL")); + return NULL; +} +EXPORT_SYMBOL(tegra_io_dpd_get); + +static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); +static DEFINE_SPINLOCK(tegra_io_dpd_lock); + +void tegra_io_dpd_enable(struct tegra_io_dpd *hnd) +{ + unsigned int enable_mask; + unsigned int dpd_status; + unsigned int dpd_enable_lsb; + + if (WARN_ON(!hnd)) + return; + spin_lock(&tegra_io_dpd_lock); + dpd_enable_lsb = (hnd->io_dpd_reg_index) ? APBDEV_DPD2_ENABLE_LSB : + APBDEV_DPD_ENABLE_LSB; + writel(0x1, pmc + PMC_DPD_SAMPLE); + writel(0x10, pmc + APBDEV_PMC_SEL_DPD_TIM_0); + enable_mask = ((1 << hnd->io_dpd_bit) | (2 << dpd_enable_lsb)); + writel(enable_mask, pmc + (APBDEV_PMC_IO_DPD_REQ_0 + + hnd->io_dpd_reg_index * 8)); + udelay(1); + dpd_status = readl(pmc + (APBDEV_PMC_IO_DPD_STATUS_0 + + hnd->io_dpd_reg_index * 8)); + if (!(dpd_status & (1 << hnd->io_dpd_bit))) + pr_info("Error: dpd%d enable failed, status=%#x\n", + (hnd->io_dpd_reg_index + 1), dpd_status); + /* Sample register must be reset before next sample operation */ + writel(0x0, pmc + PMC_DPD_SAMPLE); + spin_unlock(&tegra_io_dpd_lock); + return; +} +EXPORT_SYMBOL(tegra_io_dpd_enable); + +void tegra_io_dpd_disable(struct tegra_io_dpd *hnd) +{ + unsigned int enable_mask; + unsigned int dpd_status; + unsigned int dpd_enable_lsb; + + if (WARN_ON(!hnd)) + return; + spin_lock(&tegra_io_dpd_lock); + dpd_enable_lsb = (hnd->io_dpd_reg_index) ? APBDEV_DPD2_ENABLE_LSB : + APBDEV_DPD_ENABLE_LSB; + enable_mask = ((1 << hnd->io_dpd_bit) | (1 << dpd_enable_lsb)); + writel(enable_mask, pmc + (APBDEV_PMC_IO_DPD_REQ_0 + + hnd->io_dpd_reg_index * 8)); + dpd_status = readl(pmc + (APBDEV_PMC_IO_DPD_STATUS_0 + + hnd->io_dpd_reg_index * 8)); + if (dpd_status & (1 << hnd->io_dpd_bit)) + pr_info("Error: dpd%d disable failed, status=%#x\n", + (hnd->io_dpd_reg_index + 1), dpd_status); + spin_unlock(&tegra_io_dpd_lock); + return; +} +EXPORT_SYMBOL(tegra_io_dpd_disable); diff --git a/arch/arm/mach-tegra/pm.h b/arch/arm/mach-tegra/pm.h index 4f6eee19af1a..0ad1f24612cc 100644 --- a/arch/arm/mach-tegra/pm.h +++ b/arch/arm/mach-tegra/pm.h @@ -62,6 +62,13 @@ struct tegra_suspend_platform_data { void (*board_resume)(int lp_state, enum resume_stage stg); }; +/* Tegra io dpd entry - for each supported driver */ +struct tegra_io_dpd { + const char *name; /* driver name */ + u8 io_dpd_reg_index; /* io dpd register index */ + u8 io_dpd_bit; /* bit position for driver in dpd register */ +}; + unsigned long tegra_cpu_power_good_time(void); unsigned long tegra_cpu_power_off_time(void); unsigned long tegra_cpu_lp2_min_residency(void); |