summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorBitan Biswas <bbiswas@nvidia.com>2011-12-30 18:10:36 +0530
committerVarun Wadekar <vwadekar@nvidia.com>2012-01-04 11:44:36 +0530
commit8de2ce3de0a3463516c30a6d6891d6716218e819 (patch)
tree03d161e5630f07be16caf98b358de789e018e185 /arch
parentd42874773d71b8f71225adba714f6d12ccacd31f (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.h25
-rw-r--r--arch/arm/mach-tegra/pm-t2.c21
-rw-r--r--arch/arm/mach-tegra/pm-t3.c99
-rw-r--r--arch/arm/mach-tegra/pm.h7
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);