mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 13:14:02 +02:00
phy fixes for 7.3
Couple of driver fixes - Atomic context delay in renesas driver - TMDS and PLL rate calculation fixes for mediatek driver -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmqwD8UACgkQfBQHDyUj g0dzqBAAuGIVwSpUaEVAHD7TKcLqrmLpF4kuGXN4mGB+i8Hg3ivCH7n6/cKONOeA LPkdnl7ABRqNYX935oXtRAUuy0CnoIKJKaxrp0ap1x5QtAcyAKWEW+Ej/rHL9JV7 JHt/YQFcMhcvKE1lGUYdFA9eF2PQf0h3Xw0BcaB83WqAlsoWh9EnEOjDnfkv4rZi PMIW5/lXlpkWEfyptomcNHycGbltnLP323IkIscyS6qX7dIfldoN4pinwNKrIvHM CNrg8PPYefjFltVZ7q2u/MB8IeDpYGKNlyGC3Kvspsa04o8Qb0TTMb3aZ+AOn3rJ Ccq69UwdnMARx+V9Gc9gY5Jp6Q503SPwFGhRTybT9iyjft9yIGkaEZL1miWOWpZZ Fsv3xukBZhDVy1jGt6tsyfUVvRh6eu835jYijp4NHBeo1To7/clcKTTAT5o1/upC qWeM/FarR3JB/sAHrHKnA/R3Yh9FTpy5lTD6FhXa95SufJmB12rKbjUYNMNG3EOx OgYpeBeuy8ZXtkzPO36LXFv6OomQkxjThMAZ/syn1T8HStWULkhj9MxkrH0BRsB0 SsxIBkzG7tKlwQizJGDugum9uvxFX0104voNhTkn9DPO2oo4LnxGlsonfqJj7XPD TJoF9/IWV+3bQCL9fLU0mBvniQf/jzEaGXoGX+qY1YtXm8I5jTE= =xn2f -----END PGP SIGNATURE----- Merge tag 'phy-fixes-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy Pull phy fixes from Vinod Koul: - avoid atomic context delay in renesas driver - TMDS and PLL rate calculation fixes for mediatek driver * tag 'phy-fixes-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: phy: mediatek: phy-mtk-hdmi-mt8195: Fix TMDS clk bit ratio setting phy: mediatek: phy-mtk-hdmi-mt8195: Fix PLL calc divisor overflow phy: renesas: rcar-gen3-usb2: Avoid long delay in atomic context
This commit is contained in:
commit
60ee24f055
|
|
@ -36,7 +36,7 @@ mtk_phy_tmds_clk_ratio(struct mtk_hdmi_phy *hdmi_phy, bool enable)
|
|||
* clock bit ratio 1:40, under 3.4Gbps, clock bit ratio 1:10
|
||||
*/
|
||||
if (enable)
|
||||
mtk_phy_update_field(regs + HDMI20_CLK_CFG, REG_TXC_DIV, 3);
|
||||
mtk_phy_update_field(regs + HDMI20_CLK_CFG, REG_TXC_DIV, VAL_TXC_DIV4);
|
||||
else
|
||||
mtk_phy_clear_bits(regs + HDMI20_CLK_CFG, REG_TXC_DIV);
|
||||
}
|
||||
|
|
@ -290,7 +290,7 @@ static int mtk_hdmi_pll_calc(struct mtk_hdmi_phy *hdmi_phy, struct clk_hw *hw,
|
|||
posdiv2 = 1;
|
||||
|
||||
/* Digital clk divider, max /32 */
|
||||
digital_div = div_u64(ns_hdmipll_ck, posdiv1 * posdiv2 * pixel_clk);
|
||||
digital_div = div64_u64(ns_hdmipll_ck, posdiv1 * posdiv2 * pixel_clk);
|
||||
if (!(digital_div <= 32 && digital_div >= 1))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
#define HDMI20_CLK_CFG 0x70
|
||||
#define REG_TXC_DIV GENMASK(31, 30)
|
||||
#define VAL_TXC_DIV2 1
|
||||
#define VAL_TXC_DIV4 2
|
||||
#define VAL_TXC_DIV8 3
|
||||
|
||||
#define HDMI_1_CFG_0 0x00
|
||||
#define RG_HDMITX21_DRV_IBIAS_CLK GENMASK(10, 5)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/reset.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/usb/of.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
/******* USB2.0 Host registers (original offset is +0x200) *******/
|
||||
|
|
@ -106,6 +107,13 @@
|
|||
/* RZ/G2L specific */
|
||||
#define USB2_LINECTRL1_USB2_IDMON BIT(0)
|
||||
|
||||
/*
|
||||
* The OTG initialization is expected to finish in 20ms. Choose a large enough
|
||||
* timeout to avoid waiters exit prematurely the waiting section under heavy
|
||||
* CPU load.
|
||||
*/
|
||||
#define USB2_OTG_INIT_TIMEOUT msecs_to_jiffies(120)
|
||||
|
||||
#define NUM_OF_PHYS 4
|
||||
enum rcar_gen3_phy_index {
|
||||
PHY_INDEX_BOTH_HC,
|
||||
|
|
@ -138,12 +146,20 @@ struct rcar_gen3_chan {
|
|||
struct rcar_gen3_phy rphys[NUM_OF_PHYS];
|
||||
struct regulator *vbus;
|
||||
struct work_struct work;
|
||||
wait_queue_head_t otg_init_done;
|
||||
spinlock_t lock; /* protects access to hardware and driver data structure. */
|
||||
enum usb_dr_mode dr_mode;
|
||||
bool extcon_host;
|
||||
bool is_otg_channel;
|
||||
bool uses_otg_pins;
|
||||
bool otg_internal_reg;
|
||||
/*
|
||||
* The OTG can be initialized only once and needs to release the spinlock
|
||||
* and wait for 20 ms due to hardware constraints. If a thread executes
|
||||
* PHY configuration code while the OTG PHY is waiting for the 20 ms, the
|
||||
* thread will have to wait for the OTG PHY initialization to complete.
|
||||
*/
|
||||
bool otg_initializing;
|
||||
};
|
||||
|
||||
struct rcar_gen3_phy_drv_data {
|
||||
|
|
@ -392,26 +408,58 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr,
|
|||
struct rcar_gen3_chan *ch = dev_get_drvdata(dev);
|
||||
bool is_b_device;
|
||||
enum phy_mode cur_mode, new_mode;
|
||||
int retries = NUM_OF_PHYS;
|
||||
unsigned long flags;
|
||||
int ret = -EIO;
|
||||
|
||||
guard(spinlock_irqsave)(&ch->lock);
|
||||
spin_lock_irqsave(&ch->lock, flags);
|
||||
|
||||
if (!ch->is_otg_channel || !rcar_gen3_is_any_otg_rphy_initialized(ch))
|
||||
return -EIO;
|
||||
if (!ch->is_otg_channel)
|
||||
goto unlock;
|
||||
|
||||
if (sysfs_streq(buf, "host"))
|
||||
while (retries-- && ch->otg_initializing) {
|
||||
spin_unlock_irqrestore(&ch->lock, flags);
|
||||
|
||||
ret = wait_event_timeout(ch->otg_init_done, !ch->otg_initializing,
|
||||
USB2_OTG_INIT_TIMEOUT);
|
||||
ret = ret ? 0 : -ETIMEDOUT;
|
||||
if (ret && !retries)
|
||||
goto exit;
|
||||
|
||||
spin_lock_irqsave(&ch->lock, flags);
|
||||
}
|
||||
|
||||
/* If another thread started a new initialization just return -EBUSY. */
|
||||
if (ch->otg_initializing) {
|
||||
ret = -EBUSY;
|
||||
goto unlock;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (!rcar_gen3_is_any_otg_rphy_initialized(ch)) {
|
||||
ret = -EIO;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (sysfs_streq(buf, "host")) {
|
||||
new_mode = PHY_MODE_USB_HOST;
|
||||
else if (sysfs_streq(buf, "peripheral"))
|
||||
} else if (sysfs_streq(buf, "peripheral")) {
|
||||
new_mode = PHY_MODE_USB_DEVICE;
|
||||
else
|
||||
return -EINVAL;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* is_b_device: true is B-Device. false is A-Device. */
|
||||
is_b_device = rcar_gen3_check_id(ch);
|
||||
cur_mode = rcar_gen3_get_phy_mode(ch);
|
||||
|
||||
/* If current and new mode is the same, this returns the error */
|
||||
if (cur_mode == new_mode)
|
||||
return -EINVAL;
|
||||
if (cur_mode == new_mode) {
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (new_mode == PHY_MODE_USB_HOST) { /* And is_host must be false */
|
||||
if (!is_b_device) /* A-Peripheral */
|
||||
|
|
@ -425,7 +473,10 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr,
|
|||
rcar_gen3_init_for_peri(ch);
|
||||
}
|
||||
|
||||
return count;
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&ch->lock, flags);
|
||||
exit:
|
||||
return ret ?: count;
|
||||
}
|
||||
|
||||
static ssize_t role_show(struct device *dev, struct device_attribute *attr,
|
||||
|
|
@ -441,14 +492,11 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr,
|
|||
}
|
||||
static DEVICE_ATTR_RW(role);
|
||||
|
||||
static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
|
||||
static void rcar_gen3_init_otg_phase0(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 |
|
||||
|
|
@ -471,7 +519,11 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
|
|||
writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL);
|
||||
}
|
||||
}
|
||||
mdelay(20);
|
||||
}
|
||||
|
||||
static void rcar_gen3_init_otg_phase1(struct rcar_gen3_chan *ch)
|
||||
{
|
||||
void __iomem *usb2_base = ch->base;
|
||||
|
||||
writel(0xffffffff, usb2_base + USB2_OBINTSTA);
|
||||
writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTEN);
|
||||
|
|
@ -502,6 +554,7 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
|
|||
void __iomem *usb2_base = ch->base;
|
||||
struct device *dev = ch->dev;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
unsigned long flags;
|
||||
u32 status;
|
||||
|
||||
pm_runtime_get_noresume(dev);
|
||||
|
|
@ -509,33 +562,102 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
|
|||
if (pm_runtime_suspended(dev))
|
||||
goto rpm_put;
|
||||
|
||||
scoped_guard(spinlock, &ch->lock) {
|
||||
status = readl(usb2_base + USB2_OBINTSTA);
|
||||
if (status & ch->phy_data->obint_enable_bits) {
|
||||
dev_vdbg(dev, "%s: %08x\n", __func__, status);
|
||||
if (ch->phy_data->vblvl_ctrl)
|
||||
writel(USB2_OBINTSTA_CLEAR, usb2_base + USB2_OBINTSTA);
|
||||
else
|
||||
writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTSTA);
|
||||
rcar_gen3_device_recognition(ch);
|
||||
rcar_gen3_configure_vblvl_ctrl(ch);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
spin_lock_irqsave(&ch->lock, flags);
|
||||
|
||||
status = readl(usb2_base + USB2_OBINTSTA);
|
||||
if (status & ch->phy_data->obint_enable_bits) {
|
||||
dev_vdbg(dev, "%s: %08x\n", __func__, status);
|
||||
if (ch->phy_data->vblvl_ctrl)
|
||||
writel(USB2_OBINTSTA_CLEAR, usb2_base + USB2_OBINTSTA);
|
||||
else
|
||||
writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTSTA);
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
|
||||
/* This should not happen! */
|
||||
if (ch->otg_initializing)
|
||||
goto unlock;
|
||||
|
||||
rcar_gen3_device_recognition(ch);
|
||||
rcar_gen3_configure_vblvl_ctrl(ch);
|
||||
}
|
||||
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&ch->lock, flags);
|
||||
rpm_put:
|
||||
pm_runtime_put_noidle(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rcar_gen3_phy_usb2_irqs_mask_all(struct rcar_gen3_chan *channel,
|
||||
u32 *masked_irqs_bits)
|
||||
{
|
||||
u32 val, bitmask = USB2_INT_ENABLE_UCOM_INTEN;
|
||||
void __iomem *usb2_base = channel->base;
|
||||
|
||||
for (unsigned int i = 0; i < NUM_OF_PHYS; i++)
|
||||
bitmask |= channel->rphys[i].int_enable_bits;
|
||||
|
||||
val = readl(usb2_base + USB2_INT_ENABLE);
|
||||
*masked_irqs_bits = val & bitmask;
|
||||
val &= ~bitmask;
|
||||
writel(val, usb2_base + USB2_INT_ENABLE);
|
||||
|
||||
/*
|
||||
* Don't report channel->phy_data->obint_enable_bits IRQs. These are
|
||||
* unmasked anyway in rcar_gen3_init_otg_phase1().
|
||||
*/
|
||||
val = readl(usb2_base + USB2_OBINTEN);
|
||||
val &= ~channel->phy_data->obint_enable_bits;
|
||||
writel(val, usb2_base + USB2_OBINTEN);
|
||||
}
|
||||
|
||||
static void rcar_gen3_phy_usb2_irqs_unmask(struct rcar_gen3_chan *channel,
|
||||
u32 irqs_bits)
|
||||
{
|
||||
u32 val, bitmask = USB2_INT_ENABLE_UCOM_INTEN;
|
||||
void __iomem *usb2_base = channel->base;
|
||||
|
||||
for (unsigned int i = 0; i < NUM_OF_PHYS; i++)
|
||||
bitmask |= channel->rphys[i].int_enable_bits;
|
||||
|
||||
val = readl(usb2_base + USB2_INT_ENABLE);
|
||||
val &= ~bitmask;
|
||||
val |= irqs_bits;
|
||||
writel(val, usb2_base + USB2_INT_ENABLE);
|
||||
}
|
||||
|
||||
static int rcar_gen3_phy_usb2_init(struct phy *p)
|
||||
{
|
||||
struct rcar_gen3_phy *rphy = phy_get_drvdata(p);
|
||||
struct rcar_gen3_chan *channel = rphy->ch;
|
||||
void __iomem *usb2_base = channel->base;
|
||||
int retries = NUM_OF_PHYS;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
guard(spinlock_irqsave)(&channel->lock);
|
||||
spin_lock_irqsave(&channel->lock, flags);
|
||||
|
||||
while (retries-- && channel->otg_initializing) {
|
||||
spin_unlock_irqrestore(&channel->lock, flags);
|
||||
|
||||
ret = wait_event_timeout(channel->otg_init_done, !channel->otg_initializing,
|
||||
USB2_OTG_INIT_TIMEOUT);
|
||||
ret = ret ? 0 : -ETIMEDOUT;
|
||||
if (ret && !retries)
|
||||
return ret;
|
||||
|
||||
spin_lock_irqsave(&channel->lock, flags);
|
||||
}
|
||||
|
||||
/* If another thread started a new initialization just return -EBUSY. */
|
||||
if (channel->otg_initializing) {
|
||||
ret = -EBUSY;
|
||||
goto unlock;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* Initialize USB2 part */
|
||||
val = readl(usb2_base + USB2_INT_ENABLE);
|
||||
|
|
@ -548,8 +670,23 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
|
|||
}
|
||||
|
||||
/* Initialize otg part (only if we initialize a PHY with IRQs). */
|
||||
if (rphy->int_enable_bits)
|
||||
rcar_gen3_init_otg(channel);
|
||||
if (rphy->int_enable_bits && channel->is_otg_channel &&
|
||||
!rcar_gen3_is_any_otg_rphy_initialized(channel)) {
|
||||
u32 masked_irq_bits = 0;
|
||||
|
||||
rcar_gen3_init_otg_phase0(channel);
|
||||
rcar_gen3_phy_usb2_irqs_mask_all(channel, &masked_irq_bits);
|
||||
channel->otg_initializing = true;
|
||||
spin_unlock_irqrestore(&channel->lock, flags);
|
||||
|
||||
fsleep(20000);
|
||||
|
||||
spin_lock_irqsave(&channel->lock, flags);
|
||||
rcar_gen3_phy_usb2_irqs_unmask(channel, masked_irq_bits);
|
||||
rcar_gen3_init_otg_phase1(channel);
|
||||
channel->otg_initializing = false;
|
||||
wake_up_all(&channel->otg_init_done);
|
||||
}
|
||||
|
||||
if (channel->phy_data->vblvl_ctrl) {
|
||||
/* SIDDQ mode release */
|
||||
|
|
@ -568,7 +705,10 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
|
|||
|
||||
rphy->initialized = true;
|
||||
|
||||
return 0;
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&channel->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rcar_gen3_phy_usb2_exit(struct phy *p)
|
||||
|
|
@ -576,9 +716,32 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
|
|||
struct rcar_gen3_phy *rphy = phy_get_drvdata(p);
|
||||
struct rcar_gen3_chan *channel = rphy->ch;
|
||||
void __iomem *usb2_base = channel->base;
|
||||
int retries = NUM_OF_PHYS;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
guard(spinlock_irqsave)(&channel->lock);
|
||||
spin_lock_irqsave(&channel->lock, flags);
|
||||
|
||||
while (retries-- && channel->otg_initializing) {
|
||||
spin_unlock_irqrestore(&channel->lock, flags);
|
||||
|
||||
ret = wait_event_timeout(channel->otg_init_done, !channel->otg_initializing,
|
||||
USB2_OTG_INIT_TIMEOUT);
|
||||
ret = ret ? 0 : -ETIMEDOUT;
|
||||
if (ret && !retries)
|
||||
return ret;
|
||||
|
||||
spin_lock_irqsave(&channel->lock, flags);
|
||||
}
|
||||
|
||||
/* If another thread started a new initialization just return -EBUSY. */
|
||||
if (channel->otg_initializing) {
|
||||
ret = -EBUSY;
|
||||
goto unlock;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
rphy->initialized = false;
|
||||
|
||||
|
|
@ -588,7 +751,9 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
|
|||
val &= ~USB2_INT_ENABLE_UCOM_INTEN;
|
||||
writel(val, usb2_base + USB2_INT_ENABLE);
|
||||
|
||||
return 0;
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&channel->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rcar_gen3_phy_usb2_power_on(struct phy *p)
|
||||
|
|
@ -596,8 +761,10 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
|
|||
struct rcar_gen3_phy *rphy = phy_get_drvdata(p);
|
||||
struct rcar_gen3_chan *channel = rphy->ch;
|
||||
void __iomem *usb2_base = channel->base;
|
||||
int retries = NUM_OF_PHYS;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
if (channel->vbus && !channel->otg_internal_reg) {
|
||||
ret = regulator_enable(channel->vbus);
|
||||
|
|
@ -605,7 +772,27 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
|
|||
return ret;
|
||||
}
|
||||
|
||||
guard(spinlock_irqsave)(&channel->lock);
|
||||
spin_lock_irqsave(&channel->lock, flags);
|
||||
|
||||
while (retries-- && channel->otg_initializing) {
|
||||
spin_unlock_irqrestore(&channel->lock, flags);
|
||||
|
||||
ret = wait_event_timeout(channel->otg_init_done, !channel->otg_initializing,
|
||||
USB2_OTG_INIT_TIMEOUT);
|
||||
ret = ret ? 0 : -ETIMEDOUT;
|
||||
if (ret && !retries)
|
||||
goto disable_regulator;
|
||||
|
||||
spin_lock_irqsave(&channel->lock, flags);
|
||||
}
|
||||
|
||||
/* If another thread started a new initialization just return -EBUSY. */
|
||||
if (channel->otg_initializing) {
|
||||
ret = -EBUSY;
|
||||
goto unlock;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (!rcar_gen3_are_all_rphys_power_off(channel))
|
||||
goto out;
|
||||
|
|
@ -620,27 +807,59 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
|
|||
/* The powered flag should be set for any other phys anyway */
|
||||
rphy->powered = true;
|
||||
|
||||
return 0;
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&channel->lock, flags);
|
||||
|
||||
disable_regulator:
|
||||
if (ret && channel->vbus && !channel->otg_internal_reg)
|
||||
regulator_disable(channel->vbus);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rcar_gen3_phy_usb2_power_off(struct phy *p)
|
||||
{
|
||||
struct rcar_gen3_phy *rphy = phy_get_drvdata(p);
|
||||
struct rcar_gen3_chan *channel = rphy->ch;
|
||||
int ret = 0;
|
||||
int retries = NUM_OF_PHYS;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
scoped_guard(spinlock_irqsave, &channel->lock) {
|
||||
rphy->powered = false;
|
||||
spin_lock_irqsave(&channel->lock, flags);
|
||||
|
||||
if (rcar_gen3_are_all_rphys_power_off(channel)) {
|
||||
u32 val = readl(channel->base + USB2_USBCTR);
|
||||
while (retries-- && channel->otg_initializing) {
|
||||
spin_unlock_irqrestore(&channel->lock, flags);
|
||||
|
||||
val |= USB2_USBCTR_PLL_RST;
|
||||
writel(val, channel->base + USB2_USBCTR);
|
||||
}
|
||||
ret = wait_event_timeout(channel->otg_init_done, !channel->otg_initializing,
|
||||
USB2_OTG_INIT_TIMEOUT);
|
||||
ret = ret ? 0 : -ETIMEDOUT;
|
||||
if (ret && !retries)
|
||||
return ret;
|
||||
|
||||
spin_lock_irqsave(&channel->lock, flags);
|
||||
}
|
||||
|
||||
if (channel->vbus && !channel->otg_internal_reg)
|
||||
/* If another thread started a new initialization just return -EBUSY. */
|
||||
if (channel->otg_initializing) {
|
||||
ret = -EBUSY;
|
||||
goto unlock;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
rphy->powered = false;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&channel->lock, flags);
|
||||
|
||||
if (!ret && channel->vbus && !channel->otg_internal_reg)
|
||||
ret = regulator_disable(channel->vbus);
|
||||
|
||||
return ret;
|
||||
|
|
@ -1022,6 +1241,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
|
||||
spin_lock_init(&channel->lock);
|
||||
init_waitqueue_head(&channel->otg_init_done);
|
||||
for (i = 0; i < NUM_OF_PHYS; i++) {
|
||||
channel->rphys[i].phy = devm_phy_create(dev, NULL,
|
||||
channel->phy_data->phy_usb2_ops);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user