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
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQIcBAABAgAGBQJVHrrMAAoJEA5ceFyATYLZV8kP/074teM4HZMAqmUVRG+nRr8b
 Eb8QYOzpnazUKtUovMYePzLjIZ3kvlMepSVVZiZqP6Uc2s6bnhTUN758HZBTdMVO
 Cer63lcp5eM6yBSIL4kNo3+18ikql3LJK9kQZoLGszZmVJzwwqhL/cWxl8+WfZ+P
 U71ciL07xmQD1c1GbRsuDBykaDKnf4M9HVUzP9w/pFANKYWWHdR3bj53kz9W7bGm
 gF/6wVFfxkknPfQjlqo9VUoSPN3P+WIcoM2rPG1b1u2adAAKFSYvXX2eJKWZF6Cz
 L9IZn1bTB0tMkrbswpMRqPtKjfmGyi1Acx8jt8WVA5pjNZ4K2P+9T7vsWifEnYa/
 BDYdJJRzZSL89m9zwEFvLF490pTJrk33eFbqzHDGmDcdtj8KY8XZ9Fp5R2Lmj26s
 mtST0Pi+j9SGg95KZBcXd2l1EJmdDutEYy7LgVvkLk4IFPfOyaAFEhSNW+Qi+Lh9
 SkDqbZUrk9ZxzsWqYJW5LVbQlscJ2NzQuf5AgkrXsufXO0B8RAV5bt0f88ENmQsJ
 rbbbWIb/ljT6YbZqT8z2X8T0PNZBknSfepb5LO5QAZMMJJm2202TondsISytvC9U
 fS5sBIDzuiiMtOA9FwA5Yl1bPWq6QY4OwqIMX3LAs10ylJhbuqJ7nK5qH3O4bpk+
 DzOCd1oLJhXjnOXIujz2
 =0gB+
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Greg Kroah-Hartman 2015-04-10 13:47:50 +02:00
commit 2aebe3f3b2
26 changed files with 655 additions and 110 deletions

View File

@ -0,0 +1,24 @@
Device tree binding documentation for am816x USB PHY
=========================
Required properties:
- compatible : should be "ti,dm816x-usb-phy"
- reg : offset and length of the PHY register set.
- reg-names : name for the phy registers
- clocks : phandle to the clock
- clock-names : name of the clock
- syscon: phandle for the syscon node to access misc registers
- #phy-cells : from the generic PHY bindings, must be 1
- syscon: phandle for the syscon node to access misc registers
Example:
usb_phy0: usb-phy@20 {
compatible = "ti,dm8168-usb-phy";
reg = <0x20 0x8>;
reg-names = "phy";
clocks = <&main_fapll 6>;
clock-names = "refclk";
#phy-cells = <0>;
syscon = <&scm_conf>;
};

View File

@ -20,8 +20,8 @@ Required nodes : A sub-node is required for each channel the controller
Required properties (port (child) node): Required properties (port (child) node):
- #phy-cells : Should be 1 (See second example) - #phy-cells : Should be 1 (See second example)
Cell after port phandle is device type from: Cell after port phandle is device type from:
- MIPHY_TYPE_SATA - PHY_TYPE_SATA
- MIPHY_TYPE_PCI - PHY_TYPE_PCI
- reg : Address and length of register sets for each device in - reg : Address and length of register sets for each device in
"reg-names" "reg-names"
- reg-names : The names of the register addresses corresponding to the - reg-names : The names of the register addresses corresponding to the
@ -68,10 +68,10 @@ property, containing a phandle to the phy port node and a device type.
Example: Example:
#include <dt-bindings/phy/phy-miphy365x.h> #include <dt-bindings/phy/phy.h>
sata0: sata@fe380000 { sata0: sata@fe380000 {
... ...
phys = <&phy_port0 MIPHY_TYPE_SATA>; phys = <&phy_port0 PHY_TYPE_SATA>;
... ...
}; };

View File

@ -128,6 +128,7 @@ Required properties:
- compatible : Should be set to one of the following supported values: - compatible : Should be set to one of the following supported values:
- "samsung,exynos5250-usbdrd-phy" - for exynos5250 SoC, - "samsung,exynos5250-usbdrd-phy" - for exynos5250 SoC,
- "samsung,exynos5420-usbdrd-phy" - for exynos5420 SoC. - "samsung,exynos5420-usbdrd-phy" - for exynos5420 SoC.
- "samsung,exynos5433-usbdrd-phy" - for exynos5433 SoC.
- "samsung,exynos7-usbdrd-phy" - for exynos7 SoC. - "samsung,exynos7-usbdrd-phy" - for exynos7 SoC.
- reg : Register offset and length of USB DRD PHY register set; - reg : Register offset and length of USB DRD PHY register set;
- clocks: Clock IDs array as required by the controller - clocks: Clock IDs array as required by the controller
@ -139,7 +140,7 @@ Required properties:
PHY operations, associated by phy name. It is used to PHY operations, associated by phy name. It is used to
determine bit values for clock settings register. determine bit values for clock settings register.
For Exynos5420 this is given as 'sclk_usbphy30' in CMU. For Exynos5420 this is given as 'sclk_usbphy30' in CMU.
- optional clocks: Exynos7 SoC has now following additional - optional clocks: Exynos5433 & Exynos7 SoC has now following additional
gate clocks available: gate clocks available:
- phy_pipe: for PIPE3 phy - phy_pipe: for PIPE3 phy
- phy_utmi: for UTMI+ phy - phy_utmi: for UTMI+ phy

View File

@ -0,0 +1,38 @@
Allwinner sun9i USB PHY
-----------------------
Required properties:
- compatible : should be one of
* allwinner,sun9i-a80-usb-phy
- reg : a list of offset + length pairs
- #phy-cells : from the generic phy bindings, must be 0
- phy_type : "hsic" for HSIC usage;
other values or absence of this property indicates normal USB
- clocks : phandle + clock specifier for the phy clocks
- clock-names : depending on the "phy_type" property,
* "phy" for normal USB
* "hsic_480M", "hsic_12M" for HSIC
- resets : a list of phandle + reset specifier pairs
- reset-names : depending on the "phy_type" property,
* "phy" for normal USB
* "hsic" for HSIC
Optional Properties:
- phy-supply : from the generic phy bindings, a phandle to a regulator that
provides power to VBUS.
It is recommended to list all clocks and resets available.
The driver will only use those matching the phy_type.
Example:
usbphy1: phy@00a01800 {
compatible = "allwinner,sun9i-a80-usb-phy";
reg = <0x00a01800 0x4>;
clocks = <&usb_phy_clk 2>, <&usb_phy_clk 10>,
<&usb_phy_clk 3>;
clock-names = "hsic_480M", "hsic_12M", "phy";
resets = <&usb_phy_clk 18>, <&usb_phy_clk 19>;
reset-names = "hsic", "phy";
status = "disabled";
#phy-cells = <0>;
};

View File

@ -1468,6 +1468,8 @@ F: drivers/clocksource/arm_global_timer.c
F: drivers/i2c/busses/i2c-st.c F: drivers/i2c/busses/i2c-st.c
F: drivers/media/rc/st_rc.c F: drivers/media/rc/st_rc.c
F: drivers/mmc/host/sdhci-st.c F: drivers/mmc/host/sdhci-st.c
F: drivers/phy/phy-miphy28lp.c
F: drivers/phy/phy-miphy365x.c
F: drivers/phy/phy-stih407-usb.c F: drivers/phy/phy-stih407-usb.c
F: drivers/phy/phy-stih41x-usb.c F: drivers/phy/phy-stih41x-usb.c
F: drivers/pinctrl/pinctrl-st.c F: drivers/pinctrl/pinctrl-st.c

View File

@ -10,7 +10,7 @@
#include "stih416-clock.dtsi" #include "stih416-clock.dtsi"
#include "stih416-pinctrl.dtsi" #include "stih416-pinctrl.dtsi"
#include <dt-bindings/phy/phy-miphy365x.h> #include <dt-bindings/phy/phy.h>
#include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/reset-controller/stih416-resets.h> #include <dt-bindings/reset-controller/stih416-resets.h>
/ { / {
@ -306,7 +306,7 @@ sata0: sata@fe380000 {
reg = <0xfe380000 0x1000>; reg = <0xfe380000 0x1000>;
interrupts = <GIC_SPI 157 IRQ_TYPE_NONE>; interrupts = <GIC_SPI 157 IRQ_TYPE_NONE>;
interrupt-names = "hostc"; interrupt-names = "hostc";
phys = <&phy_port0 MIPHY_TYPE_SATA>; phys = <&phy_port0 PHY_TYPE_SATA>;
phy-names = "sata-phy"; phy-names = "sata-phy";
resets = <&powerdown STIH416_SATA0_POWERDOWN>, resets = <&powerdown STIH416_SATA0_POWERDOWN>,
<&softreset STIH416_SATA0_SOFTRESET>; <&softreset STIH416_SATA0_SOFTRESET>;

View File

@ -35,6 +35,13 @@ config ARMADA375_USBCLUSTER_PHY
depends on OF depends on OF
select GENERIC_PHY 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 config PHY_EXYNOS_MIPI_VIDEO
tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver" tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver"
depends on HAS_IOMEM depends on HAS_IOMEM
@ -174,6 +181,17 @@ config PHY_SUN4I_USB
This driver controls the entire USB PHY block, both the USB OTG This driver controls the entire USB PHY block, both the USB OTG
parts, as well as the 2 regular USB 2 host PHYs. 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 config PHY_SAMSUNG_USB2
tristate "Samsung USB 2.0 PHY driver" tristate "Samsung USB 2.0 PHY driver"
depends on HAS_IOMEM depends on HAS_IOMEM

View File

@ -5,6 +5,7 @@
obj-$(CONFIG_GENERIC_PHY) += phy-core.o obj-$(CONFIG_GENERIC_PHY) += phy-core.o
obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o
obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.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_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o
obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o
obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.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_EXYNOS5250_SATA) += phy-exynos5250-sata.o
obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o
obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.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 obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o
phy-exynos-usb2-y += phy-samsung-usb2.o phy-exynos-usb2-y += phy-samsung-usb2.o
phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o

View File

@ -218,7 +218,7 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
if (priv->nphys == 0) if (priv->nphys == 0)
return -ENODEV; return -ENODEV;
priv->phys = devm_kzalloc(dev, priv->nphys * sizeof(*priv->phys), priv->phys = devm_kcalloc(dev, priv->nphys, sizeof(*priv->phys),
GFP_KERNEL); GFP_KERNEL);
if (!priv->phys) if (!priv->phys)
return -ENOMEM; return -ENOMEM;

View File

@ -103,9 +103,6 @@
#define MODE_TEST_EN BIT(11) #define MODE_TEST_EN BIT(11)
#define ANA_TEST_DC_CTRL(x) ((x) << 12) #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[] = { static const u32 phy_berlin_pll_dividers[] = {
/* Berlin 2 */ /* Berlin 2 */
CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54), CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54),
@ -115,14 +112,13 @@ static const u32 phy_berlin_pll_dividers[] = {
struct phy_berlin_usb_priv { struct phy_berlin_usb_priv {
void __iomem *base; void __iomem *base;
struct phy *phy;
struct reset_control *rst_ctrl; struct reset_control *rst_ctrl;
u32 pll_divider; u32 pll_divider;
}; };
static int phy_berlin_usb_power_on(struct phy *phy) 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); 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); of_match_device(phy_berlin_sata_of_match, &pdev->dev);
struct phy_berlin_usb_priv *priv; struct phy_berlin_usb_priv *priv;
struct resource *res; struct resource *res;
struct phy *phy;
struct phy_provider *phy_provider; struct phy_provider *phy_provider;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 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->pll_divider = *((u32 *)match->data);
priv->phy = devm_phy_create(&pdev->dev, NULL, &phy_berlin_usb_ops); phy = devm_phy_create(&pdev->dev, NULL, &phy_berlin_usb_ops);
if (IS_ERR(priv->phy)) { if (IS_ERR(phy)) {
dev_err(&pdev->dev, "failed to create PHY\n"); dev_err(&pdev->dev, "failed to create PHY\n");
return PTR_ERR(priv->phy); return PTR_ERR(phy);
} }
platform_set_drvdata(pdev, priv); platform_set_drvdata(pdev, priv);
phy_set_drvdata(phy, priv);
phy_provider = phy_provider =
devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
if (IS_ERR(phy_provider)) return PTR_ERR_OR_ZERO(phy_provider);
return PTR_ERR(phy_provider);
return 0;
} }
static struct platform_driver phy_berlin_usb_driver = { static struct platform_driver phy_berlin_usb_driver = {

View File

@ -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");

View File

@ -624,6 +624,13 @@ static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = {
.has_common_clk_gate = true, .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 = { static const struct exynos5_usbdrd_phy_drvdata exynos7_usbdrd_phy = {
.phy_cfg = phy_cfg_exynos5, .phy_cfg = phy_cfg_exynos5,
.pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
@ -637,6 +644,9 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = {
}, { }, {
.compatible = "samsung,exynos5420-usbdrd-phy", .compatible = "samsung,exynos5420-usbdrd-phy",
.data = &exynos5420_usbdrd_phy .data = &exynos5420_usbdrd_phy
}, {
.compatible = "samsung,exynos5433-usbdrd-phy",
.data = &exynos5433_usbdrd_phy
}, { }, {
.compatible = "samsung,exynos7-usbdrd-phy", .compatible = "samsung,exynos7-usbdrd-phy",
.data = &exynos7_usbdrd_phy .data = &exynos7_usbdrd_phy

View File

@ -1259,10 +1259,7 @@ static int miphy28lp_probe(struct platform_device *pdev)
} }
provider = devm_of_phy_provider_register(&pdev->dev, miphy28lp_xlate); provider = devm_of_phy_provider_register(&pdev->dev, miphy28lp_xlate);
if (IS_ERR(provider)) return PTR_ERR_OR_ZERO(provider);
return PTR_ERR(provider);
return 0;
} }
static const struct of_device_id miphy28lp_of_match[] = { static const struct of_device_id miphy28lp_of_match[] = {

View File

@ -25,7 +25,7 @@
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <dt-bindings/phy/phy-miphy365x.h> #include <dt-bindings/phy/phy.h>
#define HFC_TIMEOUT 100 #define HFC_TIMEOUT 100
@ -177,7 +177,7 @@ static u8 rx_tx_spd[] = {
static int miphy365x_set_path(struct miphy365x_phy *miphy_phy, static int miphy365x_set_path(struct miphy365x_phy *miphy_phy,
struct miphy365x_dev *miphy_dev) 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, return regmap_update_bits(miphy_dev->regmap,
miphy_phy->ctrlreg, miphy_phy->ctrlreg,
@ -431,7 +431,7 @@ static int miphy365x_init(struct phy *phy)
} }
/* Initialise Miphy for PCIe or SATA */ /* 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); ret = miphy365x_init_pcie_port(miphy_phy, miphy_dev);
else else
ret = miphy365x_init_sata_port(miphy_phy, miphy_dev); 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; return ret;
} }
if (!((!strncmp(name, "sata", 4) && type == MIPHY_TYPE_SATA) || if (!((!strncmp(name, "sata", 4) && type == PHY_TYPE_SATA) ||
(!strncmp(name, "pcie", 4) && type == MIPHY_TYPE_PCIE))) (!strncmp(name, "pcie", 4) && type == PHY_TYPE_PCIE)))
return 0; return 0;
miphy_phy->base = of_iomap(phynode, index); 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]; miphy_phy->type = args->args[0];
if (!(miphy_phy->type == MIPHY_TYPE_SATA || if (!(miphy_phy->type == PHY_TYPE_SATA ||
miphy_phy->type == MIPHY_TYPE_PCIE)) { miphy_phy->type == PHY_TYPE_PCIE)) {
dev_err(dev, "Unsupported device type: %d\n", miphy_phy->type); dev_err(dev, "Unsupported device type: %d\n", miphy_phy->type);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }

View File

@ -216,7 +216,6 @@ void omap_control_usb_set_mode(struct device *dev,
return; return;
ctrl_phy = dev_get_drvdata(dev); ctrl_phy = dev_get_drvdata(dev);
if (!ctrl_phy) { if (!ctrl_phy) {
dev_err(dev, "Invalid control phy device\n"); dev_err(dev, "Invalid control phy device\n");
return; return;
@ -241,8 +240,6 @@ void omap_control_usb_set_mode(struct device *dev,
} }
EXPORT_SYMBOL_GPL(omap_control_usb_set_mode); 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 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 usb2_data = OMAP_CTRL_TYPE_USB2;
static const enum omap_control_phy_type pipe3_data = OMAP_CTRL_TYPE_PIPE3; 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); MODULE_DEVICE_TABLE(of, omap_control_phy_id_table);
#endif
static int omap_control_phy_probe(struct platform_device *pdev) 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; const struct of_device_id *of_id;
struct omap_control_phy *control_phy; struct omap_control_phy *control_phy;
of_id = of_match_device(of_match_ptr(omap_control_phy_id_table), of_id = of_match_device(omap_control_phy_id_table, &pdev->dev);
&pdev->dev);
if (!of_id) if (!of_id)
return -EINVAL; return -EINVAL;
@ -344,7 +338,7 @@ static struct platform_driver omap_control_phy_driver = {
.probe = omap_control_phy_probe, .probe = omap_control_phy_probe,
.driver = { .driver = {
.name = "omap-control-phy", .name = "omap-control-phy",
.of_match_table = of_match_ptr(omap_control_phy_id_table), .of_match_table = omap_control_phy_id_table,
}, },
}; };

View File

@ -144,7 +144,6 @@ static struct phy_ops ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
#ifdef CONFIG_OF
static const struct usb_phy_data omap_usb2_data = { static const struct usb_phy_data omap_usb2_data = {
.label = "omap_usb2", .label = "omap_usb2",
.flags = OMAP_USB2_HAS_START_SRP | OMAP_USB2_HAS_SET_VBUS, .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); MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
#endif
static int omap_usb2_probe(struct platform_device *pdev) 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; const struct of_device_id *of_id;
struct usb_phy_data *phy_data; 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) if (!of_id)
return -EINVAL; return -EINVAL;
@ -378,7 +376,7 @@ static struct platform_driver omap_usb2_driver = {
.driver = { .driver = {
.name = "omap-usb2", .name = "omap-usb2",
.pm = DEV_PM_OPS, .pm = DEV_PM_OPS,
.of_match_table = of_match_ptr(omap_usb2_id_table), .of_match_table = omap_usb2_id_table,
}, },
}; };

View File

@ -73,6 +73,7 @@ int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
out: out:
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(ufs_qcom_phy_calibrate);
struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev, struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev,
struct ufs_qcom_phy *common_cfg, 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)) { if (IS_ERR(generic_phy)) {
err = PTR_ERR(generic_phy); err = PTR_ERR(generic_phy);
dev_err(dev, "%s: failed to create phy %d\n", __func__, err); dev_err(dev, "%s: failed to create phy %d\n", __func__, err);
generic_phy = NULL;
goto out; goto out;
} }
@ -110,6 +112,7 @@ struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev,
out: out:
return generic_phy; return generic_phy;
} }
EXPORT_SYMBOL_GPL(ufs_qcom_phy_generic_probe);
/* /*
* This assumes the embedded phy structure inside generic_phy is of type * 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); return (struct ufs_qcom_phy *)phy_get_drvdata(generic_phy);
} }
EXPORT_SYMBOL_GPL(get_ufs_qcom_phy);
static static
int ufs_qcom_phy_base_init(struct platform_device *pdev, 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; int err = 0;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_mem"); 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); phy_common->mmio = devm_ioremap_resource(dev, res);
if (IS_ERR((void const *)phy_common->mmio)) { if (IS_ERR((void const *)phy_common->mmio)) {
err = PTR_ERR((void const *)phy_common->mmio); err = PTR_ERR((void const *)phy_common->mmio);
phy_common->mmio = NULL; phy_common->mmio = NULL;
dev_err(dev, "%s: ioremap for phy_mem resource failed %d\n", dev_err(dev, "%s: ioremap for phy_mem resource failed %d\n",
__func__, err); __func__, err);
goto out; return err;
} }
/* "dev_ref_clk_ctrl_mem" is optional resource */ /* "dev_ref_clk_ctrl_mem" is optional resource */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"dev_ref_clk_ctrl_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); phy_common->dev_ref_clk_ctrl_mmio = devm_ioremap_resource(dev, res);
if (IS_ERR((void const *)phy_common->dev_ref_clk_ctrl_mmio)) { if (IS_ERR((void const *)phy_common->dev_ref_clk_ctrl_mmio))
err = PTR_ERR((void const *)phy_common->dev_ref_clk_ctrl_mmio);
phy_common->dev_ref_clk_ctrl_mmio = NULL; 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 0;
return err;
} }
static int __ufs_qcom_phy_clk_get(struct phy *phy, static int __ufs_qcom_phy_clk_get(struct phy *phy,
@ -228,6 +215,7 @@ ufs_qcom_phy_init_clks(struct phy *generic_phy,
out: out:
return err; return err;
} }
EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_clks);
int int
ufs_qcom_phy_init_vregulators(struct phy *generic_phy, ufs_qcom_phy_init_vregulators(struct phy *generic_phy,
@ -252,6 +240,7 @@ ufs_qcom_phy_init_vregulators(struct phy *generic_phy,
out: out:
return err; return err;
} }
EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_vregulators);
static int __ufs_qcom_phy_init_vreg(struct phy *phy, static int __ufs_qcom_phy_init_vreg(struct phy *phy,
struct ufs_qcom_phy_vreg *vreg, const char *name, bool optional) 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; return 0;
} }
EXPORT_SYMBOL_GPL(ufs_qcom_phy_remove);
int ufs_qcom_phy_exit(struct phy *generic_phy) int ufs_qcom_phy_exit(struct phy *generic_phy)
{ {
@ -657,6 +647,7 @@ int ufs_qcom_phy_exit(struct phy *generic_phy)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(ufs_qcom_phy_exit);
int ufs_qcom_phy_is_pcs_ready(struct phy *generic_phy) int ufs_qcom_phy_is_pcs_ready(struct phy *generic_phy)
{ {
@ -725,6 +716,7 @@ int ufs_qcom_phy_power_on(struct phy *generic_phy)
out: out:
return err; return err;
} }
EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_on);
int ufs_qcom_phy_power_off(struct phy *generic_phy) 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; return 0;
} }
EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_off);

View File

@ -37,10 +37,14 @@ static int samsung_usb2_phy_power_on(struct phy *phy)
spin_lock(&drv->lock); spin_lock(&drv->lock);
ret = inst->cfg->power_on(inst); ret = inst->cfg->power_on(inst);
spin_unlock(&drv->lock); spin_unlock(&drv->lock);
if (ret)
goto err_power_on;
} }
return 0; return 0;
err_power_on:
clk_disable_unprepare(drv->ref_clk);
err_instance_clk: err_instance_clk:
clk_disable_unprepare(drv->clk); clk_disable_unprepare(drv->clk);
err_main_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_instance *inst = phy_get_drvdata(phy);
struct samsung_usb2_phy_driver *drv = inst->drv; 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", dev_dbg(drv->dev, "Request to power_off \"%s\" usb phy\n",
inst->cfg->label); inst->cfg->label);
@ -59,10 +63,12 @@ static int samsung_usb2_phy_power_off(struct phy *phy)
spin_lock(&drv->lock); spin_lock(&drv->lock);
ret = inst->cfg->power_off(inst); ret = inst->cfg->power_off(inst);
spin_unlock(&drv->lock); spin_unlock(&drv->lock);
if (ret)
return ret;
} }
clk_disable_unprepare(drv->ref_clk); clk_disable_unprepare(drv->ref_clk);
clk_disable_unprepare(drv->clk); clk_disable_unprepare(drv->clk);
return ret; return 0;
} }
static struct phy_ops samsung_usb2_phy_ops = { static struct phy_ops samsung_usb2_phy_ops = {

View File

@ -192,14 +192,14 @@ static struct phy *spear1310_miphy_xlate(struct device *dev,
if (args->args_count < 1) { if (args->args_count < 1) {
dev_err(dev, "DT did not pass correct no of args\n"); dev_err(dev, "DT did not pass correct no of args\n");
return NULL; return ERR_PTR(-ENODEV);
} }
priv->mode = args->args[0]; priv->mode = args->args[0];
if (priv->mode != SATA && priv->mode != PCIE) { if (priv->mode != SATA && priv->mode != PCIE) {
dev_err(dev, "DT did not pass correct phy mode\n"); dev_err(dev, "DT did not pass correct phy mode\n");
return NULL; return ERR_PTR(-ENODEV);
} }
return priv->phy; return priv->phy;

View File

@ -229,14 +229,14 @@ static struct phy *spear1340_miphy_xlate(struct device *dev,
if (args->args_count < 1) { if (args->args_count < 1) {
dev_err(dev, "DT did not pass correct no of args\n"); dev_err(dev, "DT did not pass correct no of args\n");
return NULL; return ERR_PTR(-ENODEV);
} }
priv->mode = args->args[0]; priv->mode = args->args[0];
if (priv->mode != SATA && priv->mode != PCIE) { if (priv->mode != SATA && priv->mode != PCIE) {
dev_err(dev, "DT did not pass correct phy mode\n"); dev_err(dev, "DT did not pass correct phy mode\n");
return NULL; return ERR_PTR(-ENODEV);
} }
return priv->phy; return priv->phy;

View File

@ -87,8 +87,12 @@ static int stih41x_usb_phy_power_on(struct phy *phy)
return ret; return ret;
} }
return regmap_update_bits(phy_dev->regmap, phy_dev->cfg->syscfg, ret = regmap_update_bits(phy_dev->regmap, phy_dev->cfg->syscfg,
phy_dev->cfg->oscok, phy_dev->cfg->oscok); 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) static int stih41x_usb_phy_power_off(struct phy *phy)

202
drivers/phy/phy-sun9i-usb.c Normal file
View File

@ -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");

View File

@ -287,9 +287,7 @@ static struct phy_ops ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
#ifdef CONFIG_OF
static const struct of_device_id ti_pipe3_id_table[]; static const struct of_device_id ti_pipe3_id_table[];
#endif
static int ti_pipe3_probe(struct platform_device *pdev) 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); spin_lock_init(&phy->lock);
if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
match = of_match_device(of_match_ptr(ti_pipe3_id_table), match = of_match_device(ti_pipe3_id_table, &pdev->dev);
&pdev->dev);
if (!match) if (!match)
return -EINVAL; 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) SET_SYSTEM_SLEEP_PM_OPS(ti_pipe3_suspend, ti_pipe3_resume)
}; };
#ifdef CONFIG_OF
static const struct of_device_id ti_pipe3_id_table[] = { static const struct of_device_id ti_pipe3_id_table[] = {
{ {
.compatible = "ti,phy-usb3", .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); MODULE_DEVICE_TABLE(of, ti_pipe3_id_table);
#endif
static struct platform_driver ti_pipe3_driver = { static struct platform_driver ti_pipe3_driver = {
.probe = ti_pipe3_probe, .probe = ti_pipe3_probe,
@ -598,7 +593,7 @@ static struct platform_driver ti_pipe3_driver = {
.driver = { .driver = {
.name = "ti-pipe3", .name = "ti-pipe3",
.pm = &ti_pipe3_pm_ops, .pm = &ti_pipe3_pm_ops,
.of_match_table = of_match_ptr(ti_pipe3_id_table), .of_match_table = ti_pipe3_id_table,
}, },
}; };

View File

@ -1657,7 +1657,6 @@ static int xgene_phy_probe(struct platform_device *pdev)
struct phy_provider *phy_provider; struct phy_provider *phy_provider;
struct xgene_phy_ctx *ctx; struct xgene_phy_ctx *ctx;
struct resource *res; struct resource *res;
int rc = 0;
u32 default_spd[] = DEFAULT_SATA_SPD_SEL; u32 default_spd[] = DEFAULT_SATA_SPD_SEL;
u32 default_txboost_gain[] = DEFAULT_SATA_TXBOOST_GAIN; u32 default_txboost_gain[] = DEFAULT_SATA_TXBOOST_GAIN;
u32 default_txeye_direction[] = DEFAULT_SATA_TXEYEDIRECTION; 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); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ctx->sds_base = devm_ioremap_resource(&pdev->dev, res); ctx->sds_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(ctx->sds_base)) { if (IS_ERR(ctx->sds_base))
rc = PTR_ERR(ctx->sds_base); return PTR_ERR(ctx->sds_base);
goto error;
}
/* Retrieve optional clock */ /* Retrieve optional clock */
ctx->clk = clk_get(&pdev->dev, NULL); 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); ctx->phy = devm_phy_create(ctx->dev, NULL, &xgene_phy_ops);
if (IS_ERR(ctx->phy)) { if (IS_ERR(ctx->phy)) {
dev_dbg(&pdev->dev, "Failed to create PHY\n"); dev_dbg(&pdev->dev, "Failed to create PHY\n");
rc = PTR_ERR(ctx->phy); return PTR_ERR(ctx->phy);
goto error;
} }
phy_set_drvdata(ctx->phy, ctx); phy_set_drvdata(ctx->phy, ctx);
phy_provider = devm_of_phy_provider_register(ctx->dev, phy_provider = devm_of_phy_provider_register(ctx->dev, xgene_phy_xlate);
xgene_phy_xlate); return PTR_ERR_OR_ZERO(phy_provider);
if (IS_ERR(phy_provider)) {
rc = PTR_ERR(phy_provider);
goto error;
}
return 0;
error:
return rc;
} }
static const struct of_device_id xgene_phy_of_match[] = { static const struct of_device_id xgene_phy_of_match[] = {

View File

@ -1,14 +0,0 @@
/*
* This header provides constants for the phy framework
* based on the STMicroelectronics MiPHY365x.
*
* Author: Lee Jones <lee.jones@linaro.org>
*/
#ifndef _DT_BINDINGS_PHY_MIPHY
#define _DT_BINDINGS_PHY_MIPHY
#define MIPHY_TYPE_SATA 1
#define MIPHY_TYPE_PCIE 2
#define MIPHY_TYPE_USB 3
#endif /* _DT_BINDINGS_PHY_MIPHY */

View File

@ -36,6 +36,9 @@
#define EXYNOS5420_MTCADC_PHY_CONTROL (0x724) #define EXYNOS5420_MTCADC_PHY_CONTROL (0x724)
#define EXYNOS5420_DPTX_PHY_CONTROL (0x728) #define EXYNOS5420_DPTX_PHY_CONTROL (0x728)
/* Exynos5433 specific register definitions */
#define EXYNOS5433_USBHOST30_PHY_CONTROL (0x728)
#define EXYNOS5_PHY_ENABLE BIT(0) #define EXYNOS5_PHY_ENABLE BIT(0)
#define EXYNOS5_MIPI_PHY_S_RESETN BIT(1) #define EXYNOS5_MIPI_PHY_S_RESETN BIT(1)