aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan T. Ivanov <iivanov@mm-sol.com>2014-04-28 09:34:15 -0400
committerFelipe Balbi <balbi@ti.com>2014-04-30 12:28:44 -0400
commit8364f9af237f47fa128bd4e4f7b45beef890c994 (patch)
tree8508652e8e910d97ef6ac89df1104ef861099098
parentf60c114a3ae528dfc6750baad58cf822d0b282a2 (diff)
usb: phy: msm: Add device tree support and binding information
Allows controller to be specified via device tree. Signed-off-by: Ivan T. Ivanov <iivanov@mm-sol.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--Documentation/devicetree/bindings/usb/msm-hsusb.txt67
-rw-r--r--drivers/usb/phy/phy-msm-usb.c113
-rw-r--r--include/linux/usb/msm_hsusb.h6
3 files changed, 165 insertions, 21 deletions
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 5ea26c631e3a..ee4123de3de4 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -15,3 +15,70 @@ Example EHCI controller device node:
15 usb-phy = <&usb_otg>; 15 usb-phy = <&usb_otg>;
16 }; 16 };
17 17
18USB PHY with optional OTG:
19
20Required properties:
21- compatible: Should contain:
22 "qcom,usb-otg-ci" for chipsets with ChipIdea 45nm PHY
23 "qcom,usb-otg-snps" for chipsets with Synopsys 28nm PHY
24
25- regs: Offset and length of the register set in the memory map
26- interrupts: interrupt-specifier for the OTG interrupt.
27
28- clocks: A list of phandle + clock-specifier pairs for the
29 clocks listed in clock-names
30- clock-names: Should contain the following:
31 "phy" USB PHY reference clock
32 "core" Protocol engine clock
33 "iface" Interface bus clock
34 "alt_core" Protocol engine clock for targets with asynchronous
35 reset methodology. (optional)
36
37- vdccx-supply: phandle to the regulator for the vdd supply for
38 digital circuit operation.
39- v1p8-supply: phandle to the regulator for the 1.8V supply
40- v3p3-supply: phandle to the regulator for the 3.3V supply
41
42- resets: A list of phandle + reset-specifier pairs for the
43 resets listed in reset-names
44- reset-names: Should contain the following:
45 "phy" USB PHY controller reset
46 "link" USB LINK controller reset
47
48- qcom,otg-control: OTG control (VBUS and ID notifications) can be one of
49 1 - PHY control
50 2 - PMIC control
51
52Optional properties:
53- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg"
54
55- qcom,phy-init-sequence: PHY configuration sequence values. This is related to Device
56 Mode Eye Diagram test. Start address at which these values will be
57 written is ULPI_EXT_VENDOR_SPECIFIC. Value of -1 is reserved as
58 "do not overwrite default value at this address".
59 For example: qcom,phy-init-sequence = < -1 0x63 >;
60 Will update only value at address ULPI_EXT_VENDOR_SPECIFIC + 1.
61
62Example HSUSB OTG controller device node:
63
64 usb@f9a55000 {
65 compatible = "qcom,usb-otg-snps";
66 reg = <0xf9a55000 0x400>;
67 interrupts = <0 134 0>;
68 dr_mode = "peripheral";
69
70 clocks = <&gcc GCC_XO_CLK>, <&gcc GCC_USB_HS_SYSTEM_CLK>,
71 <&gcc GCC_USB_HS_AHB_CLK>;
72
73 clock-names = "phy", "core", "iface";
74
75 vddcx-supply = <&pm8841_s2_corner>;
76 v1p8-supply = <&pm8941_l6>;
77 v3p3-supply = <&pm8941_l24>;
78
79 resets = <&gcc GCC_USB2A_PHY_BCR>, <&gcc GCC_USB_HS_BCR>;
80 reset-names = "phy", "link";
81
82 qcom,otg-control = <1>;
83 qcom,phy-init-sequence = < -1 0x63 >;
84 };
diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c
index 7e968aa143ce..1bf2d4ee29d2 100644
--- a/drivers/usb/phy/phy-msm-usb.c
+++ b/drivers/usb/phy/phy-msm-usb.c
@@ -30,9 +30,12 @@
30#include <linux/debugfs.h> 30#include <linux/debugfs.h>
31#include <linux/seq_file.h> 31#include <linux/seq_file.h>
32#include <linux/pm_runtime.h> 32#include <linux/pm_runtime.h>
33#include <linux/of.h>
34#include <linux/of_device.h>
33 35
34#include <linux/usb.h> 36#include <linux/usb.h>
35#include <linux/usb/otg.h> 37#include <linux/usb/otg.h>
38#include <linux/usb/of.h>
36#include <linux/usb/ulpi.h> 39#include <linux/usb/ulpi.h>
37#include <linux/usb/gadget.h> 40#include <linux/usb/gadget.h>
38#include <linux/usb/hcd.h> 41#include <linux/usb/hcd.h>
@@ -217,16 +220,16 @@ static struct usb_phy_io_ops msm_otg_io_ops = {
217static void ulpi_init(struct msm_otg *motg) 220static void ulpi_init(struct msm_otg *motg)
218{ 221{
219 struct msm_otg_platform_data *pdata = motg->pdata; 222 struct msm_otg_platform_data *pdata = motg->pdata;
220 int *seq = pdata->phy_init_seq; 223 int *seq = pdata->phy_init_seq, idx;
224 u32 addr = ULPI_EXT_VENDOR_SPECIFIC;
221 225
222 if (!seq) 226 for (idx = 0; idx < pdata->phy_init_sz; idx++) {
223 return; 227 if (seq[idx] == -1)
228 continue;
224 229
225 while (seq[0] >= 0) {
226 dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n", 230 dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
227 seq[0], seq[1]); 231 seq[idx], addr + idx);
228 ulpi_write(&motg->phy, seq[0], seq[1]); 232 ulpi_write(&motg->phy, seq[idx], addr + idx);
229 seq += 2;
230 } 233 }
231} 234}
232 235
@@ -1343,26 +1346,96 @@ static void msm_otg_debugfs_cleanup(void)
1343 debugfs_remove(msm_otg_dbg_root); 1346 debugfs_remove(msm_otg_dbg_root);
1344} 1347}
1345 1348
1349static struct of_device_id msm_otg_dt_match[] = {
1350 {
1351 .compatible = "qcom,usb-otg-ci",
1352 .data = (void *) CI_45NM_INTEGRATED_PHY
1353 },
1354 {
1355 .compatible = "qcom,usb-otg-snps",
1356 .data = (void *) SNPS_28NM_INTEGRATED_PHY
1357 },
1358 { }
1359};
1360MODULE_DEVICE_TABLE(of, msm_otg_dt_match);
1361
1362static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
1363{
1364 struct msm_otg_platform_data *pdata;
1365 const struct of_device_id *id;
1366 struct device_node *node = pdev->dev.of_node;
1367 struct property *prop;
1368 int len, ret, words;
1369 u32 val;
1370
1371 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
1372 if (!pdata)
1373 return -ENOMEM;
1374
1375 motg->pdata = pdata;
1376
1377 id = of_match_device(msm_otg_dt_match, &pdev->dev);
1378 pdata->phy_type = (int) id->data;
1379
1380 pdata->mode = of_usb_get_dr_mode(node);
1381 if (pdata->mode == USB_DR_MODE_UNKNOWN)
1382 pdata->mode = USB_DR_MODE_OTG;
1383
1384 pdata->otg_control = OTG_PHY_CONTROL;
1385 if (!of_property_read_u32(node, "qcom,otg-control", &val))
1386 if (val == OTG_PMIC_CONTROL)
1387 pdata->otg_control = val;
1388
1389 prop = of_find_property(node, "qcom,phy-init-sequence", &len);
1390 if (!prop || !len)
1391 return 0;
1392
1393 words = len / sizeof(u32);
1394
1395 if (words >= ULPI_EXT_VENDOR_SPECIFIC) {
1396 dev_warn(&pdev->dev, "Too big PHY init sequence %d\n", words);
1397 return 0;
1398 }
1399
1400 pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
1401 if (!pdata->phy_init_seq) {
1402 dev_warn(&pdev->dev, "No space for PHY init sequence\n");
1403 return 0;
1404 }
1405
1406 ret = of_property_read_u32_array(node, "qcom,phy-init-sequence",
1407 pdata->phy_init_seq, words);
1408 if (!ret)
1409 pdata->phy_init_sz = words;
1410
1411 return 0;
1412}
1413
1346static int msm_otg_probe(struct platform_device *pdev) 1414static int msm_otg_probe(struct platform_device *pdev)
1347{ 1415{
1348 struct regulator_bulk_data regs[3]; 1416 struct regulator_bulk_data regs[3];
1349 int ret = 0; 1417 int ret = 0;
1418 struct device_node *np = pdev->dev.of_node;
1419 struct msm_otg_platform_data *pdata;
1350 struct resource *res; 1420 struct resource *res;
1351 struct msm_otg *motg; 1421 struct msm_otg *motg;
1352 struct usb_phy *phy; 1422 struct usb_phy *phy;
1353 1423
1354 dev_info(&pdev->dev, "msm_otg probe\n");
1355 if (!dev_get_platdata(&pdev->dev)) {
1356 dev_err(&pdev->dev, "No platform data given. Bailing out\n");
1357 return -ENODEV;
1358 }
1359
1360 motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL); 1424 motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL);
1361 if (!motg) { 1425 if (!motg) {
1362 dev_err(&pdev->dev, "unable to allocate msm_otg\n"); 1426 dev_err(&pdev->dev, "unable to allocate msm_otg\n");
1363 return -ENOMEM; 1427 return -ENOMEM;
1364 } 1428 }
1365 1429
1430 pdata = dev_get_platdata(&pdev->dev);
1431 if (!pdata) {
1432 if (!np)
1433 return -ENXIO;
1434 ret = msm_otg_read_dt(pdev, motg);
1435 if (ret)
1436 return ret;
1437 }
1438
1366 motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), 1439 motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
1367 GFP_KERNEL); 1440 GFP_KERNEL);
1368 if (!motg->phy.otg) { 1441 if (!motg->phy.otg) {
@@ -1370,17 +1443,17 @@ static int msm_otg_probe(struct platform_device *pdev)
1370 return -ENOMEM; 1443 return -ENOMEM;
1371 } 1444 }
1372 1445
1373 motg->pdata = dev_get_platdata(&pdev->dev);
1374 phy = &motg->phy; 1446 phy = &motg->phy;
1375 phy->dev = &pdev->dev; 1447 phy->dev = &pdev->dev;
1376 1448
1377 motg->phy_reset_clk = devm_clk_get(&pdev->dev, "usb_phy_clk"); 1449 motg->phy_reset_clk = devm_clk_get(&pdev->dev,
1450 np ? "phy" : "usb_phy_clk");
1378 if (IS_ERR(motg->phy_reset_clk)) { 1451 if (IS_ERR(motg->phy_reset_clk)) {
1379 dev_err(&pdev->dev, "failed to get usb_phy_clk\n"); 1452 dev_err(&pdev->dev, "failed to get usb_phy_clk\n");
1380 return PTR_ERR(motg->phy_reset_clk); 1453 return PTR_ERR(motg->phy_reset_clk);
1381 } 1454 }
1382 1455
1383 motg->clk = devm_clk_get(&pdev->dev, "usb_hs_clk"); 1456 motg->clk = devm_clk_get(&pdev->dev, np ? "core" : "usb_hs_clk");
1384 if (IS_ERR(motg->clk)) { 1457 if (IS_ERR(motg->clk)) {
1385 dev_err(&pdev->dev, "failed to get usb_hs_clk\n"); 1458 dev_err(&pdev->dev, "failed to get usb_hs_clk\n");
1386 return PTR_ERR(motg->clk); 1459 return PTR_ERR(motg->clk);
@@ -1392,7 +1465,7 @@ static int msm_otg_probe(struct platform_device *pdev)
1392 * operation and USB core cannot tolerate frequency changes on 1465 * operation and USB core cannot tolerate frequency changes on
1393 * CORE CLK. 1466 * CORE CLK.
1394 */ 1467 */
1395 motg->pclk = devm_clk_get(&pdev->dev, "usb_hs_pclk"); 1468 motg->pclk = devm_clk_get(&pdev->dev, np ? "iface" : "usb_hs_pclk");
1396 if (IS_ERR(motg->pclk)) { 1469 if (IS_ERR(motg->pclk)) {
1397 dev_err(&pdev->dev, "failed to get usb_hs_pclk\n"); 1470 dev_err(&pdev->dev, "failed to get usb_hs_pclk\n");
1398 return PTR_ERR(motg->pclk); 1471 return PTR_ERR(motg->pclk);
@@ -1403,7 +1476,8 @@ static int msm_otg_probe(struct platform_device *pdev)
1403 * clock is introduced to remove the dependency on AXI 1476 * clock is introduced to remove the dependency on AXI
1404 * bus frequency. 1477 * bus frequency.
1405 */ 1478 */
1406 motg->core_clk = devm_clk_get(&pdev->dev, "usb_hs_core_clk"); 1479 motg->core_clk = devm_clk_get(&pdev->dev,
1480 np ? "alt_core" : "usb_hs_core_clk");
1407 1481
1408 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1482 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1409 motg->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 1483 motg->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
@@ -1486,7 +1560,7 @@ static int msm_otg_probe(struct platform_device *pdev)
1486 device_init_wakeup(&pdev->dev, 1); 1560 device_init_wakeup(&pdev->dev, 1);
1487 1561
1488 if (motg->pdata->mode == USB_DR_MODE_OTG && 1562 if (motg->pdata->mode == USB_DR_MODE_OTG &&
1489 motg->pdata->otg_control == OTG_USER_CONTROL) { 1563 motg->pdata->otg_control == OTG_USER_CONTROL) {
1490 ret = msm_otg_debugfs_init(motg); 1564 ret = msm_otg_debugfs_init(motg);
1491 if (ret) 1565 if (ret)
1492 dev_dbg(&pdev->dev, "Can not create mode change file\n"); 1566 dev_dbg(&pdev->dev, "Can not create mode change file\n");
@@ -1639,6 +1713,7 @@ static struct platform_driver msm_otg_driver = {
1639 .name = DRIVER_NAME, 1713 .name = DRIVER_NAME,
1640 .owner = THIS_MODULE, 1714 .owner = THIS_MODULE,
1641 .pm = &msm_otg_dev_pm_ops, 1715 .pm = &msm_otg_dev_pm_ops,
1716 .of_match_table = msm_otg_dt_match,
1642 }, 1717 },
1643}; 1718};
1644 1719
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 262ed80a0b9e..bd68299c278e 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -100,8 +100,9 @@ enum usb_chg_type {
100/** 100/**
101 * struct msm_otg_platform_data - platform device data 101 * struct msm_otg_platform_data - platform device data
102 * for msm_otg driver. 102 * for msm_otg driver.
103 * @phy_init_seq: PHY configuration sequence. val, reg pairs 103 * @phy_init_seq: PHY configuration sequence values. Value of -1 is reserved as
104 * terminated by -1. 104 * "do not overwrite default vaule at this address".
105 * @phy_init_sz: PHY configuration sequence size.
105 * @vbus_power: VBUS power on/off routine. 106 * @vbus_power: VBUS power on/off routine.
106 * @power_budget: VBUS power budget in mA (0 will be treated as 500mA). 107 * @power_budget: VBUS power budget in mA (0 will be treated as 500mA).
107 * @mode: Supported mode (OTG/peripheral/host). 108 * @mode: Supported mode (OTG/peripheral/host).
@@ -109,6 +110,7 @@ enum usb_chg_type {
109 */ 110 */
110struct msm_otg_platform_data { 111struct msm_otg_platform_data {
111 int *phy_init_seq; 112 int *phy_init_seq;
113 int phy_init_sz;
112 void (*vbus_power)(bool on); 114 void (*vbus_power)(bool on);
113 unsigned power_budget; 115 unsigned power_budget;
114 enum usb_dr_mode mode; 116 enum usb_dr_mode mode;