PowerOP support for OMAP1 platforms.  Currently handles these power
parameters:

   dpllmult     DPLL_CTL reg PLL MULT bits
   dplldiv      DPLL_CTL reg PLL DIV bits
   armdiv       ARM_CKCTL reg ARMDIV bits
   dspdiv       ARM_CKCTL reg DSPDIV bits
   tcdiv        ARM_CKCTL reg TCDIV bits
   lowpwr       1 = assert ULPD LOW_PWR, voltage scale low

Other parameters such as DSPMMUDIV, LCDDIV, and ARM_PERDIV might also be
useful.

Example usage will be shown with a follow-on sysfs UI patch.

Index: linux-2.6.13-rc4/arch/arm/mach-omap1/powerop.c
===================================================================
--- /dev/null
+++ linux-2.6.13-rc4/arch/arm/mach-omap1/powerop.c
@@ -0,0 +1,157 @@
+/*
+ * PowerOP support for OMAP1
+ *
+ * Based on DPM OMAP code by Matthew Locke, Dmitry Chigirev, Vladimir
+ * Barinov, and Todd Poynor.
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <asm/arch/powerop.h>
+#include <asm/hardware.h>
+#include <asm/arch/pm.h>
+
+/* ARM_CKCTL bit shifts */
+#define CKCTL_PERDIV_OFFSET    0
+#define CKCTL_LCDDIV_OFFSET    2
+#define CKCTL_ARMDIV_OFFSET    4
+#define CKCTL_DSPDIV_OFFSET    6
+#define CKCTL_TCDIV_OFFSET     8
+#define CKCTL_DSPMMUDIV_OFFSET 10
+
+#define DPLL_CTL_MASK  0xfe0
+
+#define ULPD_MIN_MAX_REG (1 << 11)
+#define ULPD_DVS_ENABLE  (1 << 10)
+#define ULPD_LOW_PWR_REQ (1 << 1)
+#define LOW_POWER (ULPD_MIN_MAX_REG | ULPD_DVS_ENABLE | ULPD_LOW_PWR_REQ | \
+                  ULPD_LOW_PWR_EN)
+
+int
+powerop_get_point(struct powerop_point *point)
+{
+       unsigned long flags;
+       int dpll_ctl, arm_cktl;
+
+       local_irq_save(flags);
+       dpll_ctl = omap_readw(DPLL_CTL);
+       arm_cktl = omap_readw(ARM_CKCTL);
+
+       point->dpllmult = dpll_ctl >> 7 & 0x1f;
+       point->dplldiv = dpll_ctl >> 5 & 0x3;
+       point->armdiv = arm_cktl >> CKCTL_ARMDIV_OFFSET & 0x3;
+       point->dspdiv = arm_cktl >> CKCTL_DSPDIV_OFFSET & 0x3;
+       point->tcdiv = arm_cktl >> CKCTL_TCDIV_OFFSET & 0x3;
+       point->lowpwr = (omap_readw(ULPD_POWER_CTRL) & (ULPD_LOW_PWR_REQ)) ?
+               1 : 0;
+       local_irq_restore(flags);
+       return 0;
+}
+
+static void scale_dpll(int dpll_ctl)
+{
+       int i;
+
+       omap_writew((omap_readw(DPLL_CTL) & ~DPLL_CTL_MASK) | dpll_ctl,
+                   DPLL_CTL);
+
+       for (i = 0; i < 0x1FF; i++)
+               nop();
+
+       /*
+        * Wait for PLL relock.
+        */
+
+       while ((omap_readw(DPLL_CTL) & 0x1) == 0);
+}
+
+static void set_low_pwr(int lowpwr)
+{
+       int cur_lowpwr;
+
+       if (lowpwr == -1)
+               return;
+
+       cur_lowpwr = (omap_readw(ULPD_POWER_CTRL) & (ULPD_LOW_PWR_REQ)) ?
+               1 : 0;
+
+       if (cur_lowpwr != lowpwr) {
+               if (lowpwr)
+                       omap_writew(omap_readw(ULPD_POWER_CTRL) | LOW_POWER,
+                                   ULPD_POWER_CTRL);
+               else
+                       omap_writew(omap_readw(ULPD_POWER_CTRL) & ~LOW_POWER,
+                                   ULPD_POWER_CTRL);
+       }
+}
+
+int
+powerop_set_point(struct powerop_point *point)
+{
+       int dpll_ctl = 0;
+       int dpll_mod = 0;
+       int arm_ctl = 0;
+       int arm_msk = 0;
+       int cur_dpll_ctl;
+       unsigned long flags;
+
+       if ((point->dpllmult != -1) && (point->dplldiv != -1)) {
+               dpll_ctl = (point->dpllmult << 7) |
+                       (point->dplldiv << 5);
+               dpll_mod = 1;
+       }
+
+       if (point->armdiv != -1) {
+               arm_ctl |= (point->armdiv << CKCTL_ARMDIV_OFFSET);
+               arm_msk |= (3 << CKCTL_ARMDIV_OFFSET);
+       }
+
+       if (point->dspdiv != -1) {
+               arm_ctl |= (point->dspdiv << CKCTL_DSPDIV_OFFSET);
+               arm_msk |= (3 << CKCTL_DSPDIV_OFFSET);
+       }
+
+       if (point->tcdiv != -1) {
+               arm_ctl |= (point->tcdiv << CKCTL_TCDIV_OFFSET);
+               arm_msk |= (3 << CKCTL_TCDIV_OFFSET);
+       }
+
+       local_irq_save(flags);
+       cur_dpll_ctl = omap_readw(DPLL_CTL) & DPLL_CTL_MASK;
+
+       if (dpll_mod && (dpll_ctl < cur_dpll_ctl))
+               scale_dpll(dpll_ctl);
+
+       if (arm_msk != 0)
+               omap_writew((omap_readw(ARM_CKCTL) & ~arm_msk) | arm_ctl,
+                           ARM_CKCTL);
+
+       if (dpll_mod && (dpll_ctl > cur_dpll_ctl))
+               scale_dpll(dpll_ctl);
+
+       set_low_pwr(point->lowpwr);
+       local_irq_restore(flags);
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(powerop_get_point);
+EXPORT_SYMBOL_GPL(powerop_set_point);
+
+static int __init powerop_init(void)
+{
+       return 0;
+}
+
+static void __exit powerop_exit(void)
+{
+}
+
+module_init(powerop_init);
+module_exit(powerop_exit);
Index: linux-2.6.13-rc4/include/asm-arm/arch-omap/powerop.h
===================================================================
--- /dev/null
+++ linux-2.6.13-rc4/include/asm-arm/arch-omap/powerop.h
@@ -0,0 +1,27 @@
+/*
+ * PowerOP support for OMAP1
+ *
+ * Based on DPM OMAP code by Matthew Locke, Dmitry Chigirev, Vladimir
+ * Barinov, and Todd Poynor.
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef __ASM_ARCH_OMAP_POWEROP_H
+#define __ASM_ARCH_OMAP_POWEROP_H
+
+/* -1 for any following fields indicates no change from current op */
+
+struct powerop_point {
+        int lowpwr;    /* 1 = assert ULPD DVS LOW_PWR */
+       int dpllmult;   /* DPLL_CTL PLL MULT 0..31 */
+       int dplldiv;    /* DPLL_CTL PLL DIV 0..3 */
+       int armdiv;     /* ARM_CKCTL ARMDIV 0..3 */
+       int dspdiv;     /* ARM_CKCTL DSPDIV 0..3 */
+       int tcdiv;      /* ARM_CKCTL TCDIV 0..3 */
+};
+
+#endif /* __ASM_ARCH_OMAP_POWEROP_H */
Index: linux-2.6.13-rc4/arch/arm/mach-omap1/Kconfig
===================================================================
--- linux-2.6.13-rc4.orig/arch/arm/mach-omap1/Kconfig
+++ linux-2.6.13-rc4/arch/arm/mach-omap1/Kconfig
@@ -152,3 +152,6 @@ config OMAP_ARM_30MHZ
 
 source "arch/arm/plat-omap/dsp/Kconfig"
 
+config POWEROP
+       bool "PowerOP Platform Core Power Management for OMAP1"
+       help
Index: linux-2.6.13-rc4/arch/arm/mach-omap1/Makefile
===================================================================
--- linux-2.6.13-rc4.orig/arch/arm/mach-omap1/Makefile
+++ linux-2.6.13-rc4/arch/arm/mach-omap1/Makefile
@@ -29,3 +29,4 @@ led-$(CONFIG_MACH_OMAP_PERSEUS2)      += leds
 led-$(CONFIG_MACH_OMAP_OSK)            += leds-osk.o
 obj-$(CONFIG_LEDS)                     += $(led-y)
 
+obj-$(CONFIG_POWEROP)                  += powerop.o
Index: linux-2.6.13-rc4/include/asm-arm/powerop.h
===================================================================
--- /dev/null
+++ linux-2.6.13-rc4/include/asm-arm/powerop.h
@@ -0,0 +1,18 @@
+/*
+ * PowerOP support for ARM
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef __ASM_POWEROP_H
+#define __ASM_POWEROP_H
+
+#include <asm/arch/powerop.h>
+
+extern int powerop_get_point(struct powerop_point *point);
+extern int powerop_set_point(struct powerop_point *point);
+
+#endif /* __ASM_POWEROP_H */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to