* @test_mode: the selected test mode
* @platdata: platform specific information supplied by parent device
* @vbus_active: is VBUS active
- * @usb_phy: pointer to USB PHY, if any
+ * @phy: pointer to PHY, if any
+ * @usb_phy: pointer to USB PHY, if any and if using the USB PHY framework
* @hcd: pointer to usb_hcd for ehci host driver
* @debugfs: root dentry for this controller in debugfs
* @id_event: indicates there is an id event, and handled at ci_otg_work
struct ci_hdrc_platform_data *platdata;
int vbus_active;
+ struct phy *phy;
+ /* old usb_phy interface */
struct usb_phy *usb_phy;
struct usb_hcd *hcd;
struct dentry *debugfs;
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
+#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/idr.h>
}
}
+/**
+ * _ci_usb_phy_init: initialize phy taking in account both phy and usb_phy
+ * interfaces
+ * @ci: the controller
+ *
+ * This function returns an error code if the phy failed to init
+ */
+static int _ci_usb_phy_init(struct ci_hdrc *ci)
+{
+ int ret;
+
+ if (ci->phy) {
+ ret = phy_init(ci->phy);
+ if (ret)
+ return ret;
+
+ ret = phy_power_on(ci->phy);
+ if (ret) {
+ phy_exit(ci->phy);
+ return ret;
+ }
+ } else {
+ ret = usb_phy_init(ci->usb_phy);
+ }
+
+ return ret;
+}
+
+/**
+ * _ci_usb_phy_exit: deinitialize phy taking in account both phy and usb_phy
+ * interfaces
+ * @ci: the controller
+ */
+static void ci_usb_phy_exit(struct ci_hdrc *ci)
+{
+ if (ci->phy) {
+ phy_power_off(ci->phy);
+ phy_exit(ci->phy);
+ } else {
+ usb_phy_shutdown(ci->usb_phy);
+ }
+}
+
/**
* ci_usb_phy_init: initialize phy according to different phy type
* @ci: the controller
case USBPHY_INTERFACE_MODE_UTMI:
case USBPHY_INTERFACE_MODE_UTMIW:
case USBPHY_INTERFACE_MODE_HSIC:
- ret = usb_phy_init(ci->usb_phy);
+ ret = _ci_usb_phy_init(ci);
if (ret)
return ret;
hw_phymode_configure(ci);
case USBPHY_INTERFACE_MODE_ULPI:
case USBPHY_INTERFACE_MODE_SERIAL:
hw_phymode_configure(ci);
- ret = usb_phy_init(ci->usb_phy);
+ ret = _ci_usb_phy_init(ci);
if (ret)
return ret;
break;
default:
- ret = usb_phy_init(ci->usb_phy);
+ ret = _ci_usb_phy_init(ci);
}
return ret;
return -ENODEV;
}
- if (ci->platdata->usb_phy)
+ if (ci->platdata->phy) {
+ ci->phy = ci->platdata->phy;
+ } else if (ci->platdata->usb_phy) {
ci->usb_phy = ci->platdata->usb_phy;
- else
+ } else {
+ ci->phy = devm_phy_get(dev, "usb-phy");
ci->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
- if (IS_ERR(ci->usb_phy)) {
- ret = PTR_ERR(ci->usb_phy);
- /*
- * if -ENXIO is returned, it means PHY layer wasn't
- * enabled, so it makes no sense to return -EPROBE_DEFER
- * in that case, since no PHY driver will ever probe.
- */
- if (ret == -ENXIO)
- return ret;
+ /* if both generic PHY and USB PHY layers aren't enabled */
+ if (PTR_ERR(ci->phy) == -ENOSYS &&
+ PTR_ERR(ci->usb_phy) == -ENXIO)
+ return -ENXIO;
+
+ if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy))
+ return -EPROBE_DEFER;
- dev_err(dev, "no usb2 phy configured\n");
- return -EPROBE_DEFER;
+ if (IS_ERR(ci->phy))
+ ci->phy = NULL;
+ else if (IS_ERR(ci->usb_phy))
+ ci->usb_phy = NULL;
}
ret = ci_usb_phy_init(ci);
stop:
ci_role_destroy(ci);
deinit_phy:
- usb_phy_shutdown(ci->usb_phy);
+ ci_usb_phy_exit(ci);
return ret;
}
free_irq(ci->irq, ci);
ci_role_destroy(ci);
ci_hdrc_enter_lpm(ci, true);
- usb_phy_shutdown(ci->usb_phy);
+ ci_usb_phy_exit(ci);
return 0;
}