diff options
Diffstat (limited to 'drivers/phy')
-rw-r--r-- | drivers/phy/Kconfig | 11 | ||||
-rw-r--r-- | drivers/phy/Makefile | 1 | ||||
-rw-r--r-- | drivers/phy/phy-bcm-ns-usb2.c | 4 | ||||
-rw-r--r-- | drivers/phy/phy-core.c | 15 | ||||
-rw-r--r-- | drivers/phy/phy-da8xx-usb.c | 245 | ||||
-rw-r--r-- | drivers/phy/phy-exynos-mipi-video.c | 6 | ||||
-rw-r--r-- | drivers/phy/phy-miphy28lp.c | 3 | ||||
-rw-r--r-- | drivers/phy/phy-qcom-ufs-qmp-14nm.c | 1 | ||||
-rw-r--r-- | drivers/phy/phy-qcom-ufs-qmp-20nm.c | 1 | ||||
-rw-r--r-- | drivers/phy/phy-rcar-gen3-usb2.c | 40 | ||||
-rw-r--r-- | drivers/phy/phy-rockchip-dp.c | 2 | ||||
-rw-r--r-- | drivers/phy/phy-rockchip-usb.c | 23 | ||||
-rw-r--r-- | drivers/phy/phy-stih407-usb.c | 4 | ||||
-rw-r--r-- | drivers/phy/phy-sun4i-usb.c | 44 | ||||
-rw-r--r-- | drivers/phy/phy-ti-pipe3.c | 15 | ||||
-rw-r--r-- | drivers/phy/phy-twl4030-usb.c | 14 | ||||
-rw-r--r-- | drivers/phy/phy-xgene.c | 4 |
17 files changed, 374 insertions, 59 deletions
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index b869b98835f4..cc0b69545385 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -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 @@ -176,6 +186,7 @@ config TWL4030_USB tristate "TWL4030 USB Transceiver Driver" depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS depends on USB_SUPPORT + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't 'y' select GENERIC_PHY select USB_PHY help diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 9c3e73ccabc4..fa8480e89724 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -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 diff --git a/drivers/phy/phy-bcm-ns-usb2.c b/drivers/phy/phy-bcm-ns-usb2.c index 95ab6b2a0de5..58dff80e9386 100644 --- a/drivers/phy/phy-bcm-ns-usb2.c +++ b/drivers/phy/phy-bcm-ns-usb2.c @@ -109,8 +109,8 @@ static int bcm_ns_usb2_probe(struct platform_device *pdev) } usb2->phy = devm_phy_create(dev, NULL, &ops); - if (IS_ERR(dev)) - return PTR_ERR(dev); + if (IS_ERR(usb2->phy)) + return PTR_ERR(usb2->phy); phy_set_drvdata(usb2->phy, usb2); platform_set_drvdata(pdev, usb2); diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index b72e9a3b6429..8eca906b6e70 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -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 diff --git a/drivers/phy/phy-da8xx-usb.c b/drivers/phy/phy-da8xx-usb.c new file mode 100644 index 000000000000..b2e59b6170ac --- /dev/null +++ b/drivers/phy/phy-da8xx-usb.c @@ -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"); diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c index cc093ebfda94..8b851f718123 100644 --- a/drivers/phy/phy-exynos-mipi-video.c +++ b/drivers/phy/phy-exynos-mipi-video.c @@ -233,8 +233,12 @@ static inline int __is_running(const struct exynos_mipi_phy_desc *data, struct exynos_mipi_video_phy *state) { u32 val; + int ret; + + ret = regmap_read(state->regmaps[data->resetn_map], data->resetn_reg, &val); + if (ret) + return 0; - regmap_read(state->regmaps[data->resetn_map], data->resetn_reg, &val); return val & data->resetn_val; } diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c index 3acd2a1808df..213e2e15339c 100644 --- a/drivers/phy/phy-miphy28lp.c +++ b/drivers/phy/phy-miphy28lp.c @@ -1143,7 +1143,8 @@ static int miphy28lp_probe_resets(struct device_node *node, struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; int err; - miphy_phy->miphy_rst = of_reset_control_get(node, "miphy-sw-rst"); + miphy_phy->miphy_rst = + of_reset_control_get_shared(node, "miphy-sw-rst"); if (IS_ERR(miphy_phy->miphy_rst)) { dev_err(miphy_dev->dev, diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.c b/drivers/phy/phy-qcom-ufs-qmp-14nm.c index 56631e77c11d..6ee51490f786 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-14nm.c +++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.c @@ -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; } diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/phy-qcom-ufs-qmp-20nm.c index b16ea77d07b9..770087ab05e2 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-20nm.c +++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c @@ -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; } diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c index 76bb88f0700a..31156c9c4707 100644 --- a/drivers/phy/phy-rcar-gen3-usb2.c +++ b/drivers/phy/phy-rcar-gen3-usb2.c @@ -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,14 +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); -} - -static bool rcar_gen3_check_vbus(struct rcar_gen3_chan *ch) -{ - return !!(readl(ch->base + USB2_ADPCTRL) & - USB2_ADPCTRL_OTGSESSVLD); + ch->extcon_host = false; + schedule_work(&ch->work); } static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) @@ -157,13 +168,7 @@ static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch) { - bool is_host = true; - - /* B-device? */ - if (rcar_gen3_check_id(ch) && rcar_gen3_check_vbus(ch)) - is_host = false; - - if (is_host) + if (!rcar_gen3_check_id(ch)) rcar_gen3_init_for_host(ch); else rcar_gen3_init_for_peri(ch); @@ -313,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) diff --git a/drivers/phy/phy-rockchip-dp.c b/drivers/phy/phy-rockchip-dp.c index 793ecb6d87bc..8b267a746576 100644 --- a/drivers/phy/phy-rockchip-dp.c +++ b/drivers/phy/phy-rockchip-dp.c @@ -90,7 +90,7 @@ static int rockchip_dp_phy_probe(struct platform_device *pdev) return -ENODEV; dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); - if (IS_ERR(dp)) + if (!dp) return -ENOMEM; dp->dev = dev; diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c index d60b149cff0f..2a7381f4fe4c 100644 --- a/drivers/phy/phy-rockchip-usb.c +++ b/drivers/phy/phy-rockchip-usb.c @@ -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)); diff --git a/drivers/phy/phy-stih407-usb.c b/drivers/phy/phy-stih407-usb.c index 1d5ae5f8ef69..b1f44ab669fb 100644 --- a/drivers/phy/phy-stih407-usb.c +++ b/drivers/phy/phy-stih407-usb.c @@ -105,13 +105,13 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev) phy_dev->dev = dev; dev_set_drvdata(dev, phy_dev); - phy_dev->rstc = devm_reset_control_get(dev, "global"); + phy_dev->rstc = devm_reset_control_get_shared(dev, "global"); if (IS_ERR(phy_dev->rstc)) { dev_err(dev, "failed to ctrl picoPHY reset\n"); return PTR_ERR(phy_dev->rstc); } - phy_dev->rstport = devm_reset_control_get(dev, "port"); + phy_dev->rstport = devm_reset_control_get_exclusive(dev, "port"); if (IS_ERR(phy_dev->rstport)) { dev_err(dev, "failed to ctrl picoPHY reset\n"); return PTR_ERR(phy_dev->rstport); diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index bae54f7a1f48..0a45bc6088ae 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -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; @@ -175,7 +175,7 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data, { struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy); u32 temp, usbc_bit = BIT(phy->index * 2); - void *phyctl = phy_data->base + phy_data->cfg->phyctl_offset; + void __iomem *phyctl = phy_data->base + phy_data->cfg->phyctl_offset; int i; mutex_lock(&phy_data->mutex); @@ -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); } @@ -514,9 +532,9 @@ static int sun4i_usb_phy_remove(struct platform_device *pdev) if (data->vbus_power_nb_registered) power_supply_unreg_notifier(&data->vbus_power_nb); - if (data->id_det_irq >= 0) + if (data->id_det_irq > 0) devm_free_irq(dev, data->id_det_irq, data); - if (data->vbus_det_irq >= 0) + if (data->vbus_det_irq > 0) devm_free_irq(dev, data->vbus_det_irq, data); cancel_delayed_work_sync(&data->detect); @@ -644,12 +662,7 @@ 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) { + if (data->id_det_irq > 0) { ret = devm_request_irq(dev, data->id_det_irq, sun4i_usb_phy0_id_vbus_det_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, @@ -660,7 +673,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) } } - if (data->vbus_det_irq >= 0) { + 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, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, @@ -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, diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index 0a477d24cf76..bf46844dc387 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c @@ -293,11 +293,18 @@ static int ti_pipe3_init(struct phy *x) ret = ti_pipe3_dpll_wait_lock(phy); } - /* Program the DPLL only if not locked */ + /* SATA has issues if re-programmed when locked */ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS); - if (!(val & PLL_LOCK)) - if (ti_pipe3_dpll_program(phy)) - return -EINVAL; + if ((val & PLL_LOCK) && of_device_is_compatible(phy->dev->of_node, + "ti,phy-pipe3-sata")) + return ret; + + /* Program the DPLL */ + ret = ti_pipe3_dpll_program(phy); + if (ret) { + ti_pipe3_disable_clocks(phy); + return -EINVAL; + } return ret; } diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c index 6b6af6cba454..d9b10a39a2cf 100644 --- a/drivers/phy/phy-twl4030-usb.c +++ b/drivers/phy/phy-twl4030-usb.c @@ -463,7 +463,8 @@ static int twl4030_phy_power_on(struct phy *phy) twl4030_usb_set_mode(twl, twl->usb_mode); if (twl->usb_mode == T2_USB_MODE_ULPI) twl4030_i2c_access(twl, 0); - schedule_delayed_work(&twl->id_workaround_work, 0); + twl->linkstat = MUSB_UNKNOWN; + schedule_delayed_work(&twl->id_workaround_work, HZ); return 0; } @@ -537,6 +538,7 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) struct twl4030_usb *twl = _twl; enum musb_vbus_id_status status; bool status_changed = false; + int err; status = twl4030_usb_linkstat(twl); @@ -567,7 +569,9 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) pm_runtime_mark_last_busy(twl->dev); pm_runtime_put_autosuspend(twl->dev); } - musb_mailbox(status); + err = musb_mailbox(status); + if (err) + twl->linkstat = MUSB_UNKNOWN; } /* don't schedule during sleep - irq works right then */ @@ -595,7 +599,8 @@ static int twl4030_phy_init(struct phy *phy) struct twl4030_usb *twl = phy_get_drvdata(phy); pm_runtime_get_sync(twl->dev); - schedule_delayed_work(&twl->id_workaround_work, 0); + twl->linkstat = MUSB_UNKNOWN; + schedule_delayed_work(&twl->id_workaround_work, HZ); pm_runtime_mark_last_busy(twl->dev); pm_runtime_put_autosuspend(twl->dev); @@ -763,7 +768,8 @@ static int twl4030_usb_remove(struct platform_device *pdev) if (cable_present(twl->linkstat)) pm_runtime_put_noidle(twl->dev); pm_runtime_mark_last_busy(twl->dev); - pm_runtime_put_sync_suspend(twl->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_put_sync(twl->dev); pm_runtime_disable(twl->dev); /* autogate 60MHz ULPI clock, diff --git a/drivers/phy/phy-xgene.c b/drivers/phy/phy-xgene.c index 385362e5b2f6..ae266e0c8368 100644 --- a/drivers/phy/phy-xgene.c +++ b/drivers/phy/phy-xgene.c @@ -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 */ |