diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-04-10 13:47:50 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-04-10 13:47:50 +0200 |
commit | 2aebe3f3b20724e09ec76b196e16404d1ea573d9 (patch) | |
tree | ef667cb786a58d3bb2639ad5c488e5bac501defa /drivers/phy | |
parent | c8d1bc12c7986c166bd3504213d9df2bc11ad7d6 (diff) | |
parent | e95cf393d2097a7744f98de1c7936fcbde0843e3 (diff) | |
download | linux-2aebe3f3b20724e09ec76b196e16404d1ea573d9.tar.gz linux-2aebe3f3b20724e09ec76b196e16404d1ea573d9.tar.bz2 linux-2aebe3f3b20724e09ec76b196e16404d1ea573d9.zip |
Merge tag 'for-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy into usb-next
Kishon writes:
New Features
============
*) Add driver for USB PHYs on sun9i
*) Add driver for USB PHY on dm816x
*) Modified exynos5-usbdrd driver to add support for Exynos5433 SoC
Fixes
=====
*) Fix power_on/power_off failure paths in some drivers
*) Make miphy365x use generic PHY type constants
*) Fix build errors due to missing export symbols in qcom-ufs driver
*) Make all the functions return proper error values
Cleanups
========
*) use PTR_ERR_OR_ZERO to simplify code
*) use devm_kcalloc instead of devm_kzalloc with multiply
*) remove un-necessary ifdef CONFIG_OF
Diffstat (limited to 'drivers/phy')
-rw-r--r-- | drivers/phy/Kconfig | 18 | ||||
-rw-r--r-- | drivers/phy/Makefile | 2 | ||||
-rw-r--r-- | drivers/phy/phy-berlin-sata.c | 2 | ||||
-rw-r--r-- | drivers/phy/phy-berlin-usb.c | 19 | ||||
-rw-r--r-- | drivers/phy/phy-dm816x-usb.c | 290 | ||||
-rw-r--r-- | drivers/phy/phy-exynos5-usbdrd.c | 10 | ||||
-rw-r--r-- | drivers/phy/phy-miphy28lp.c | 5 | ||||
-rw-r--r-- | drivers/phy/phy-miphy365x.c | 14 | ||||
-rw-r--r-- | drivers/phy/phy-omap-control.c | 10 | ||||
-rw-r--r-- | drivers/phy/phy-omap-usb2.c | 6 | ||||
-rw-r--r-- | drivers/phy/phy-qcom-ufs.c | 33 | ||||
-rw-r--r-- | drivers/phy/phy-samsung-usb2.c | 10 | ||||
-rw-r--r-- | drivers/phy/phy-spear1310-miphy.c | 4 | ||||
-rw-r--r-- | drivers/phy/phy-spear1340-miphy.c | 4 | ||||
-rw-r--r-- | drivers/phy/phy-stih41x-usb.c | 8 | ||||
-rw-r--r-- | drivers/phy/phy-sun9i-usb.c | 202 | ||||
-rw-r--r-- | drivers/phy/phy-ti-pipe3.c | 9 | ||||
-rw-r--r-- | drivers/phy/phy-xgene.c | 23 |
18 files changed, 580 insertions, 89 deletions
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 2962de205ba7..a53bd5b52df9 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -35,6 +35,13 @@ config ARMADA375_USBCLUSTER_PHY depends on OF select GENERIC_PHY +config PHY_DM816X_USB + tristate "TI dm816x USB PHY driver" + depends on ARCH_OMAP2PLUS + select GENERIC_PHY + help + Enable this for dm816x USB to work. + config PHY_EXYNOS_MIPI_VIDEO tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver" depends on HAS_IOMEM @@ -174,6 +181,17 @@ config PHY_SUN4I_USB This driver controls the entire USB PHY block, both the USB OTG parts, as well as the 2 regular USB 2 host PHYs. +config PHY_SUN9I_USB + tristate "Allwinner sun9i SoC USB PHY driver" + depends on ARCH_SUNXI && HAS_IOMEM && OF + depends on RESET_CONTROLLER + select GENERIC_PHY + help + Enable this to support the transceiver that is part of Allwinner + sun9i SoCs. + + This driver controls each individual USB 2 host PHY. + config PHY_SAMSUNG_USB2 tristate "Samsung USB 2.0 PHY driver" depends on HAS_IOMEM diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index f080e1bb2a74..f12625178780 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_GENERIC_PHY) += phy-core.o obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o +obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o @@ -20,6 +21,7 @@ obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o obj-$(CONFIG_PHY_EXYNOS5250_SATA) += phy-exynos5250-sata.o obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o +obj-$(CONFIG_PHY_SUN9I_USB) += phy-sun9i-usb.o obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o phy-exynos-usb2-y += phy-samsung-usb2.o phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o diff --git a/drivers/phy/phy-berlin-sata.c b/drivers/phy/phy-berlin-sata.c index 099eee8851e5..6f3e06d687de 100644 --- a/drivers/phy/phy-berlin-sata.c +++ b/drivers/phy/phy-berlin-sata.c @@ -218,7 +218,7 @@ static int phy_berlin_sata_probe(struct platform_device *pdev) if (priv->nphys == 0) return -ENODEV; - priv->phys = devm_kzalloc(dev, priv->nphys * sizeof(*priv->phys), + priv->phys = devm_kcalloc(dev, priv->nphys, sizeof(*priv->phys), GFP_KERNEL); if (!priv->phys) return -ENOMEM; diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c index c8a8d53a6ece..c6fc95b53083 100644 --- a/drivers/phy/phy-berlin-usb.c +++ b/drivers/phy/phy-berlin-usb.c @@ -103,9 +103,6 @@ #define MODE_TEST_EN BIT(11) #define ANA_TEST_DC_CTRL(x) ((x) << 12) -#define to_phy_berlin_usb_priv(p) \ - container_of((p), struct phy_berlin_usb_priv, phy) - static const u32 phy_berlin_pll_dividers[] = { /* Berlin 2 */ CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54), @@ -115,14 +112,13 @@ static const u32 phy_berlin_pll_dividers[] = { struct phy_berlin_usb_priv { void __iomem *base; - struct phy *phy; struct reset_control *rst_ctrl; u32 pll_divider; }; static int phy_berlin_usb_power_on(struct phy *phy) { - struct phy_berlin_usb_priv *priv = dev_get_drvdata(phy->dev.parent); + struct phy_berlin_usb_priv *priv = phy_get_drvdata(phy); reset_control_reset(priv->rst_ctrl); @@ -175,6 +171,7 @@ static int phy_berlin_usb_probe(struct platform_device *pdev) of_match_device(phy_berlin_sata_of_match, &pdev->dev); struct phy_berlin_usb_priv *priv; struct resource *res; + struct phy *phy; struct phy_provider *phy_provider; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -192,20 +189,18 @@ static int phy_berlin_usb_probe(struct platform_device *pdev) priv->pll_divider = *((u32 *)match->data); - priv->phy = devm_phy_create(&pdev->dev, NULL, &phy_berlin_usb_ops); - if (IS_ERR(priv->phy)) { + phy = devm_phy_create(&pdev->dev, NULL, &phy_berlin_usb_ops); + if (IS_ERR(phy)) { dev_err(&pdev->dev, "failed to create PHY\n"); - return PTR_ERR(priv->phy); + return PTR_ERR(phy); } platform_set_drvdata(pdev, priv); + phy_set_drvdata(phy, priv); phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); - if (IS_ERR(phy_provider)) - return PTR_ERR(phy_provider); - - return 0; + return PTR_ERR_OR_ZERO(phy_provider); } static struct platform_driver phy_berlin_usb_driver = { diff --git a/drivers/phy/phy-dm816x-usb.c b/drivers/phy/phy-dm816x-usb.c new file mode 100644 index 000000000000..7b42555ddd51 --- /dev/null +++ b/drivers/phy/phy-dm816x-usb.c @@ -0,0 +1,290 @@ +/* + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/io.h> +#include <linux/usb/phy_companion.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/pm_runtime.h> +#include <linux/delay.h> +#include <linux/phy/phy.h> +#include <linux/of_platform.h> + +#include <linux/mfd/syscon.h> + +/* + * TRM has two sets of USB_CTRL registers.. The correct register bits + * are in TRM section 24.9.8.2 USB_CTRL Register. The TRM documents the + * phy as being SR70LX Synopsys USB 2.0 OTG nanoPHY. It also seems at + * least dm816x rev c ignores writes to USB_CTRL register, but the TI + * kernel is writing to those so it's possible that later revisions + * have worknig USB_CTRL register. + * + * Also note that At least USB_CTRL register seems to be dm816x specific + * according to the TRM. It's possible that USBPHY_CTRL is more generic, + * but that would have to be checked against the SR70LX documentation + * which does not seem to be publicly available. + * + * Finally, the phy on dm814x and am335x is different from dm816x. + */ +#define DM816X_USB_CTRL_PHYCLKSRC BIT(8) /* 1 = PLL ref clock */ +#define DM816X_USB_CTRL_PHYSLEEP1 BIT(1) /* Enable the first phy */ +#define DM816X_USB_CTRL_PHYSLEEP0 BIT(0) /* Enable the second phy */ + +#define DM816X_USBPHY_CTRL_TXRISETUNE 1 +#define DM816X_USBPHY_CTRL_TXVREFTUNE 0xc +#define DM816X_USBPHY_CTRL_TXPREEMTUNE 0x2 + +struct dm816x_usb_phy { + struct regmap *syscon; + struct device *dev; + unsigned int instance; + struct clk *refclk; + struct usb_phy phy; + unsigned int usb_ctrl; /* Shared between phy0 and phy1 */ + unsigned int usbphy_ctrl; +}; + +static int dm816x_usb_phy_set_host(struct usb_otg *otg, struct usb_bus *host) +{ + otg->host = host; + if (!host) + otg->state = OTG_STATE_UNDEFINED; + + return 0; +} + +static int dm816x_usb_phy_set_peripheral(struct usb_otg *otg, + struct usb_gadget *gadget) +{ + otg->gadget = gadget; + if (!gadget) + otg->state = OTG_STATE_UNDEFINED; + + return 0; +} + +static int dm816x_usb_phy_init(struct phy *x) +{ + struct dm816x_usb_phy *phy = phy_get_drvdata(x); + unsigned int val; + int error; + + if (clk_get_rate(phy->refclk) != 24000000) + dev_warn(phy->dev, "nonstandard phy refclk\n"); + + /* Set PLL ref clock and put phys to sleep */ + error = regmap_update_bits(phy->syscon, phy->usb_ctrl, + DM816X_USB_CTRL_PHYCLKSRC | + DM816X_USB_CTRL_PHYSLEEP1 | + DM816X_USB_CTRL_PHYSLEEP0, + 0); + regmap_read(phy->syscon, phy->usb_ctrl, &val); + if ((val & 3) != 0) + dev_info(phy->dev, + "Working dm816x USB_CTRL! (0x%08x)\n", + val); + + /* + * TI kernel sets these values for "symmetrical eye diagram and + * better signal quality" so let's assume somebody checked the + * values with a scope and set them here too. + */ + regmap_read(phy->syscon, phy->usbphy_ctrl, &val); + val |= DM816X_USBPHY_CTRL_TXRISETUNE | + DM816X_USBPHY_CTRL_TXVREFTUNE | + DM816X_USBPHY_CTRL_TXPREEMTUNE; + regmap_write(phy->syscon, phy->usbphy_ctrl, val); + + return 0; +} + +static struct phy_ops ops = { + .init = dm816x_usb_phy_init, + .owner = THIS_MODULE, +}; + +static int dm816x_usb_phy_runtime_suspend(struct device *dev) +{ + struct dm816x_usb_phy *phy = dev_get_drvdata(dev); + unsigned int mask, val; + int error = 0; + + mask = BIT(phy->instance); + val = ~BIT(phy->instance); + error = regmap_update_bits(phy->syscon, phy->usb_ctrl, + mask, val); + if (error) + dev_err(phy->dev, "phy%i failed to power off\n", + phy->instance); + clk_disable(phy->refclk); + + return 0; +} + +static int dm816x_usb_phy_runtime_resume(struct device *dev) +{ + struct dm816x_usb_phy *phy = dev_get_drvdata(dev); + unsigned int mask, val; + int error; + + error = clk_enable(phy->refclk); + if (error) + return error; + + /* + * Note that at least dm816x rev c does not seem to do + * anything with the USB_CTRL register. But let's follow + * what the TI tree is doing in case later revisions use + * USB_CTRL. + */ + mask = BIT(phy->instance); + val = BIT(phy->instance); + error = regmap_update_bits(phy->syscon, phy->usb_ctrl, + mask, val); + if (error) { + dev_err(phy->dev, "phy%i failed to power on\n", + phy->instance); + clk_disable(phy->refclk); + return error; + } + + return 0; +} + +static UNIVERSAL_DEV_PM_OPS(dm816x_usb_phy_pm_ops, + dm816x_usb_phy_runtime_suspend, + dm816x_usb_phy_runtime_resume, + NULL); + +#ifdef CONFIG_OF +static const struct of_device_id dm816x_usb_phy_id_table[] = { + { + .compatible = "ti,dm8168-usb-phy", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, dm816x_usb_phy_id_table); +#endif + +static int dm816x_usb_phy_probe(struct platform_device *pdev) +{ + struct dm816x_usb_phy *phy; + struct resource *res; + struct phy *generic_phy; + struct phy_provider *phy_provider; + struct usb_otg *otg; + const struct of_device_id *of_id; + const struct usb_phy_data *phy_data; + int error; + + of_id = of_match_device(of_match_ptr(dm816x_usb_phy_id_table), + &pdev->dev); + if (!of_id) + return -EINVAL; + + phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENOENT; + + phy->syscon = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "syscon"); + if (IS_ERR(phy->syscon)) + return PTR_ERR(phy->syscon); + + /* + * According to sprs614e.pdf, the first usb_ctrl is shared and + * the second instance for usb_ctrl is reserved.. Also the + * register bits are different from earlier TRMs. + */ + phy->usb_ctrl = 0x20; + phy->usbphy_ctrl = (res->start & 0xff) + 4; + if (phy->usbphy_ctrl == 0x2c) + phy->instance = 1; + + phy_data = of_id->data; + + otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); + if (!otg) + return -ENOMEM; + + phy->dev = &pdev->dev; + phy->phy.dev = phy->dev; + phy->phy.label = "dm8168_usb_phy"; + phy->phy.otg = otg; + phy->phy.type = USB_PHY_TYPE_USB2; + otg->set_host = dm816x_usb_phy_set_host; + otg->set_peripheral = dm816x_usb_phy_set_peripheral; + otg->usb_phy = &phy->phy; + + platform_set_drvdata(pdev, phy); + + phy->refclk = devm_clk_get(phy->dev, "refclk"); + if (IS_ERR(phy->refclk)) + return PTR_ERR(phy->refclk); + error = clk_prepare(phy->refclk); + if (error) + return error; + + pm_runtime_enable(phy->dev); + generic_phy = devm_phy_create(phy->dev, NULL, &ops); + if (IS_ERR(generic_phy)) + return PTR_ERR(generic_phy); + + phy_set_drvdata(generic_phy, phy); + + phy_provider = devm_of_phy_provider_register(phy->dev, + of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); + + usb_add_phy_dev(&phy->phy); + + return 0; +} + +static int dm816x_usb_phy_remove(struct platform_device *pdev) +{ + struct dm816x_usb_phy *phy = platform_get_drvdata(pdev); + + usb_remove_phy(&phy->phy); + pm_runtime_disable(phy->dev); + clk_unprepare(phy->refclk); + + return 0; +} + +static struct platform_driver dm816x_usb_phy_driver = { + .probe = dm816x_usb_phy_probe, + .remove = dm816x_usb_phy_remove, + .driver = { + .name = "dm816x-usb-phy", + .pm = &dm816x_usb_phy_pm_ops, + .of_match_table = of_match_ptr(dm816x_usb_phy_id_table), + }, +}; + +module_platform_driver(dm816x_usb_phy_driver); + +MODULE_ALIAS("platform:dm816x_usb"); +MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); +MODULE_DESCRIPTION("dm816x usb phy driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/phy-exynos5-usbdrd.c index e2a0be750ad9..d72ef15b0d68 100644 --- a/drivers/phy/phy-exynos5-usbdrd.c +++ b/drivers/phy/phy-exynos5-usbdrd.c @@ -624,6 +624,13 @@ static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = { .has_common_clk_gate = true, }; +static const struct exynos5_usbdrd_phy_drvdata exynos5433_usbdrd_phy = { + .phy_cfg = phy_cfg_exynos5, + .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, + .pmu_offset_usbdrd1_phy = EXYNOS5433_USBHOST30_PHY_CONTROL, + .has_common_clk_gate = false, +}; + static const struct exynos5_usbdrd_phy_drvdata exynos7_usbdrd_phy = { .phy_cfg = phy_cfg_exynos5, .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, @@ -638,6 +645,9 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { .compatible = "samsung,exynos5420-usbdrd-phy", .data = &exynos5420_usbdrd_phy }, { + .compatible = "samsung,exynos5433-usbdrd-phy", + .data = &exynos5433_usbdrd_phy + }, { .compatible = "samsung,exynos7-usbdrd-phy", .data = &exynos7_usbdrd_phy }, diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c index 933435214acc..c4cc11dcb2a2 100644 --- a/drivers/phy/phy-miphy28lp.c +++ b/drivers/phy/phy-miphy28lp.c @@ -1259,10 +1259,7 @@ static int miphy28lp_probe(struct platform_device *pdev) } provider = devm_of_phy_provider_register(&pdev->dev, miphy28lp_xlate); - if (IS_ERR(provider)) - return PTR_ERR(provider); - - return 0; + return PTR_ERR_OR_ZERO(provider); } static const struct of_device_id miphy28lp_of_match[] = { diff --git a/drivers/phy/phy-miphy365x.c b/drivers/phy/phy-miphy365x.c index 51b459db9137..019c2d75344e 100644 --- a/drivers/phy/phy-miphy365x.c +++ b/drivers/phy/phy-miphy365x.c @@ -25,7 +25,7 @@ #include <linux/mfd/syscon.h> #include <linux/regmap.h> -#include <dt-bindings/phy/phy-miphy365x.h> +#include <dt-bindings/phy/phy.h> #define HFC_TIMEOUT 100 @@ -177,7 +177,7 @@ static u8 rx_tx_spd[] = { static int miphy365x_set_path(struct miphy365x_phy *miphy_phy, struct miphy365x_dev *miphy_dev) { - bool sata = (miphy_phy->type == MIPHY_TYPE_SATA); + bool sata = (miphy_phy->type == PHY_TYPE_SATA); return regmap_update_bits(miphy_dev->regmap, miphy_phy->ctrlreg, @@ -431,7 +431,7 @@ static int miphy365x_init(struct phy *phy) } /* Initialise Miphy for PCIe or SATA */ - if (miphy_phy->type == MIPHY_TYPE_PCIE) + if (miphy_phy->type == PHY_TYPE_PCIE) ret = miphy365x_init_pcie_port(miphy_phy, miphy_dev); else ret = miphy365x_init_sata_port(miphy_phy, miphy_dev); @@ -455,8 +455,8 @@ int miphy365x_get_addr(struct device *dev, struct miphy365x_phy *miphy_phy, return ret; } - if (!((!strncmp(name, "sata", 4) && type == MIPHY_TYPE_SATA) || - (!strncmp(name, "pcie", 4) && type == MIPHY_TYPE_PCIE))) + if (!((!strncmp(name, "sata", 4) && type == PHY_TYPE_SATA) || + (!strncmp(name, "pcie", 4) && type == PHY_TYPE_PCIE))) return 0; miphy_phy->base = of_iomap(phynode, index); @@ -499,8 +499,8 @@ static struct phy *miphy365x_xlate(struct device *dev, miphy_phy->type = args->args[0]; - if (!(miphy_phy->type == MIPHY_TYPE_SATA || - miphy_phy->type == MIPHY_TYPE_PCIE)) { + if (!(miphy_phy->type == PHY_TYPE_SATA || + miphy_phy->type == PHY_TYPE_PCIE)) { dev_err(dev, "Unsupported device type: %d\n", miphy_phy->type); return ERR_PTR(-EINVAL); } diff --git a/drivers/phy/phy-omap-control.c b/drivers/phy/phy-omap-control.c index 93252e053a31..e9c41b3fa0ee 100644 --- a/drivers/phy/phy-omap-control.c +++ b/drivers/phy/phy-omap-control.c @@ -216,7 +216,6 @@ void omap_control_usb_set_mode(struct device *dev, return; ctrl_phy = dev_get_drvdata(dev); - if (!ctrl_phy) { dev_err(dev, "Invalid control phy device\n"); return; @@ -241,8 +240,6 @@ void omap_control_usb_set_mode(struct device *dev, } EXPORT_SYMBOL_GPL(omap_control_usb_set_mode); -#ifdef CONFIG_OF - static const enum omap_control_phy_type otghs_data = OMAP_CTRL_TYPE_OTGHS; static const enum omap_control_phy_type usb2_data = OMAP_CTRL_TYPE_USB2; static const enum omap_control_phy_type pipe3_data = OMAP_CTRL_TYPE_PIPE3; @@ -278,8 +275,6 @@ static const struct of_device_id omap_control_phy_id_table[] = { {}, }; MODULE_DEVICE_TABLE(of, omap_control_phy_id_table); -#endif - static int omap_control_phy_probe(struct platform_device *pdev) { @@ -287,8 +282,7 @@ static int omap_control_phy_probe(struct platform_device *pdev) const struct of_device_id *of_id; struct omap_control_phy *control_phy; - of_id = of_match_device(of_match_ptr(omap_control_phy_id_table), - &pdev->dev); + of_id = of_match_device(omap_control_phy_id_table, &pdev->dev); if (!of_id) return -EINVAL; @@ -344,7 +338,7 @@ static struct platform_driver omap_control_phy_driver = { .probe = omap_control_phy_probe, .driver = { .name = "omap-control-phy", - .of_match_table = of_match_ptr(omap_control_phy_id_table), + .of_match_table = omap_control_phy_id_table, }, }; diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c index 4757e765696a..183ef4368101 100644 --- a/drivers/phy/phy-omap-usb2.c +++ b/drivers/phy/phy-omap-usb2.c @@ -144,7 +144,6 @@ static struct phy_ops ops = { .owner = THIS_MODULE, }; -#ifdef CONFIG_OF static const struct usb_phy_data omap_usb2_data = { .label = "omap_usb2", .flags = OMAP_USB2_HAS_START_SRP | OMAP_USB2_HAS_SET_VBUS, @@ -185,7 +184,6 @@ static const struct of_device_id omap_usb2_id_table[] = { {}, }; MODULE_DEVICE_TABLE(of, omap_usb2_id_table); -#endif static int omap_usb2_probe(struct platform_device *pdev) { @@ -200,7 +198,7 @@ static int omap_usb2_probe(struct platform_device *pdev) const struct of_device_id *of_id; struct usb_phy_data *phy_data; - of_id = of_match_device(of_match_ptr(omap_usb2_id_table), &pdev->dev); + of_id = of_match_device(omap_usb2_id_table, &pdev->dev); if (!of_id) return -EINVAL; @@ -378,7 +376,7 @@ static struct platform_driver omap_usb2_driver = { .driver = { .name = "omap-usb2", .pm = DEV_PM_OPS, - .of_match_table = of_match_ptr(omap_usb2_id_table), + .of_match_table = omap_usb2_id_table, }, }; diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c index 44ee983d57fe..c4199e605ce2 100644 --- a/drivers/phy/phy-qcom-ufs.c +++ b/drivers/phy/phy-qcom-ufs.c @@ -73,6 +73,7 @@ int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, out: return ret; } +EXPORT_SYMBOL_GPL(ufs_qcom_phy_calibrate); struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev, struct ufs_qcom_phy *common_cfg, @@ -101,6 +102,7 @@ struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev, if (IS_ERR(generic_phy)) { err = PTR_ERR(generic_phy); dev_err(dev, "%s: failed to create phy %d\n", __func__, err); + generic_phy = NULL; goto out; } @@ -110,6 +112,7 @@ struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev, out: return generic_phy; } +EXPORT_SYMBOL_GPL(ufs_qcom_phy_generic_probe); /* * This assumes the embedded phy structure inside generic_phy is of type @@ -121,6 +124,7 @@ struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy) { return (struct ufs_qcom_phy *)phy_get_drvdata(generic_phy); } +EXPORT_SYMBOL_GPL(get_ufs_qcom_phy); static int ufs_qcom_phy_base_init(struct platform_device *pdev, @@ -131,40 +135,23 @@ int ufs_qcom_phy_base_init(struct platform_device *pdev, int err = 0; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_mem"); - if (!res) { - dev_err(dev, "%s: phy_mem resource not found\n", __func__); - err = -ENOMEM; - goto out; - } - phy_common->mmio = devm_ioremap_resource(dev, res); if (IS_ERR((void const *)phy_common->mmio)) { err = PTR_ERR((void const *)phy_common->mmio); phy_common->mmio = NULL; dev_err(dev, "%s: ioremap for phy_mem resource failed %d\n", __func__, err); - goto out; + return err; } /* "dev_ref_clk_ctrl_mem" is optional resource */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dev_ref_clk_ctrl_mem"); - if (!res) { - dev_dbg(dev, "%s: dev_ref_clk_ctrl_mem resource not found\n", - __func__); - goto out; - } - phy_common->dev_ref_clk_ctrl_mmio = devm_ioremap_resource(dev, res); - if (IS_ERR((void const *)phy_common->dev_ref_clk_ctrl_mmio)) { - err = PTR_ERR((void const *)phy_common->dev_ref_clk_ctrl_mmio); + if (IS_ERR((void const *)phy_common->dev_ref_clk_ctrl_mmio)) phy_common->dev_ref_clk_ctrl_mmio = NULL; - dev_err(dev, "%s: ioremap for dev_ref_clk_ctrl_mem resource failed %d\n", - __func__, err); - } -out: - return err; + return 0; } static int __ufs_qcom_phy_clk_get(struct phy *phy, @@ -228,6 +215,7 @@ ufs_qcom_phy_init_clks(struct phy *generic_phy, out: return err; } +EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_clks); int ufs_qcom_phy_init_vregulators(struct phy *generic_phy, @@ -252,6 +240,7 @@ ufs_qcom_phy_init_vregulators(struct phy *generic_phy, out: return err; } +EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_vregulators); static int __ufs_qcom_phy_init_vreg(struct phy *phy, struct ufs_qcom_phy_vreg *vreg, const char *name, bool optional) @@ -647,6 +636,7 @@ int ufs_qcom_phy_remove(struct phy *generic_phy, return 0; } +EXPORT_SYMBOL_GPL(ufs_qcom_phy_remove); int ufs_qcom_phy_exit(struct phy *generic_phy) { @@ -657,6 +647,7 @@ int ufs_qcom_phy_exit(struct phy *generic_phy) return 0; } +EXPORT_SYMBOL_GPL(ufs_qcom_phy_exit); int ufs_qcom_phy_is_pcs_ready(struct phy *generic_phy) { @@ -725,6 +716,7 @@ out_disable_phy: out: return err; } +EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_on); int ufs_qcom_phy_power_off(struct phy *generic_phy) { @@ -743,3 +735,4 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy) return 0; } +EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_off); diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c index 4a12f66b7fb5..55b6994932e3 100644 --- a/drivers/phy/phy-samsung-usb2.c +++ b/drivers/phy/phy-samsung-usb2.c @@ -37,10 +37,14 @@ static int samsung_usb2_phy_power_on(struct phy *phy) spin_lock(&drv->lock); ret = inst->cfg->power_on(inst); spin_unlock(&drv->lock); + if (ret) + goto err_power_on; } return 0; +err_power_on: + clk_disable_unprepare(drv->ref_clk); err_instance_clk: clk_disable_unprepare(drv->clk); err_main_clk: @@ -51,7 +55,7 @@ static int samsung_usb2_phy_power_off(struct phy *phy) { struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy); struct samsung_usb2_phy_driver *drv = inst->drv; - int ret = 0; + int ret; dev_dbg(drv->dev, "Request to power_off \"%s\" usb phy\n", inst->cfg->label); @@ -59,10 +63,12 @@ static int samsung_usb2_phy_power_off(struct phy *phy) spin_lock(&drv->lock); ret = inst->cfg->power_off(inst); spin_unlock(&drv->lock); + if (ret) + return ret; } clk_disable_unprepare(drv->ref_clk); clk_disable_unprepare(drv->clk); - return ret; + return 0; } static struct phy_ops samsung_usb2_phy_ops = { diff --git a/drivers/phy/phy-spear1310-miphy.c b/drivers/phy/phy-spear1310-miphy.c index 9f47fae7eecb..65ae640cfbd1 100644 --- a/drivers/phy/phy-spear1310-miphy.c +++ b/drivers/phy/phy-spear1310-miphy.c @@ -192,14 +192,14 @@ static struct phy *spear1310_miphy_xlate(struct device *dev, if (args->args_count < 1) { dev_err(dev, "DT did not pass correct no of args\n"); - return NULL; + return ERR_PTR(-ENODEV); } priv->mode = args->args[0]; if (priv->mode != SATA && priv->mode != PCIE) { dev_err(dev, "DT did not pass correct phy mode\n"); - return NULL; + return ERR_PTR(-ENODEV); } return priv->phy; diff --git a/drivers/phy/phy-spear1340-miphy.c b/drivers/phy/phy-spear1340-miphy.c index e42bc200275f..1a00c2817f34 100644 --- a/drivers/phy/phy-spear1340-miphy.c +++ b/drivers/phy/phy-spear1340-miphy.c @@ -229,14 +229,14 @@ static struct phy *spear1340_miphy_xlate(struct device *dev, if (args->args_count < 1) { dev_err(dev, "DT did not pass correct no of args\n"); - return NULL; + return ERR_PTR(-ENODEV); } priv->mode = args->args[0]; if (priv->mode != SATA && priv->mode != PCIE) { dev_err(dev, "DT did not pass correct phy mode\n"); - return NULL; + return ERR_PTR(-ENODEV); } return priv->phy; diff --git a/drivers/phy/phy-stih41x-usb.c b/drivers/phy/phy-stih41x-usb.c index a603801293ff..c093b472b57d 100644 --- a/drivers/phy/phy-stih41x-usb.c +++ b/drivers/phy/phy-stih41x-usb.c @@ -87,8 +87,12 @@ static int stih41x_usb_phy_power_on(struct phy *phy) return ret; } - return regmap_update_bits(phy_dev->regmap, phy_dev->cfg->syscfg, - phy_dev->cfg->oscok, phy_dev->cfg->oscok); + ret = regmap_update_bits(phy_dev->regmap, phy_dev->cfg->syscfg, + phy_dev->cfg->oscok, phy_dev->cfg->oscok); + if (ret) + clk_disable_unprepare(phy_dev->clk); + + return ret; } static int stih41x_usb_phy_power_off(struct phy *phy) diff --git a/drivers/phy/phy-sun9i-usb.c b/drivers/phy/phy-sun9i-usb.c new file mode 100644 index 000000000000..0095914a662c --- /dev/null +++ b/drivers/phy/phy-sun9i-usb.c @@ -0,0 +1,202 @@ +/* + * Allwinner sun9i USB phy driver + * + * Copyright (C) 2014-2015 Chen-Yu Tsai <wens@csie.org> + * + * Based on phy-sun4i-usb.c from + * Hans de Goede <hdegoede@redhat.com> + * + * and code from + * Allwinner Technology Co., Ltd. <www.allwinnertech.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. + * + * 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 <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/phy/phy.h> +#include <linux/usb/of.h> +#include <linux/platform_device.h> +#include <linux/reset.h> + +#define SUNXI_AHB_INCR16_BURST_EN BIT(11) +#define SUNXI_AHB_INCR8_BURST_EN BIT(10) +#define SUNXI_AHB_INCR4_BURST_EN BIT(9) +#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8) +#define SUNXI_ULPI_BYPASS_EN BIT(0) + +/* usb1 HSIC specific bits */ +#define SUNXI_EHCI_HS_FORCE BIT(20) +#define SUNXI_HSIC_CONNECT_DET BIT(17) +#define SUNXI_HSIC_CONNECT_INT BIT(16) +#define SUNXI_HSIC BIT(1) + +struct sun9i_usb_phy { + struct phy *phy; + void __iomem *pmu; + struct reset_control *reset; + struct clk *clk; + struct clk *hsic_clk; + enum usb_phy_interface type; +}; + +static void sun9i_usb_phy_passby(struct sun9i_usb_phy *phy, int enable) +{ + u32 bits, reg_value; + + bits = SUNXI_AHB_INCR16_BURST_EN | SUNXI_AHB_INCR8_BURST_EN | + SUNXI_AHB_INCR4_BURST_EN | SUNXI_AHB_INCRX_ALIGN_EN | + SUNXI_ULPI_BYPASS_EN; + + if (phy->type == USBPHY_INTERFACE_MODE_HSIC) + bits |= SUNXI_HSIC | SUNXI_EHCI_HS_FORCE | + SUNXI_HSIC_CONNECT_DET | SUNXI_HSIC_CONNECT_INT; + + reg_value = readl(phy->pmu); + + if (enable) + reg_value |= bits; + else + reg_value &= ~bits; + + writel(reg_value, phy->pmu); +} + +static int sun9i_usb_phy_init(struct phy *_phy) +{ + struct sun9i_usb_phy *phy = phy_get_drvdata(_phy); + int ret; + + ret = clk_prepare_enable(phy->clk); + if (ret) + goto err_clk; + + ret = clk_prepare_enable(phy->hsic_clk); + if (ret) + goto err_hsic_clk; + + ret = reset_control_deassert(phy->reset); + if (ret) + goto err_reset; + + sun9i_usb_phy_passby(phy, 1); + return 0; + +err_reset: + clk_disable_unprepare(phy->hsic_clk); + +err_hsic_clk: + clk_disable_unprepare(phy->clk); + +err_clk: + return ret; +} + +static int sun9i_usb_phy_exit(struct phy *_phy) +{ + struct sun9i_usb_phy *phy = phy_get_drvdata(_phy); + + sun9i_usb_phy_passby(phy, 0); + reset_control_assert(phy->reset); + clk_disable_unprepare(phy->hsic_clk); + clk_disable_unprepare(phy->clk); + + return 0; +} + +static struct phy_ops sun9i_usb_phy_ops = { + .init = sun9i_usb_phy_init, + .exit = sun9i_usb_phy_exit, + .owner = THIS_MODULE, +}; + +static int sun9i_usb_phy_probe(struct platform_device *pdev) +{ + struct sun9i_usb_phy *phy; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct phy_provider *phy_provider; + struct resource *res; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + phy->type = of_usb_get_phy_mode(np); + if (phy->type == USBPHY_INTERFACE_MODE_HSIC) { + phy->clk = devm_clk_get(dev, "hsic_480M"); + if (IS_ERR(phy->clk)) { + dev_err(dev, "failed to get hsic_480M clock\n"); + return PTR_ERR(phy->clk); + } + + phy->hsic_clk = devm_clk_get(dev, "hsic_12M"); + if (IS_ERR(phy->clk)) { + dev_err(dev, "failed to get hsic_12M clock\n"); + return PTR_ERR(phy->clk); + } + + phy->reset = devm_reset_control_get(dev, "hsic"); + if (IS_ERR(phy->reset)) { + dev_err(dev, "failed to get reset control\n"); + return PTR_ERR(phy->reset); + } + } else { + phy->clk = devm_clk_get(dev, "phy"); + if (IS_ERR(phy->clk)) { + dev_err(dev, "failed to get phy clock\n"); + return PTR_ERR(phy->clk); + } + + phy->reset = devm_reset_control_get(dev, "phy"); + if (IS_ERR(phy->reset)) { + dev_err(dev, "failed to get reset control\n"); + return PTR_ERR(phy->reset); + } + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + phy->pmu = devm_ioremap_resource(dev, res); + if (IS_ERR(phy->pmu)) + return PTR_ERR(phy->pmu); + + phy->phy = devm_phy_create(dev, NULL, &sun9i_usb_phy_ops); + if (IS_ERR(phy->phy)) { + dev_err(dev, "failed to create PHY\n"); + return PTR_ERR(phy->phy); + } + + phy_set_drvdata(phy->phy, phy); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id sun9i_usb_phy_of_match[] = { + { .compatible = "allwinner,sun9i-a80-usb-phy" }, + { }, +}; +MODULE_DEVICE_TABLE(of, sun9i_usb_phy_of_match); + +static struct platform_driver sun9i_usb_phy_driver = { + .probe = sun9i_usb_phy_probe, + .driver = { + .of_match_table = sun9i_usb_phy_of_match, + .name = "sun9i-usb-phy", + } +}; +module_platform_driver(sun9i_usb_phy_driver); + +MODULE_DESCRIPTION("Allwinner sun9i USB phy driver"); +MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index 2ba610b72ca2..53f295c1bab1 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c @@ -287,9 +287,7 @@ static struct phy_ops ops = { .owner = THIS_MODULE, }; -#ifdef CONFIG_OF static const struct of_device_id ti_pipe3_id_table[]; -#endif static int ti_pipe3_probe(struct platform_device *pdev) { @@ -311,8 +309,7 @@ static int ti_pipe3_probe(struct platform_device *pdev) spin_lock_init(&phy->lock); if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { - match = of_match_device(of_match_ptr(ti_pipe3_id_table), - &pdev->dev); + match = of_match_device(ti_pipe3_id_table, &pdev->dev); if (!match) return -EINVAL; @@ -570,7 +567,6 @@ static const struct dev_pm_ops ti_pipe3_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(ti_pipe3_suspend, ti_pipe3_resume) }; -#ifdef CONFIG_OF static const struct of_device_id ti_pipe3_id_table[] = { { .compatible = "ti,phy-usb3", @@ -590,7 +586,6 @@ static const struct of_device_id ti_pipe3_id_table[] = { {} }; MODULE_DEVICE_TABLE(of, ti_pipe3_id_table); -#endif static struct platform_driver ti_pipe3_driver = { .probe = ti_pipe3_probe, @@ -598,7 +593,7 @@ static struct platform_driver ti_pipe3_driver = { .driver = { .name = "ti-pipe3", .pm = &ti_pipe3_pm_ops, - .of_match_table = of_match_ptr(ti_pipe3_id_table), + .of_match_table = ti_pipe3_id_table, }, }; diff --git a/drivers/phy/phy-xgene.c b/drivers/phy/phy-xgene.c index 2263cd010032..385362e5b2f6 100644 --- a/drivers/phy/phy-xgene.c +++ b/drivers/phy/phy-xgene.c @@ -1657,7 +1657,6 @@ static int xgene_phy_probe(struct platform_device *pdev) struct phy_provider *phy_provider; struct xgene_phy_ctx *ctx; struct resource *res; - int rc = 0; u32 default_spd[] = DEFAULT_SATA_SPD_SEL; u32 default_txboost_gain[] = DEFAULT_SATA_TXBOOST_GAIN; u32 default_txeye_direction[] = DEFAULT_SATA_TXEYEDIRECTION; @@ -1676,10 +1675,8 @@ static int xgene_phy_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ctx->sds_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(ctx->sds_base)) { - rc = PTR_ERR(ctx->sds_base); - goto error; - } + if (IS_ERR(ctx->sds_base)) + return PTR_ERR(ctx->sds_base); /* Retrieve optional clock */ ctx->clk = clk_get(&pdev->dev, NULL); @@ -1709,22 +1706,12 @@ static int xgene_phy_probe(struct platform_device *pdev) ctx->phy = devm_phy_create(ctx->dev, NULL, &xgene_phy_ops); if (IS_ERR(ctx->phy)) { dev_dbg(&pdev->dev, "Failed to create PHY\n"); - rc = PTR_ERR(ctx->phy); - goto error; + return PTR_ERR(ctx->phy); } phy_set_drvdata(ctx->phy, ctx); - phy_provider = devm_of_phy_provider_register(ctx->dev, - xgene_phy_xlate); - if (IS_ERR(phy_provider)) { - rc = PTR_ERR(phy_provider); - goto error; - } - - return 0; - -error: - return rc; + phy_provider = devm_of_phy_provider_register(ctx->dev, xgene_phy_xlate); + return PTR_ERR_OR_ZERO(phy_provider); } static const struct of_device_id xgene_phy_of_match[] = { |