diff options
Diffstat (limited to 'arch/arm/mach-pxa/generic.c')
-rw-r--r-- | arch/arm/mach-pxa/generic.c | 184 |
1 files changed, 125 insertions, 59 deletions
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 5510f6fdce55..1c34946ee16e 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c | |||
@@ -25,10 +25,6 @@ | |||
25 | #include <linux/pm.h> | 25 | #include <linux/pm.h> |
26 | #include <linux/string.h> | 26 | #include <linux/string.h> |
27 | 27 | ||
28 | #include <linux/sched.h> | ||
29 | #include <asm/cnt32_to_63.h> | ||
30 | #include <asm/div64.h> | ||
31 | |||
32 | #include <asm/hardware.h> | 28 | #include <asm/hardware.h> |
33 | #include <asm/irq.h> | 29 | #include <asm/irq.h> |
34 | #include <asm/system.h> | 30 | #include <asm/system.h> |
@@ -47,66 +43,39 @@ | |||
47 | #include "generic.h" | 43 | #include "generic.h" |
48 | 44 | ||
49 | /* | 45 | /* |
50 | * This is the PXA2xx sched_clock implementation. This has a resolution | 46 | * Get the clock frequency as reflected by CCCR and the turbo flag. |
51 | * of at least 308ns and a maximum value that depends on the value of | 47 | * We assume these values have been applied via a fcs. |
52 | * CLOCK_TICK_RATE. | 48 | * If info is not 0 we also display the current settings. |
53 | * | ||
54 | * The return value is guaranteed to be monotonic in that range as | ||
55 | * long as there is always less than 582 seconds between successive | ||
56 | * calls to this function. | ||
57 | */ | 49 | */ |
58 | unsigned long long sched_clock(void) | 50 | unsigned int get_clk_frequency_khz(int info) |
59 | { | 51 | { |
60 | unsigned long long v = cnt32_to_63(OSCR); | 52 | if (cpu_is_pxa21x() || cpu_is_pxa25x()) |
61 | /* Note: top bit ov v needs cleared unless multiplier is even. */ | 53 | return pxa25x_get_clk_frequency_khz(info); |
62 | 54 | else if (cpu_is_pxa27x()) | |
63 | #if CLOCK_TICK_RATE == 3686400 | 55 | return pxa27x_get_clk_frequency_khz(info); |
64 | /* 1E9 / 3686400 => 78125 / 288, max value = 32025597s (370 days). */ | 56 | else |
65 | /* The <<1 is used to get rid of tick.hi top bit */ | 57 | return pxa3xx_get_clk_frequency_khz(info); |
66 | v *= 78125<<1; | 58 | } |
67 | do_div(v, 288<<1); | 59 | EXPORT_SYMBOL(get_clk_frequency_khz); |
68 | #elif CLOCK_TICK_RATE == 3250000 | ||
69 | /* 1E9 / 3250000 => 4000 / 13, max value = 709490156s (8211 days) */ | ||
70 | v *= 4000; | ||
71 | do_div(v, 13); | ||
72 | #elif CLOCK_TICK_RATE == 3249600 | ||
73 | /* 1E9 / 3249600 => 625000 / 2031, max value = 4541295s (52 days) */ | ||
74 | v *= 625000; | ||
75 | do_div(v, 2031); | ||
76 | #else | ||
77 | #warning "consider fixing sched_clock for your value of CLOCK_TICK_RATE" | ||
78 | /* | ||
79 | * 96-bit math to perform tick * NSEC_PER_SEC / CLOCK_TICK_RATE for | ||
80 | * any value of CLOCK_TICK_RATE. Max value is in the 80 thousand | ||
81 | * years range and truncation to unsigned long long limits it to | ||
82 | * sched_clock's max range of ~584 years. This is nice but with | ||
83 | * higher computation cost. | ||
84 | */ | ||
85 | { | ||
86 | union { | ||
87 | unsigned long long val; | ||
88 | struct { unsigned long lo, hi; }; | ||
89 | } x; | ||
90 | unsigned long long y; | ||
91 | |||
92 | x.val = v; | ||
93 | x.hi &= 0x7fffffff; | ||
94 | y = (unsigned long long)x.lo * NSEC_PER_SEC; | ||
95 | x.lo = y; | ||
96 | y = (y >> 32) + (unsigned long long)x.hi * NSEC_PER_SEC; | ||
97 | x.hi = do_div(y, CLOCK_TICK_RATE); | ||
98 | do_div(x.val, CLOCK_TICK_RATE); | ||
99 | x.hi += y; | ||
100 | v = x.val; | ||
101 | } | ||
102 | #endif | ||
103 | 60 | ||
104 | return v; | 61 | /* |
62 | * Return the current memory clock frequency in units of 10kHz | ||
63 | */ | ||
64 | unsigned int get_memclk_frequency_10khz(void) | ||
65 | { | ||
66 | if (cpu_is_pxa21x() || cpu_is_pxa25x()) | ||
67 | return pxa25x_get_memclk_frequency_10khz(); | ||
68 | else if (cpu_is_pxa27x()) | ||
69 | return pxa27x_get_memclk_frequency_10khz(); | ||
70 | else | ||
71 | return pxa3xx_get_memclk_frequency_10khz(); | ||
105 | } | 72 | } |
73 | EXPORT_SYMBOL(get_memclk_frequency_10khz); | ||
106 | 74 | ||
107 | /* | 75 | /* |
108 | * Handy function to set GPIO alternate functions | 76 | * Handy function to set GPIO alternate functions |
109 | */ | 77 | */ |
78 | int pxa_last_gpio; | ||
110 | 79 | ||
111 | int pxa_gpio_mode(int gpio_mode) | 80 | int pxa_gpio_mode(int gpio_mode) |
112 | { | 81 | { |
@@ -115,7 +84,7 @@ int pxa_gpio_mode(int gpio_mode) | |||
115 | int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8; | 84 | int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8; |
116 | int gafr; | 85 | int gafr; |
117 | 86 | ||
118 | if (gpio > PXA_LAST_GPIO) | 87 | if (gpio > pxa_last_gpio) |
119 | return -EINVAL; | 88 | return -EINVAL; |
120 | 89 | ||
121 | local_irq_save(flags); | 90 | local_irq_save(flags); |
@@ -136,6 +105,44 @@ int pxa_gpio_mode(int gpio_mode) | |||
136 | 105 | ||
137 | EXPORT_SYMBOL(pxa_gpio_mode); | 106 | EXPORT_SYMBOL(pxa_gpio_mode); |
138 | 107 | ||
108 | int gpio_direction_input(unsigned gpio) | ||
109 | { | ||
110 | unsigned long flags; | ||
111 | u32 mask; | ||
112 | |||
113 | if (gpio > pxa_last_gpio) | ||
114 | return -EINVAL; | ||
115 | |||
116 | mask = GPIO_bit(gpio); | ||
117 | local_irq_save(flags); | ||
118 | GPDR(gpio) &= ~mask; | ||
119 | local_irq_restore(flags); | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | EXPORT_SYMBOL(gpio_direction_input); | ||
124 | |||
125 | int gpio_direction_output(unsigned gpio, int value) | ||
126 | { | ||
127 | unsigned long flags; | ||
128 | u32 mask; | ||
129 | |||
130 | if (gpio > pxa_last_gpio) | ||
131 | return -EINVAL; | ||
132 | |||
133 | mask = GPIO_bit(gpio); | ||
134 | local_irq_save(flags); | ||
135 | if (value) | ||
136 | GPSR(gpio) = mask; | ||
137 | else | ||
138 | GPCR(gpio) = mask; | ||
139 | GPDR(gpio) |= mask; | ||
140 | local_irq_restore(flags); | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | EXPORT_SYMBOL(gpio_direction_output); | ||
145 | |||
139 | /* | 146 | /* |
140 | * Return GPIO level | 147 | * Return GPIO level |
141 | */ | 148 | */ |
@@ -159,7 +166,7 @@ EXPORT_SYMBOL(pxa_gpio_set_value); | |||
159 | /* | 166 | /* |
160 | * Routine to safely enable or disable a clock in the CKEN | 167 | * Routine to safely enable or disable a clock in the CKEN |
161 | */ | 168 | */ |
162 | void pxa_set_cken(int clock, int enable) | 169 | void __pxa_set_cken(int clock, int enable) |
163 | { | 170 | { |
164 | unsigned long flags; | 171 | unsigned long flags; |
165 | local_irq_save(flags); | 172 | local_irq_save(flags); |
@@ -172,7 +179,7 @@ void pxa_set_cken(int clock, int enable) | |||
172 | local_irq_restore(flags); | 179 | local_irq_restore(flags); |
173 | } | 180 | } |
174 | 181 | ||
175 | EXPORT_SYMBOL(pxa_set_cken); | 182 | EXPORT_SYMBOL(__pxa_set_cken); |
176 | 183 | ||
177 | /* | 184 | /* |
178 | * Intel PXA2xx internal register mapping. | 185 | * Intel PXA2xx internal register mapping. |
@@ -329,21 +336,80 @@ void __init set_pxa_fb_parent(struct device *parent_dev) | |||
329 | pxa_device_fb.dev.parent = parent_dev; | 336 | pxa_device_fb.dev.parent = parent_dev; |
330 | } | 337 | } |
331 | 338 | ||
339 | static struct resource pxa_resource_ffuart[] = { | ||
340 | { | ||
341 | .start = __PREG(FFUART), | ||
342 | .end = __PREG(FFUART) + 35, | ||
343 | .flags = IORESOURCE_MEM, | ||
344 | }, { | ||
345 | .start = IRQ_FFUART, | ||
346 | .end = IRQ_FFUART, | ||
347 | .flags = IORESOURCE_IRQ, | ||
348 | } | ||
349 | }; | ||
350 | |||
332 | struct platform_device pxa_device_ffuart= { | 351 | struct platform_device pxa_device_ffuart= { |
333 | .name = "pxa2xx-uart", | 352 | .name = "pxa2xx-uart", |
334 | .id = 0, | 353 | .id = 0, |
354 | .resource = pxa_resource_ffuart, | ||
355 | .num_resources = ARRAY_SIZE(pxa_resource_ffuart), | ||
335 | }; | 356 | }; |
357 | |||
358 | static struct resource pxa_resource_btuart[] = { | ||
359 | { | ||
360 | .start = __PREG(BTUART), | ||
361 | .end = __PREG(BTUART) + 35, | ||
362 | .flags = IORESOURCE_MEM, | ||
363 | }, { | ||
364 | .start = IRQ_BTUART, | ||
365 | .end = IRQ_BTUART, | ||
366 | .flags = IORESOURCE_IRQ, | ||
367 | } | ||
368 | }; | ||
369 | |||
336 | struct platform_device pxa_device_btuart = { | 370 | struct platform_device pxa_device_btuart = { |
337 | .name = "pxa2xx-uart", | 371 | .name = "pxa2xx-uart", |
338 | .id = 1, | 372 | .id = 1, |
373 | .resource = pxa_resource_btuart, | ||
374 | .num_resources = ARRAY_SIZE(pxa_resource_btuart), | ||
339 | }; | 375 | }; |
376 | |||
377 | static struct resource pxa_resource_stuart[] = { | ||
378 | { | ||
379 | .start = __PREG(STUART), | ||
380 | .end = __PREG(STUART) + 35, | ||
381 | .flags = IORESOURCE_MEM, | ||
382 | }, { | ||
383 | .start = IRQ_STUART, | ||
384 | .end = IRQ_STUART, | ||
385 | .flags = IORESOURCE_IRQ, | ||
386 | } | ||
387 | }; | ||
388 | |||
340 | struct platform_device pxa_device_stuart = { | 389 | struct platform_device pxa_device_stuart = { |
341 | .name = "pxa2xx-uart", | 390 | .name = "pxa2xx-uart", |
342 | .id = 2, | 391 | .id = 2, |
392 | .resource = pxa_resource_stuart, | ||
393 | .num_resources = ARRAY_SIZE(pxa_resource_stuart), | ||
343 | }; | 394 | }; |
395 | |||
396 | static struct resource pxa_resource_hwuart[] = { | ||
397 | { | ||
398 | .start = __PREG(HWUART), | ||
399 | .end = __PREG(HWUART) + 47, | ||
400 | .flags = IORESOURCE_MEM, | ||
401 | }, { | ||
402 | .start = IRQ_HWUART, | ||
403 | .end = IRQ_HWUART, | ||
404 | .flags = IORESOURCE_IRQ, | ||
405 | } | ||
406 | }; | ||
407 | |||
344 | struct platform_device pxa_device_hwuart = { | 408 | struct platform_device pxa_device_hwuart = { |
345 | .name = "pxa2xx-uart", | 409 | .name = "pxa2xx-uart", |
346 | .id = 3, | 410 | .id = 3, |
411 | .resource = pxa_resource_hwuart, | ||
412 | .num_resources = ARRAY_SIZE(pxa_resource_hwuart), | ||
347 | }; | 413 | }; |
348 | 414 | ||
349 | static struct resource pxai2c_resources[] = { | 415 | static struct resource pxai2c_resources[] = { |