arm: tegra: power: io dpd APIs defined
Bitan Biswas [Fri, 30 Dec 2011 12:40:36 +0000 (17:40 +0530)]
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>

Rebase-Id: R6b3beef3f41d164a7b00fa90af44d8729acba05b

arch/arm/mach-tegra/include/mach/io_dpd.h [new file with mode: 0644]
arch/arm/mach-tegra/pm-t2.c
arch/arm/mach-tegra/pm-t3.c
arch/arm/mach-tegra/pm.h

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 (file)
index 0000000..16385b4
--- /dev/null
@@ -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 */
index 426199f..e81cd9d 100644 (file)
 #include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/module.h>
 
 #include <mach/irqs.h>
 
 #include "iomap.h"
+#include "pm.h"
 
 #define PMC_SCRATCH3   0x5c
 #define PMC_SCRATCH5   0x64
@@ -354,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);
index dacf0cb..b3ff9e4 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/cpu_pm.h>
 #include <linux/delay.h>
 #include <linux/irq.h>
+#include <linux/device.h>
+#include <linux/module.h>
 
 #include <mach/gpio.h>
 #include <mach/irqs.h>
@@ -422,3 +424,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);
index 7af9607..1356f92 100644 (file)
@@ -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);