Commit 21eeefe7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents 6aa6f8ca b2ea5f49
Loading
Loading
Loading
Loading
+15 −7
Original line number Diff line number Diff line
@@ -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)
	mux_state = devm_mux_state_get_optional(dev, NULL);
	if (IS_ERR(mux_state))
		return PTR_ERR(mux_state);
	} else {

	can_transceiver_phy->mux_state = mux_state;
	}

	phy = devm_phy_create(dev, dev->of_node,
			      &can_transceiver_phy_ops);
+2 −1
Original line number Diff line number Diff line
@@ -1754,6 +1754,7 @@ 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]);
	}

	if (qmp->mode == PHY_MODE_UFS_HS_B)
		qmp_ufs_init_all(qmp, &cfg->tbls_hs_b);
}

+75 −60
Original line number Diff line number Diff line
@@ -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;

	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(ch->dev, "%s: %08x\n", __func__, status);
			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,31 +460,22 @@ 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);

	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 */
	if (channel->is_otg_channel) {
		if (rcar_gen3_needs_init_otg(channel))
	/* Initialize otg part (only if we initialize a PHY with IRQs). */
	if (rphy->int_enable_bits)
		rcar_gen3_init_otg(channel);
		rphy->otg_initialized = true;
	}

	rphy->initialized = true;

@@ -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);
	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");
+1 −1
Original line number Diff line number Diff line
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -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,
Loading