18e22978cSAlexander Shishkin /* Copyright (c) 2010, Code Aurora Forum. All rights reserved. 28e22978cSAlexander Shishkin * 38e22978cSAlexander Shishkin * This program is free software; you can redistribute it and/or modify 48e22978cSAlexander Shishkin * it under the terms of the GNU General Public License version 2 and 58e22978cSAlexander Shishkin * only version 2 as published by the Free Software Foundation. 68e22978cSAlexander Shishkin */ 78e22978cSAlexander Shishkin 88e22978cSAlexander Shishkin #include <linux/module.h> 98e22978cSAlexander Shishkin #include <linux/platform_device.h> 108e22978cSAlexander Shishkin #include <linux/pm_runtime.h> 118e22978cSAlexander Shishkin #include <linux/usb/msm_hsusb_hw.h> 128e22978cSAlexander Shishkin #include <linux/usb/ulpi.h> 138e22978cSAlexander Shishkin #include <linux/usb/gadget.h> 148e22978cSAlexander Shishkin #include <linux/usb/chipidea.h> 158e22978cSAlexander Shishkin 168e22978cSAlexander Shishkin #include "ci.h" 178e22978cSAlexander Shishkin 188e22978cSAlexander Shishkin #define MSM_USB_BASE (ci->hw_bank.abs) 198e22978cSAlexander Shishkin 208e22978cSAlexander Shishkin static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event) 218e22978cSAlexander Shishkin { 228e22978cSAlexander Shishkin struct device *dev = ci->gadget.dev.parent; 238e22978cSAlexander Shishkin 248e22978cSAlexander Shishkin switch (event) { 258e22978cSAlexander Shishkin case CI_HDRC_CONTROLLER_RESET_EVENT: 268e22978cSAlexander Shishkin dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n"); 278e22978cSAlexander Shishkin writel(0, USB_AHBBURST); 288e22978cSAlexander Shishkin writel(0, USB_AHBMODE); 29*ef44cb42SAntoine Tenart usb_phy_init(ci->usb_phy); 308e22978cSAlexander Shishkin break; 318e22978cSAlexander Shishkin case CI_HDRC_CONTROLLER_STOPPED_EVENT: 328e22978cSAlexander Shishkin dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n"); 338e22978cSAlexander Shishkin /* 34*ef44cb42SAntoine Tenart * Put the phy in non-driving mode. Otherwise host 358e22978cSAlexander Shishkin * may not detect soft-disconnection. 368e22978cSAlexander Shishkin */ 37*ef44cb42SAntoine Tenart usb_phy_notify_disconnect(ci->usb_phy, USB_SPEED_UNKNOWN); 388e22978cSAlexander Shishkin break; 398e22978cSAlexander Shishkin default: 408e22978cSAlexander Shishkin dev_dbg(dev, "unknown ci_hdrc event\n"); 418e22978cSAlexander Shishkin break; 428e22978cSAlexander Shishkin } 438e22978cSAlexander Shishkin } 448e22978cSAlexander Shishkin 458e22978cSAlexander Shishkin static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = { 468e22978cSAlexander Shishkin .name = "ci_hdrc_msm", 473c6d9826SIvan T. Ivanov .capoffset = DEF_CAPOFFSET, 488e22978cSAlexander Shishkin .flags = CI_HDRC_REGS_SHARED | 498e22978cSAlexander Shishkin CI_HDRC_REQUIRE_TRANSCEIVER | 508e22978cSAlexander Shishkin CI_HDRC_DISABLE_STREAMING, 518e22978cSAlexander Shishkin 528e22978cSAlexander Shishkin .notify_event = ci_hdrc_msm_notify_event, 538e22978cSAlexander Shishkin }; 548e22978cSAlexander Shishkin 558e22978cSAlexander Shishkin static int ci_hdrc_msm_probe(struct platform_device *pdev) 568e22978cSAlexander Shishkin { 578e22978cSAlexander Shishkin struct platform_device *plat_ci; 582629b101SIvan T. Ivanov struct usb_phy *phy; 598e22978cSAlexander Shishkin 608e22978cSAlexander Shishkin dev_dbg(&pdev->dev, "ci_hdrc_msm_probe\n"); 618e22978cSAlexander Shishkin 622629b101SIvan T. Ivanov /* 632629b101SIvan T. Ivanov * OTG(PHY) driver takes care of PHY initialization, clock management, 642629b101SIvan T. Ivanov * powering up VBUS, mapping of registers address space and power 652629b101SIvan T. Ivanov * management. 662629b101SIvan T. Ivanov */ 672629b101SIvan T. Ivanov phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); 682629b101SIvan T. Ivanov if (IS_ERR(phy)) 692629b101SIvan T. Ivanov return PTR_ERR(phy); 702629b101SIvan T. Ivanov 71*ef44cb42SAntoine Tenart ci_hdrc_msm_platdata.usb_phy = phy; 722629b101SIvan T. Ivanov 738e22978cSAlexander Shishkin plat_ci = ci_hdrc_add_device(&pdev->dev, 748e22978cSAlexander Shishkin pdev->resource, pdev->num_resources, 758e22978cSAlexander Shishkin &ci_hdrc_msm_platdata); 768e22978cSAlexander Shishkin if (IS_ERR(plat_ci)) { 778e22978cSAlexander Shishkin dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n"); 788e22978cSAlexander Shishkin return PTR_ERR(plat_ci); 798e22978cSAlexander Shishkin } 808e22978cSAlexander Shishkin 818e22978cSAlexander Shishkin platform_set_drvdata(pdev, plat_ci); 828e22978cSAlexander Shishkin 838e22978cSAlexander Shishkin pm_runtime_no_callbacks(&pdev->dev); 848e22978cSAlexander Shishkin pm_runtime_enable(&pdev->dev); 858e22978cSAlexander Shishkin 868e22978cSAlexander Shishkin return 0; 878e22978cSAlexander Shishkin } 888e22978cSAlexander Shishkin 898e22978cSAlexander Shishkin static int ci_hdrc_msm_remove(struct platform_device *pdev) 908e22978cSAlexander Shishkin { 918e22978cSAlexander Shishkin struct platform_device *plat_ci = platform_get_drvdata(pdev); 928e22978cSAlexander Shishkin 938e22978cSAlexander Shishkin pm_runtime_disable(&pdev->dev); 948e22978cSAlexander Shishkin ci_hdrc_remove_device(plat_ci); 958e22978cSAlexander Shishkin 968e22978cSAlexander Shishkin return 0; 978e22978cSAlexander Shishkin } 988e22978cSAlexander Shishkin 992629b101SIvan T. Ivanov static const struct of_device_id msm_ci_dt_match[] = { 1002629b101SIvan T. Ivanov { .compatible = "qcom,ci-hdrc", }, 1012629b101SIvan T. Ivanov { } 1022629b101SIvan T. Ivanov }; 1032629b101SIvan T. Ivanov MODULE_DEVICE_TABLE(of, msm_ci_dt_match); 1042629b101SIvan T. Ivanov 1058e22978cSAlexander Shishkin static struct platform_driver ci_hdrc_msm_driver = { 1068e22978cSAlexander Shishkin .probe = ci_hdrc_msm_probe, 1078e22978cSAlexander Shishkin .remove = ci_hdrc_msm_remove, 1082629b101SIvan T. Ivanov .driver = { 1092629b101SIvan T. Ivanov .name = "msm_hsusb", 1102629b101SIvan T. Ivanov .of_match_table = msm_ci_dt_match, 1112629b101SIvan T. Ivanov }, 1128e22978cSAlexander Shishkin }; 1138e22978cSAlexander Shishkin 1148e22978cSAlexander Shishkin module_platform_driver(ci_hdrc_msm_driver); 1158e22978cSAlexander Shishkin 1168e22978cSAlexander Shishkin MODULE_ALIAS("platform:msm_hsusb"); 1178e22978cSAlexander Shishkin MODULE_ALIAS("platform:ci13xxx_msm"); 1188e22978cSAlexander Shishkin MODULE_LICENSE("GPL v2"); 119