diff options
author | Fabio Baltieri <fabio.baltieri@linaro.org> | 2013-05-15 08:03:33 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-05-28 13:03:55 -0400 |
commit | f85bff5d1ece92017a57129877573e0fa4b1050c (patch) | |
tree | 075eb04d363559da1dcdb3d9c51a45da08dabd5e /drivers/usb | |
parent | 0c380c0ee03c4465f45f19c1c3fc49edd299c922 (diff) |
usb: phy: ab8500-usb: add ab9540 support
Add support for the ab9540 variant of the ab8500 family.
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Maxime Coquelin <maxime.coquelin@st.com>
Cc: Avinash Kumar <avinash.kumar@stericsson.com>
Cc: Thirupathi Chippakurthy <thirupathi.chippakurthy@stericsson.com>
Signed-off-by: Fabio Baltieri <fabio.baltieri@linaro.org>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/phy/phy-ab8500-usb.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index ceab508b90e8..087402350b6d 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * Copyright (C) 2010-2013 ST-Ericsson AB | 6 | * Copyright (C) 2010-2013 ST-Ericsson AB |
7 | * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com> | 7 | * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com> |
8 | * Avinash Kumar <avinash.kumar@stericsson.com> | 8 | * Avinash Kumar <avinash.kumar@stericsson.com> |
9 | * Thirupathi Chippakurthy <thirupathi.chippakurthy@stericsson.com> | ||
9 | * | 10 | * |
10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -45,6 +46,7 @@ | |||
45 | #define AB8500_USB_LINE_STAT_REG 0x80 | 46 | #define AB8500_USB_LINE_STAT_REG 0x80 |
46 | #define AB8505_USB_LINE_STAT_REG 0x94 | 47 | #define AB8505_USB_LINE_STAT_REG 0x94 |
47 | #define AB8540_USB_LINK_STAT_REG 0x94 | 48 | #define AB8540_USB_LINK_STAT_REG 0x94 |
49 | #define AB9540_USB_LINK_STAT_REG 0x94 | ||
48 | #define AB8540_USB_OTG_CTL_REG 0x87 | 50 | #define AB8540_USB_OTG_CTL_REG 0x87 |
49 | #define AB8500_USB_PHY_CTRL_REG 0x8A | 51 | #define AB8500_USB_PHY_CTRL_REG 0x8A |
50 | #define AB8540_VBUS_CTRL_REG 0x82 | 52 | #define AB8540_VBUS_CTRL_REG 0x82 |
@@ -158,6 +160,37 @@ enum ab8540_usb_link_status { | |||
158 | USB_LINK_MOTOROLA_FACTORY_CBL_PHY_EN_8540 | 160 | USB_LINK_MOTOROLA_FACTORY_CBL_PHY_EN_8540 |
159 | }; | 161 | }; |
160 | 162 | ||
163 | enum ab9540_usb_link_status { | ||
164 | USB_LINK_NOT_CONFIGURED_9540 = 0, | ||
165 | USB_LINK_STD_HOST_NC_9540, | ||
166 | USB_LINK_STD_HOST_C_NS_9540, | ||
167 | USB_LINK_STD_HOST_C_S_9540, | ||
168 | USB_LINK_CDP_9540, | ||
169 | USB_LINK_RESERVED0_9540, | ||
170 | USB_LINK_RESERVED1_9540, | ||
171 | USB_LINK_DEDICATED_CHG_9540, | ||
172 | USB_LINK_ACA_RID_A_9540, | ||
173 | USB_LINK_ACA_RID_B_9540, | ||
174 | USB_LINK_ACA_RID_C_NM_9540, | ||
175 | USB_LINK_RESERVED2_9540, | ||
176 | USB_LINK_RESERVED3_9540, | ||
177 | USB_LINK_HM_IDGND_9540, | ||
178 | USB_LINK_CHARGERPORT_NOT_OK_9540, | ||
179 | USB_LINK_CHARGER_DM_HIGH_9540, | ||
180 | USB_LINK_PHYEN_NO_VBUS_NO_IDGND_9540, | ||
181 | USB_LINK_STD_UPSTREAM_NO_IDGNG_VBUS_9540, | ||
182 | USB_LINK_STD_UPSTREAM_9540, | ||
183 | USB_LINK_CHARGER_SE1_9540, | ||
184 | USB_LINK_CARKIT_CHGR_1_9540, | ||
185 | USB_LINK_CARKIT_CHGR_2_9540, | ||
186 | USB_LINK_ACA_DOCK_CHGR_9540, | ||
187 | USB_LINK_SAMSUNG_BOOT_CBL_PHY_EN_9540, | ||
188 | USB_LINK_SAMSUNG_BOOT_CBL_PHY_DISB_9540, | ||
189 | USB_LINK_SAMSUNG_UART_CBL_PHY_EN_9540, | ||
190 | USB_LINK_SAMSUNG_UART_CBL_PHY_DISB_9540, | ||
191 | USB_LINK_MOTOROLA_FACTORY_CBL_PHY_EN_9540 | ||
192 | }; | ||
193 | |||
161 | enum ab8500_usb_mode { | 194 | enum ab8500_usb_mode { |
162 | USB_IDLE = 0, | 195 | USB_IDLE = 0, |
163 | USB_PERIPHERAL, | 196 | USB_PERIPHERAL, |
@@ -378,6 +411,132 @@ static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host) | |||
378 | #define ab8500_usb_peri_phy_en(ab) ab8500_usb_phy_enable(ab, false) | 411 | #define ab8500_usb_peri_phy_en(ab) ab8500_usb_phy_enable(ab, false) |
379 | #define ab8500_usb_peri_phy_dis(ab) ab8500_usb_phy_disable(ab, false) | 412 | #define ab8500_usb_peri_phy_dis(ab) ab8500_usb_phy_disable(ab, false) |
380 | 413 | ||
414 | static int ab9540_usb_link_status_update(struct ab8500_usb *ab, | ||
415 | enum ab9540_usb_link_status lsts) | ||
416 | { | ||
417 | enum ux500_musb_vbus_id_status event = 0; | ||
418 | |||
419 | dev_dbg(ab->dev, "ab9540_usb_link_status_update %d\n", lsts); | ||
420 | |||
421 | if (ab->previous_link_status_state == USB_LINK_HM_IDGND_9540 && | ||
422 | (lsts == USB_LINK_STD_HOST_C_NS_9540 || | ||
423 | lsts == USB_LINK_STD_HOST_NC_9540)) | ||
424 | return 0; | ||
425 | |||
426 | if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_9540 && | ||
427 | (lsts == USB_LINK_STD_HOST_NC_9540)) | ||
428 | return 0; | ||
429 | |||
430 | ab->previous_link_status_state = lsts; | ||
431 | |||
432 | switch (lsts) { | ||
433 | case USB_LINK_ACA_RID_B_9540: | ||
434 | event = UX500_MUSB_RIDB; | ||
435 | case USB_LINK_NOT_CONFIGURED_9540: | ||
436 | case USB_LINK_RESERVED0_9540: | ||
437 | case USB_LINK_RESERVED1_9540: | ||
438 | case USB_LINK_RESERVED2_9540: | ||
439 | case USB_LINK_RESERVED3_9540: | ||
440 | if (ab->mode == USB_PERIPHERAL) | ||
441 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
442 | UX500_MUSB_CLEAN, &ab->vbus_draw); | ||
443 | ab->mode = USB_IDLE; | ||
444 | ab->phy.otg->default_a = false; | ||
445 | ab->vbus_draw = 0; | ||
446 | if (event != UX500_MUSB_RIDB) | ||
447 | event = UX500_MUSB_NONE; | ||
448 | /* Fallback to default B_IDLE as nothing is connected. */ | ||
449 | ab->phy.state = OTG_STATE_B_IDLE; | ||
450 | break; | ||
451 | |||
452 | case USB_LINK_ACA_RID_C_NM_9540: | ||
453 | event = UX500_MUSB_RIDC; | ||
454 | case USB_LINK_STD_HOST_NC_9540: | ||
455 | case USB_LINK_STD_HOST_C_NS_9540: | ||
456 | case USB_LINK_STD_HOST_C_S_9540: | ||
457 | case USB_LINK_CDP_9540: | ||
458 | if (ab->mode == USB_HOST) { | ||
459 | ab->mode = USB_PERIPHERAL; | ||
460 | ab8500_usb_host_phy_dis(ab); | ||
461 | ab8500_usb_peri_phy_en(ab); | ||
462 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
463 | UX500_MUSB_PREPARE, &ab->vbus_draw); | ||
464 | } | ||
465 | if (ab->mode == USB_IDLE) { | ||
466 | ab->mode = USB_PERIPHERAL; | ||
467 | ab8500_usb_peri_phy_en(ab); | ||
468 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
469 | UX500_MUSB_PREPARE, &ab->vbus_draw); | ||
470 | } | ||
471 | if (event != UX500_MUSB_RIDC) | ||
472 | event = UX500_MUSB_VBUS; | ||
473 | break; | ||
474 | |||
475 | case USB_LINK_ACA_RID_A_9540: | ||
476 | event = UX500_MUSB_RIDA; | ||
477 | case USB_LINK_HM_IDGND_9540: | ||
478 | case USB_LINK_STD_UPSTREAM_9540: | ||
479 | if (ab->mode == USB_PERIPHERAL) { | ||
480 | ab->mode = USB_HOST; | ||
481 | ab8500_usb_peri_phy_dis(ab); | ||
482 | ab8500_usb_host_phy_en(ab); | ||
483 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
484 | UX500_MUSB_PREPARE, &ab->vbus_draw); | ||
485 | } | ||
486 | if (ab->mode == USB_IDLE) { | ||
487 | ab->mode = USB_HOST; | ||
488 | ab8500_usb_host_phy_en(ab); | ||
489 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
490 | UX500_MUSB_PREPARE, &ab->vbus_draw); | ||
491 | } | ||
492 | ab->phy.otg->default_a = true; | ||
493 | if (event != UX500_MUSB_RIDA) | ||
494 | event = UX500_MUSB_ID; | ||
495 | |||
496 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
497 | event, &ab->vbus_draw); | ||
498 | break; | ||
499 | |||
500 | case USB_LINK_DEDICATED_CHG_9540: | ||
501 | ab->mode = USB_DEDICATED_CHG; | ||
502 | event = UX500_MUSB_CHARGER; | ||
503 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
504 | event, &ab->vbus_draw); | ||
505 | break; | ||
506 | |||
507 | case USB_LINK_PHYEN_NO_VBUS_NO_IDGND_9540: | ||
508 | case USB_LINK_STD_UPSTREAM_NO_IDGNG_VBUS_9540: | ||
509 | if (!(is_ab9540_2p0_or_earlier(ab->ab8500))) { | ||
510 | event = UX500_MUSB_NONE; | ||
511 | if (ab->mode == USB_HOST) { | ||
512 | ab->phy.otg->default_a = false; | ||
513 | ab->vbus_draw = 0; | ||
514 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
515 | event, &ab->vbus_draw); | ||
516 | ab8500_usb_host_phy_dis(ab); | ||
517 | ab->mode = USB_IDLE; | ||
518 | } | ||
519 | if (ab->mode == USB_PERIPHERAL) { | ||
520 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
521 | event, &ab->vbus_draw); | ||
522 | ab8500_usb_peri_phy_dis(ab); | ||
523 | atomic_notifier_call_chain(&ab->phy.notifier, | ||
524 | UX500_MUSB_CLEAN, | ||
525 | &ab->vbus_draw); | ||
526 | ab->mode = USB_IDLE; | ||
527 | ab->phy.otg->default_a = false; | ||
528 | ab->vbus_draw = 0; | ||
529 | } | ||
530 | } | ||
531 | break; | ||
532 | |||
533 | default: | ||
534 | break; | ||
535 | } | ||
536 | |||
537 | return 0; | ||
538 | } | ||
539 | |||
381 | static int ab8540_usb_link_status_update(struct ab8500_usb *ab, | 540 | static int ab8540_usb_link_status_update(struct ab8500_usb *ab, |
382 | enum ab8540_usb_link_status lsts) | 541 | enum ab8540_usb_link_status lsts) |
383 | { | 542 | { |
@@ -707,6 +866,13 @@ static int abx500_usb_link_status_update(struct ab8500_usb *ab) | |||
707 | AB8500_USB, AB8540_USB_LINK_STAT_REG, ®); | 866 | AB8500_USB, AB8540_USB_LINK_STAT_REG, ®); |
708 | lsts = (reg >> 3) & 0xFF; | 867 | lsts = (reg >> 3) & 0xFF; |
709 | ret = ab8540_usb_link_status_update(ab, lsts); | 868 | ret = ab8540_usb_link_status_update(ab, lsts); |
869 | } else if (is_ab9540(ab->ab8500)) { | ||
870 | enum ab9540_usb_link_status lsts; | ||
871 | |||
872 | abx500_get_register_interruptible(ab->dev, | ||
873 | AB8500_USB, AB9540_USB_LINK_STAT_REG, ®); | ||
874 | lsts = (reg >> 3) & 0xFF; | ||
875 | ret = ab9540_usb_link_status_update(ab, lsts); | ||
710 | } | 876 | } |
711 | 877 | ||
712 | return ret; | 878 | return ret; |
@@ -1146,6 +1312,43 @@ static void ab8500_usb_set_ab8540_tuning_values(struct ab8500_usb *ab) | |||
1146 | err); | 1312 | err); |
1147 | } | 1313 | } |
1148 | 1314 | ||
1315 | static void ab8500_usb_set_ab9540_tuning_values(struct ab8500_usb *ab) | ||
1316 | { | ||
1317 | int err; | ||
1318 | |||
1319 | /* Enable the PBT/Bank 0x12 access */ | ||
1320 | err = abx500_set_register_interruptible(ab->dev, | ||
1321 | AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, 0x01); | ||
1322 | if (err < 0) | ||
1323 | dev_err(ab->dev, "Failed to enable bank12 access err=%d\n", | ||
1324 | err); | ||
1325 | |||
1326 | err = abx500_set_register_interruptible(ab->dev, | ||
1327 | AB8500_DEBUG, AB8500_USB_PHY_TUNE1, 0xC8); | ||
1328 | if (err < 0) | ||
1329 | dev_err(ab->dev, "Failed to set PHY_TUNE1 register err=%d\n", | ||
1330 | err); | ||
1331 | |||
1332 | err = abx500_set_register_interruptible(ab->dev, | ||
1333 | AB8500_DEBUG, AB8500_USB_PHY_TUNE2, 0x60); | ||
1334 | if (err < 0) | ||
1335 | dev_err(ab->dev, "Failed to set PHY_TUNE2 register err=%d\n", | ||
1336 | err); | ||
1337 | |||
1338 | err = abx500_set_register_interruptible(ab->dev, | ||
1339 | AB8500_DEBUG, AB8500_USB_PHY_TUNE3, 0x80); | ||
1340 | if (err < 0) | ||
1341 | dev_err(ab->dev, "Failed to set PHY_TUNE3 regester err=%d\n", | ||
1342 | err); | ||
1343 | |||
1344 | /* Switch to normal mode/disable Bank 0x12 access */ | ||
1345 | err = abx500_set_register_interruptible(ab->dev, | ||
1346 | AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, 0x00); | ||
1347 | if (err < 0) | ||
1348 | dev_err(ab->dev, "Failed to switch bank12 access err=%d\n", | ||
1349 | err); | ||
1350 | } | ||
1351 | |||
1149 | static int ab8500_usb_probe(struct platform_device *pdev) | 1352 | static int ab8500_usb_probe(struct platform_device *pdev) |
1150 | { | 1353 | { |
1151 | struct ab8500_usb *ab; | 1354 | struct ab8500_usb *ab; |
@@ -1198,6 +1401,12 @@ static int ab8500_usb_probe(struct platform_device *pdev) | |||
1198 | AB8500_USB_FLAG_USE_CHECK_VBUS_STATUS | | 1401 | AB8500_USB_FLAG_USE_CHECK_VBUS_STATUS | |
1199 | AB8500_USB_FLAG_USE_VBUS_HOST_QUIRK | | 1402 | AB8500_USB_FLAG_USE_VBUS_HOST_QUIRK | |
1200 | AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE; | 1403 | AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE; |
1404 | } else if (is_ab9540(ab->ab8500)) { | ||
1405 | ab->flags |= AB8500_USB_FLAG_USE_LINK_STATUS_IRQ | | ||
1406 | AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE; | ||
1407 | if (is_ab9540_2p0_or_earlier(ab->ab8500)) | ||
1408 | ab->flags |= AB8500_USB_FLAG_USE_ID_WAKEUP_IRQ | | ||
1409 | AB8500_USB_FLAG_USE_VBUS_DET_IRQ; | ||
1201 | } | 1410 | } |
1202 | 1411 | ||
1203 | /* Disable regulator voltage setting for AB8500 <= v2.0 */ | 1412 | /* Disable regulator voltage setting for AB8500 <= v2.0 */ |
@@ -1242,6 +1451,9 @@ static int ab8500_usb_probe(struct platform_device *pdev) | |||
1242 | else if (is_ab8540(ab->ab8500)) | 1451 | else if (is_ab8540(ab->ab8500)) |
1243 | /* Phy tuning values for AB8540 */ | 1452 | /* Phy tuning values for AB8540 */ |
1244 | ab8500_usb_set_ab8540_tuning_values(ab); | 1453 | ab8500_usb_set_ab8540_tuning_values(ab); |
1454 | else if (is_ab9540(ab->ab8500)) | ||
1455 | /* Phy tuning values for AB9540 */ | ||
1456 | ab8500_usb_set_ab9540_tuning_values(ab); | ||
1245 | 1457 | ||
1246 | /* Needed to enable ID detection. */ | 1458 | /* Needed to enable ID detection. */ |
1247 | ab8500_usb_wd_workaround(ab); | 1459 | ab8500_usb_wd_workaround(ab); |
@@ -1284,6 +1496,7 @@ static int ab8500_usb_remove(struct platform_device *pdev) | |||
1284 | static struct platform_device_id ab8500_usb_devtype[] = { | 1496 | static struct platform_device_id ab8500_usb_devtype[] = { |
1285 | { .name = "ab8500-usb", }, | 1497 | { .name = "ab8500-usb", }, |
1286 | { .name = "ab8540-usb", }, | 1498 | { .name = "ab8540-usb", }, |
1499 | { .name = "ab9540-usb", }, | ||
1287 | { /* sentinel */ } | 1500 | { /* sentinel */ } |
1288 | }; | 1501 | }; |
1289 | MODULE_DEVICE_TABLE(platform, ab8500_usb_devtype); | 1502 | MODULE_DEVICE_TABLE(platform, ab8500_usb_devtype); |