Hi all,

Core voltage chaning patch attached and waiting for comments.

As for now there is no voltage changing done during suspend, because of
http://www.handhelds.org/hypermail/hx4700-port/19/1907.html . There are
no replies for that problem. I'll wait a little more here and will ask in
arm-linux mailing list.

Thanks,

-- Anton (irc: bd2)

Index: arch/arm/mach-pxa/hx4700/Kconfig
===================================================================
RCS file: /cvs/linux/kernel26/arch/arm/mach-pxa/hx4700/Kconfig,v
retrieving revision 1.22
diff -u -p -b -B -r1.22 Kconfig
--- arch/arm/mach-pxa/hx4700/Kconfig    28 Mar 2006 19:12:12 -0000      1.22
+++ arch/arm/mach-pxa/hx4700/Kconfig    4 Jun 2006 21:31:26 -0000
@@ -55,3 +55,10 @@ config HX4700_LEDS
          This enables support for HP iPAQ hx4700 color LED control
           (via the ASIC3 chip).
 
+config HX4700_VOLTAGE
+       tristate "HP iPAQ hx4700 core voltage changing"
+       depends on MACH_H4700 && CPU_FREQ_PXA
+       help
+         This enables support for core voltage changing coupled with
+         freqency change.
+
Index: arch/arm/mach-pxa/hx4700/Makefile
===================================================================
RCS file: /cvs/linux/kernel26/arch/arm/mach-pxa/hx4700/Makefile,v
retrieving revision 1.14
diff -u -p -b -B -r1.14 Makefile
--- arch/arm/mach-pxa/hx4700/Makefile   28 Mar 2006 19:12:12 -0000      1.14
+++ arch/arm/mach-pxa/hx4700/Makefile   4 Jun 2006 21:31:26 -0000
@@ -11,3 +11,4 @@ obj-$(CONFIG_HX4700_PCMCIA)   += hx4700_p
 obj-$(CONFIG_HX4700_LCD)       += hx4700_lcd.o
 obj-$(CONFIG_HX4700_TS)        += hx4700_ts.o
 obj-$(CONFIG_HX4700_BLUETOOTH)         += hx4700_bt.o
+obj-$(CONFIG_HX4700_VOLTAGE)    += hx4700_voltage.o
--- arch/arm/mach-pxa/hx4700/hx4700_voltage.c   2006-05-15 11:34:26.000000000 
+0400
+++ arch/arm/mach-pxa/hx4700/hx4700_voltage.c   2006-06-05 01:48:39.000000000 
+0400
@@ -0,0 +1,189 @@
+/* Helper module for cpufreq. Is't responsible for changing core voltage
+ * of cpu. Send commands to MAX1586B through pwr_i2c controller integrated
+ * in pxa270.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ * History:
+ * 2006-02-04 : Michal Sroczynski <[EMAIL PROTECTED]> 
+ *     initial driver for Asus730
+ * 2006-06-05 : Anton Vorontsov <[EMAIL PROTECTED]>
+ *      hx4700 port, various changes
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/cpufreq.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+
+#define DEBUG 0
+#if DEBUG
+#define dprintk(msg...) do {printk("hx4700_voltage:%s: ", __FUNCTION__);\
+                           printk(msg);} while(0);
+#else
+#define dprintk(msg...)
+#endif
+
+struct freq2mv_table_t {
+        unsigned int khz;
+        unsigned int mv;
+};
+
+static struct freq2mv_table_t freq2mv_table[] = {
+       /* Voltage values are lined up experimentally, official Intel docs
+        * lists much higher values. These lower values makes no harm. */
+       {104000,  825},
+       {156000,  850},
+       {208000,  900},
+       {312000, 1050},
+       {416000, 1100},
+       {520000, 1150},
+       {624000, 1200}
+};
+
+static inline unsigned int freq2mv(unsigned int khz)
+{
+       int i;
+       for (i = 0; i <= ARRAY_SIZE(freq2mv_table); i++) {
+               if (freq2mv_table[i].khz == khz)
+                       return freq2mv_table[i].mv;
+       }
+       // Return maximal voltage we know if no freq2mv record found
+       printk(KERN_WARNING "hx4700_voltage: unknown freq: %d\n", khz);
+       return freq2mv_table[ARRAY_SIZE(freq2mv_table)-1].mv;
+}
+
+static inline uint8_t mv2cmd (const unsigned int mv)
+{
+       uint8_t val = (mv - 700) / 25;
+       if (val > 31)
+               val = 31;
+       return val;
+}
+
+static void change_voltage(void)
+{
+       /* It is Errata 28 workaround, see Intel Specification Update
+        * POWER MANAGER: Core hangs during voltage change when there are
+        * outstanding transactions on the bus */
+
+       unsigned int unused;
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       __asm__ __volatile__("                                                
\n\
+       b      1f                                                             
\n\
+       nop                                                                   
\n\
+       .align  5                                                             
\n\
+1:                                                                            
\n\
+       ldr     r0, [%1]                   @ APB register read and compare    
\n\
+       cmp     r0, #0                     @ fence for pending slow apb reads 
\n\
+                                                                             
\n\
+       mov     r0, #0x8                   @ VC bit for PWRMODE               
\n\
+       movs    r1, #1                     @ don't execute mcr on 1st pass    
\n\
+                                                                             
\n\
+retry:                                                                        
\n\
+       ldreq   r3, [%2]                   @ only stall on the 2nd pass       
\n\
+       cmpeq   r3, #0                     @ cmp causes fence on mem 
transfers\n\
+       cmp     r1, #0                     @ is this the 2nd pass?            
\n\
+       mcreq   p14, 0, r0, c7, c0, 0      @ write to PWRMODE on 2nd pass 
only\n\
+                                                                             
\n\
+       @ Read VC bit until it is 0, indicates that the VoltageChange is 
done.\n\
+       @ On first pass, we never set the VC bit, so it will be clear 
already.\n\
+VoltageChange_loop:                                                           
\n\
+       mrc     p14, 0, r3, c7, c0, 0                                         
\n\
+       tst     r3, #0x8                                                      
\n\
+       bne     VoltageChange_loop                                            
\n\
+                                                                             
\n\
+       subs    r1, r1, #1                                                    
\n\
+       beq     retry"
+               :"=&r"(unused)
+               :"r"(&CCCR), "r"(UNCACHED_ADDR)
+               :"r0", "r1", "r3");
+
+       while (PVCR & PVCR_VCSA) { // Wait for PMIC to finish all operations
+               udelay(1);
+       }
+       
+       local_irq_restore(flags);
+
+       return;
+}
+
+static void send_cmd(uint8_t cmd)
+{
+       PVCR = 0x14; /* MAX1586B address */
+       PCMD0 = PCMD_LC | cmd;
+       change_voltage();
+       return;
+}
+
+static int do_freq_transition(struct notifier_block *nb,
+                              unsigned long val, void *data)
+{
+       struct cpufreq_freqs *f = data;
+       unsigned int new_mv = freq2mv(f->new);
+
+       dprintk("v=%ld cpu=%u old=%u new=%u flags=%hu new_mv=%u\n",
+              val,f->cpu,f->old,f->new,f->flags,new_mv);
+       
+       switch (val) {
+               case CPUFREQ_PRECHANGE:
+                       if (f->new < f->old) break;
+                       send_cmd( mv2cmd(new_mv) );
+                       break;
+
+               case CPUFREQ_POSTCHANGE:
+                       if (f->new > f->old) break;
+                       send_cmd( mv2cmd(new_mv) );
+                       break;
+
+               default:
+                       printk(KERN_WARNING "hx4700_voltage: "
+                              "Unhandled cpufreq event\n");
+                       break;
+       }
+
+       return 0;
+}
+
+struct notifier_block freq_transition = {
+       .notifier_call = do_freq_transition,
+};
+
+static int __init hx4700_voltage_init(void)
+{
+       PCFR |= PCFR_PI2C_EN;
+       pxa_set_cken(CKEN15_PWRI2C,1);
+       cpufreq_register_notifier(&freq_transition, 
CPUFREQ_TRANSITION_NOTIFIER);
+       return 0;
+}
+
+static void __exit hx4700_voltage_exit(void)
+{
+       cpufreq_unregister_notifier(&freq_transition, 
CPUFREQ_TRANSITION_NOTIFIER);
+       pxa_set_cken(CKEN15_PWRI2C,0);
+       return;
+}
+
+module_init(hx4700_voltage_init);
+module_exit(hx4700_voltage_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michal Sroczynski <[EMAIL PROTECTED]>");
+MODULE_DESCRIPTION("Core-voltage change helper for PXA270 and MAX Power IC");
_______________________________________________
Hx4700-port mailing list
[email protected]
https://www.handhelds.org/mailman/listinfo/hx4700-port

Reply via email to