1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
|
/*
* MUSB OTG controller driver for Blackfin Processors
*
* Copyright 2006-2008 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/workqueue.h>
#include <linux/usb/gadget.h>
#include "mach/emi_mpu.h"
#include <linux/mu3d/hal/mu3d_hal_osal.h>
#include "musb_core.h"
#ifdef CONFIG_MTK_UART_USB_SWITCH
#include <linux/mu3phy/mtk-phy-asic.h>
#include <mach/mt_typedefs.h>
#endif
extern struct musb *_mu3d_musb;
#ifdef CONFIG_MTK_UART_USB_SWITCH
typedef enum
{
PORT_MODE_USB = 0,
PORT_MODE_UART,
PORT_MODE_MAX
} PORT_MODE;
extern bool in_uart_mode;
extern void uart_usb_switch_dump_register(void);
extern bool usb_phy_check_in_uart_mode(void);
extern void usb_phy_switch_to_usb(void);
extern void usb_phy_switch_to_uart(void);
extern void __iomem *ap_uart0_base;
#endif
#ifndef FOR_BRING_UP
#ifndef CONFIG_MTK_FPGA
extern void wake_up_bat(void);
#endif
#endif
#ifdef FOR_BRING_UP
static inline void BATTERY_SetUSBState(int usb_state) {};
static inline CHARGER_TYPE mt_charger_type_detection(void) { return STANDARD_HOST; };
static inline bool upmu_is_chr_det(void) { return true; };
static inline u32 upmu_get_rgs_chrdet(void) { return 1; };
#else /* NOT CONFIG_ARM64 */
extern CHARGER_TYPE mt_charger_type_detection(void);
extern bool upmu_is_chr_det(void);
extern void BATTERY_SetUSBState(int usb_state);
extern u32 upmu_get_rgs_chrdet(void);
#endif
#ifdef CONFIG_MTK_XHCI
extern bool mtk_is_host_mode(void);
#else
int mtk_is_host_mode(void){return 0;}
#endif
unsigned int cable_mode = CABLE_MODE_NORMAL;
#ifdef CONFIG_MTK_UART_USB_SWITCH
u32 port_mode = PORT_MODE_USB;
u32 sw_tx = 0;
u32 sw_rx = 0;
u32 sw_uart_path = 0;
#endif
/* ================================ */
/* connect and disconnect functions */
/* ================================ */
bool mt_usb_is_device(void)
{
#ifndef CONFIG_MTK_FPGA
bool tmp = mtk_is_host_mode();
os_printk(K_INFO, "%s mode\n", tmp?"HOST":"DEV");
return !tmp;
#else
return true;
#endif
}
enum status{INIT, ON, OFF};
#ifdef CONFIG_USBIF_COMPLIANCE
static enum status connection_work_dev_status = INIT;
void init_connection_work(void){
connection_work_dev_status = INIT;
}
#endif
#ifndef CONFIG_USBIF_COMPLIANCE
struct timespec connect_timestamp = { 0, 0};
void set_connect_timestamp(void)
{
connect_timestamp = CURRENT_TIME;
pr_debug( "set timestamp = %llu\n", timespec_to_ns(&connect_timestamp));
}
void clr_connect_timestamp(void)
{
connect_timestamp.tv_sec = 0;
connect_timestamp.tv_nsec = 0;
pr_debug( "clr timestamp = %llu\n", timespec_to_ns(&connect_timestamp));
}
struct timespec get_connect_timestamp(void)
{
pr_debug( "get timestamp = %llu\n", timespec_to_ns(&connect_timestamp));
return connect_timestamp;
}
#endif
void connection_work(struct work_struct *data)
{
struct musb *musb = container_of(to_delayed_work(data), struct musb, connection_work);
#ifndef CONFIG_USBIF_COMPLIANCE
static enum status connection_work_dev_status = INIT;
#endif
#ifdef CONFIG_MTK_UART_USB_SWITCH
if (!usb_phy_check_in_uart_mode()) {
#endif
bool is_usb_cable = usb_cable_connected();
#ifndef CONFIG_MTK_FPGA
if(!mt_usb_is_device()){
connection_work_dev_status = OFF;
usb_fake_powerdown(musb->is_clk_on);
musb->is_clk_on = 0;
os_printk(K_INFO, "%s, Host mode. directly return\n", __func__);
return;
}
#endif
os_printk(K_INFO, "%s musb %s, cable %s\n", __func__, ((connection_work_dev_status==0)?"INIT":((connection_work_dev_status==1)?"ON":"OFF")), (is_usb_cable?"IN":"OUT"));
if ((is_usb_cable == true) && (connection_work_dev_status != ON) && (musb->usb_mode == CABLE_MODE_NORMAL)) {
connection_work_dev_status = ON;
#ifndef CONFIG_USBIF_COMPLIANCE
set_connect_timestamp();
#endif
if (!wake_lock_active(&musb->usb_wakelock))
wake_lock(&musb->usb_wakelock);
/* FIXME: Should use usb_udc_start() & usb_gadget_connect(), like usb_udc_softconn_store().
* But have no time to think how to handle. However i think it is the correct way.*/
musb_start(musb);
os_printk(K_INFO, "%s ----Connect----\n", __func__);
} else if (((is_usb_cable == false) && (connection_work_dev_status != OFF)) || (musb->usb_mode != CABLE_MODE_NORMAL)) {
connection_work_dev_status = OFF;
#ifndef CONFIG_USBIF_COMPLIANCE
clr_connect_timestamp();
#endif
/*FIXME: we should use usb_gadget_disconnect() & usb_udc_stop(). like usb_udc_softconn_store().
* But have no time to think how to handle. However i think it is the correct way.*/
musb_stop(musb);
if (wake_lock_active(&musb->usb_wakelock))
wake_unlock(&musb->usb_wakelock);
os_printk(K_INFO, "%s ----Disconnect----\n", __func__);
} else {
/* This if-elseif is to set wakelock when booting with USB cable.
* Because battery driver does _NOT_ notify at this codition.*/
//if( (is_usb_cable == true) && !wake_lock_active(&musb->usb_wakelock)) {
// os_printk(K_INFO, "%s Boot wakelock\n", __func__);
// wake_lock(&musb->usb_wakelock);
//} else if( (is_usb_cable == false) && wake_lock_active(&musb->usb_wakelock)) {
// os_printk(K_INFO, "%s Boot unwakelock\n", __func__);
// wake_unlock(&musb->usb_wakelock);
//}
os_printk(K_INFO, "%s directly return\n", __func__);
}
#ifdef CONFIG_MTK_UART_USB_SWITCH
} else {
#if 0
usb_fake_powerdown(musb->is_clk_on);
musb->is_clk_on = 0;
#else
os_printk(K_INFO, "%s, in UART MODE!!!\n", __func__);
#endif
}
#endif
}
bool mt_usb_is_ready(void)
{
os_printk(K_INFO, "USB is ready or not\n");
#ifdef NEVER
if(!mtk_musb || !mtk_musb->is_ready)
return false;
else
return true;
#endif /* NEVER */
return true;
}
void mt_usb_connect(void)
{
os_printk(K_INFO, "%s+\n", __func__);
if(_mu3d_musb) {
struct delayed_work *work;
work = &_mu3d_musb->connection_work;
schedule_delayed_work_on(0, work, 0);
} else {
os_printk(K_INFO, "%s musb_musb not ready\n", __func__);
}
os_printk(K_INFO, "%s-\n", __func__);
}
EXPORT_SYMBOL_GPL(mt_usb_connect);
void mt_usb_disconnect(void)
{
os_printk(K_INFO, "%s+\n", __func__);
if(_mu3d_musb) {
struct delayed_work *work;
work = &_mu3d_musb->connection_work;
schedule_delayed_work_on(0, work, 0);
} else {
os_printk(K_INFO, "%s musb_musb not ready\n", __func__);
}
os_printk(K_INFO, "%s-\n", __func__);
}
EXPORT_SYMBOL_GPL(mt_usb_disconnect);
bool usb_cable_connected(void)
{
#ifndef CONFIG_MTK_FPGA
#ifdef CONFIG_POWER_EXT
CHARGER_TYPE chg_type = mt_charger_type_detection();
os_printk(K_INFO, "%s ext-chrdet=%d type=%d\n", __func__, upmu_get_rgs_chrdet(), chg_type);
if (upmu_get_rgs_chrdet() && (chg_type == STANDARD_HOST))
{
return true;
}
#else
if (upmu_is_chr_det())
{
CHARGER_TYPE chg_type = mt_charger_type_detection();
os_printk(K_INFO, "%s type=%d\n", __func__, chg_type);
if (chg_type == STANDARD_HOST)
return true;
}
#endif
os_printk(K_INFO, "%s no USB Host detect!\n", __func__);
return false;
#else
os_printk(K_INFO, "%s [FPGA] always true\n", __func__);
return true;
#endif
}
EXPORT_SYMBOL_GPL(usb_cable_connected);
#ifdef NEVER
void musb_platform_reset(struct musb *musb)
{
u16 swrst = 0;
void __iomem *mbase = musb->mregs;
swrst = musb_readw(mbase,MUSB_SWRST);
swrst |= (MUSB_SWRST_DISUSBRESET | MUSB_SWRST_SWRST);
musb_writew(mbase, MUSB_SWRST,swrst);
}
#endif /* NEVER */
void usb_check_connect(void)
{
os_printk(K_INFO, "usb_check_connect\n");
#ifndef CONFIG_MTK_FPGA
if (usb_cable_connected())
mt_usb_connect();
#endif
}
void musb_sync_with_bat(struct musb *musb, int usb_state)
{
os_printk(K_INFO, "musb_sync_with_bat\n");
#ifndef CONFIG_MTK_FPGA
BATTERY_SetUSBState(usb_state);
#ifndef FOR_BRING_UP
wake_up_bat();
#endif
#endif
}
EXPORT_SYMBOL_GPL(musb_sync_with_bat);
/*--FOR INSTANT POWER ON USAGE--------------------------------------------------*/
static inline struct musb *dev_to_musb(struct device *dev)
{
return dev_get_drvdata(dev);
}
const char* const usb_mode_str[CABLE_MODE_MAX] = {"CHRG_ONLY", "NORMAL", "HOST_ONLY"};
ssize_t musb_cmode_show(struct device* dev, struct device_attribute *attr, char *buf)
{
if (!dev) {
os_printk(K_ERR, "dev is null!!\n");
return 0;
}
return sprintf(buf, "%d\n", cable_mode);
}
ssize_t musb_cmode_store(struct device* dev, struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned int cmode;
struct musb *musb = dev_to_musb(dev);
if (!dev) {
os_printk(K_ERR, "dev is null!!\n");
return count;
} else if (1 == sscanf(buf, "%d", &cmode)) {
os_printk(K_INFO, "%s %s --> %s\n", __func__, usb_mode_str[cable_mode], usb_mode_str[cmode]);
if (cmode >= CABLE_MODE_MAX)
cmode = CABLE_MODE_NORMAL;
if (cable_mode != cmode) {
if (cmode == CABLE_MODE_CHRG_ONLY) { // IPO shutdown, disable USB
if(musb) {
musb->usb_mode = CABLE_MODE_CHRG_ONLY;
mt_usb_disconnect();
}
} else if (cmode == CABLE_MODE_HOST_ONLY) {
if(musb) {
musb->usb_mode = CABLE_MODE_HOST_ONLY;
mt_usb_disconnect();
}
} else { // IPO bootup, enable USB
if(musb) {
musb->usb_mode = CABLE_MODE_NORMAL;
mt_usb_connect();
}
}
cable_mode = cmode;
}
}
return count;
}
#ifdef CONFIG_MTK_UART_USB_SWITCH
ssize_t musb_portmode_show(struct device* dev, struct device_attribute *attr, char *buf)
{
if (!dev) {
printk("dev is null!!\n");
return 0;
}
if (usb_phy_check_in_uart_mode())
port_mode = PORT_MODE_UART;
else
port_mode = PORT_MODE_USB;
if (port_mode == PORT_MODE_USB) {
printk("\nUSB Port mode -> USB\n");
} else if (port_mode == PORT_MODE_UART) {
printk("\nUSB Port mode -> UART\n");
}
uart_usb_switch_dump_register();
return scnprintf(buf, PAGE_SIZE, "%d\n", port_mode);
}
ssize_t musb_portmode_store(struct device* dev, struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned int portmode;
if (!dev) {
printk("dev is null!!\n");
return count;
} else if (1 == sscanf(buf, "%d", &portmode)) {
printk("\nUSB Port mode: current => %d (port_mode), change to => %d (portmode)\n", port_mode, portmode);
if (portmode >= PORT_MODE_MAX)
portmode = PORT_MODE_USB;
if (port_mode != portmode) {
if(portmode == PORT_MODE_USB) { // Changing to USB Mode
printk("USB Port mode -> USB\n");
usb_phy_switch_to_usb();
} else if(portmode == PORT_MODE_UART) { // Changing to UART Mode
printk("USB Port mode -> UART\n");
usb_phy_switch_to_uart();
}
uart_usb_switch_dump_register();
port_mode = portmode;
}
}
return count;
}
ssize_t musb_tx_show(struct device* dev, struct device_attribute *attr, char *buf)
{
u8 var;
u8 var2;
if (!dev) {
printk("dev is null!!\n");
return 0;
}
var = U3PhyReadReg8((u3phy_addr_t)(U3D_U2PHYDTM1+0x2));
var2 = (var >> 3) & ~0xFE;
printk("[MUSB]addr: 0x6E (TX), value: %x - %x\n", var, var2);
sw_tx = var;
return scnprintf(buf, PAGE_SIZE, "%x\n", var2);
}
ssize_t musb_tx_store(struct device* dev, struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned int val;
u8 var;
u8 var2;
if (!dev) {
printk("dev is null!!\n");
return count;
} else if (1 == sscanf(buf, "%d", &val)) {
printk("\n Write TX : %d\n", val);
#ifdef CONFIG_MTK_FPGA
var = USB_PHY_Read_Register8(U3D_U2PHYDTM1+0x2);
#else
var = U3PhyReadReg8((u3phy_addr_t)(U3D_U2PHYDTM1+0x2));
#endif
if (val == 0) {
var2 = var & ~(1 << 3);
} else {
var2 = var | (1 << 3);
}
#ifdef CONFIG_MTK_FPGA
USB_PHY_Write_Register8(var2, U3D_U2PHYDTM1+0x2);
var = USB_PHY_Read_Register8(U3D_U2PHYDTM1+0x2);
#else
//U3PhyWriteField32(U3D_USBPHYDTM1+0x2, E60802_RG_USB20_BC11_SW_EN_OFST, E60802_RG_USB20_BC11_SW_EN, 0);
//Jeremy TODO 0320
var = U3PhyReadReg8((u3phy_addr_t)(U3D_U2PHYDTM1+0x2));
#endif
var2 = (var >> 3) & ~0xFE;
printk("[MUSB]addr: U3D_U2PHYDTM1 (0x6E) TX [AFTER WRITE], value after: %x - %x\n", var, var2);
sw_tx = var;
}
return count;
}
ssize_t musb_rx_show(struct device* dev, struct device_attribute *attr, char *buf)
{
u8 var;
u8 var2;
if (!dev) {
printk("dev is null!!\n");
return 0;
}
#ifdef CONFIG_MTK_FPGA
var = USB_PHY_Read_Register8(U3D_U2PHYDMON1+0x3);
#else
var = U3PhyReadReg8((u3phy_addr_t)(U3D_U2PHYDMON1+0x3));
#endif
var2 = (var >> 7) & ~0xFE;
printk("[MUSB]addr: U3D_U2PHYDMON1 (0x77) (RX), value: %x - %x\n", var, var2);
sw_rx = var;
return scnprintf(buf, PAGE_SIZE, "%x\n", var2);
}
ssize_t musb_uart_path_show(struct device* dev, struct device_attribute *attr, char *buf)
{
u8 var=0;
if (!dev) {
printk("dev is null!!\n");
return 0;
}
var = DRV_Reg8(ap_uart0_base + 0xB0);
printk("[MUSB]addr: (UART0) 0xB0, value: %x\n\n", DRV_Reg8(ap_uart0_base + 0xB0));
sw_uart_path = var;
return scnprintf(buf, PAGE_SIZE, "%x\n", var);
}
#endif
#ifdef NEVER
#ifdef CONFIG_MTK_FPGA
static struct i2c_client *usb_i2c_client = NULL;
static const struct i2c_device_id usb_i2c_id[] = {{"mtk-usb",0},{}};
static struct i2c_board_info __initdata usb_i2c_dev = { I2C_BOARD_INFO("mtk-usb", 0x60)};
void USB_PHY_Write_Register8(UINT8 var, UINT8 addr)
{
char buffer[2];
buffer[0] = addr;
buffer[1] = var;
i2c_master_send(usb_i2c_client, &buffer, 2);
}
UINT8 USB_PHY_Read_Register8(UINT8 addr)
{
UINT8 var;
i2c_master_send(usb_i2c_client, &addr, 1);
i2c_master_recv(usb_i2c_client, &var, 1);
return var;
}
static int usb_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
printk("[MUSB]usb_i2c_probe, start\n");
usb_i2c_client = client;
//disable usb mac suspend
DRV_WriteReg8(USB_SIF_BASE + 0x86a, 0x00);
//usb phy initial sequence
USB_PHY_Write_Register8(0x00, 0xFF);
USB_PHY_Write_Register8(0x04, 0x61);
USB_PHY_Write_Register8(0x00, 0x68);
USB_PHY_Write_Register8(0x00, 0x6a);
USB_PHY_Write_Register8(0x6e, 0x00);
USB_PHY_Write_Register8(0x0c, 0x1b);
USB_PHY_Write_Register8(0x44, 0x08);
USB_PHY_Write_Register8(0x55, 0x11);
USB_PHY_Write_Register8(0x68, 0x1a);
printk("[MUSB]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
printk("[MUSB]addr: 0x61, value: %x\n", USB_PHY_Read_Register8(0x61));
printk("[MUSB]addr: 0x68, value: %x\n", USB_PHY_Read_Register8(0x68));
printk("[MUSB]addr: 0x6a, value: %x\n", USB_PHY_Read_Register8(0x6a));
printk("[MUSB]addr: 0x00, value: %x\n", USB_PHY_Read_Register8(0x00));
printk("[MUSB]addr: 0x1b, value: %x\n", USB_PHY_Read_Register8(0x1b));
printk("[MUSB]addr: 0x08, value: %x\n", USB_PHY_Read_Register8(0x08));
printk("[MUSB]addr: 0x11, value: %x\n", USB_PHY_Read_Register8(0x11));
printk("[MUSB]addr: 0x1a, value: %x\n", USB_PHY_Read_Register8(0x1a));
printk("[MUSB]usb_i2c_probe, end\n");
return 0;
}
static int usb_i2c_detect(struct i2c_client *client, int kind, struct i2c_board_info *info) {
strcpy(info->type, "mtk-usb");
return 0;
}
static int usb_i2c_remove(struct i2c_client *client) {return 0;}
struct i2c_driver usb_i2c_driver = {
.probe = usb_i2c_probe,
.remove = usb_i2c_remove,
.detect = usb_i2c_detect,
.driver = {
.name = "mtk-usb",
},
.id_table = usb_i2c_id,
};
int add_usb_i2c_driver()
{
i2c_register_board_info(0, &usb_i2c_dev, 1);
if(i2c_add_driver(&usb_i2c_driver)!=0)
{
printk("[MUSB]usb_i2c_driver initialization failed!!\n");
return -1;
}
else
{
printk("[MUSB]usb_i2c_driver initialization succeed!!\n");
}
return 0;
}
#endif //End of CONFIG_MTK_FPGA
#endif /* NEVER */
|