From: Kishon Vijay Abraham I Date: Fri, 27 Sep 2013 06:23:26 +0000 (+0530) Subject: usb: phy: omap-usb2: use the new generic PHY framework X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=5d93d1e76afbe629caf5d995fd7f8ddd6e3d4d01;p=deliverable%2Flinux.git usb: phy: omap-usb2: use the new generic PHY framework Used the generic PHY framework API to create the PHY. Now the power off and power on are done in omap_usb_power_off and omap_usb_power_on respectively. The omap-usb2 driver is also moved to driver/phy. However using the old USB PHY library cannot be completely removed because OTG is intertwined with PHY and moving to the new framework will break OTG. Once we have a separate OTG state machine, we can get rid of the USB PHY library. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Sylwester Nawrocki Acked-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 349bef2e6e4e..38c3477ead4c 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -15,4 +15,16 @@ config GENERIC_PHY phy users can obtain reference to the PHY. All the users of this framework should select this config. +config OMAP_USB2 + tristate "OMAP USB2 PHY Driver" + depends on ARCH_OMAP2PLUS + select GENERIC_PHY + select USB_PHY + select OMAP_CONTROL_USB + help + Enable this to support the transceiver that is part of SOC. This + driver takes care of all the PHY functionality apart from comparator. + The USB OTG controller communicates with the comparator using this + driver. + endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 9e9560fbb14d..ed5b088abaee 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_GENERIC_PHY) += phy-core.o +obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c new file mode 100644 index 000000000000..4d7b4e5a9659 --- /dev/null +++ b/drivers/phy/phy-omap-usb2.c @@ -0,0 +1,309 @@ +/* + * omap-usb2.c - USB PHY, talking to musb controller in OMAP. + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Author: Kishon Vijay Abraham I + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * omap_usb2_set_comparator - links the comparator present in the sytem with + * this phy + * @comparator - the companion phy(comparator) for this phy + * + * The phy companion driver should call this API passing the phy_companion + * filled with set_vbus and start_srp to be used by usb phy. + * + * For use by phy companion driver + */ +int omap_usb2_set_comparator(struct phy_companion *comparator) +{ + struct omap_usb *phy; + struct usb_phy *x = usb_get_phy(USB_PHY_TYPE_USB2); + + if (IS_ERR(x)) + return -ENODEV; + + phy = phy_to_omapusb(x); + phy->comparator = comparator; + return 0; +} +EXPORT_SYMBOL_GPL(omap_usb2_set_comparator); + +static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled) +{ + struct omap_usb *phy = phy_to_omapusb(otg->phy); + + if (!phy->comparator) + return -ENODEV; + + return phy->comparator->set_vbus(phy->comparator, enabled); +} + +static int omap_usb_start_srp(struct usb_otg *otg) +{ + struct omap_usb *phy = phy_to_omapusb(otg->phy); + + if (!phy->comparator) + return -ENODEV; + + return phy->comparator->start_srp(phy->comparator); +} + +static int omap_usb_set_host(struct usb_otg *otg, struct usb_bus *host) +{ + struct usb_phy *phy = otg->phy; + + otg->host = host; + if (!host) + phy->state = OTG_STATE_UNDEFINED; + + return 0; +} + +static int omap_usb_set_peripheral(struct usb_otg *otg, + struct usb_gadget *gadget) +{ + struct usb_phy *phy = otg->phy; + + otg->gadget = gadget; + if (!gadget) + phy->state = OTG_STATE_UNDEFINED; + + return 0; +} + +static int omap_usb2_suspend(struct usb_phy *x, int suspend) +{ + struct omap_usb *phy = phy_to_omapusb(x); + int ret; + + if (suspend && !phy->is_suspended) { + omap_control_usb_phy_power(phy->control_dev, 0); + pm_runtime_put_sync(phy->dev); + phy->is_suspended = 1; + } else if (!suspend && phy->is_suspended) { + ret = pm_runtime_get_sync(phy->dev); + if (ret < 0) { + dev_err(phy->dev, "get_sync failed with err %d\n", ret); + return ret; + } + omap_control_usb_phy_power(phy->control_dev, 1); + phy->is_suspended = 0; + } + + return 0; +} + +static int omap_usb_power_off(struct phy *x) +{ + struct omap_usb *phy = phy_get_drvdata(x); + + omap_control_usb_phy_power(phy->control_dev, 0); + + return 0; +} + +static int omap_usb_power_on(struct phy *x) +{ + struct omap_usb *phy = phy_get_drvdata(x); + + omap_control_usb_phy_power(phy->control_dev, 1); + + return 0; +} + +static struct phy_ops ops = { + .power_on = omap_usb_power_on, + .power_off = omap_usb_power_off, + .owner = THIS_MODULE, +}; + +static int omap_usb2_probe(struct platform_device *pdev) +{ + struct omap_usb *phy; + struct phy *generic_phy; + struct usb_otg *otg; + struct phy_provider *phy_provider; + + phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); + if (!phy) { + dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n"); + return -ENOMEM; + } + + otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); + if (!otg) { + dev_err(&pdev->dev, "unable to allocate memory for USB OTG\n"); + return -ENOMEM; + } + + phy->dev = &pdev->dev; + + phy->phy.dev = phy->dev; + phy->phy.label = "omap-usb2"; + phy->phy.set_suspend = omap_usb2_suspend; + phy->phy.otg = otg; + phy->phy.type = USB_PHY_TYPE_USB2; + + phy_provider = devm_of_phy_provider_register(phy->dev, + of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); + + phy->control_dev = omap_get_control_dev(); + if (IS_ERR(phy->control_dev)) { + dev_dbg(&pdev->dev, "Failed to get control device\n"); + return -ENODEV; + } + + phy->is_suspended = 1; + omap_control_usb_phy_power(phy->control_dev, 0); + + otg->set_host = omap_usb_set_host; + otg->set_peripheral = omap_usb_set_peripheral; + otg->set_vbus = omap_usb_set_vbus; + otg->start_srp = omap_usb_start_srp; + otg->phy = &phy->phy; + + platform_set_drvdata(pdev, phy); + pm_runtime_enable(phy->dev); + + generic_phy = devm_phy_create(phy->dev, &ops, NULL); + if (IS_ERR(generic_phy)) + return PTR_ERR(generic_phy); + + phy_set_drvdata(generic_phy, phy); + + phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k"); + if (IS_ERR(phy->wkupclk)) { + dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n"); + return PTR_ERR(phy->wkupclk); + } + clk_prepare(phy->wkupclk); + + phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m"); + if (IS_ERR(phy->optclk)) + dev_vdbg(&pdev->dev, "unable to get refclk960m\n"); + else + clk_prepare(phy->optclk); + + usb_add_phy_dev(&phy->phy); + + return 0; +} + +static int omap_usb2_remove(struct platform_device *pdev) +{ + struct omap_usb *phy = platform_get_drvdata(pdev); + + clk_unprepare(phy->wkupclk); + if (!IS_ERR(phy->optclk)) + clk_unprepare(phy->optclk); + usb_remove_phy(&phy->phy); + + return 0; +} + +#ifdef CONFIG_PM_RUNTIME + +static int omap_usb2_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct omap_usb *phy = platform_get_drvdata(pdev); + + clk_disable(phy->wkupclk); + if (!IS_ERR(phy->optclk)) + clk_disable(phy->optclk); + + return 0; +} + +static int omap_usb2_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct omap_usb *phy = platform_get_drvdata(pdev); + int ret; + + ret = clk_enable(phy->wkupclk); + if (ret < 0) { + dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); + goto err0; + } + + if (!IS_ERR(phy->optclk)) { + ret = clk_enable(phy->optclk); + if (ret < 0) { + dev_err(phy->dev, "Failed to enable optclk %d\n", ret); + goto err1; + } + } + + return 0; + +err1: + clk_disable(phy->wkupclk); + +err0: + return ret; +} + +static const struct dev_pm_ops omap_usb2_pm_ops = { + SET_RUNTIME_PM_OPS(omap_usb2_runtime_suspend, omap_usb2_runtime_resume, + NULL) +}; + +#define DEV_PM_OPS (&omap_usb2_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif + +#ifdef CONFIG_OF +static const struct of_device_id omap_usb2_id_table[] = { + { .compatible = "ti,omap-usb2" }, + {} +}; +MODULE_DEVICE_TABLE(of, omap_usb2_id_table); +#endif + +static struct platform_driver omap_usb2_driver = { + .probe = omap_usb2_probe, + .remove = omap_usb2_remove, + .driver = { + .name = "omap-usb2", + .owner = THIS_MODULE, + .pm = DEV_PM_OPS, + .of_match_table = of_match_ptr(omap_usb2_id_table), + }, +}; + +module_platform_driver(omap_usb2_driver); + +MODULE_ALIAS("platform: omap_usb2"); +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_DESCRIPTION("OMAP USB2 phy driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 51ffe11cf38a..2ce041109993 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -66,17 +66,6 @@ config OMAP_CONTROL_USB power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an additional register to power on USB3 PHY. -config OMAP_USB2 - tristate "OMAP USB2 PHY Driver" - depends on ARCH_OMAP2PLUS - select OMAP_CONTROL_USB - select USB_PHY - help - Enable this to support the transceiver that is part of SOC. This - driver takes care of all the PHY functionality apart from comparator. - The USB OTG controller communicates with the comparator using this - driver. - config OMAP_USB3 tristate "OMAP USB3 PHY Driver" depends on ARCH_OMAP2PLUS || COMPILE_TEST diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index 2135e85f46ed..fa4db0e4bdb9 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_NOP_USB_XCEIV) += phy-generic.o obj-$(CONFIG_OMAP_CONTROL_USB) += phy-omap-control.o obj-$(CONFIG_AM335X_CONTROL_USB) += phy-am335x-control.o obj-$(CONFIG_AM335X_PHY_USB) += phy-am335x.o -obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o obj-$(CONFIG_OMAP_USB3) += phy-omap-usb3.o obj-$(CONFIG_SAMSUNG_USBPHY) += phy-samsung-usb.o obj-$(CONFIG_SAMSUNG_USB2PHY) += phy-samsung-usb2.o diff --git a/drivers/usb/phy/phy-omap-usb2.c b/drivers/usb/phy/phy-omap-usb2.c deleted file mode 100644 index d266861d24f7..000000000000 --- a/drivers/usb/phy/phy-omap-usb2.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * omap-usb2.c - USB PHY, talking to musb controller in OMAP. - * - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Author: Kishon Vijay Abraham I - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * omap_usb2_set_comparator - links the comparator present in the sytem with - * this phy - * @comparator - the companion phy(comparator) for this phy - * - * The phy companion driver should call this API passing the phy_companion - * filled with set_vbus and start_srp to be used by usb phy. - * - * For use by phy companion driver - */ -int omap_usb2_set_comparator(struct phy_companion *comparator) -{ - struct omap_usb *phy; - struct usb_phy *x = usb_get_phy(USB_PHY_TYPE_USB2); - - if (IS_ERR(x)) - return -ENODEV; - - phy = phy_to_omapusb(x); - phy->comparator = comparator; - return 0; -} -EXPORT_SYMBOL_GPL(omap_usb2_set_comparator); - -static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled) -{ - struct omap_usb *phy = phy_to_omapusb(otg->phy); - - if (!phy->comparator) - return -ENODEV; - - return phy->comparator->set_vbus(phy->comparator, enabled); -} - -static int omap_usb_start_srp(struct usb_otg *otg) -{ - struct omap_usb *phy = phy_to_omapusb(otg->phy); - - if (!phy->comparator) - return -ENODEV; - - return phy->comparator->start_srp(phy->comparator); -} - -static int omap_usb_set_host(struct usb_otg *otg, struct usb_bus *host) -{ - struct usb_phy *phy = otg->phy; - - otg->host = host; - if (!host) - phy->state = OTG_STATE_UNDEFINED; - - return 0; -} - -static int omap_usb_set_peripheral(struct usb_otg *otg, - struct usb_gadget *gadget) -{ - struct usb_phy *phy = otg->phy; - - otg->gadget = gadget; - if (!gadget) - phy->state = OTG_STATE_UNDEFINED; - - return 0; -} - -static int omap_usb2_suspend(struct usb_phy *x, int suspend) -{ - struct omap_usb *phy = phy_to_omapusb(x); - int ret; - - if (suspend && !phy->is_suspended) { - omap_control_usb_phy_power(phy->control_dev, 0); - pm_runtime_put_sync(phy->dev); - phy->is_suspended = 1; - } else if (!suspend && phy->is_suspended) { - ret = pm_runtime_get_sync(phy->dev); - if (ret < 0) { - dev_err(phy->dev, "get_sync failed with err %d\n", ret); - return ret; - } - omap_control_usb_phy_power(phy->control_dev, 1); - phy->is_suspended = 0; - } - - return 0; -} - -static int omap_usb2_probe(struct platform_device *pdev) -{ - struct omap_usb *phy; - struct usb_otg *otg; - - phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); - if (!phy) { - dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n"); - return -ENOMEM; - } - - otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); - if (!otg) { - dev_err(&pdev->dev, "unable to allocate memory for USB OTG\n"); - return -ENOMEM; - } - - phy->dev = &pdev->dev; - - phy->phy.dev = phy->dev; - phy->phy.label = "omap-usb2"; - phy->phy.set_suspend = omap_usb2_suspend; - phy->phy.otg = otg; - phy->phy.type = USB_PHY_TYPE_USB2; - - phy->control_dev = omap_get_control_dev(); - if (IS_ERR(phy->control_dev)) { - dev_dbg(&pdev->dev, "Failed to get control device\n"); - return -ENODEV; - } - - phy->is_suspended = 1; - omap_control_usb_phy_power(phy->control_dev, 0); - - otg->set_host = omap_usb_set_host; - otg->set_peripheral = omap_usb_set_peripheral; - otg->set_vbus = omap_usb_set_vbus; - otg->start_srp = omap_usb_start_srp; - otg->phy = &phy->phy; - - phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k"); - if (IS_ERR(phy->wkupclk)) { - dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n"); - return PTR_ERR(phy->wkupclk); - } - clk_prepare(phy->wkupclk); - - phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m"); - if (IS_ERR(phy->optclk)) - dev_vdbg(&pdev->dev, "unable to get refclk960m\n"); - else - clk_prepare(phy->optclk); - - usb_add_phy_dev(&phy->phy); - - platform_set_drvdata(pdev, phy); - - pm_runtime_enable(phy->dev); - - return 0; -} - -static int omap_usb2_remove(struct platform_device *pdev) -{ - struct omap_usb *phy = platform_get_drvdata(pdev); - - clk_unprepare(phy->wkupclk); - if (!IS_ERR(phy->optclk)) - clk_unprepare(phy->optclk); - usb_remove_phy(&phy->phy); - - return 0; -} - -#ifdef CONFIG_PM_RUNTIME - -static int omap_usb2_runtime_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct omap_usb *phy = platform_get_drvdata(pdev); - - clk_disable(phy->wkupclk); - if (!IS_ERR(phy->optclk)) - clk_disable(phy->optclk); - - return 0; -} - -static int omap_usb2_runtime_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct omap_usb *phy = platform_get_drvdata(pdev); - int ret; - - ret = clk_enable(phy->wkupclk); - if (ret < 0) { - dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); - goto err0; - } - - if (!IS_ERR(phy->optclk)) { - ret = clk_enable(phy->optclk); - if (ret < 0) { - dev_err(phy->dev, "Failed to enable optclk %d\n", ret); - goto err1; - } - } - - return 0; - -err1: - clk_disable(phy->wkupclk); - -err0: - return ret; -} - -static const struct dev_pm_ops omap_usb2_pm_ops = { - SET_RUNTIME_PM_OPS(omap_usb2_runtime_suspend, omap_usb2_runtime_resume, - NULL) -}; - -#define DEV_PM_OPS (&omap_usb2_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif - -#ifdef CONFIG_OF -static const struct of_device_id omap_usb2_id_table[] = { - { .compatible = "ti,omap-usb2" }, - {} -}; -MODULE_DEVICE_TABLE(of, omap_usb2_id_table); -#endif - -static struct platform_driver omap_usb2_driver = { - .probe = omap_usb2_probe, - .remove = omap_usb2_remove, - .driver = { - .name = "omap-usb2", - .owner = THIS_MODULE, - .pm = DEV_PM_OPS, - .of_match_table = of_match_ptr(omap_usb2_id_table), - }, -}; - -module_platform_driver(omap_usb2_driver); - -MODULE_ALIAS("platform: omap_usb2"); -MODULE_AUTHOR("Texas Instruments Inc."); -MODULE_DESCRIPTION("OMAP USB2 phy driver"); -MODULE_LICENSE("GPL v2");