2 * Copyright (C) 2010 Samsung Electrnoics
5 #include <linux/init.h>
6 #include <linux/kernel.h>
8 #include <linux/module.h>
9 #include <linux/slab.h>
13 #include <asm/mach-types.h>
15 #include <plat/map-s5p.h>
18 #include "gpio-mobile.h"
20 struct mobile_gpios_data *gpios_data;
22 static void setup_gpio_group(void *base, int offset,
23 const struct s5p_gpio_group *group, int size)
25 struct s5p_gpio_group *g = (struct s5p_gpio_group *) group;
31 for (i = 0; i < size; i++, g++) {
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);
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);
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);
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);
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);
69 if (offset == TEST_OFFSET) {
70 printk(" DRV 0x0%08x, 0x%08x\n",
71 value, __raw_readl(addr + DRV_OFFSET));
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);
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);
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));
90 static void show_difference(void *base, int offset,
91 const struct s5p_gpio_group *group, int size)
93 struct s5p_gpio_group *g = (struct s5p_gpio_group *) group;
99 for (i = 0; i < size; i++, g++) {
103 value = (__raw_readl(addr + CON_OFFSET) >> (n * 4)) & 0xf;
105 S3C_PMDBG("CON[%d]: %x (%x recommended)\n",
106 g->num, value, g->con);
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;
112 S3C_PMDBG("DAT[%d]: %x (%x recommended)\n",
113 g->num, value, g->dat);
117 value = (__raw_readl(addr + PUD_OFFSET) >> (n * 2)) & 0x3;
119 S3C_PMDBG("PUD[%d]: %x (%x recommended)\n",
120 g->num, value, g->pud);
123 value = (__raw_readl(addr + DRV_OFFSET) >> (n * 2)) & 0x3;
125 S3C_PMDBG("DRV[%d]: %x (%x recommended)\n",
126 g->num, value, g->drv);
130 int mobile_get_gpio(int pin)
136 size = gpios_data->gpios_size;
139 return gpios_data->gpios[pin];
141 return gpios_data->gpios[pin - size];
144 void mobile_gpios_register(struct mobile_gpios_data *data)
146 struct s5p_gpio_group_info *info;
150 gpios_data = kmalloc(sizeof(struct mobile_gpios_data), GFP_KERNEL);
153 info = gpios_data->infos;
154 size = gpios_data->infos_size;
156 for (i = 0; i < size; i++)
157 setup_gpio_group(info[i].base, info[i].offset, info[i].group, info[i].size);
159 printk("It is already registered.\n");
162 void mobile_gpios_groupx_difference(void)
164 struct s5p_gpio_group *x0, *x1, *x2, *x3;
165 int x0_size, x1_size, x2_size, x3_size;
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;
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);
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);
198 void mobile_gpios_init(void)
200 /* Check hwrev to call properly gpio_init function */
201 if (machine_is_slp7_c210() || machine_is_nuri())
202 mobile_gpios_init_slp7();
204 else if (machine_is_slp10_c210())
205 mobile_gpios_init_slp10();
207 else if (machine_is_c1_c210())
208 mobile_gpios_init_c1();
210 else if (machine_is_u1_c210())
211 mobile_gpios_init_u1();
213 else if (machine_is_u1hd_c210())
214 mobile_gpios_init_u1hd();
216 else if (machine_is_q1_c210())
217 mobile_gpios_init_q1();
219 else if (machine_is_p8_c210())
220 mobile_gpios_init_p8();
223 printk(KERN_ERR "%s: The board isn't identifid\n", __func__);
226 - If you want to add the new board with S5PV310 SoC,
227 you should add gpio_init function related to new board. */