Skip to content

Commit

Permalink
Merge tag 'phy-fixes-6.15' of git://git.kernel.org/pub/scm/linux/kern…
Browse files Browse the repository at this point in the history
…el/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
  • Loading branch information
Linus Torvalds committed May 17, 2025
2 parents 6aa6f8c + b2ea5f4 commit 21eeefe
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 92 deletions.
22 changes: 15 additions & 7 deletions drivers/phy/phy-can-transceiver.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
135 changes: 75 additions & 60 deletions drivers/phy/renesas/phy-rcar-gen3-usb2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -107,7 +108,6 @@ struct rcar_gen3_phy {
struct rcar_gen3_chan *ch;
u32 int_enable_bits;
bool initialized;
bool otg_initialized;
bool powered;
};

Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -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"))
Expand Down Expand Up @@ -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" :
Expand All @@ -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 |
Expand All @@ -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);
Expand All @@ -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;

pm_runtime_get_noresume(dev);

if (pm_runtime_suspended(dev))
goto rpm_put;

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;
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;
}

Expand All @@ -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;
Expand All @@ -484,20 +489,16 @@ 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;
if (!rcar_gen3_is_any_rphy_initialized(channel))
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;
}

Expand All @@ -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);
Expand All @@ -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;
}
Expand All @@ -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;
}

Expand Down Expand Up @@ -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");
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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");
Expand Down
2 changes: 1 addition & 1 deletion drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
7 changes: 7 additions & 0 deletions drivers/phy/starfive/phy-jh7110-usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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)
Expand All @@ -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;
}

Expand Down
Loading

0 comments on commit 21eeefe

Please sign in to comment.