blob: 635ef312053e745370c6ccfeaffa14c2bf17fd84 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* linux/arch/arm/mach-msm/rpc_hsusb.c
2 *
3 * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
4 *
5 * All source code in this file is licensed under the following license except
6 * where indicated.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published
10 * by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 *
16 * See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you can find it at http://www.fsf.org
19 */
20
21#include <linux/err.h>
22#include <linux/slab.h>
23#include <mach/rpc_hsusb.h>
24#include <asm/mach-types.h>
25
26static struct msm_rpc_endpoint *usb_ep;
27static struct msm_rpc_endpoint *chg_ep;
28
29#define MSM_RPC_CHG_PROG 0x3000001a
30
31struct msm_chg_rpc_ids {
32 unsigned long vers_comp;
33 unsigned chg_usb_charger_connected_proc;
34 unsigned chg_usb_charger_disconnected_proc;
35 unsigned chg_usb_i_is_available_proc;
36 unsigned chg_usb_i_is_not_available_proc;
37};
38
39struct msm_hsusb_rpc_ids {
40 unsigned long prog;
41 unsigned long vers_comp;
42 unsigned long init_phy;
43 unsigned long vbus_pwr_up;
44 unsigned long vbus_pwr_down;
45 unsigned long update_product_id;
46 unsigned long update_serial_num;
47 unsigned long update_is_serial_num_null;
48 unsigned long reset_rework_installed;
49 unsigned long enable_pmic_ulpi_data0;
50 unsigned long disable_pmic_ulpi_data0;
51};
52
53static struct msm_hsusb_rpc_ids usb_rpc_ids;
54static struct msm_chg_rpc_ids chg_rpc_ids;
55
56static int msm_hsusb_init_rpc_ids(unsigned long vers)
57{
58 if (vers == 0x00010001) {
59 usb_rpc_ids.prog = 0x30000064;
60 usb_rpc_ids.vers_comp = 0x00010001;
61 usb_rpc_ids.init_phy = 2;
62 usb_rpc_ids.vbus_pwr_up = 6;
63 usb_rpc_ids.vbus_pwr_down = 7;
64 usb_rpc_ids.update_product_id = 8;
65 usb_rpc_ids.update_serial_num = 9;
66 usb_rpc_ids.update_is_serial_num_null = 10;
67 usb_rpc_ids.reset_rework_installed = 17;
68 usb_rpc_ids.enable_pmic_ulpi_data0 = 18;
69 usb_rpc_ids.disable_pmic_ulpi_data0 = 19;
70 return 0;
71 } else if (vers == 0x00010002) {
72 usb_rpc_ids.prog = 0x30000064;
73 usb_rpc_ids.vers_comp = 0x00010002;
74 usb_rpc_ids.init_phy = 2;
75 usb_rpc_ids.vbus_pwr_up = 6;
76 usb_rpc_ids.vbus_pwr_down = 7;
77 usb_rpc_ids.update_product_id = 8;
78 usb_rpc_ids.update_serial_num = 9;
79 usb_rpc_ids.update_is_serial_num_null = 10;
80 usb_rpc_ids.reset_rework_installed = 17;
81 usb_rpc_ids.enable_pmic_ulpi_data0 = 18;
82 usb_rpc_ids.disable_pmic_ulpi_data0 = 19;
83 return 0;
84 } else {
85 pr_err("%s: no matches found for version\n",
86 __func__);
87 return -ENODATA;
88 }
89}
90
91static int msm_chg_init_rpc(unsigned long vers)
92{
93 if (((vers & RPC_VERSION_MAJOR_MASK) == 0x00010000) ||
94 ((vers & RPC_VERSION_MAJOR_MASK) == 0x00020000) ||
95 ((vers & RPC_VERSION_MAJOR_MASK) == 0x00030000) ||
96 ((vers & RPC_VERSION_MAJOR_MASK) == 0x00040000)) {
97 chg_ep = msm_rpc_connect_compatible(MSM_RPC_CHG_PROG, vers,
98 MSM_RPC_UNINTERRUPTIBLE);
99 if (IS_ERR(chg_ep))
100 return -ENODATA;
101 chg_rpc_ids.vers_comp = vers;
102 chg_rpc_ids.chg_usb_charger_connected_proc = 7;
103 chg_rpc_ids.chg_usb_charger_disconnected_proc = 8;
104 chg_rpc_ids.chg_usb_i_is_available_proc = 9;
105 chg_rpc_ids.chg_usb_i_is_not_available_proc = 10;
106 return 0;
107 } else
108 return -ENODATA;
109}
110
111/* rpc connect for hsusb */
112int msm_hsusb_rpc_connect(void)
113{
114
115 if (usb_ep && !IS_ERR(usb_ep)) {
116 pr_debug("%s: usb_ep already connected\n", __func__);
117 return 0;
118 }
119
120 /* Initialize rpc ids */
121 if (msm_hsusb_init_rpc_ids(0x00010001)) {
122 pr_err("%s: rpc ids initialization failed\n"
123 , __func__);
124 return -ENODATA;
125 }
126
127 usb_ep = msm_rpc_connect_compatible(usb_rpc_ids.prog,
128 usb_rpc_ids.vers_comp,
129 MSM_RPC_UNINTERRUPTIBLE);
130
131 if (IS_ERR(usb_ep)) {
132 pr_err("%s: connect compatible failed vers = %lx\n",
133 __func__, usb_rpc_ids.vers_comp);
134
135 /* Initialize rpc ids */
136 if (msm_hsusb_init_rpc_ids(0x00010002)) {
137 pr_err("%s: rpc ids initialization failed\n",
138 __func__);
139 return -ENODATA;
140 }
141 usb_ep = msm_rpc_connect_compatible(usb_rpc_ids.prog,
142 usb_rpc_ids.vers_comp,
143 MSM_RPC_UNINTERRUPTIBLE);
144 }
145
146 if (IS_ERR(usb_ep)) {
147 pr_err("%s: connect compatible failed vers = %lx\n",
148 __func__, usb_rpc_ids.vers_comp);
149 return -EAGAIN;
150 } else
151 pr_debug("%s: rpc connect success vers = %lx\n",
152 __func__, usb_rpc_ids.vers_comp);
153
154 return 0;
155}
156EXPORT_SYMBOL(msm_hsusb_rpc_connect);
157
158/* rpc connect for charging */
159int msm_chg_rpc_connect(void)
160{
161 uint32_t chg_vers;
162
163 if (machine_is_msm7x27_surf() || machine_is_qsd8x50_surf())
164 return -ENOTSUPP;
165
166 if (chg_ep && !IS_ERR(chg_ep)) {
167 pr_debug("%s: chg_ep already connected\n", __func__);
168 return 0;
169 }
170
171 chg_vers = 0x00040001;
172 if (!msm_chg_init_rpc(chg_vers))
173 goto chg_found;
174
175 chg_vers = 0x00030001;
176 if (!msm_chg_init_rpc(chg_vers))
177 goto chg_found;
178
179 chg_vers = 0x00020001;
180 if (!msm_chg_init_rpc(chg_vers))
181 goto chg_found;
182
183 chg_vers = 0x00010001;
184 if (!msm_chg_init_rpc(chg_vers))
185 goto chg_found;
186
187 pr_err("%s: connect compatible failed \n",
188 __func__);
189 return -EAGAIN;
190
191chg_found:
192 pr_debug("%s: connected to rpc vers = %x\n",
193 __func__, chg_vers);
194 return 0;
195}
196EXPORT_SYMBOL(msm_chg_rpc_connect);
197
198/* rpc call for phy_reset */
199int msm_hsusb_phy_reset(void)
200{
201 int rc = 0;
202 struct hsusb_phy_start_req {
203 struct rpc_request_hdr hdr;
204 } req;
205
206 if (!usb_ep || IS_ERR(usb_ep)) {
207 pr_err("%s: phy_reset rpc failed before call,"
208 "rc = %ld\n", __func__, PTR_ERR(usb_ep));
209 return -EAGAIN;
210 }
211
212 rc = msm_rpc_call(usb_ep, usb_rpc_ids.init_phy,
213 &req, sizeof(req), 5 * HZ);
214
215 if (rc < 0) {
216 pr_err("%s: phy_reset rpc failed! rc = %d\n",
217 __func__, rc);
218 } else
219 pr_debug("msm_hsusb_phy_reset\n");
220
221 return rc;
222}
223EXPORT_SYMBOL(msm_hsusb_phy_reset);
224
225/* rpc call for vbus powerup */
226int msm_hsusb_vbus_powerup(void)
227{
228 int rc = 0;
229 struct hsusb_phy_start_req {
230 struct rpc_request_hdr hdr;
231 } req;
232
233 if (!usb_ep || IS_ERR(usb_ep)) {
234 pr_err("%s: vbus_powerup rpc failed before call,"
235 "rc = %ld\n", __func__, PTR_ERR(usb_ep));
236 return -EAGAIN;
237 }
238
239 rc = msm_rpc_call(usb_ep, usb_rpc_ids.vbus_pwr_up,
240 &req, sizeof(req), 5 * HZ);
241
242 if (rc < 0) {
243 pr_err("%s: vbus_powerup failed! rc = %d\n",
244 __func__, rc);
245 } else
246 pr_debug("msm_hsusb_vbus_powerup\n");
247
248 return rc;
249}
250EXPORT_SYMBOL(msm_hsusb_vbus_powerup);
251
252/* rpc call for vbus shutdown */
253int msm_hsusb_vbus_shutdown(void)
254{
255 int rc = 0;
256 struct hsusb_phy_start_req {
257 struct rpc_request_hdr hdr;
258 } req;
259
260 if (!usb_ep || IS_ERR(usb_ep)) {
261 pr_err("%s: vbus_shutdown rpc failed before call,"
262 "rc = %ld\n", __func__, PTR_ERR(usb_ep));
263 return -EAGAIN;
264 }
265
266 rc = msm_rpc_call(usb_ep, usb_rpc_ids.vbus_pwr_down,
267 &req, sizeof(req), 5 * HZ);
268
269 if (rc < 0) {
270 pr_err("%s: vbus_shutdown failed! rc = %d\n",
271 __func__, rc);
272 } else
273 pr_debug("msm_hsusb_vbus_shutdown\n");
274
275 return rc;
276}
277EXPORT_SYMBOL(msm_hsusb_vbus_shutdown);
278
279int msm_hsusb_send_productID(uint32_t product_id)
280{
281 int rc = 0;
282 struct hsusb_phy_start_req {
283 struct rpc_request_hdr hdr;
284 uint32_t product_id;
285 } req;
286
287 if (!usb_ep || IS_ERR(usb_ep)) {
288 pr_err("%s: rpc connect failed: rc = %ld\n",
289 __func__, PTR_ERR(usb_ep));
290 return -EAGAIN;
291 }
292
293 req.product_id = cpu_to_be32(product_id);
294 rc = msm_rpc_call(usb_ep, usb_rpc_ids.update_product_id,
295 &req, sizeof(req),
296 5 * HZ);
297 if (rc < 0)
298 pr_err("%s: rpc call failed! error: %d\n",
299 __func__, rc);
300 else
301 pr_debug("%s: rpc call success\n" , __func__);
302
303 return rc;
304}
305EXPORT_SYMBOL(msm_hsusb_send_productID);
306
307int msm_hsusb_send_serial_number(const char *serial_number)
308{
309 int rc = 0, serial_len, rlen;
310 struct hsusb_send_sn_req {
311 struct rpc_request_hdr hdr;
312 uint32_t length;
313 char sn[0];
314 } *req;
315
316 if (!usb_ep || IS_ERR(usb_ep)) {
317 pr_err("%s: rpc connect failed: rc = %ld\n",
318 __func__, PTR_ERR(usb_ep));
319 return -EAGAIN;
320 }
321
322 /*
323 * USB driver passes null terminated string to us. Modem processor
324 * expects serial number to be 32 bit aligned.
325 */
326 serial_len = strlen(serial_number)+1;
327 rlen = sizeof(struct rpc_request_hdr) + sizeof(uint32_t) +
328 ((serial_len + 3) & ~3);
329
330 req = kmalloc(rlen, GFP_KERNEL);
331 if (!req)
332 return -ENOMEM;
333
334 req->length = cpu_to_be32(serial_len);
335 strncpy(req->sn , serial_number, serial_len);
336 rc = msm_rpc_call(usb_ep, usb_rpc_ids.update_serial_num,
337 req, rlen, 5 * HZ);
338 if (rc < 0)
339 pr_err("%s: rpc call failed! error: %d\n",
340 __func__, rc);
341 else
342 pr_debug("%s: rpc call success\n", __func__);
343
344 kfree(req);
345 return rc;
346}
347EXPORT_SYMBOL(msm_hsusb_send_serial_number);
348
349int msm_hsusb_is_serial_num_null(uint32_t val)
350{
351 int rc = 0;
352 struct hsusb_phy_start_req {
353 struct rpc_request_hdr hdr;
354 uint32_t value;
355 } req;
356
357 if (!usb_ep || IS_ERR(usb_ep)) {
358 pr_err("%s: rpc connect failed: rc = %ld\n",
359 __func__, PTR_ERR(usb_ep));
360 return -EAGAIN;
361 }
362 if (!usb_rpc_ids.update_is_serial_num_null) {
363 pr_err("%s: proc id not supported \n", __func__);
364 return -ENODATA;
365 }
366
367 req.value = cpu_to_be32(val);
368 rc = msm_rpc_call(usb_ep, usb_rpc_ids.update_is_serial_num_null,
369 &req, sizeof(req),
370 5 * HZ);
371 if (rc < 0)
372 pr_err("%s: rpc call failed! error: %d\n" ,
373 __func__, rc);
374 else
375 pr_debug("%s: rpc call success\n", __func__);
376
377 return rc;
378}
379EXPORT_SYMBOL(msm_hsusb_is_serial_num_null);
380
381int msm_chg_usb_charger_connected(uint32_t device)
382{
383 int rc = 0;
384 struct hsusb_start_req {
385 struct rpc_request_hdr hdr;
386 uint32_t otg_dev;
387 } req;
388
389 if (!chg_ep || IS_ERR(chg_ep))
390 return -EAGAIN;
391 req.otg_dev = cpu_to_be32(device);
392 rc = msm_rpc_call(chg_ep, chg_rpc_ids.chg_usb_charger_connected_proc,
393 &req, sizeof(req), 5 * HZ);
394
395 if (rc < 0) {
396 pr_err("%s: charger_connected failed! rc = %d\n",
397 __func__, rc);
398 } else
399 pr_debug("msm_chg_usb_charger_connected\n");
400
401 return rc;
402}
403EXPORT_SYMBOL(msm_chg_usb_charger_connected);
404
405int msm_chg_usb_i_is_available(uint32_t sample)
406{
407 int rc = 0;
408 struct hsusb_start_req {
409 struct rpc_request_hdr hdr;
410 uint32_t i_ma;
411 } req;
412
413 if (!chg_ep || IS_ERR(chg_ep))
414 return -EAGAIN;
415 req.i_ma = cpu_to_be32(sample);
416 rc = msm_rpc_call(chg_ep, chg_rpc_ids.chg_usb_i_is_available_proc,
417 &req, sizeof(req), 5 * HZ);
418
419 if (rc < 0) {
420 pr_err("%s: charger_i_available failed! rc = %d\n",
421 __func__, rc);
422 } else
423 pr_debug("msm_chg_usb_i_is_available(%u)\n", sample);
424
425 return rc;
426}
427EXPORT_SYMBOL(msm_chg_usb_i_is_available);
428
429int msm_chg_usb_i_is_not_available(void)
430{
431 int rc = 0;
432 struct hsusb_start_req {
433 struct rpc_request_hdr hdr;
434 } req;
435
436 if (!chg_ep || IS_ERR(chg_ep))
437 return -EAGAIN;
438 rc = msm_rpc_call(chg_ep, chg_rpc_ids.chg_usb_i_is_not_available_proc,
439 &req, sizeof(req), 5 * HZ);
440
441 if (rc < 0) {
442 pr_err("%s: charger_i_not_available failed! rc ="
443 "%d \n", __func__, rc);
444 } else
445 pr_debug("msm_chg_usb_i_is_not_available\n");
446
447 return rc;
448}
449EXPORT_SYMBOL(msm_chg_usb_i_is_not_available);
450
451int msm_chg_usb_charger_disconnected(void)
452{
453 int rc = 0;
454 struct hsusb_start_req {
455 struct rpc_request_hdr hdr;
456 } req;
457
458 if (!chg_ep || IS_ERR(chg_ep))
459 return -EAGAIN;
460 rc = msm_rpc_call(chg_ep, chg_rpc_ids.chg_usb_charger_disconnected_proc,
461 &req, sizeof(req), 5 * HZ);
462
463 if (rc < 0) {
464 pr_err("%s: charger_disconnected failed! rc = %d\n",
465 __func__, rc);
466 } else
467 pr_debug("msm_chg_usb_charger_disconnected\n");
468
469 return rc;
470}
471EXPORT_SYMBOL(msm_chg_usb_charger_disconnected);
472
473/* rpc call to close connection */
474int msm_hsusb_rpc_close(void)
475{
476 int rc = 0;
477
478 if (IS_ERR(usb_ep)) {
479 pr_err("%s: rpc_close failed before call, rc = %ld\n",
480 __func__, PTR_ERR(usb_ep));
481 return -EAGAIN;
482 }
483
484 rc = msm_rpc_close(usb_ep);
485 usb_ep = NULL;
486
487 if (rc < 0) {
488 pr_err("%s: close rpc failed! rc = %d\n",
489 __func__, rc);
490 return -EAGAIN;
491 } else
492 pr_debug("rpc close success\n");
493
494 return rc;
495}
496EXPORT_SYMBOL(msm_hsusb_rpc_close);
497
498/* rpc call to close charging connection */
499int msm_chg_rpc_close(void)
500{
501 int rc = 0;
502
503 if (IS_ERR(chg_ep)) {
504 pr_err("%s: rpc_close failed before call, rc = %ld\n",
505 __func__, PTR_ERR(chg_ep));
506 return -EAGAIN;
507 }
508
509 rc = msm_rpc_close(chg_ep);
510 chg_ep = NULL;
511
512 if (rc < 0) {
513 pr_err("%s: close rpc failed! rc = %d\n",
514 __func__, rc);
515 return -EAGAIN;
516 } else
517 pr_debug("rpc close success\n");
518
519 return rc;
520}
521EXPORT_SYMBOL(msm_chg_rpc_close);
522
523int msm_hsusb_reset_rework_installed(void)
524{
525 int rc = 0;
526 struct hsusb_start_req {
527 struct rpc_request_hdr hdr;
528 } req;
529 struct hsusb_rpc_rep {
530 struct rpc_reply_hdr hdr;
531 uint32_t rework;
532 } rep;
533
534 memset(&rep, 0, sizeof(rep));
535
536 if (!usb_ep || IS_ERR(usb_ep)) {
537 pr_err("%s: hsusb rpc connection not initialized, rc = %ld\n",
538 __func__, PTR_ERR(usb_ep));
539 return -EAGAIN;
540 }
541
542 rc = msm_rpc_call_reply(usb_ep, usb_rpc_ids.reset_rework_installed,
543 &req, sizeof(req),
544 &rep, sizeof(rep), 5 * HZ);
545
546 if (rc < 0) {
547 pr_err("%s: rpc call failed! error: (%d)"
548 "proc id: (%lx)\n",
549 __func__, rc,
550 usb_rpc_ids.reset_rework_installed);
551 return rc;
552 }
553
554 pr_info("%s: rework: (%d)\n", __func__, rep.rework);
555 return be32_to_cpu(rep.rework);
556}
557EXPORT_SYMBOL(msm_hsusb_reset_rework_installed);
558
559static int msm_hsusb_pmic_ulpidata0_config(int enable)
560{
561 int rc = 0;
562 struct hsusb_start_req {
563 struct rpc_request_hdr hdr;
564 } req;
565
566 if (!usb_ep || IS_ERR(usb_ep)) {
567 pr_err("%s: hsusb rpc connection not initialized, rc = %ld\n",
568 __func__, PTR_ERR(usb_ep));
569 return -EAGAIN;
570 }
571
572 if (enable)
573 rc = msm_rpc_call(usb_ep, usb_rpc_ids.enable_pmic_ulpi_data0,
574 &req, sizeof(req), 5 * HZ);
575 else
576 rc = msm_rpc_call(usb_ep, usb_rpc_ids.disable_pmic_ulpi_data0,
577 &req, sizeof(req), 5 * HZ);
578
579 if (rc < 0)
580 pr_err("%s: rpc call failed! error: %d\n",
581 __func__, rc);
582 return rc;
583}
584
585int msm_hsusb_enable_pmic_ulpidata0(void)
586{
587 return msm_hsusb_pmic_ulpidata0_config(1);
588}
589EXPORT_SYMBOL(msm_hsusb_enable_pmic_ulpidata0);
590
591int msm_hsusb_disable_pmic_ulpidata0(void)
592{
593 return msm_hsusb_pmic_ulpidata0_config(0);
594}
595EXPORT_SYMBOL(msm_hsusb_disable_pmic_ulpidata0);
596
597
598/* wrapper for sending pid and serial# info to bootloader */
599int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum)
600{
601 int ret;
602
603 ret = msm_hsusb_send_productID(pid);
604 if (ret)
605 return ret;
606
607 if (!snum) {
608 ret = msm_hsusb_is_serial_num_null(1);
609 if (ret)
610 return ret;
611 }
612
613 ret = msm_hsusb_is_serial_num_null(0);
614 if (ret)
615 return ret;
616 ret = msm_hsusb_send_serial_number(snum);
617 if (ret)
618 return ret;
619
620 return 0;
621}
622
623
624#ifdef CONFIG_USB_GADGET_MSM_72K
625/* charger api wrappers */
626int hsusb_chg_init(int connect)
627{
628 if (connect)
629 return msm_chg_rpc_connect();
630 else
631 return msm_chg_rpc_close();
632}
633EXPORT_SYMBOL(hsusb_chg_init);
634
635void hsusb_chg_vbus_draw(unsigned mA)
636{
637 msm_chg_usb_i_is_available(mA);
638}
639EXPORT_SYMBOL(hsusb_chg_vbus_draw);
640
641void hsusb_chg_connected(enum chg_type chgtype)
642{
643 char *chg_types[] = {"STD DOWNSTREAM PORT",
644 "CARKIT",
645 "DEDICATED CHARGER",
646 "INVALID"};
647
648 if (chgtype == USB_CHG_TYPE__INVALID) {
649 msm_chg_usb_i_is_not_available();
650 msm_chg_usb_charger_disconnected();
651 return;
652 }
653
654 pr_info("\nCharger Type: %s\n", chg_types[chgtype]);
655
656 msm_chg_usb_charger_connected(chgtype);
657}
658EXPORT_SYMBOL(hsusb_chg_connected);
659#endif