phy: for 4.8 -rc1
*) Add a new phy_ops for setting the phy mode *) Add a new phy driver for DA8xx SoC USB PHY *) Minor fixes and cleanups Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJXel4TAAoJEA5ceFyATYLZrXYP/1RcGZCktZxW43MQNNtGUjlR 4jhc36FlVQ+9Lrlp5ewLW6RPl/Z1D2ImYyTvxsWDRZhlj0T0N7F/AgwFWQXKPiKs l5opMvBL04dIy98M0Za68sr9SlPNxTZNyirejVm8oMtv2vA0+b18/YDZM2YFbt0N dTzVfJqvqrvFMSg2avVcTjARRQBnT5zNnKEjniDetVCSZ2yaD+yabrZ3OLh2JhZX AJdjvvxkOAVHqF1hBB1D/cNpf5N6fjgUu+xTI8MDDkYf81A3mOm8w7MjYDpusLjO Ix/AcuJqzg2216BzdyGF7zzg4wfgl3WmITXqUy+G9wuW4JPOZmeakTfppErAJPHr Quw1fIl0Je6l3xuSGGKIyPy3L4v5YvJeeZkhDzxATzhstKgk1fL4KJBN4lEjdRcs SeME8e1GVTiKFjFy4RTiP8bGBuUYRSHZVhLK7eeqcyE0hzQUD2LEyGQgLaj1s86k U+zFQoTNJwSenZsWINb/Skzwjg2E3kqEWsTbgLNDy02llvBaEykfVdjh6qk+4J5x 1GbywhJiba5x/1G1v5M4U2A1Fnw3u4Rhb5k64Qqur2mWNIDEUc85M0G8+m6z9io3 LqRitKkXxP6t/sp7KK3YAas6WnD5jRALgZpRBCsCYXW2lbTGb9Odi54LH4165xMP UFBoZLM1VDnK1Ja5fLbX =5bMI -----END PGP SIGNATURE----- Merge tag 'phy-for-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy into usb-testing Kishon writes: phy: for 4.8 -rc1 *) Add a new phy_ops for setting the phy mode *) Add a new phy driver for DA8xx SoC USB PHY *) Minor fixes and cleanups Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
This commit is contained in:
commit
ca2b6faeb9
40
Documentation/devicetree/bindings/phy/phy-da8xx-usb.txt
Normal file
40
Documentation/devicetree/bindings/phy/phy-da8xx-usb.txt
Normal file
@ -0,0 +1,40 @@
|
||||
TI DA8xx/OMAP-L1xx/AM18xx USB PHY
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "ti,da830-usb-phy".
|
||||
- #phy-cells: must be 1.
|
||||
|
||||
This device controls the PHY for both the USB 1.1 OHCI and USB 2.0 OTG
|
||||
controllers on DA8xx SoCs. Consumers of this device should use index 0 for
|
||||
the USB 2.0 phy device and index 1 for the USB 1.1 phy device.
|
||||
|
||||
It also requires a "syscon" node with compatible = "ti,da830-cfgchip", "syscon"
|
||||
to access the CFGCHIP2 register.
|
||||
|
||||
Example:
|
||||
|
||||
cfgchip: cfgchip@1417c {
|
||||
compatible = "ti,da830-cfgchip", "syscon";
|
||||
reg = <0x1417c 0x14>;
|
||||
};
|
||||
|
||||
usb_phy: usb-phy {
|
||||
compatible = "ti,da830-usb-phy";
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
|
||||
usb20: usb@200000 {
|
||||
compatible = "ti,da830-musb";
|
||||
reg = <0x200000 0x1000>;
|
||||
interrupts = <58>;
|
||||
phys = <&usb_phy 0>;
|
||||
phy-names = "usb-phy";
|
||||
};
|
||||
|
||||
usb11: usb@225000 {
|
||||
compatible = "ti,da830-ohci";
|
||||
reg = <0x225000 0x1000>;
|
||||
interrupts = <59>;
|
||||
phys = <&usb_phy 1>;
|
||||
phy-names = "usb-phy";
|
||||
};
|
@ -5,11 +5,13 @@ Required properties:
|
||||
"rockchip,rk3066a-usb-phy"
|
||||
"rockchip,rk3188-usb-phy"
|
||||
"rockchip,rk3288-usb-phy"
|
||||
- rockchip,grf : phandle to the syscon managing the "general
|
||||
register files"
|
||||
- #address-cells: should be 1
|
||||
- #size-cells: should be 0
|
||||
|
||||
Deprecated properties:
|
||||
- rockchip,grf : phandle to the syscon managing the "general
|
||||
register files" - phy should be a child of the GRF instead
|
||||
|
||||
Sub-nodes:
|
||||
Each PHY should be represented as a sub-node.
|
||||
|
||||
@ -28,14 +30,19 @@ Optional Properties:
|
||||
|
||||
Example:
|
||||
|
||||
usbphy: phy {
|
||||
compatible = "rockchip,rk3288-usb-phy";
|
||||
rockchip,grf = <&grf>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
grf: syscon@ff770000 {
|
||||
compatible = "rockchip,rk3288-grf", "syscon", "simple-mfd";
|
||||
|
||||
usbphy0: usb-phy0 {
|
||||
#phy-cells = <0>;
|
||||
reg = <0x320>;
|
||||
...
|
||||
|
||||
usbphy: phy {
|
||||
compatible = "rockchip,rk3288-usb-phy";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
usbphy0: usb-phy0 {
|
||||
#phy-cells = <0>;
|
||||
reg = <0x320>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -44,6 +44,16 @@ config ARMADA375_USBCLUSTER_PHY
|
||||
depends on OF && HAS_IOMEM
|
||||
select GENERIC_PHY
|
||||
|
||||
config PHY_DA8XX_USB
|
||||
tristate "TI DA8xx USB PHY Driver"
|
||||
depends on ARCH_DAVINCI_DA8XX
|
||||
select GENERIC_PHY
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Enable this to support the USB PHY on DA8xx SoCs.
|
||||
|
||||
This driver controls both the USB 1.1 PHY and the USB 2.0 PHY.
|
||||
|
||||
config PHY_DM816X_USB
|
||||
tristate "TI dm816x USB PHY driver"
|
||||
depends on ARCH_OMAP2PLUS
|
||||
|
@ -6,6 +6,7 @@ obj-$(CONFIG_GENERIC_PHY) += phy-core.o
|
||||
obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o
|
||||
obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o
|
||||
obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o
|
||||
obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.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
|
||||
|
@ -342,6 +342,21 @@ int phy_power_off(struct phy *phy)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phy_power_off);
|
||||
|
||||
int phy_set_mode(struct phy *phy, enum phy_mode mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!phy || !phy->ops->set_mode)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&phy->mutex);
|
||||
ret = phy->ops->set_mode(phy, mode);
|
||||
mutex_unlock(&phy->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phy_set_mode);
|
||||
|
||||
/**
|
||||
* _of_phy_get() - lookup and obtain a reference to a phy by phandle
|
||||
* @np: device_node for which to get the phy
|
||||
|
245
drivers/phy/phy-da8xx-usb.c
Normal file
245
drivers/phy/phy-da8xx-usb.c
Normal file
@ -0,0 +1,245 @@
|
||||
/*
|
||||
* phy-da8xx-usb - TI DaVinci DA8xx USB PHY driver
|
||||
*
|
||||
* Copyright (C) 2016 David Lechner <david@lechnology.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; version 2 of the License.
|
||||
*
|
||||
* 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/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mfd/da8xx-cfgchip.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
struct da8xx_usb_phy {
|
||||
struct phy_provider *phy_provider;
|
||||
struct phy *usb11_phy;
|
||||
struct phy *usb20_phy;
|
||||
struct clk *usb11_clk;
|
||||
struct clk *usb20_clk;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static int da8xx_usb11_phy_power_on(struct phy *phy)
|
||||
{
|
||||
struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(d_phy->usb11_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_USB1SUSPENDM,
|
||||
CFGCHIP2_USB1SUSPENDM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int da8xx_usb11_phy_power_off(struct phy *phy)
|
||||
{
|
||||
struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
|
||||
|
||||
regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_USB1SUSPENDM, 0);
|
||||
|
||||
clk_disable_unprepare(d_phy->usb11_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops da8xx_usb11_phy_ops = {
|
||||
.power_on = da8xx_usb11_phy_power_on,
|
||||
.power_off = da8xx_usb11_phy_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int da8xx_usb20_phy_power_on(struct phy *phy)
|
||||
{
|
||||
struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(d_phy->usb20_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGPWRDN, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int da8xx_usb20_phy_power_off(struct phy *phy)
|
||||
{
|
||||
struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
|
||||
|
||||
regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGPWRDN,
|
||||
CFGCHIP2_OTGPWRDN);
|
||||
|
||||
clk_disable_unprepare(d_phy->usb20_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int da8xx_usb20_phy_set_mode(struct phy *phy, enum phy_mode mode)
|
||||
{
|
||||
struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
|
||||
u32 val;
|
||||
|
||||
switch (mode) {
|
||||
case PHY_MODE_USB_HOST: /* Force VBUS valid, ID = 0 */
|
||||
val = CFGCHIP2_OTGMODE_FORCE_HOST;
|
||||
break;
|
||||
case PHY_MODE_USB_DEVICE: /* Force VBUS valid, ID = 1 */
|
||||
val = CFGCHIP2_OTGMODE_FORCE_DEVICE;
|
||||
break;
|
||||
case PHY_MODE_USB_OTG: /* Don't override the VBUS/ID comparators */
|
||||
val = CFGCHIP2_OTGMODE_NO_OVERRIDE;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGMODE_MASK,
|
||||
val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops da8xx_usb20_phy_ops = {
|
||||
.power_on = da8xx_usb20_phy_power_on,
|
||||
.power_off = da8xx_usb20_phy_power_off,
|
||||
.set_mode = da8xx_usb20_phy_set_mode,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct phy *da8xx_usb_phy_of_xlate(struct device *dev,
|
||||
struct of_phandle_args *args)
|
||||
{
|
||||
struct da8xx_usb_phy *d_phy = dev_get_drvdata(dev);
|
||||
|
||||
if (!d_phy)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
switch (args->args[0]) {
|
||||
case 0:
|
||||
return d_phy->usb20_phy;
|
||||
case 1:
|
||||
return d_phy->usb11_phy;
|
||||
default:
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
static int da8xx_usb_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct da8xx_usb_phy *d_phy;
|
||||
|
||||
d_phy = devm_kzalloc(dev, sizeof(*d_phy), GFP_KERNEL);
|
||||
if (!d_phy)
|
||||
return -ENOMEM;
|
||||
|
||||
if (node)
|
||||
d_phy->regmap = syscon_regmap_lookup_by_compatible(
|
||||
"ti,da830-cfgchip");
|
||||
else
|
||||
d_phy->regmap = syscon_regmap_lookup_by_pdevname("syscon.0");
|
||||
if (IS_ERR(d_phy->regmap)) {
|
||||
dev_err(dev, "Failed to get syscon\n");
|
||||
return PTR_ERR(d_phy->regmap);
|
||||
}
|
||||
|
||||
d_phy->usb11_clk = devm_clk_get(dev, "usb11_phy");
|
||||
if (IS_ERR(d_phy->usb11_clk)) {
|
||||
dev_err(dev, "Failed to get usb11_phy clock\n");
|
||||
return PTR_ERR(d_phy->usb11_clk);
|
||||
}
|
||||
|
||||
d_phy->usb20_clk = devm_clk_get(dev, "usb20_phy");
|
||||
if (IS_ERR(d_phy->usb20_clk)) {
|
||||
dev_err(dev, "Failed to get usb20_phy clock\n");
|
||||
return PTR_ERR(d_phy->usb20_clk);
|
||||
}
|
||||
|
||||
d_phy->usb11_phy = devm_phy_create(dev, node, &da8xx_usb11_phy_ops);
|
||||
if (IS_ERR(d_phy->usb11_phy)) {
|
||||
dev_err(dev, "Failed to create usb11 phy\n");
|
||||
return PTR_ERR(d_phy->usb11_phy);
|
||||
}
|
||||
|
||||
d_phy->usb20_phy = devm_phy_create(dev, node, &da8xx_usb20_phy_ops);
|
||||
if (IS_ERR(d_phy->usb20_phy)) {
|
||||
dev_err(dev, "Failed to create usb20 phy\n");
|
||||
return PTR_ERR(d_phy->usb20_phy);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, d_phy);
|
||||
phy_set_drvdata(d_phy->usb11_phy, d_phy);
|
||||
phy_set_drvdata(d_phy->usb20_phy, d_phy);
|
||||
|
||||
if (node) {
|
||||
d_phy->phy_provider = devm_of_phy_provider_register(dev,
|
||||
da8xx_usb_phy_of_xlate);
|
||||
if (IS_ERR(d_phy->phy_provider)) {
|
||||
dev_err(dev, "Failed to create phy provider\n");
|
||||
return PTR_ERR(d_phy->phy_provider);
|
||||
}
|
||||
} else {
|
||||
int ret;
|
||||
|
||||
ret = phy_create_lookup(d_phy->usb11_phy, "usb-phy", "ohci.0");
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to create usb11 phy lookup\n");
|
||||
ret = phy_create_lookup(d_phy->usb20_phy, "usb-phy",
|
||||
"musb-da8xx");
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to create usb20 phy lookup\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int da8xx_usb_phy_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct da8xx_usb_phy *d_phy = platform_get_drvdata(pdev);
|
||||
|
||||
if (!pdev->dev.of_node) {
|
||||
phy_remove_lookup(d_phy->usb20_phy, "usb-phy", "musb-da8xx");
|
||||
phy_remove_lookup(d_phy->usb11_phy, "usb-phy", "ohci.0");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id da8xx_usb_phy_ids[] = {
|
||||
{ .compatible = "ti,da830-usb-phy" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, da8xx_usb_phy_ids);
|
||||
|
||||
static struct platform_driver da8xx_usb_phy_driver = {
|
||||
.probe = da8xx_usb_phy_probe,
|
||||
.remove = da8xx_usb_phy_remove,
|
||||
.driver = {
|
||||
.name = "da8xx-usb-phy",
|
||||
.of_match_table = da8xx_usb_phy_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(da8xx_usb_phy_driver);
|
||||
|
||||
MODULE_ALIAS("platform:da8xx-usb-phy");
|
||||
MODULE_AUTHOR("David Lechner <david@lechnology.com>");
|
||||
MODULE_DESCRIPTION("TI DA8xx USB PHY driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -140,7 +140,6 @@ static int ufs_qcom_phy_qmp_14nm_probe(struct platform_device *pdev)
|
||||
|
||||
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
|
||||
if (!phy) {
|
||||
dev_err(dev, "%s: failed to allocate phy\n", __func__);
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
@ -196,7 +196,6 @@ static int ufs_qcom_phy_qmp_20nm_probe(struct platform_device *pdev)
|
||||
|
||||
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
|
||||
if (!phy) {
|
||||
dev_err(dev, "%s: failed to allocate phy\n", __func__);
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
/******* USB2.0 Host registers (original offset is +0x200) *******/
|
||||
#define USB2_INT_ENABLE 0x000
|
||||
@ -81,9 +82,25 @@ struct rcar_gen3_chan {
|
||||
struct extcon_dev *extcon;
|
||||
struct phy *phy;
|
||||
struct regulator *vbus;
|
||||
struct work_struct work;
|
||||
bool extcon_host;
|
||||
bool has_otg;
|
||||
};
|
||||
|
||||
static void rcar_gen3_phy_usb2_work(struct work_struct *work)
|
||||
{
|
||||
struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan,
|
||||
work);
|
||||
|
||||
if (ch->extcon_host) {
|
||||
extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true);
|
||||
extcon_set_cable_state_(ch->extcon, EXTCON_USB, false);
|
||||
} else {
|
||||
extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false);
|
||||
extcon_set_cable_state_(ch->extcon, EXTCON_USB, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host)
|
||||
{
|
||||
void __iomem *usb2_base = ch->base;
|
||||
@ -130,8 +147,8 @@ static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch)
|
||||
rcar_gen3_set_host_mode(ch, 1);
|
||||
rcar_gen3_enable_vbus_ctrl(ch, 1);
|
||||
|
||||
extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true);
|
||||
extcon_set_cable_state_(ch->extcon, EXTCON_USB, false);
|
||||
ch->extcon_host = true;
|
||||
schedule_work(&ch->work);
|
||||
}
|
||||
|
||||
static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch)
|
||||
@ -140,8 +157,8 @@ static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch)
|
||||
rcar_gen3_set_host_mode(ch, 0);
|
||||
rcar_gen3_enable_vbus_ctrl(ch, 0);
|
||||
|
||||
extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false);
|
||||
extcon_set_cable_state_(ch->extcon, EXTCON_USB, true);
|
||||
ch->extcon_host = false;
|
||||
schedule_work(&ch->work);
|
||||
}
|
||||
|
||||
static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch)
|
||||
@ -301,6 +318,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
||||
if (irq >= 0) {
|
||||
int ret;
|
||||
|
||||
INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
|
||||
irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
|
||||
IRQF_SHARED, dev_name(dev), channel);
|
||||
if (irq < 0)
|
||||
|
@ -236,9 +236,10 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
|
||||
goto err_clk_prov;
|
||||
}
|
||||
|
||||
err = devm_add_action(base->dev, rockchip_usb_phy_action, rk_phy);
|
||||
err = devm_add_action_or_reset(base->dev, rockchip_usb_phy_action,
|
||||
rk_phy);
|
||||
if (err)
|
||||
goto err_devm_action;
|
||||
return err;
|
||||
|
||||
rk_phy->phy = devm_phy_create(base->dev, child, &ops);
|
||||
if (IS_ERR(rk_phy->phy)) {
|
||||
@ -256,9 +257,6 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
|
||||
else
|
||||
return rockchip_usb_phy_power(rk_phy, 1);
|
||||
|
||||
err_devm_action:
|
||||
if (!rk_phy->uart_enabled)
|
||||
of_clk_del_provider(child);
|
||||
err_clk_prov:
|
||||
if (!rk_phy->uart_enabled)
|
||||
clk_unregister(rk_phy->clk480m);
|
||||
@ -397,8 +395,13 @@ static int rockchip_usb_phy_probe(struct platform_device *pdev)
|
||||
phy_base->pdata = match->data;
|
||||
|
||||
phy_base->dev = dev;
|
||||
phy_base->reg_base = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"rockchip,grf");
|
||||
phy_base->reg_base = ERR_PTR(-ENODEV);
|
||||
if (dev->parent && dev->parent->of_node)
|
||||
phy_base->reg_base = syscon_node_to_regmap(
|
||||
dev->parent->of_node);
|
||||
if (IS_ERR(phy_base->reg_base))
|
||||
phy_base->reg_base = syscon_regmap_lookup_by_phandle(
|
||||
dev->of_node, "rockchip,grf");
|
||||
if (IS_ERR(phy_base->reg_base)) {
|
||||
dev_err(&pdev->dev, "Missing rockchip,grf property\n");
|
||||
return PTR_ERR(phy_base->reg_base);
|
||||
@ -463,7 +466,11 @@ static int __init rockchip_init_usb_uart(void)
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
|
||||
grf = ERR_PTR(-ENODEV);
|
||||
if (np->parent)
|
||||
grf = syscon_node_to_regmap(np->parent);
|
||||
if (IS_ERR(grf))
|
||||
grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
|
||||
if (IS_ERR(grf)) {
|
||||
pr_err("%s: Missing rockchip,grf property, %lu\n",
|
||||
__func__, PTR_ERR(grf));
|
||||
|
@ -94,6 +94,7 @@
|
||||
|
||||
enum sun4i_usb_phy_type {
|
||||
sun4i_a10_phy,
|
||||
sun6i_a31_phy,
|
||||
sun8i_a33_phy,
|
||||
sun8i_h3_phy,
|
||||
};
|
||||
@ -122,7 +123,6 @@ struct sun4i_usb_phy_data {
|
||||
/* phy0 / otg related variables */
|
||||
struct extcon_dev *extcon;
|
||||
bool phy0_init;
|
||||
bool phy0_poll;
|
||||
struct gpio_desc *id_det_gpio;
|
||||
struct gpio_desc *vbus_det_gpio;
|
||||
struct power_supply *vbus_power_supply;
|
||||
@ -343,6 +343,24 @@ static bool sun4i_usb_phy0_have_vbus_det(struct sun4i_usb_phy_data *data)
|
||||
return data->vbus_det_gpio || data->vbus_power_supply;
|
||||
}
|
||||
|
||||
static bool sun4i_usb_phy0_poll(struct sun4i_usb_phy_data *data)
|
||||
{
|
||||
if ((data->id_det_gpio && data->id_det_irq <= 0) ||
|
||||
(data->vbus_det_gpio && data->vbus_det_irq <= 0))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* The A31 companion pmic (axp221) does not generate vbus change
|
||||
* interrupts when the board is driving vbus, so we must poll
|
||||
* when using the pmic for vbus-det _and_ we're driving vbus.
|
||||
*/
|
||||
if (data->cfg->type == sun6i_a31_phy &&
|
||||
data->vbus_power_supply && data->phys[0].regulator_on)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int sun4i_usb_phy_power_on(struct phy *_phy)
|
||||
{
|
||||
struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
|
||||
@ -364,7 +382,7 @@ static int sun4i_usb_phy_power_on(struct phy *_phy)
|
||||
phy->regulator_on = true;
|
||||
|
||||
/* We must report Vbus high within OTG_TIME_A_WAIT_VRISE msec. */
|
||||
if (phy->index == 0 && data->vbus_det_gpio && data->phy0_poll)
|
||||
if (phy->index == 0 && sun4i_usb_phy0_poll(data))
|
||||
mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME);
|
||||
|
||||
return 0;
|
||||
@ -385,7 +403,7 @@ static int sun4i_usb_phy_power_off(struct phy *_phy)
|
||||
* phy0 vbus typically slowly discharges, sometimes this causes the
|
||||
* Vbus gpio to not trigger an edge irq on Vbus off, so force a rescan.
|
||||
*/
|
||||
if (phy->index == 0 && data->vbus_det_gpio && !data->phy0_poll)
|
||||
if (phy->index == 0 && !sun4i_usb_phy0_poll(data))
|
||||
mod_delayed_work(system_wq, &data->detect, POLL_TIME);
|
||||
|
||||
return 0;
|
||||
@ -468,7 +486,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
|
||||
if (vbus_notify)
|
||||
extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det);
|
||||
|
||||
if (data->phy0_poll)
|
||||
if (sun4i_usb_phy0_poll(data))
|
||||
queue_delayed_work(system_wq, &data->detect, POLL_TIME);
|
||||
}
|
||||
|
||||
@ -644,11 +662,6 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
data->id_det_irq = gpiod_to_irq(data->id_det_gpio);
|
||||
data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio);
|
||||
if ((data->id_det_gpio && data->id_det_irq <= 0) ||
|
||||
(data->vbus_det_gpio && data->vbus_det_irq <= 0))
|
||||
data->phy0_poll = true;
|
||||
|
||||
if (data->id_det_irq > 0) {
|
||||
ret = devm_request_irq(dev, data->id_det_irq,
|
||||
sun4i_usb_phy0_id_vbus_det_irq,
|
||||
@ -660,6 +673,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio);
|
||||
if (data->vbus_det_irq > 0) {
|
||||
ret = devm_request_irq(dev, data->vbus_det_irq,
|
||||
sun4i_usb_phy0_id_vbus_det_irq,
|
||||
@ -711,7 +725,7 @@ static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
|
||||
|
||||
static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = {
|
||||
.num_phys = 3,
|
||||
.type = sun4i_a10_phy,
|
||||
.type = sun6i_a31_phy,
|
||||
.disc_thresh = 3,
|
||||
.phyctl_offset = REG_PHYCTL_A10,
|
||||
.dedicated_clocks = true,
|
||||
|
@ -518,7 +518,7 @@ enum clk_type_t {
|
||||
CLK_INT_SING = 2, /* Internal single ended */
|
||||
};
|
||||
|
||||
enum phy_mode {
|
||||
enum xgene_phy_mode {
|
||||
MODE_SATA = 0, /* List them for simple reference */
|
||||
MODE_SGMII = 1,
|
||||
MODE_PCIE = 2,
|
||||
@ -542,7 +542,7 @@ struct xgene_sata_override_param {
|
||||
struct xgene_phy_ctx {
|
||||
struct device *dev;
|
||||
struct phy *phy;
|
||||
enum phy_mode mode; /* Mode of operation */
|
||||
enum xgene_phy_mode mode; /* Mode of operation */
|
||||
enum clk_type_t clk_type; /* Input clock selection */
|
||||
void __iomem *sds_base; /* PHY CSR base addr */
|
||||
struct clk *clk; /* Optional clock */
|
||||
|
@ -22,12 +22,20 @@
|
||||
|
||||
struct phy;
|
||||
|
||||
enum phy_mode {
|
||||
PHY_MODE_INVALID,
|
||||
PHY_MODE_USB_HOST,
|
||||
PHY_MODE_USB_DEVICE,
|
||||
PHY_MODE_USB_OTG,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct phy_ops - set of function pointers for performing phy operations
|
||||
* @init: operation to be performed for initializing phy
|
||||
* @exit: operation to be performed while exiting
|
||||
* @power_on: powering on the phy
|
||||
* @power_off: powering off the phy
|
||||
* @set_mode: set the mode of the phy
|
||||
* @owner: the module owner containing the ops
|
||||
*/
|
||||
struct phy_ops {
|
||||
@ -35,6 +43,7 @@ struct phy_ops {
|
||||
int (*exit)(struct phy *phy);
|
||||
int (*power_on)(struct phy *phy);
|
||||
int (*power_off)(struct phy *phy);
|
||||
int (*set_mode)(struct phy *phy, enum phy_mode mode);
|
||||
struct module *owner;
|
||||
};
|
||||
|
||||
@ -126,6 +135,7 @@ int phy_init(struct phy *phy);
|
||||
int phy_exit(struct phy *phy);
|
||||
int phy_power_on(struct phy *phy);
|
||||
int phy_power_off(struct phy *phy);
|
||||
int phy_set_mode(struct phy *phy, enum phy_mode mode);
|
||||
static inline int phy_get_bus_width(struct phy *phy)
|
||||
{
|
||||
return phy->attrs.bus_width;
|
||||
@ -233,6 +243,13 @@ static inline int phy_power_off(struct phy *phy)
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int phy_set_mode(struct phy *phy, enum phy_mode mode)
|
||||
{
|
||||
if (!phy)
|
||||
return 0;
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int phy_get_bus_width(struct phy *phy)
|
||||
{
|
||||
return -ENOSYS;
|
||||
|
Loading…
Reference in New Issue
Block a user