upload tizen1.0 source
[kernel/linux-2.6.36.git] / arch / arm / mach-s5pv310 / gpio-mobile.c
1 /*
2  * Copyright (C) 2010 Samsung Electrnoics
3  */
4
5 #include <linux/init.h>
6 #include <linux/kernel.h>
7 #include <linux/io.h>
8 #include <linux/module.h>
9 #include <linux/slab.h>
10
11 #include <mach/map.h>
12
13 #include <asm/mach-types.h>
14
15 #include <plat/map-s5p.h>
16 #include <plat/pm.h>
17
18 #include "gpio-mobile.h"
19
20 struct mobile_gpios_data *gpios_data;
21
22 static void setup_gpio_group(void *base, int offset,
23                         const struct s5p_gpio_group *group, int size)
24 {
25         struct s5p_gpio_group *g = (struct s5p_gpio_group *) group;
26         int i, n, value;
27         void *addr;
28
29         addr = base + offset;
30
31         for (i = 0; i < size; i++, g++) {
32                 n = g->num;
33
34 #ifdef TEST_OFFSET
35                 if (offset == TEST_OFFSET) {
36                         printk("[%d] 0x%x, %d, %d, %d, %d, %d\n", g->num,
37                                 g->con, g->dat, g->pud, g->drv,
38                                 g->conpdn, g->pudpdn);
39                 }
40 #endif
41
42                 /* CON */
43                 if (g->con != SKIP_SFN) {
44                         value = __raw_readl(addr + CON_OFFSET);
45                         value &= ~(0xf << (n * 4));
46                         value |= (g->con << (n * 4));
47                         __raw_writel(value, addr + CON_OFFSET);
48                 }
49                 /* DAT: Set when GPIO is OUTPUT mode and not NONE */
50                 if (g->con == SFN(0x1) && g->dat != NONE) {
51                         value = __raw_readl(addr + DAT_OFFSET);
52                         value &= ~(0x1 << (n * 1));
53                         value |= (g->dat << (n * 1));
54                         __raw_writel(value, addr + DAT_OFFSET);
55                 }
56                 /* PUD */
57                 if (g->pud != XXXXXX) {
58                         value = __raw_readl(addr + PUD_OFFSET);
59                         value &= ~(0x3 << (n * 2));
60                         value |= (g->pud << (n * 2));
61                         __raw_writel(value, addr + PUD_OFFSET);
62                 }
63                 /* DRV */
64                 value = __raw_readl(addr + DRV_OFFSET);
65                 value &= ~(0x3 << (n * 2));
66                 value |= (g->drv << (n * 2));
67                 __raw_writel(value, addr + DRV_OFFSET);
68 #ifdef TEST_OFFSET
69                 if (offset == TEST_OFFSET) {
70                         printk(" DRV 0x0%08x, 0x%08x\n",
71                                 value, __raw_readl(addr + DRV_OFFSET));
72                 }
73 #endif
74                 /* CONPDN */
75                 value = __raw_readl(addr + CONPDN_OFFSET);
76                 value &= ~(0x3 << (n * 2));
77                 value |= (g->conpdn << (n * 2));
78                 __raw_writel(value, addr + CONPDN_OFFSET);
79                 /* PUDPDN */
80                 value = __raw_readl(addr + PUDPDN_OFFSET);
81                 value &= ~(0x3 << (n * 2));
82                 value |= (g->pudpdn << (n * 2));
83                 __raw_writel(value, addr + PUDPDN_OFFSET);
84         }
85         S3C_PMDBG("0x%03x: CON 0x%08x, PUP 0x%08x\n", (unsigned int) offset,
86                         __raw_readl(addr + CON_OFFSET),
87                         __raw_readl(addr + PUD_OFFSET));
88 }
89
90 static void show_difference(void *base, int offset,
91                 const struct s5p_gpio_group *group, int size)
92 {
93         struct s5p_gpio_group *g = (struct s5p_gpio_group *) group;
94         int i, n, value;
95         void *addr;
96
97         addr = base + offset;
98
99         for (i = 0; i < size; i++, g++) {
100                 n = g->num;
101
102                 /* CON */
103                 value = (__raw_readl(addr + CON_OFFSET) >> (n * 4)) & 0xf;
104                 if (g->con != value)
105                         S3C_PMDBG("CON[%d]: %x (%x recommended)\n",
106                                         g->num, value, g->con);
107
108                 /* DAT: Set when GPIO is OUTPUT mode and not NONE */
109                 if (g->dat != NONE && (g->con == 0x1 || value == 0x1)) {
110                         value = (__raw_readl(addr + DAT_OFFSET) >> (n * 1)) & 0x1;
111                         if (g->dat != value)
112                                 S3C_PMDBG("DAT[%d]: %x (%x recommended)\n",
113                                                 g->num, value, g->dat);
114                 }
115
116                 /* PUD */
117                 value = (__raw_readl(addr + PUD_OFFSET) >> (n * 2)) & 0x3;
118                 if (g->pud != value)
119                         S3C_PMDBG("PUD[%d]: %x (%x recommended)\n",
120                                         g->num, value, g->pud);
121
122                 /* DRV */
123                 value = (__raw_readl(addr + DRV_OFFSET) >> (n * 2)) & 0x3;
124                 if (g->drv != value)
125                         S3C_PMDBG("DRV[%d]: %x (%x recommended)\n",
126                                         g->num, value, g->drv);
127         }
128 }
129
130 int mobile_get_gpio(int pin)
131 {
132         int size;
133
134         if (!gpios_data)
135                 return -1;
136         size = gpios_data->gpios_size;
137
138         if (pin < size)
139                 return gpios_data->gpios[pin];
140
141         return gpios_data->gpios[pin - size];
142 }
143
144 void mobile_gpios_register(struct mobile_gpios_data *data)
145 {
146         struct s5p_gpio_group_info *info;
147         int i, size;
148
149         if (!gpios_data) {
150                 gpios_data = kmalloc(sizeof(struct mobile_gpios_data), GFP_KERNEL);
151                 gpios_data = data;
152
153                 info = gpios_data->infos;
154                 size = gpios_data->infos_size;
155
156                 for (i = 0; i < size; i++)
157                         setup_gpio_group(info[i].base, info[i].offset, info[i].group, info[i].size);
158         } else
159                 printk("It is already registered.\n");
160 }
161
162 void mobile_gpios_groupx_difference(void)
163 {
164         struct s5p_gpio_group *x0, *x1, *x2, *x3;
165         int x0_size, x1_size, x2_size, x3_size;
166
167         if (!gpios_data)
168                 return;
169
170         x0 = gpios_data->x0;
171         x1 = gpios_data->x1;
172         x2 = gpios_data->x2;
173         x3 = gpios_data->x3;
174
175         x0_size = gpios_data->x0_size;
176         x1_size = gpios_data->x1_size;
177         x2_size = gpios_data->x2_size;
178         x3_size = gpios_data->x3_size;
179
180         S3C_PMDBG("Difference in GPX0 from the recommended sleep values\n");
181         show_difference(S5P_VA_GPIO2, 0xC00, x0, x0_size);
182         S3C_PMDBG("Difference in GPX1 from the recommended sleep values\n");
183         show_difference(S5P_VA_GPIO2, 0xC20, x1, x1_size);
184         S3C_PMDBG("Difference in GPX2 from the recommended sleep values\n");
185         show_difference(S5P_VA_GPIO2, 0xC40, x2, x2_size);
186         S3C_PMDBG("Difference in GPX3 from the recommended sleep values\n");
187         show_difference(S5P_VA_GPIO2, 0xC60, x3, x3_size);
188 }
189
190 extern void __init mobile_gpios_init_slp7(void);
191 extern void __init mobile_gpios_init_slp10(void);
192 extern void __init mobile_gpios_init_c1(void);
193 extern void __init mobile_gpios_init_u1(void);
194 extern void __init mobile_gpios_init_u1hd(void);
195 extern void __init mobile_gpios_init_q1(void);
196 extern void __init mobile_gpios_init_p8(void);
197
198 void mobile_gpios_init(void)
199 {
200         /* Check hwrev to call properly gpio_init function */
201         if (machine_is_slp7_c210() || machine_is_nuri())
202                 mobile_gpios_init_slp7();
203
204         else if (machine_is_slp10_c210())
205                 mobile_gpios_init_slp10();
206
207         else if (machine_is_c1_c210())
208                 mobile_gpios_init_c1();
209
210         else if (machine_is_u1_c210())
211                 mobile_gpios_init_u1();
212
213         else if (machine_is_u1hd_c210())
214                 mobile_gpios_init_u1hd();
215
216         else if (machine_is_q1_c210())
217                 mobile_gpios_init_q1();
218
219         else if (machine_is_p8_c210())
220                 mobile_gpios_init_p8();
221
222         else
223                 printk(KERN_ERR "%s: The board isn't identifid\n", __func__);
224
225         /* TODO
226          - If you want to add the new board with S5PV310 SoC,
227            you should add gpio_init function related to new board. */
228 }