diff options
author | Ivan T. Ivanov <iivanov@mm-sol.com> | 2014-04-28 09:34:15 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2014-04-30 12:28:44 -0400 |
commit | 8364f9af237f47fa128bd4e4f7b45beef890c994 (patch) | |
tree | 8508652e8e910d97ef6ac89df1104ef861099098 /drivers/usb/phy | |
parent | f60c114a3ae528dfc6750baad58cf822d0b282a2 (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>
Diffstat (limited to 'drivers/usb/phy')
-rw-r--r-- | drivers/usb/phy/phy-msm-usb.c | 113 |
1 files changed, 94 insertions, 19 deletions
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 = { | |||
217 | static void ulpi_init(struct msm_otg *motg) | 220 | static 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 | ||
1349 | static 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 | }; | ||
1360 | MODULE_DEVICE_TABLE(of, msm_otg_dt_match); | ||
1361 | |||
1362 | static 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 | |||
1346 | static int msm_otg_probe(struct platform_device *pdev) | 1414 | static 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 | ||