Commit 810797c1 authored by 周琰杰 (Zhou Yanjie)'s avatar 周琰杰 (Zhou Yanjie) Committed by Stephen Boyd

clk: X1000: Add support for calculat REFCLK of USB PHY.

Add functions for calculat the rate of REFCLK, which is needed by
USB PHY in Ingenic X1000 SoC.
Tested-by: default avatar周正 (Zhou Zheng) <sernia.zhou@foxmail.com>
Signed-off-by: default avatar周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
Link: https://lore.kernel.org/r/20200630163852.47267-4-zhouyanjie@wanyeetech.comSigned-off-by: default avatarStephen Boyd <sboyd@kernel.org>
parent beb61eb0
...@@ -48,8 +48,87 @@ ...@@ -48,8 +48,87 @@
#define USBPCR_SIDDQ BIT(21) #define USBPCR_SIDDQ BIT(21)
#define USBPCR_OTG_DISABLE BIT(20) #define USBPCR_OTG_DISABLE BIT(20)
/* bits within the USBPCR1 register */
#define USBPCR1_REFCLKSEL_SHIFT 26
#define USBPCR1_REFCLKSEL_MASK (0x3 << USBPCR1_REFCLKSEL_SHIFT)
#define USBPCR1_REFCLKSEL_CORE (0x2 << USBPCR1_REFCLKSEL_SHIFT)
#define USBPCR1_REFCLKDIV_SHIFT 24
#define USBPCR1_REFCLKDIV_MASK (0x3 << USBPCR1_REFCLKDIV_SHIFT)
#define USBPCR1_REFCLKDIV_48 (0x2 << USBPCR1_REFCLKDIV_SHIFT)
#define USBPCR1_REFCLKDIV_24 (0x1 << USBPCR1_REFCLKDIV_SHIFT)
#define USBPCR1_REFCLKDIV_12 (0x0 << USBPCR1_REFCLKDIV_SHIFT)
static struct ingenic_cgu *cgu; static struct ingenic_cgu *cgu;
static unsigned long x1000_otg_phy_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
u32 usbpcr1;
unsigned refclk_div;
usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
refclk_div = usbpcr1 & USBPCR1_REFCLKDIV_MASK;
switch (refclk_div) {
case USBPCR1_REFCLKDIV_12:
return 12000000;
case USBPCR1_REFCLKDIV_24:
return 24000000;
case USBPCR1_REFCLKDIV_48:
return 48000000;
}
return parent_rate;
}
static long x1000_otg_phy_round_rate(struct clk_hw *hw, unsigned long req_rate,
unsigned long *parent_rate)
{
if (req_rate < 18000000)
return 12000000;
if (req_rate < 36000000)
return 24000000;
return 48000000;
}
static int x1000_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,
unsigned long parent_rate)
{
unsigned long flags;
u32 usbpcr1, div_bits;
switch (req_rate) {
case 12000000:
div_bits = USBPCR1_REFCLKDIV_12;
break;
case 24000000:
div_bits = USBPCR1_REFCLKDIV_24;
break;
case 48000000:
div_bits = USBPCR1_REFCLKDIV_48;
break;
default:
return -EINVAL;
}
spin_lock_irqsave(&cgu->lock, flags);
usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
usbpcr1 &= ~USBPCR1_REFCLKDIV_MASK;
usbpcr1 |= div_bits;
writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
spin_unlock_irqrestore(&cgu->lock, flags);
return 0;
}
static int x1000_usb_phy_enable(struct clk_hw *hw) static int x1000_usb_phy_enable(struct clk_hw *hw)
{ {
void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
...@@ -80,6 +159,10 @@ static int x1000_usb_phy_is_enabled(struct clk_hw *hw) ...@@ -80,6 +159,10 @@ static int x1000_usb_phy_is_enabled(struct clk_hw *hw)
} }
static const struct clk_ops x1000_otg_phy_ops = { static const struct clk_ops x1000_otg_phy_ops = {
.recalc_rate = x1000_otg_phy_recalc_rate,
.round_rate = x1000_otg_phy_round_rate,
.set_rate = x1000_otg_phy_set_rate,
.enable = x1000_usb_phy_enable, .enable = x1000_usb_phy_enable,
.disable = x1000_usb_phy_disable, .disable = x1000_usb_phy_disable,
.is_enabled = x1000_usb_phy_is_enabled, .is_enabled = x1000_usb_phy_is_enabled,
...@@ -144,7 +227,6 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = { ...@@ -144,7 +227,6 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
}, },
}, },
/* Custom (SoC-specific) OTG PHY */ /* Custom (SoC-specific) OTG PHY */
[X1000_CLK_OTGPHY] = { [X1000_CLK_OTGPHY] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment