Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 19c05573 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'for_3.14' of...

Merge tag 'for_3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy into char-misc-next

Kishon writes:

Pull request for PHY subsystem contains few fixes in PHY-CORE mostly
w.r.t PM and reference counting and also a new PHY driver used by SATA
in Marvell SoC.
parents dde86f41 e3eae857
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -21,6 +21,12 @@ config PHY_EXYNOS_MIPI_VIDEO
	  Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P
	  and EXYNOS SoCs.

config PHY_MVEBU_SATA
	def_bool y
	depends on ARCH_KIRKWOOD || ARCH_DOVE
	depends on OF
	select GENERIC_PHY

config OMAP_USB2
	tristate "OMAP USB2 PHY Driver"
	depends on ARCH_OMAP2PLUS
+1 −0
Original line number Diff line number Diff line
@@ -5,5 +5,6 @@
obj-$(CONFIG_GENERIC_PHY)		+= phy-core.o
obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
obj-$(CONFIG_PHY_MVEBU_SATA)		+= phy-mvebu-sata.o
obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
+31 −13
Original line number Diff line number Diff line
@@ -94,19 +94,31 @@ static struct phy_provider *of_phy_provider_lookup(struct device_node *node)

int phy_pm_runtime_get(struct phy *phy)
{
	int ret;

	if (!pm_runtime_enabled(&phy->dev))
		return -ENOTSUPP;

	return pm_runtime_get(&phy->dev);
	ret = pm_runtime_get(&phy->dev);
	if (ret < 0 && ret != -EINPROGRESS)
		pm_runtime_put_noidle(&phy->dev);

	return ret;
}
EXPORT_SYMBOL_GPL(phy_pm_runtime_get);

int phy_pm_runtime_get_sync(struct phy *phy)
{
	int ret;

	if (!pm_runtime_enabled(&phy->dev))
		return -ENOTSUPP;

	return pm_runtime_get_sync(&phy->dev);
	ret = pm_runtime_get_sync(&phy->dev);
	if (ret < 0)
		pm_runtime_put_sync(&phy->dev);

	return ret;
}
EXPORT_SYMBOL_GPL(phy_pm_runtime_get_sync);

@@ -155,13 +167,14 @@ int phy_init(struct phy *phy)
		return ret;

	mutex_lock(&phy->mutex);
	if (phy->init_count++ == 0 && phy->ops->init) {
	if (phy->init_count == 0 && phy->ops->init) {
		ret = phy->ops->init(phy);
		if (ret < 0) {
			dev_err(&phy->dev, "phy init failed --> %d\n", ret);
			goto out;
		}
	}
	++phy->init_count;

out:
	mutex_unlock(&phy->mutex);
@@ -179,13 +192,14 @@ int phy_exit(struct phy *phy)
		return ret;

	mutex_lock(&phy->mutex);
	if (--phy->init_count == 0 && phy->ops->exit) {
	if (phy->init_count == 1 && phy->ops->exit) {
		ret = phy->ops->exit(phy);
		if (ret < 0) {
			dev_err(&phy->dev, "phy exit failed --> %d\n", ret);
			goto out;
		}
	}
	--phy->init_count;

out:
	mutex_unlock(&phy->mutex);
@@ -196,23 +210,27 @@ EXPORT_SYMBOL_GPL(phy_exit);

int phy_power_on(struct phy *phy)
{
	int ret = -ENOTSUPP;
	int ret;

	ret = phy_pm_runtime_get_sync(phy);
	if (ret < 0 && ret != -ENOTSUPP)
		return ret;

	mutex_lock(&phy->mutex);
	if (phy->power_count++ == 0 && phy->ops->power_on) {
	if (phy->power_count == 0 && phy->ops->power_on) {
		ret = phy->ops->power_on(phy);
		if (ret < 0) {
			dev_err(&phy->dev, "phy poweron failed --> %d\n", ret);
			goto out;
		}
	}
	++phy->power_count;
	mutex_unlock(&phy->mutex);
	return 0;

out:
	mutex_unlock(&phy->mutex);
	phy_pm_runtime_put_sync(phy);

	return ret;
}
@@ -220,22 +238,22 @@ EXPORT_SYMBOL_GPL(phy_power_on);

int phy_power_off(struct phy *phy)
{
	int ret = -ENOTSUPP;
	int ret;

	mutex_lock(&phy->mutex);
	if (--phy->power_count == 0 && phy->ops->power_off) {
	if (phy->power_count == 1 && phy->ops->power_off) {
		ret =  phy->ops->power_off(phy);
		if (ret < 0) {
			dev_err(&phy->dev, "phy poweroff failed --> %d\n", ret);
			goto out;
			mutex_unlock(&phy->mutex);
			return ret;
		}
	}

out:
	--phy->power_count;
	mutex_unlock(&phy->mutex);
	phy_pm_runtime_put(phy);

	return ret;
	return 0;
}
EXPORT_SYMBOL_GPL(phy_power_off);

@@ -360,7 +378,7 @@ EXPORT_SYMBOL_GPL(of_phy_simple_xlate);
struct phy *phy_get(struct device *dev, const char *string)
{
	int index = 0;
	struct phy *phy = NULL;
	struct phy *phy;

	if (string == NULL) {
		dev_WARN(dev, "missing string\n");
+137 −0
Original line number Diff line number Diff line
/*
 *	phy-mvebu-sata.c: SATA Phy driver for the Marvell mvebu SoCs.
 *
 *	Copyright (C) 2013 Andrew Lunn <andrew@lunn.ch>
 *
 *	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.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/phy/phy.h>
#include <linux/io.h>
#include <linux/platform_device.h>

struct priv {
	struct clk	*clk;
	void __iomem	*base;
};

#define SATA_PHY_MODE_2	0x0330
#define  MODE_2_FORCE_PU_TX	BIT(0)
#define  MODE_2_FORCE_PU_RX	BIT(1)
#define  MODE_2_PU_PLL		BIT(2)
#define  MODE_2_PU_IVREF	BIT(3)
#define SATA_IF_CTRL	0x0050
#define  CTRL_PHY_SHUTDOWN	BIT(9)

static int phy_mvebu_sata_power_on(struct phy *phy)
{
	struct priv *priv = phy_get_drvdata(phy);
	u32 reg;

	clk_prepare_enable(priv->clk);

	/* Enable PLL and IVREF */
	reg = readl(priv->base + SATA_PHY_MODE_2);
	reg |= (MODE_2_FORCE_PU_TX | MODE_2_FORCE_PU_RX |
		MODE_2_PU_PLL | MODE_2_PU_IVREF);
	writel(reg , priv->base + SATA_PHY_MODE_2);

	/* Enable PHY */
	reg = readl(priv->base + SATA_IF_CTRL);
	reg &= ~CTRL_PHY_SHUTDOWN;
	writel(reg, priv->base + SATA_IF_CTRL);

	clk_disable_unprepare(priv->clk);

	return 0;
}

static int phy_mvebu_sata_power_off(struct phy *phy)
{
	struct priv *priv = phy_get_drvdata(phy);
	u32 reg;

	clk_prepare_enable(priv->clk);

	/* Disable PLL and IVREF */
	reg = readl(priv->base + SATA_PHY_MODE_2);
	reg &= ~(MODE_2_FORCE_PU_TX | MODE_2_FORCE_PU_RX |
		 MODE_2_PU_PLL | MODE_2_PU_IVREF);
	writel(reg, priv->base + SATA_PHY_MODE_2);

	/* Disable PHY */
	reg = readl(priv->base + SATA_IF_CTRL);
	reg |= CTRL_PHY_SHUTDOWN;
	writel(reg, priv->base + SATA_IF_CTRL);

	clk_disable_unprepare(priv->clk);

	return 0;
}

static struct phy_ops phy_mvebu_sata_ops = {
	.power_on	= phy_mvebu_sata_power_on,
	.power_off	= phy_mvebu_sata_power_off,
	.owner		= THIS_MODULE,
};

static int phy_mvebu_sata_probe(struct platform_device *pdev)
{
	struct phy_provider *phy_provider;
	struct resource *res;
	struct priv *priv;
	struct phy *phy;

	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	priv->base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(priv->base))
		return PTR_ERR(priv->base);

	priv->clk = devm_clk_get(&pdev->dev, "sata");
	if (IS_ERR(priv->clk))
		return PTR_ERR(priv->clk);

	phy_provider = devm_of_phy_provider_register(&pdev->dev,
						     of_phy_simple_xlate);
	if (IS_ERR(phy_provider))
		return PTR_ERR(phy_provider);

	phy = devm_phy_create(&pdev->dev, &phy_mvebu_sata_ops, NULL);
	if (IS_ERR(phy))
		return PTR_ERR(phy);

	phy_set_drvdata(phy, priv);

	/* The boot loader may of left it on. Turn it off. */
	phy_mvebu_sata_power_off(phy);

	return 0;
}

static const struct of_device_id phy_mvebu_sata_of_match[] = {
	{ .compatible = "marvell,mvebu-sata-phy" },
	{ },
};
MODULE_DEVICE_TABLE(of, phy_mvebu_sata_of_match);

static struct platform_driver phy_mvebu_sata_driver = {
	.probe	= phy_mvebu_sata_probe,
	.driver = {
		.name	= "phy-mvebu-sata",
		.owner	= THIS_MODULE,
		.of_match_table	= phy_mvebu_sata_of_match,
	}
};
module_platform_driver(phy_mvebu_sata_driver);

MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
MODULE_DESCRIPTION("Marvell MVEBU SATA PHY driver");
MODULE_LICENSE("GPL v2");