blob: f85f681c03933a74db82ab279a845a7bafe59818 [file] [log] [blame]
eric miao7facc2f92008-03-05 17:16:29 +08001/*
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 */