Merge tag 'phy-fixes-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy
Pull phy fixes from Vinod Koul:
"A bunch of renesas fixes and few smaller fixes in other drivers:
- Rensas fixes for unbind ole detection, irq, locking etc
- tegra fixes for error handling at init and UTMI power states and
stray unlock fix
- rockchip missing assignment and pll output fixes
- startfive usb host detection fixes"
* tag 'phy-fixes-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy:
phy: Fix error handling in tegra_xusb_port_init
phy: renesas: rcar-gen3-usb2: Set timing registers only once
phy: renesas: rcar-gen3-usb2: Assert PLL reset on PHY power off
phy: renesas: rcar-gen3-usb2: Lock around hardware registers and driver data
phy: renesas: rcar-gen3-usb2: Move IRQ request in probe
phy: renesas: rcar-gen3-usb2: Fix role detection on unbind/bind
phy: tegra: xusb: remove a stray unlock
phy: phy-rockchip-samsung-hdptx: Fix PHY PLL output 50.25MHz error
phy: starfive: jh7110-usb: Fix USB 2.0 host occasional detection failure
phy: rockchip-samsung-dcphy: Add missing assignment
phy: can-transceiver: Re-instate "mux-states" property presence check
phy: qcom-qmp-ufs: check for mode type for phy setting
phy: tegra: xusb: Use a bitmask for UTMI pad power state tracking
This commit is contained in:
@@ -93,6 +93,16 @@ static const struct of_device_id can_transceiver_phy_ids[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, can_transceiver_phy_ids);
|
||||
|
||||
/* Temporary wrapper until the multiplexer subsystem supports optional muxes */
|
||||
static inline struct mux_state *
|
||||
devm_mux_state_get_optional(struct device *dev, const char *mux_name)
|
||||
{
|
||||
if (!of_property_present(dev->of_node, "mux-states"))
|
||||
return NULL;
|
||||
|
||||
return devm_mux_state_get(dev, mux_name);
|
||||
}
|
||||
|
||||
static int can_transceiver_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct phy_provider *phy_provider;
|
||||
@@ -114,13 +124,11 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
|
||||
match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node);
|
||||
drvdata = match->data;
|
||||
|
||||
mux_state = devm_mux_state_get(dev, NULL);
|
||||
if (IS_ERR(mux_state)) {
|
||||
if (PTR_ERR(mux_state) == -EPROBE_DEFER)
|
||||
return PTR_ERR(mux_state);
|
||||
} else {
|
||||
can_transceiver_phy->mux_state = mux_state;
|
||||
}
|
||||
mux_state = devm_mux_state_get_optional(dev, NULL);
|
||||
if (IS_ERR(mux_state))
|
||||
return PTR_ERR(mux_state);
|
||||
|
||||
can_transceiver_phy->mux_state = mux_state;
|
||||
|
||||
phy = devm_phy_create(dev, dev->of_node,
|
||||
&can_transceiver_phy_ops);
|
||||
|
||||
@@ -1754,7 +1754,8 @@ static void qmp_ufs_init_registers(struct qmp_ufs *qmp, const struct qmp_phy_cfg
|
||||
qmp_ufs_init_all(qmp, &cfg->tbls_hs_overlay[i]);
|
||||
}
|
||||
|
||||
qmp_ufs_init_all(qmp, &cfg->tbls_hs_b);
|
||||
if (qmp->mode == PHY_MODE_UFS_HS_B)
|
||||
qmp_ufs_init_all(qmp, &cfg->tbls_hs_b);
|
||||
}
|
||||
|
||||
static int qmp_ufs_com_init(struct qmp_ufs *qmp)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* Copyright (C) 2014 Cogent Embedded, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/extcon-provider.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
@@ -107,7 +108,6 @@ struct rcar_gen3_phy {
|
||||
struct rcar_gen3_chan *ch;
|
||||
u32 int_enable_bits;
|
||||
bool initialized;
|
||||
bool otg_initialized;
|
||||
bool powered;
|
||||
};
|
||||
|
||||
@@ -119,9 +119,8 @@ struct rcar_gen3_chan {
|
||||
struct regulator *vbus;
|
||||
struct reset_control *rstc;
|
||||
struct work_struct work;
|
||||
struct mutex lock; /* protects rphys[...].powered */
|
||||
spinlock_t lock; /* protects access to hardware and driver data structure. */
|
||||
enum usb_dr_mode dr_mode;
|
||||
int irq;
|
||||
u32 obint_enable_bits;
|
||||
bool extcon_host;
|
||||
bool is_otg_channel;
|
||||
@@ -320,16 +319,15 @@ static bool rcar_gen3_is_any_rphy_initialized(struct rcar_gen3_chan *ch)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool rcar_gen3_needs_init_otg(struct rcar_gen3_chan *ch)
|
||||
static bool rcar_gen3_is_any_otg_rphy_initialized(struct rcar_gen3_chan *ch)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_OF_PHYS; i++) {
|
||||
if (ch->rphys[i].otg_initialized)
|
||||
return false;
|
||||
for (enum rcar_gen3_phy_index i = PHY_INDEX_BOTH_HC; i <= PHY_INDEX_EHCI;
|
||||
i++) {
|
||||
if (ch->rphys[i].initialized)
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool rcar_gen3_are_all_rphys_power_off(struct rcar_gen3_chan *ch)
|
||||
@@ -351,7 +349,9 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr,
|
||||
bool is_b_device;
|
||||
enum phy_mode cur_mode, new_mode;
|
||||
|
||||
if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch))
|
||||
guard(spinlock_irqsave)(&ch->lock);
|
||||
|
||||
if (!ch->is_otg_channel || !rcar_gen3_is_any_otg_rphy_initialized(ch))
|
||||
return -EIO;
|
||||
|
||||
if (sysfs_streq(buf, "host"))
|
||||
@@ -389,7 +389,7 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
struct rcar_gen3_chan *ch = dev_get_drvdata(dev);
|
||||
|
||||
if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch))
|
||||
if (!ch->is_otg_channel || !rcar_gen3_is_any_otg_rphy_initialized(ch))
|
||||
return -EIO;
|
||||
|
||||
return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" :
|
||||
@@ -402,6 +402,9 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
|
||||
void __iomem *usb2_base = ch->base;
|
||||
u32 val;
|
||||
|
||||
if (!ch->is_otg_channel || rcar_gen3_is_any_otg_rphy_initialized(ch))
|
||||
return;
|
||||
|
||||
/* Should not use functions of read-modify-write a register */
|
||||
val = readl(usb2_base + USB2_LINECTRL1);
|
||||
val = (val & ~USB2_LINECTRL1_DP_RPD) | USB2_LINECTRL1_DPRPD_EN |
|
||||
@@ -415,7 +418,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
|
||||
val = readl(usb2_base + USB2_ADPCTRL);
|
||||
writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL);
|
||||
}
|
||||
msleep(20);
|
||||
mdelay(20);
|
||||
|
||||
writel(0xffffffff, usb2_base + USB2_OBINTSTA);
|
||||
writel(ch->obint_enable_bits, usb2_base + USB2_OBINTEN);
|
||||
@@ -427,16 +430,27 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
|
||||
{
|
||||
struct rcar_gen3_chan *ch = _ch;
|
||||
void __iomem *usb2_base = ch->base;
|
||||
u32 status = readl(usb2_base + USB2_OBINTSTA);
|
||||
struct device *dev = ch->dev;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
u32 status;
|
||||
|
||||
if (status & ch->obint_enable_bits) {
|
||||
dev_vdbg(ch->dev, "%s: %08x\n", __func__, status);
|
||||
writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA);
|
||||
rcar_gen3_device_recognition(ch);
|
||||
ret = IRQ_HANDLED;
|
||||
pm_runtime_get_noresume(dev);
|
||||
|
||||
if (pm_runtime_suspended(dev))
|
||||
goto rpm_put;
|
||||
|
||||
scoped_guard(spinlock, &ch->lock) {
|
||||
status = readl(usb2_base + USB2_OBINTSTA);
|
||||
if (status & ch->obint_enable_bits) {
|
||||
dev_vdbg(dev, "%s: %08x\n", __func__, status);
|
||||
writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA);
|
||||
rcar_gen3_device_recognition(ch);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
rpm_put:
|
||||
pm_runtime_put_noidle(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -446,32 +460,23 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
|
||||
struct rcar_gen3_chan *channel = rphy->ch;
|
||||
void __iomem *usb2_base = channel->base;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (!rcar_gen3_is_any_rphy_initialized(channel) && channel->irq >= 0) {
|
||||
INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
|
||||
ret = request_irq(channel->irq, rcar_gen3_phy_usb2_irq,
|
||||
IRQF_SHARED, dev_name(channel->dev), channel);
|
||||
if (ret < 0) {
|
||||
dev_err(channel->dev, "No irq handler (%d)\n", channel->irq);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
guard(spinlock_irqsave)(&channel->lock);
|
||||
|
||||
/* Initialize USB2 part */
|
||||
val = readl(usb2_base + USB2_INT_ENABLE);
|
||||
val |= USB2_INT_ENABLE_UCOM_INTEN | rphy->int_enable_bits;
|
||||
writel(val, usb2_base + USB2_INT_ENABLE);
|
||||
writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET);
|
||||
writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET);
|
||||
|
||||
/* Initialize otg part */
|
||||
if (channel->is_otg_channel) {
|
||||
if (rcar_gen3_needs_init_otg(channel))
|
||||
rcar_gen3_init_otg(channel);
|
||||
rphy->otg_initialized = true;
|
||||
if (!rcar_gen3_is_any_rphy_initialized(channel)) {
|
||||
writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET);
|
||||
writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET);
|
||||
}
|
||||
|
||||
/* Initialize otg part (only if we initialize a PHY with IRQs). */
|
||||
if (rphy->int_enable_bits)
|
||||
rcar_gen3_init_otg(channel);
|
||||
|
||||
rphy->initialized = true;
|
||||
|
||||
return 0;
|
||||
@@ -484,10 +489,9 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
|
||||
void __iomem *usb2_base = channel->base;
|
||||
u32 val;
|
||||
|
||||
rphy->initialized = false;
|
||||
guard(spinlock_irqsave)(&channel->lock);
|
||||
|
||||
if (channel->is_otg_channel)
|
||||
rphy->otg_initialized = false;
|
||||
rphy->initialized = false;
|
||||
|
||||
val = readl(usb2_base + USB2_INT_ENABLE);
|
||||
val &= ~rphy->int_enable_bits;
|
||||
@@ -495,9 +499,6 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
|
||||
val &= ~USB2_INT_ENABLE_UCOM_INTEN;
|
||||
writel(val, usb2_base + USB2_INT_ENABLE);
|
||||
|
||||
if (channel->irq >= 0 && !rcar_gen3_is_any_rphy_initialized(channel))
|
||||
free_irq(channel->irq, channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -509,16 +510,17 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&channel->lock);
|
||||
if (!rcar_gen3_are_all_rphys_power_off(channel))
|
||||
goto out;
|
||||
|
||||
if (channel->vbus) {
|
||||
ret = regulator_enable(channel->vbus);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
guard(spinlock_irqsave)(&channel->lock);
|
||||
|
||||
if (!rcar_gen3_are_all_rphys_power_off(channel))
|
||||
goto out;
|
||||
|
||||
val = readl(usb2_base + USB2_USBCTR);
|
||||
val |= USB2_USBCTR_PLL_RST;
|
||||
writel(val, usb2_base + USB2_USBCTR);
|
||||
@@ -528,7 +530,6 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
|
||||
out:
|
||||
/* The powered flag should be set for any other phys anyway */
|
||||
rphy->powered = true;
|
||||
mutex_unlock(&channel->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -539,18 +540,20 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p)
|
||||
struct rcar_gen3_chan *channel = rphy->ch;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&channel->lock);
|
||||
rphy->powered = false;
|
||||
scoped_guard(spinlock_irqsave, &channel->lock) {
|
||||
rphy->powered = false;
|
||||
|
||||
if (!rcar_gen3_are_all_rphys_power_off(channel))
|
||||
goto out;
|
||||
if (rcar_gen3_are_all_rphys_power_off(channel)) {
|
||||
u32 val = readl(channel->base + USB2_USBCTR);
|
||||
|
||||
val |= USB2_USBCTR_PLL_RST;
|
||||
writel(val, channel->base + USB2_USBCTR);
|
||||
}
|
||||
}
|
||||
|
||||
if (channel->vbus)
|
||||
ret = regulator_disable(channel->vbus);
|
||||
|
||||
out:
|
||||
mutex_unlock(&channel->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -703,7 +706,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rcar_gen3_chan *channel;
|
||||
struct phy_provider *provider;
|
||||
int ret = 0, i;
|
||||
int ret = 0, i, irq;
|
||||
|
||||
if (!dev->of_node) {
|
||||
dev_err(dev, "This driver needs device tree\n");
|
||||
@@ -719,8 +722,6 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(channel->base);
|
||||
|
||||
channel->obint_enable_bits = USB2_OBINT_BITS;
|
||||
/* get irq number here and request_irq for OTG in phy_init */
|
||||
channel->irq = platform_get_irq_optional(pdev, 0);
|
||||
channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node);
|
||||
if (channel->dr_mode != USB_DR_MODE_UNKNOWN) {
|
||||
channel->is_otg_channel = true;
|
||||
@@ -763,7 +764,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
||||
if (phy_data->no_adp_ctrl)
|
||||
channel->obint_enable_bits = USB2_OBINT_IDCHG_EN;
|
||||
|
||||
mutex_init(&channel->lock);
|
||||
spin_lock_init(&channel->lock);
|
||||
for (i = 0; i < NUM_OF_PHYS; i++) {
|
||||
channel->rphys[i].phy = devm_phy_create(dev, NULL,
|
||||
phy_data->phy_usb2_ops);
|
||||
@@ -789,6 +790,20 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
||||
channel->vbus = NULL;
|
||||
}
|
||||
|
||||
irq = platform_get_irq_optional(pdev, 0);
|
||||
if (irq < 0 && irq != -ENXIO) {
|
||||
ret = irq;
|
||||
goto error;
|
||||
} else if (irq > 0) {
|
||||
INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
|
||||
ret = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
|
||||
IRQF_SHARED, dev_name(dev), channel);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to request irq (%d)\n", irq);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
provider = devm_of_phy_provider_register(dev, rcar_gen3_phy_usb2_xlate);
|
||||
if (IS_ERR(provider)) {
|
||||
dev_err(dev, "Failed to register PHY provider\n");
|
||||
|
||||
@@ -1653,7 +1653,7 @@ static __maybe_unused int samsung_mipi_dcphy_runtime_resume(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
clk_prepare_enable(samsung->ref_clk);
|
||||
ret = clk_prepare_enable(samsung->ref_clk);
|
||||
if (ret) {
|
||||
dev_err(samsung->dev, "Failed to enable reference clock, %d\n", ret);
|
||||
clk_disable_unprepare(samsung->pclk);
|
||||
|
||||
@@ -476,6 +476,8 @@ static const struct ropll_config ropll_tmds_cfg[] = {
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 650000, 162, 162, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 54, 0, 16, 4, 1,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 502500, 84, 84, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 11, 1, 4, 5,
|
||||
4, 11, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 337500, 0x70, 0x70, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 0x2, 0, 0x01, 5,
|
||||
1, 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 400000, 100, 100, 1, 1, 11, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include <linux/usb/of.h>
|
||||
|
||||
#define USB_125M_CLK_RATE 125000000
|
||||
#define USB_CLK_MODE_OFF 0x0
|
||||
#define USB_CLK_MODE_RX_NORMAL_PWR BIT(1)
|
||||
#define USB_LS_KEEPALIVE_OFF 0x4
|
||||
#define USB_LS_KEEPALIVE_ENABLE BIT(4)
|
||||
|
||||
@@ -78,6 +80,7 @@ static int jh7110_usb2_phy_init(struct phy *_phy)
|
||||
{
|
||||
struct jh7110_usb2_phy *phy = phy_get_drvdata(_phy);
|
||||
int ret;
|
||||
unsigned int val;
|
||||
|
||||
ret = clk_set_rate(phy->usb_125m_clk, USB_125M_CLK_RATE);
|
||||
if (ret)
|
||||
@@ -87,6 +90,10 @@ static int jh7110_usb2_phy_init(struct phy *_phy)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = readl(phy->regs + USB_CLK_MODE_OFF);
|
||||
val |= USB_CLK_MODE_RX_NORMAL_PWR;
|
||||
writel(val, phy->regs + USB_CLK_MODE_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -237,6 +237,8 @@
|
||||
#define DATA0_VAL_PD BIT(1)
|
||||
#define USE_XUSB_AO BIT(4)
|
||||
|
||||
#define TEGRA_UTMI_PAD_MAX 4
|
||||
|
||||
#define TEGRA186_LANE(_name, _offset, _shift, _mask, _type) \
|
||||
{ \
|
||||
.name = _name, \
|
||||
@@ -269,7 +271,7 @@ struct tegra186_xusb_padctl {
|
||||
|
||||
/* UTMI bias and tracking */
|
||||
struct clk *usb2_trk_clk;
|
||||
unsigned int bias_pad_enable;
|
||||
DECLARE_BITMAP(utmi_pad_enabled, TEGRA_UTMI_PAD_MAX);
|
||||
|
||||
/* padctl context */
|
||||
struct tegra186_xusb_padctl_context context;
|
||||
@@ -603,12 +605,8 @@ static void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl)
|
||||
u32 value;
|
||||
int err;
|
||||
|
||||
mutex_lock(&padctl->lock);
|
||||
|
||||
if (priv->bias_pad_enable++ > 0) {
|
||||
mutex_unlock(&padctl->lock);
|
||||
if (!bitmap_empty(priv->utmi_pad_enabled, TEGRA_UTMI_PAD_MAX))
|
||||
return;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(priv->usb2_trk_clk);
|
||||
if (err < 0)
|
||||
@@ -658,8 +656,6 @@ static void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl)
|
||||
} else {
|
||||
clk_disable_unprepare(priv->usb2_trk_clk);
|
||||
}
|
||||
|
||||
mutex_unlock(&padctl->lock);
|
||||
}
|
||||
|
||||
static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl)
|
||||
@@ -667,17 +663,8 @@ static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl)
|
||||
struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
|
||||
u32 value;
|
||||
|
||||
mutex_lock(&padctl->lock);
|
||||
|
||||
if (WARN_ON(priv->bias_pad_enable == 0)) {
|
||||
mutex_unlock(&padctl->lock);
|
||||
if (!bitmap_empty(priv->utmi_pad_enabled, TEGRA_UTMI_PAD_MAX))
|
||||
return;
|
||||
}
|
||||
|
||||
if (--priv->bias_pad_enable > 0) {
|
||||
mutex_unlock(&padctl->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
|
||||
value |= USB2_PD_TRK;
|
||||
@@ -690,13 +677,13 @@ static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl)
|
||||
clk_disable_unprepare(priv->usb2_trk_clk);
|
||||
}
|
||||
|
||||
mutex_unlock(&padctl->lock);
|
||||
}
|
||||
|
||||
static void tegra186_utmi_pad_power_on(struct phy *phy)
|
||||
{
|
||||
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
|
||||
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
|
||||
struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
|
||||
struct tegra_xusb_usb2_port *port;
|
||||
struct device *dev = padctl->dev;
|
||||
unsigned int index = lane->index;
|
||||
@@ -705,9 +692,16 @@ static void tegra186_utmi_pad_power_on(struct phy *phy)
|
||||
if (!phy)
|
||||
return;
|
||||
|
||||
mutex_lock(&padctl->lock);
|
||||
if (test_bit(index, priv->utmi_pad_enabled)) {
|
||||
mutex_unlock(&padctl->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
port = tegra_xusb_find_usb2_port(padctl, index);
|
||||
if (!port) {
|
||||
dev_err(dev, "no port found for USB2 lane %u\n", index);
|
||||
mutex_unlock(&padctl->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -724,18 +718,28 @@ static void tegra186_utmi_pad_power_on(struct phy *phy)
|
||||
value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
|
||||
value &= ~USB2_OTG_PD_DR;
|
||||
padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
|
||||
|
||||
set_bit(index, priv->utmi_pad_enabled);
|
||||
mutex_unlock(&padctl->lock);
|
||||
}
|
||||
|
||||
static void tegra186_utmi_pad_power_down(struct phy *phy)
|
||||
{
|
||||
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
|
||||
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
|
||||
struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
|
||||
unsigned int index = lane->index;
|
||||
u32 value;
|
||||
|
||||
if (!phy)
|
||||
return;
|
||||
|
||||
mutex_lock(&padctl->lock);
|
||||
if (!test_bit(index, priv->utmi_pad_enabled)) {
|
||||
mutex_unlock(&padctl->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
dev_dbg(padctl->dev, "power down UTMI pad %u\n", index);
|
||||
|
||||
value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
|
||||
@@ -748,7 +752,11 @@ static void tegra186_utmi_pad_power_down(struct phy *phy)
|
||||
|
||||
udelay(2);
|
||||
|
||||
clear_bit(index, priv->utmi_pad_enabled);
|
||||
|
||||
tegra186_utmi_bias_pad_power_off(padctl);
|
||||
|
||||
mutex_unlock(&padctl->lock);
|
||||
}
|
||||
|
||||
static int tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
|
||||
|
||||
@@ -548,16 +548,16 @@ static int tegra_xusb_port_init(struct tegra_xusb_port *port,
|
||||
|
||||
err = dev_set_name(&port->dev, "%s-%u", name, index);
|
||||
if (err < 0)
|
||||
goto unregister;
|
||||
goto put_device;
|
||||
|
||||
err = device_add(&port->dev);
|
||||
if (err < 0)
|
||||
goto unregister;
|
||||
goto put_device;
|
||||
|
||||
return 0;
|
||||
|
||||
unregister:
|
||||
device_unregister(&port->dev);
|
||||
put_device:
|
||||
put_device(&port->dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user