Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds
[pandora-kernel.git] / arch / arm / mach-pxa / pxa25x.c
1 /*
2  *  linux/arch/arm/mach-pxa/pxa25x.c
3  *
4  *  Author:     Nicolas Pitre
5  *  Created:    Jun 15, 2001
6  *  Copyright:  MontaVista Software Inc.
7  *
8  * Code specific to PXA21x/25x/26x variants.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  * Since this file should be linked before any other machine specific file,
15  * the __initcall() here will be executed first.  This serves as default
16  * initialization stuff for PXA machines which can be overridden later if
17  * need be.
18  */
19 #include <linux/module.h>
20 #include <linux/kernel.h>
21 #include <linux/init.h>
22 #include <linux/platform_device.h>
23 #include <linux/pm.h>
24
25 #include <asm/hardware.h>
26 #include <asm/arch/irqs.h>
27 #include <asm/arch/pxa-regs.h>
28 #include <asm/arch/pm.h>
29 #include <asm/arch/dma.h>
30
31 #include "generic.h"
32 #include "devices.h"
33
34 /*
35  * Various clock factors driven by the CCCR register.
36  */
37
38 /* Crystal Frequency to Memory Frequency Multiplier (L) */
39 static unsigned char L_clk_mult[32] = { 0, 27, 32, 36, 40, 45, 0, };
40
41 /* Memory Frequency to Run Mode Frequency Multiplier (M) */
42 static unsigned char M_clk_mult[4] = { 0, 1, 2, 4 };
43
44 /* Run Mode Frequency to Turbo Mode Frequency Multiplier (N) */
45 /* Note: we store the value N * 2 here. */
46 static unsigned char N2_clk_mult[8] = { 0, 0, 2, 3, 4, 0, 6, 0 };
47
48 /* Crystal clock */
49 #define BASE_CLK        3686400
50
51 /*
52  * Get the clock frequency as reflected by CCCR and the turbo flag.
53  * We assume these values have been applied via a fcs.
54  * If info is not 0 we also display the current settings.
55  */
56 unsigned int get_clk_frequency_khz(int info)
57 {
58         unsigned long cccr, turbo;
59         unsigned int l, L, m, M, n2, N;
60
61         cccr = CCCR;
62         asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (turbo) );
63
64         l  =  L_clk_mult[(cccr >> 0) & 0x1f];
65         m  =  M_clk_mult[(cccr >> 5) & 0x03];
66         n2 = N2_clk_mult[(cccr >> 7) & 0x07];
67
68         L = l * BASE_CLK;
69         M = m * L;
70         N = n2 * M / 2;
71
72         if(info)
73         {
74                 L += 5000;
75                 printk( KERN_INFO "Memory clock: %d.%02dMHz (*%d)\n",
76                         L / 1000000, (L % 1000000) / 10000, l );
77                 M += 5000;
78                 printk( KERN_INFO "Run Mode clock: %d.%02dMHz (*%d)\n",
79                         M / 1000000, (M % 1000000) / 10000, m );
80                 N += 5000;
81                 printk( KERN_INFO "Turbo Mode clock: %d.%02dMHz (*%d.%d, %sactive)\n",
82                         N / 1000000, (N % 1000000) / 10000, n2 / 2, (n2 % 2) * 5,
83                         (turbo & 1) ? "" : "in" );
84         }
85
86         return (turbo & 1) ? (N/1000) : (M/1000);
87 }
88
89 EXPORT_SYMBOL(get_clk_frequency_khz);
90
91 /*
92  * Return the current memory clock frequency in units of 10kHz
93  */
94 unsigned int get_memclk_frequency_10khz(void)
95 {
96         return L_clk_mult[(CCCR >> 0) & 0x1f] * BASE_CLK / 10000;
97 }
98
99 EXPORT_SYMBOL(get_memclk_frequency_10khz);
100
101 /*
102  * Return the current LCD clock frequency in units of 10kHz
103  */
104 unsigned int get_lcdclk_frequency_10khz(void)
105 {
106         return get_memclk_frequency_10khz();
107 }
108
109 EXPORT_SYMBOL(get_lcdclk_frequency_10khz);
110
111 #ifdef CONFIG_PM
112
113 void pxa_cpu_pm_enter(suspend_state_t state)
114 {
115         extern void pxa_cpu_suspend(unsigned int);
116         extern void pxa_cpu_resume(void);
117
118         CKEN = 0;
119
120         switch (state) {
121         case PM_SUSPEND_MEM:
122                 /* set resume return address */
123                 PSPR = virt_to_phys(pxa_cpu_resume);
124                 pxa_cpu_suspend(PWRMODE_SLEEP);
125                 break;
126         }
127 }
128
129 static struct pm_ops pxa25x_pm_ops = {
130         .enter          = pxa_pm_enter,
131         .valid          = pm_valid_only_mem,
132 };
133 #endif
134
135 void __init pxa25x_init_irq(void)
136 {
137         pxa_init_irq_low();
138         pxa_init_irq_gpio(85);
139 }
140
141 static struct platform_device *pxa25x_devices[] __initdata = {
142         &pxamci_device,
143         &pxaudc_device,
144         &pxafb_device,
145         &ffuart_device,
146         &btuart_device,
147         &stuart_device,
148         &pxai2c_device,
149         &pxai2s_device,
150         &pxaficp_device,
151         &pxartc_device,
152 };
153
154 static int __init pxa25x_init(void)
155 {
156         int ret = 0;
157
158         if (cpu_is_pxa21x() || cpu_is_pxa25x()) {
159                 if ((ret = pxa_init_dma(16)))
160                         return ret;
161 #ifdef CONFIG_PM
162                 pm_set_ops(&pxa25x_pm_ops);
163 #endif
164                 ret = platform_add_devices(pxa25x_devices,
165                                            ARRAY_SIZE(pxa25x_devices));
166         }
167         /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
168         if (cpu_is_pxa25x())
169                 ret = platform_device_register(&hwuart_device);
170
171         return ret;
172 }
173
174 subsys_initcall(pxa25x_init);