Commit | Line | Data |
---|---|---|
6fa3eb70 S |
1 | |
2 | #include <ssw.h> | |
3 | ||
4 | /*--------------Feature option---------------*/ | |
5 | #define __ENABLE_SSW_SYSFS 1 | |
6 | ||
7 | ||
8 | /*--------------SIM mode list----------------*/ | |
9 | #define SINGLE_TALK_MDSYS (0x1) | |
10 | #define SINGLE_TALK_MDSYS_LITE (0x2) | |
11 | #define DUAL_TALK (0x3) | |
12 | #define DUAL_TALK_SWAP (0x4) | |
13 | ||
14 | /*----------------Error Code-----------------*/ | |
15 | #define SSW_SUCCESS (0) | |
16 | #define SSW_INVALID_PARA (-1) | |
17 | ||
18 | ||
19 | /*--------------Global varible---------------*/ | |
20 | unsigned int sim_mode_curr = SINGLE_TALK_MDSYS; | |
21 | ||
22 | unsigned int get_sim_switch_type(void) | |
23 | { | |
24 | printk("[ccci/ssw]SSW_GENERIC\n"); | |
25 | return SSW_INTERN; | |
26 | } | |
27 | EXPORT_SYMBOL(get_sim_switch_type); | |
28 | ||
29 | struct mutex sim_switch_mutex; | |
30 | ||
31 | ||
32 | static inline void sim_switch_writel(void *addr, unsigned offset, u32 data) | |
33 | { | |
34 | *((volatile unsigned int*)(addr + offset)) = data; | |
35 | } | |
36 | ||
37 | static inline u32 sim_switch_readl(const void *addr, unsigned offset) | |
38 | { | |
39 | ||
40 | u32 rc = 0; | |
41 | rc = *((volatile unsigned int*)(addr + offset)); | |
42 | return rc; | |
43 | } | |
44 | ||
45 | static int set_sim_gpio(unsigned int mode); | |
46 | static int get_current_ssw_mode(void); | |
47 | ||
48 | /*---------------------------------------------------------------------------*/ | |
49 | /*define sysfs entry for configuring debug level and sysrq*/ | |
50 | ssize_t ssw_attr_show(struct kobject *kobj, struct attribute *attr, char *buffer); | |
51 | ssize_t ssw_attr_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size); | |
52 | ssize_t ssw_mode_show(struct kobject *kobj, char *page); | |
53 | ssize_t ssw_mode_store(struct kobject *kobj, const char *page, size_t size); | |
54 | ||
55 | struct sysfs_ops ssw_sysfs_ops = { | |
56 | .show = ssw_attr_show, | |
57 | .store = ssw_attr_store, | |
58 | }; | |
59 | ||
60 | struct ssw_sys_entry { | |
61 | struct attribute attr; | |
62 | ssize_t (*show)(struct kobject *kobj, char *page); | |
63 | ssize_t (*store)(struct kobject *kobj, const char *page, size_t size); | |
64 | }; | |
65 | ||
66 | static struct ssw_sys_entry mode_entry = { | |
67 | { .name = "mode", .mode = S_IRUGO | S_IWUSR }, // remove .owner = NULL, | |
68 | ssw_mode_show, | |
69 | ssw_mode_store, | |
70 | }; | |
71 | ||
72 | struct attribute *ssw_attributes[] = { | |
73 | &mode_entry.attr, | |
74 | NULL, | |
75 | }; | |
76 | ||
77 | struct kobj_type ssw_ktype = { | |
78 | .sysfs_ops = &ssw_sysfs_ops, | |
79 | .default_attrs = ssw_attributes, | |
80 | }; | |
81 | ||
82 | static struct ssw_sysobj_t { | |
83 | struct kobject kobj; | |
84 | } ssw_sysobj; | |
85 | ||
86 | ||
87 | int ssw_sysfs_init(void) | |
88 | { | |
89 | struct ssw_sysobj_t *obj = &ssw_sysobj; | |
90 | ||
91 | memset(&obj->kobj, 0x00, sizeof(obj->kobj)); | |
92 | ||
93 | obj->kobj.parent = kernel_kobj; | |
94 | if (kobject_init_and_add(&obj->kobj, &ssw_ktype, NULL, "mtk_ssw")) { | |
95 | kobject_put(&obj->kobj); | |
96 | return -ENOMEM; | |
97 | } | |
98 | kobject_uevent(&obj->kobj, KOBJ_ADD); | |
99 | ||
100 | return 0; | |
101 | } | |
102 | ||
103 | ssize_t ssw_attr_show(struct kobject *kobj, struct attribute *attr, char *buffer) | |
104 | { | |
105 | struct ssw_sys_entry *entry = container_of(attr, struct ssw_sys_entry, attr); | |
106 | return entry->show(kobj, buffer); | |
107 | } | |
108 | ||
109 | ssize_t ssw_attr_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size) | |
110 | { | |
111 | struct ssw_sys_entry *entry = container_of(attr, struct ssw_sys_entry, attr); | |
112 | return entry->store(kobj, buffer, size); | |
113 | } | |
114 | ||
115 | ssize_t ssw_mode_show(struct kobject *kobj, char *buffer) | |
116 | { | |
117 | int remain = PAGE_SIZE; | |
118 | int len; | |
119 | char *ptr = buffer; | |
120 | ||
121 | len = scnprintf(ptr, remain, "0x%x\n", get_current_ssw_mode()); | |
122 | ptr += len; | |
123 | remain -= len; | |
124 | SSW_DBG("ssw_mode_show\n"); | |
125 | ||
126 | return (PAGE_SIZE-remain); | |
127 | } | |
128 | ||
129 | ssize_t ssw_mode_store(struct kobject *kobj, const char *buffer, size_t size) | |
130 | { | |
131 | int mode; | |
132 | int res = sscanf(buffer, "%x", &mode); | |
133 | ||
134 | if (res != 1) | |
135 | { | |
136 | printk("%s: expect 1 numbers\n", __FUNCTION__); | |
137 | } | |
138 | else | |
139 | { | |
140 | SSW_DBG("ssw_mode_store %d\n", mode); | |
141 | //Switch sim mode | |
142 | if ((sim_mode_curr != mode) && (SSW_SUCCESS == set_sim_gpio(mode))) | |
143 | { | |
144 | sim_mode_curr = mode; | |
145 | } | |
146 | } | |
147 | return size; | |
148 | } | |
149 | /*---------------------------------------------------------------------------*/ | |
150 | ||
151 | ||
152 | ||
153 | int get_current_ssw_mode(void) | |
154 | { | |
155 | return sim_mode_curr; | |
156 | } | |
157 | ||
158 | ||
159 | static int set_sim_gpio(unsigned int mode) | |
160 | { | |
161 | SSW_DBG("set_sim_gpio %d\n", mode); | |
162 | ||
163 | switch(mode) | |
164 | { | |
165 | case SINGLE_TALK_MDSYS: | |
166 | #if defined(GPIO_SIM1_SCLK) && defined(GPIO_SIM1_SIO) && defined(GPIO_SIM2_SCLK) && defined(GPIO_SIM2_SIO) | |
167 | mt_set_gpio_mode(GPIO_SIM1_SCLK, 1); //SIM1_SCLK | |
168 | mt_set_gpio_mode(GPIO_SIM1_SIO, 1); //SIM1_SIO | |
169 | mt_set_gpio_mode(GPIO_SIM2_SCLK, 1); //SIM2_SCLK | |
170 | mt_set_gpio_mode(GPIO_SIM2_SIO, 1); //SIM2_SIO | |
171 | //mt_set_gpio_mode(GPIO_SIM1_SRST, 4); //SIM1_SRST, 6582 not use reset pin | |
172 | //mt_set_gpio_mode(GPIO_SIM2_SRST, 4); //SIM2_SRST, 6582 not use reset pin | |
173 | #endif | |
174 | break; | |
175 | ||
176 | default: | |
177 | SSW_DBG("Mode(%d) not supported!!!", mode); | |
178 | return SSW_INVALID_PARA; | |
179 | } | |
180 | ||
181 | #if 0 | |
182 | SSW_DBG("Current sim mode(%d), GPIO0_MODE(%d, %d), GPIO1_MODE(%d, %d), GPIO2_MODE(%d, %d), GPIO3_MODE(%d, %d), GPIO89_MODE(%d, %d), GPIO90_MODE(%d, %d)\n", \ | |
183 | mode, mt_get_gpio_mode(GPIO0), mt_get_gpio_dir(GPIO0), mt_get_gpio_mode(GPIO1), mt_get_gpio_dir(GPIO1), \ | |
184 | mt_get_gpio_mode(GPIO2), mt_get_gpio_dir(GPIO2), mt_get_gpio_mode(GPIO3), mt_get_gpio_dir(GPIO3), \ | |
185 | mt_get_gpio_mode(GPIO89), mt_get_gpio_dir(GPIO89), mt_get_gpio_mode(GPIO90), mt_get_gpio_dir(GPIO90)); | |
186 | #else | |
187 | #if defined(GPIO_SIM1_SCLK) && defined(GPIO_SIM1_SIO) && defined(GPIO_SIM2_SCLK) && defined(GPIO_SIM2_SIO) | |
188 | SSW_DBG("Current sim mode(%d), GPIO_SIM1_SCLK_MODE(%d, %d), GPIO_SIM1_SIO_MODE(%d, %d), GPIO_SIM2_SCLK_MODE(%d, %d), GPIO_SIM2_SIO_MODE(%d, %d)\n", \ | |
189 | mode, mt_get_gpio_mode(GPIO_SIM1_SCLK), mt_get_gpio_dir(GPIO_SIM1_SCLK), mt_get_gpio_mode(GPIO_SIM1_SIO), mt_get_gpio_dir(GPIO_SIM1_SIO), \ | |
190 | mt_get_gpio_mode(GPIO_SIM2_SCLK), mt_get_gpio_dir(GPIO_SIM2_SCLK), mt_get_gpio_mode(GPIO_SIM2_SIO), mt_get_gpio_dir(GPIO_SIM2_SIO)); | |
191 | #endif | |
192 | #endif | |
193 | ||
194 | return SSW_SUCCESS; | |
195 | } | |
196 | ||
197 | ||
198 | int switch_sim_mode(int id, char *buf, unsigned int len) | |
199 | { | |
200 | unsigned int mode = *((unsigned int *)buf); | |
201 | ||
202 | SSW_DBG("sim switch: %d(%d)\n", mode, sim_mode_curr); | |
203 | ||
204 | mutex_lock(&sim_switch_mutex); | |
205 | ||
206 | if ((sim_mode_curr != mode) && (SSW_SUCCESS == set_sim_gpio(mode))) | |
207 | { | |
208 | sim_mode_curr = mode; | |
209 | } | |
210 | ||
211 | mutex_unlock(&sim_switch_mutex); | |
212 | ||
213 | SSW_DBG("sim switch(%d) OK\n", sim_mode_curr); | |
214 | ||
215 | return 0; | |
216 | ||
217 | } | |
218 | EXPORT_SYMBOL(switch_sim_mode); | |
219 | ||
220 | //To decide sim mode according to compile option | |
221 | static int get_sim_mode_init(void) | |
222 | { | |
223 | unsigned int sim_mode = 0; | |
224 | unsigned int md1_enable, md2_enable = 0; | |
225 | ||
226 | md1_enable = get_modem_is_enabled(MD_SYS1); | |
227 | md2_enable = get_modem_is_enabled(MD_SYS2); | |
228 | ||
229 | if (md1_enable){ | |
230 | sim_mode = SINGLE_TALK_MDSYS; | |
231 | if (md2_enable) | |
232 | sim_mode = DUAL_TALK; | |
233 | } | |
234 | else if (md2_enable) | |
235 | sim_mode = SINGLE_TALK_MDSYS_LITE; | |
236 | ||
237 | return sim_mode; | |
238 | } | |
239 | ||
240 | //sim switch hardware initial | |
241 | static int sim_switch_init(void) | |
242 | { | |
243 | SSW_DBG("sim_switch_init\n"); | |
244 | ||
245 | //better to set pull_en and pull_sel first, then mode | |
246 | //if GPIO in sim mode, no need to set direction, because hw has done this when setting mode | |
247 | /* | |
248 | mt_set_gpio_dir(GPIO_SIM1_SCLK, GPIO_DIR_OUT); //GPIO0->SIM2_CLK, out | |
249 | mt_set_gpio_dir(GPIO_SIM1_SIO, GPIO_DIR_IN); //GPIO1->SIM2_SIO, in | |
250 | mt_set_gpio_dir(GPIO_SIM2_SCLK, GPIO_DIR_OUT); //GPIO2->SIM1_CLK, out | |
251 | mt_set_gpio_dir(GPIO_SIM2_SIO, GPIO_DIR_IN); //GPIO3->SIM1_SIO, in | |
252 | */ | |
253 | //mt_set_gpio_dir(GPIO89, GPIO_DIR_OUT); //GPIO89->SIM1_SRST, out, 6572 not use reset pin | |
254 | //mt_set_gpio_dir(GPIO90, GPIO_DIR_OUT); //GPIO90->SIM2_SRST, out, 6572 not use reset pin | |
255 | ||
256 | sim_mode_curr = get_sim_mode_init(); | |
257 | if (SSW_SUCCESS != set_sim_gpio(sim_mode_curr)) | |
258 | { | |
259 | SSW_DBG("sim_switch_init fail \n"); | |
260 | return SSW_INVALID_PARA; | |
261 | } | |
262 | ||
263 | return 0; | |
264 | } | |
265 | ||
266 | ||
267 | static int sim_switch_probe(struct platform_device *dev) | |
268 | { | |
269 | SSW_DBG("Enter sim_switch_probe\n"); | |
270 | ||
271 | //sim_switch_init(); | |
272 | ||
273 | mutex_init(&sim_switch_mutex); | |
274 | ||
275 | //register_ccci_kern_func(ID_SSW_SWITCH_MODE, switch_sim_mode); | |
276 | ||
277 | return 0; | |
278 | } | |
279 | ||
280 | static int sim_switch_remove(struct platform_device *dev) | |
281 | { | |
282 | //SSW_DBG("sim_switch_remove \n"); | |
283 | return 0; | |
284 | } | |
285 | ||
286 | static void sim_switch_shutdown(struct platform_device *dev) | |
287 | { | |
288 | //SSW_DBG("sim_switch_shutdown \n"); | |
289 | } | |
290 | ||
291 | static int sim_switch_suspend(struct platform_device *dev, pm_message_t state) | |
292 | { | |
293 | //SSW_DBG("sim_switch_suspend \n"); | |
294 | return 0; | |
295 | } | |
296 | ||
297 | static int sim_switch_resume(struct platform_device *dev) | |
298 | { | |
299 | //SSW_DBG("sim_switch_resume \n"); | |
300 | return 0; | |
301 | } | |
302 | ||
303 | ||
304 | static struct platform_driver sim_switch_driver = | |
305 | { | |
306 | .driver = { | |
307 | .name = "sim-switch", | |
308 | }, | |
309 | .probe = sim_switch_probe, | |
310 | .remove = sim_switch_remove, | |
311 | .shutdown = sim_switch_shutdown, | |
312 | .suspend = sim_switch_suspend, | |
313 | .resume = sim_switch_resume, | |
314 | }; | |
315 | ||
316 | ||
317 | static int __init sim_switch_driver_init(void) | |
318 | { | |
319 | int ret = 0; | |
320 | ||
321 | SSW_DBG("sim_switch_driver_init\n"); | |
322 | ret = platform_driver_register(&sim_switch_driver); | |
323 | if (ret) { | |
324 | SSW_DBG("ssw_driver register fail(%d)\n", ret); | |
325 | return ret; | |
326 | } | |
327 | #if __ENABLE_SSW_SYSFS | |
328 | ssw_sysfs_init(); | |
329 | #endif | |
330 | ||
331 | sim_switch_init(); | |
332 | ||
333 | return ret; | |
334 | } | |
335 | ||
336 | ||
337 | static void __exit sim_switch_driver_exit(void) | |
338 | { | |
339 | return; | |
340 | } | |
341 | ||
342 | ||
343 | module_init(sim_switch_driver_init); | |
344 | module_exit(sim_switch_driver_exit); | |
345 | ||
346 | ||
347 | MODULE_DESCRIPTION("MTK SIM Switch Driver"); | |
348 | MODULE_AUTHOR("Anny <Anny.Hu@mediatek.com>"); | |
349 | MODULE_LICENSE("GPL"); |