Commit c156bf2c authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'for-3.17-rc' of...

Merge tag 'for-3.17-rc' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy into usb-linus

Kishon writes:

for_3.17-rc

Fix regressions to runtime PM on OMAP and other minor fixes.
parents 69e273c0 fbb1a770
...@@ -7912,6 +7912,19 @@ S: Supported ...@@ -7912,6 +7912,19 @@ S: Supported
L: netdev@vger.kernel.org L: netdev@vger.kernel.org
F: drivers/net/ethernet/samsung/sxgbe/ F: drivers/net/ethernet/samsung/sxgbe/
SAMSUNG USB2 PHY DRIVER
M: Kamil Debski <k.debski@samsung.com>
L: linux-kernel@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/phy/samsung-phy.txt
F: Documentation/phy/samsung-usb2.txt
F: drivers/phy/phy-exynos4210-usb2.c
F: drivers/phy/phy-exynos4x12-usb2.c
F: drivers/phy/phy-exynos5250-usb2.c
F: drivers/phy/phy-s5pv210-usb2.c
F: drivers/phy/phy-samsung-usb2.c
F: drivers/phy/phy-samsung-usb2.h
SERIAL DRIVERS SERIAL DRIVERS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
L: linux-serial@vger.kernel.org L: linux-serial@vger.kernel.org
......
...@@ -41,9 +41,9 @@ config PHY_MVEBU_SATA ...@@ -41,9 +41,9 @@ config PHY_MVEBU_SATA
config PHY_MIPHY365X config PHY_MIPHY365X
tristate "STMicroelectronics MIPHY365X PHY driver for STiH41x series" tristate "STMicroelectronics MIPHY365X PHY driver for STiH41x series"
depends on ARCH_STI depends on ARCH_STI
depends on GENERIC_PHY
depends on HAS_IOMEM depends on HAS_IOMEM
depends on OF depends on OF
select GENERIC_PHY
help help
Enable this to support the miphy transceiver (for SATA/PCIE) Enable this to support the miphy transceiver (for SATA/PCIE)
that is part of STMicroelectronics STiH41x SoC series. that is part of STMicroelectronics STiH41x SoC series.
......
...@@ -542,6 +542,7 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { ...@@ -542,6 +542,7 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = {
}, },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, exynos5_usbdrd_phy_of_match);
static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
{ {
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/usb/otg.h> #include <linux/usb/otg.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/pm_runtime.h>
#include <linux/usb/musb-omap.h> #include <linux/usb/musb-omap.h>
#include <linux/usb/ulpi.h> #include <linux/usb/ulpi.h>
#include <linux/i2c/twl.h> #include <linux/i2c/twl.h>
...@@ -422,37 +423,55 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on) ...@@ -422,37 +423,55 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on)
} }
} }
static int twl4030_phy_power_off(struct phy *phy) static int twl4030_usb_runtime_suspend(struct device *dev)
{ {
struct twl4030_usb *twl = phy_get_drvdata(phy); struct twl4030_usb *twl = dev_get_drvdata(dev);
dev_dbg(twl->dev, "%s\n", __func__);
if (twl->asleep) if (twl->asleep)
return 0; return 0;
twl4030_phy_power(twl, 0); twl4030_phy_power(twl, 0);
twl->asleep = 1; twl->asleep = 1;
dev_dbg(twl->dev, "%s\n", __func__);
return 0; return 0;
} }
static void __twl4030_phy_power_on(struct twl4030_usb *twl) static int twl4030_usb_runtime_resume(struct device *dev)
{ {
struct twl4030_usb *twl = dev_get_drvdata(dev);
dev_dbg(twl->dev, "%s\n", __func__);
if (!twl->asleep)
return 0;
twl4030_phy_power(twl, 1); twl4030_phy_power(twl, 1);
twl4030_i2c_access(twl, 1); twl->asleep = 0;
twl4030_usb_set_mode(twl, twl->usb_mode);
if (twl->usb_mode == T2_USB_MODE_ULPI) return 0;
twl4030_i2c_access(twl, 0);
} }
static int twl4030_phy_power_on(struct phy *phy) static int twl4030_phy_power_off(struct phy *phy)
{ {
struct twl4030_usb *twl = phy_get_drvdata(phy); struct twl4030_usb *twl = phy_get_drvdata(phy);
if (!twl->asleep) dev_dbg(twl->dev, "%s\n", __func__);
pm_runtime_mark_last_busy(twl->dev);
pm_runtime_put_autosuspend(twl->dev);
return 0; return 0;
__twl4030_phy_power_on(twl); }
twl->asleep = 0;
static int twl4030_phy_power_on(struct phy *phy)
{
struct twl4030_usb *twl = phy_get_drvdata(phy);
dev_dbg(twl->dev, "%s\n", __func__); dev_dbg(twl->dev, "%s\n", __func__);
pm_runtime_get_sync(twl->dev);
twl4030_i2c_access(twl, 1);
twl4030_usb_set_mode(twl, twl->usb_mode);
if (twl->usb_mode == T2_USB_MODE_ULPI)
twl4030_i2c_access(twl, 0);
/* /*
* XXX When VBUS gets driven after musb goes to A mode, * XXX When VBUS gets driven after musb goes to A mode,
...@@ -558,8 +577,26 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) ...@@ -558,8 +577,26 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
* USB_LINK_VBUS state. musb_hdrc won't care until it * USB_LINK_VBUS state. musb_hdrc won't care until it
* starts to handle softconnect right. * starts to handle softconnect right.
*/ */
if ((status == OMAP_MUSB_VBUS_VALID) ||
(status == OMAP_MUSB_ID_GROUND)) {
if (twl->asleep)
pm_runtime_get_sync(twl->dev);
} else {
if (!twl->asleep) {
pm_runtime_mark_last_busy(twl->dev);
pm_runtime_put_autosuspend(twl->dev);
}
}
omap_musb_mailbox(status); omap_musb_mailbox(status);
} }
/* don't schedule during sleep - irq works right then */
if (status == OMAP_MUSB_ID_GROUND && !twl->asleep) {
cancel_delayed_work(&twl->id_workaround_work);
schedule_delayed_work(&twl->id_workaround_work, HZ);
}
if (irq)
sysfs_notify(&twl->dev->kobj, NULL, "vbus"); sysfs_notify(&twl->dev->kobj, NULL, "vbus");
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -569,29 +606,8 @@ static void twl4030_id_workaround_work(struct work_struct *work) ...@@ -569,29 +606,8 @@ static void twl4030_id_workaround_work(struct work_struct *work)
{ {
struct twl4030_usb *twl = container_of(work, struct twl4030_usb, struct twl4030_usb *twl = container_of(work, struct twl4030_usb,
id_workaround_work.work); id_workaround_work.work);
enum omap_musb_vbus_id_status status;
bool status_changed = false;
status = twl4030_usb_linkstat(twl);
spin_lock_irq(&twl->lock);
if (status >= 0 && status != twl->linkstat) {
twl->linkstat = status;
status_changed = true;
}
spin_unlock_irq(&twl->lock);
if (status_changed) {
dev_dbg(twl->dev, "handle missing status change to %d\n",
status);
omap_musb_mailbox(status);
}
/* don't schedule during sleep - irq works right then */ twl4030_usb_irq(0, twl);
if (status == OMAP_MUSB_ID_GROUND && !twl->asleep) {
cancel_delayed_work(&twl->id_workaround_work);
schedule_delayed_work(&twl->id_workaround_work, HZ);
}
} }
static int twl4030_phy_init(struct phy *phy) static int twl4030_phy_init(struct phy *phy)
...@@ -599,22 +615,17 @@ static int twl4030_phy_init(struct phy *phy) ...@@ -599,22 +615,17 @@ static int twl4030_phy_init(struct phy *phy)
struct twl4030_usb *twl = phy_get_drvdata(phy); struct twl4030_usb *twl = phy_get_drvdata(phy);
enum omap_musb_vbus_id_status status; enum omap_musb_vbus_id_status status;
/* pm_runtime_get_sync(twl->dev);
* Start in sleep state, we'll get called through set_suspend()
* callback when musb is runtime resumed and it's time to start.
*/
__twl4030_phy_power(twl, 0);
twl->asleep = 1;
status = twl4030_usb_linkstat(twl); status = twl4030_usb_linkstat(twl);
twl->linkstat = status; twl->linkstat = status;
if (status == OMAP_MUSB_ID_GROUND || status == OMAP_MUSB_VBUS_VALID) { if (status == OMAP_MUSB_ID_GROUND || status == OMAP_MUSB_VBUS_VALID)
omap_musb_mailbox(twl->linkstat); omap_musb_mailbox(twl->linkstat);
twl4030_phy_power_on(phy);
}
sysfs_notify(&twl->dev->kobj, NULL, "vbus"); sysfs_notify(&twl->dev->kobj, NULL, "vbus");
pm_runtime_mark_last_busy(twl->dev);
pm_runtime_put_autosuspend(twl->dev);
return 0; return 0;
} }
...@@ -650,6 +661,11 @@ static const struct phy_ops ops = { ...@@ -650,6 +661,11 @@ static const struct phy_ops ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static const struct dev_pm_ops twl4030_usb_pm_ops = {
SET_RUNTIME_PM_OPS(twl4030_usb_runtime_suspend,
twl4030_usb_runtime_resume, NULL)
};
static int twl4030_usb_probe(struct platform_device *pdev) static int twl4030_usb_probe(struct platform_device *pdev)
{ {
struct twl4030_usb_data *pdata = dev_get_platdata(&pdev->dev); struct twl4030_usb_data *pdata = dev_get_platdata(&pdev->dev);
...@@ -726,6 +742,11 @@ static int twl4030_usb_probe(struct platform_device *pdev) ...@@ -726,6 +742,11 @@ static int twl4030_usb_probe(struct platform_device *pdev)
ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier); ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 2000);
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
/* Our job is to use irqs and status from the power module /* Our job is to use irqs and status from the power module
* to keep the transceiver disabled when nothing's connected. * to keep the transceiver disabled when nothing's connected.
* *
...@@ -744,6 +765,9 @@ static int twl4030_usb_probe(struct platform_device *pdev) ...@@ -744,6 +765,9 @@ static int twl4030_usb_probe(struct platform_device *pdev)
return status; return status;
} }
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(twl->dev);
dev_info(&pdev->dev, "Initialized TWL4030 USB module\n"); dev_info(&pdev->dev, "Initialized TWL4030 USB module\n");
return 0; return 0;
} }
...@@ -753,6 +777,7 @@ static int twl4030_usb_remove(struct platform_device *pdev) ...@@ -753,6 +777,7 @@ static int twl4030_usb_remove(struct platform_device *pdev)
struct twl4030_usb *twl = platform_get_drvdata(pdev); struct twl4030_usb *twl = platform_get_drvdata(pdev);
int val; int val;
pm_runtime_get_sync(twl->dev);
cancel_delayed_work(&twl->id_workaround_work); cancel_delayed_work(&twl->id_workaround_work);
device_remove_file(twl->dev, &dev_attr_vbus); device_remove_file(twl->dev, &dev_attr_vbus);
...@@ -772,9 +797,8 @@ static int twl4030_usb_remove(struct platform_device *pdev) ...@@ -772,9 +797,8 @@ static int twl4030_usb_remove(struct platform_device *pdev)
/* disable complete OTG block */ /* disable complete OTG block */
twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB); twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
pm_runtime_mark_last_busy(twl->dev);
if (!twl->asleep) pm_runtime_put(twl->dev);
twl4030_phy_power(twl, 0);
return 0; return 0;
} }
...@@ -792,6 +816,7 @@ static struct platform_driver twl4030_usb_driver = { ...@@ -792,6 +816,7 @@ static struct platform_driver twl4030_usb_driver = {
.remove = twl4030_usb_remove, .remove = twl4030_usb_remove,
.driver = { .driver = {
.name = "twl4030_usb", .name = "twl4030_usb",
.pm = &twl4030_usb_pm_ops,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(twl4030_usb_id_table), .of_match_table = of_match_ptr(twl4030_usb_id_table),
}, },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment