aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-pxa/mfp-pxa2xx.c
diff options
context:
space:
mode:
authoreric miao <eric.miao@marvell.com>2008-03-05 04:16:29 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2008-04-19 06:29:04 -0400
commit7facc2f9374159795af2a3f8b3e682b4ee230643 (patch)
tree7a62c65e06f480d6924c00108ef8efc625054ccb /arch/arm/mach-pxa/mfp-pxa2xx.c
parenta683b14df8f4320d0ef6cac93a6d9806173bf339 (diff)
[ARM] pxa: add MFP-alike pin configuration support for pxa{25x, 27x}
Pin configuration on pxa{25x,27x} has now separated from generic GPIO into dedicated mfp-pxa2xx.c by this patch. The name "mfp" is borrowed from pxa3xx and is used here to alert the difference between the two concepts: pin configuration and generic GPIOs. A GPIO can be called a "GPIO" _only_ when the corresponding pin is configured so. A pin configuration on pxa{25x,27x} is composed of: - alternate function selection (or pin mux as commonly called) - low power state or sleep state - wakeup enabling from low power mode The following MFP_xxx bit definitions in mfp.h are re-used: - MFP_PIN(x) - MFP_AFx - MFP_LPM_DRIVE_{LOW, HIGH} - MFP_LPM_EDGE_* Selecting alternate function on pxa{25x, 27x} involves configuration of GPIO direction register GPDRx, so a new bit and MFP_DIR_{IN, OUT} are introduced. And pin configurations are defined by the following two macros: - MFP_CFG_IN : for input alternate functions - MFP_CFG_OUT : for output alternate functions Every configuration should provide a low power state if it configured as output using MFP_CFG_OUT(). As a general guideline, the low power state should be decided to minimize the overall power dissipation. As an example, it is better to drive the pin as high level in low power mode if the GPIO is configured as an active low chip select. Pins configured as GPIO are defined by MFP_CFG_IN(). This is to avoid side effects when it is firstly configured as output. The actual direction of the GPIO is configured by gpio_direction_{input, output} Wakeup enabling on pxa{25x, 27x} is actually GPIO based wakeup, thus the device based enable_irq_wake() mechanism is not applicable here. E.g. invoking enable_irq_wake() with a GPIO IRQ as in the following code to enable OTG wakeup is by no means portable and intuitive, and it is valid _only_ when GPIO35 is configured as USB_P2_1: enable_irq_wake( gpio_to_irq(35) ); To make things worse, not every GPIO is able to wakeup the system. Only a small number of them can, on either rising or falling edge, or when level is high (for keypad GPIOs). Thus, another new bit is introduced to indicate that the GPIO will wakeup the system: - MFP_LPM_WAKEUP_ENABLE The following macros can be used in platform code, and be OR'ed to the GPIO configuration to enable its wakeup: - WAKEUP_ON_EDGE_{RISE, FALL, BOTH} - WAKEUP_ON_LEVEL_HIGH The WAKEUP_ON_LEVEL_HIGH is used for keypad GPIOs _only_, there is no edge settings for those GPIOs. These WAKEUP_ON_* flags OR'ed on wrong GPIOs will be ignored in case that platform code author is careless enough. The tradeoff here is that the wakeup source is fully determined by the platform configuration, instead of enable_irq_wake(). Signed-off-by: eric miao <eric.miao@marvell.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-pxa/mfp-pxa2xx.c')
-rw-r--r--arch/arm/mach-pxa/mfp-pxa2xx.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c
new file mode 100644
index 000000000000..f85f681c0393
--- /dev/null
+++ b/arch/arm/mach-pxa/mfp-pxa2xx.c
@@ -0,0 +1,190 @@
1/*
2 * linux/arch/arm/mach-pxa/mfp-pxa2xx.c
3 *
4 * PXA2xx pin mux configuration support
5 *
6 * The GPIOs on PXA2xx can be configured as one of many alternate
7 * functions, this is by concept samilar to the MFP configuration
8 * on PXA3xx, what's more important, the low power pin state and
9 * wakeup detection are also supported by the same framework.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 */
15
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/init.h>
19#include <linux/sysdev.h>
20
21#include <asm/arch/hardware.h>
22#include <asm/arch/pxa-regs.h>
23#include <asm/arch/mfp-pxa2xx.h>
24
25#include "generic.h"
26
27#define PGSR(x) __REG2(0x40F00020, ((x) & 0x60) >> 3)
28
29#define PWER_WE35 (1 << 24)
30
31static struct {
32 unsigned valid : 1;
33 unsigned can_wakeup : 1;
34 unsigned keypad_gpio : 1;
35 unsigned int mask; /* bit mask in PWER or PKWR */
36 unsigned long config;
37} gpio_desc[MFP_PIN_GPIO127 + 1];
38
39static inline int __mfp_config_gpio(unsigned gpio, unsigned long c)
40{
41 unsigned long gafr, mask = GPIO_bit(gpio);
42 int fn;
43
44 fn = MFP_AF(c);
45 if (fn > 3)
46 return -EINVAL;
47
48 /* alternate function and direction */
49 gafr = GAFR(gpio) & ~(0x3 << ((gpio & 0xf) * 2));
50 GAFR(gpio) = gafr | (fn << ((gpio & 0xf) * 2));
51
52 if (c & MFP_DIR_OUT)
53 GPDR(gpio) |= mask;
54 else
55 GPDR(gpio) &= ~mask;
56
57 /* low power state */
58 switch (c & MFP_LPM_STATE_MASK) {
59 case MFP_LPM_DRIVE_HIGH:
60 PGSR(gpio) |= mask;
61 break;
62 case MFP_LPM_DRIVE_LOW:
63 PGSR(gpio) &= ~mask;
64 break;
65 case MFP_LPM_INPUT:
66 break;
67 default:
68 pr_warning("%s: invalid low power state for GPIO%d\n",
69 __func__, gpio);
70 return -EINVAL;
71 }
72
73 /* wakeup enabling */
74 if ((c & MFP_LPM_WAKEUP_ENABLE) == 0)
75 return 0;
76
77 if (!gpio_desc[gpio].can_wakeup || c & MFP_DIR_OUT) {
78 pr_warning("%s: GPIO%d unable to wakeup\n",
79 __func__, gpio);
80 return -EINVAL;
81 }
82
83 if (gpio_desc[gpio].keypad_gpio)
84 PKWR |= gpio_desc[gpio].mask;
85 else {
86 PWER |= gpio_desc[gpio].mask;
87
88 if (c & MFP_LPM_EDGE_RISE)
89 PRER |= gpio_desc[gpio].mask;
90
91 if (c & MFP_LPM_EDGE_FALL)
92 PFER |= gpio_desc[gpio].mask;
93 }
94
95 return 0;
96}
97
98void pxa2xx_mfp_config(unsigned long *mfp_cfgs, int num)
99{
100 unsigned long flags;
101 unsigned long *c;
102 int i, gpio;
103
104 for (i = 0, c = mfp_cfgs; i < num; i++, c++) {
105
106 gpio = mfp_to_gpio(MFP_PIN(*c));
107
108 if (!gpio_desc[gpio].valid) {
109 pr_warning("%s: GPIO%d is invalid pin\n",
110 __func__, gpio);
111 continue;
112 }
113
114 local_irq_save(flags);
115
116 gpio_desc[gpio].config = *c;
117 __mfp_config_gpio(gpio, *c);
118
119 local_irq_restore(flags);
120 }
121}
122
123#ifdef CONFIG_PXA25x
124static int __init pxa25x_mfp_init(void)
125{
126 int i;
127
128 if (cpu_is_pxa25x()) {
129 for (i = 0; i <= 84; i++)
130 gpio_desc[i].valid = 1;
131
132 for (i = 0; i <= 15; i++) {
133 gpio_desc[i].can_wakeup = 1;
134 gpio_desc[i].mask = GPIO_bit(i);
135 }
136 }
137
138 return 0;
139}
140postcore_initcall(pxa25x_mfp_init);
141#endif /* CONFIG_PXA25x */
142
143#ifdef CONFIG_PXA27x
144static int pxa27x_pkwr_gpio[] __initdata = {
145 13, 16, 17, 34, 36, 37, 38, 39, 90, 91, 93, 94,
146 95, 96, 97, 98, 99, 100, 101, 102
147};
148
149static int __init pxa27x_mfp_init(void)
150{
151 int i, gpio;
152
153 if (cpu_is_pxa27x()) {
154 for (i = 0; i <= 120; i++) {
155 /* skip GPIO2, 5, 6, 7, 8, they are not
156 * valid pins allow configuration
157 */
158 if (i == 2 || i == 5 || i == 6 ||
159 i == 7 || i == 8)
160 continue;
161
162 gpio_desc[i].valid = 1;
163 }
164
165 /* Keypad GPIOs */
166 for (i = 0; i < ARRAY_SIZE(pxa27x_pkwr_gpio); i++) {
167 gpio = pxa27x_pkwr_gpio[i];
168 gpio_desc[gpio].can_wakeup = 1;
169 gpio_desc[gpio].keypad_gpio = 1;
170 gpio_desc[gpio].mask = 1 << i;
171 }
172
173 /* Overwrite GPIO13 as a PWER wakeup source */
174 for (i = 0; i <= 15; i++) {
175 /* skip GPIO2, 5, 6, 7, 8 */
176 if (GPIO_bit(i) & 0x1e4)
177 continue;
178
179 gpio_desc[i].can_wakeup = 1;
180 gpio_desc[i].mask = GPIO_bit(i);
181 }
182
183 gpio_desc[35].can_wakeup = 1;
184 gpio_desc[35].mask = PWER_WE35;
185 }
186
187 return 0;
188}
189postcore_initcall(pxa27x_mfp_init);
190#endif /* CONFIG_PXA27x */