[PATCH v7 19/42] clk: davinci: cfgchip: Add TI DA8XX USB PHY clocks
This adds a new driver for the USB PHY clocks in the CFGCHIP2 syscon register on TI DA8XX-type SoCs. The USB0 (USB 2.0) PHY clock is an interesting case because it calls clk_enable() in a reentrant way. The USB 2.0 PSC only has to be enabled temporarily while we are locking the PLL, which takes place during the clk_enable() callback. Signed-off-by: David Lechner--- v7 changes: - convert to platform device - rename clk local variable to usb0/usb1 - put code in da8xx-cfgchip.c instead of creating a new file v6 changes: - rename clocks to usb{0,1}_clk48 - rename USB 2.0 PSC clock to "fck" - simplify {s,g}et_parent implementations - use pr_fmt macro drivers/clk/davinci/da8xx-cfgchip.c | 351 1 file changed, 351 insertions(+) diff --git a/drivers/clk/davinci/da8xx-cfgchip.c b/drivers/clk/davinci/da8xx-cfgchip.c index 386da99..7d5cf16 100644 --- a/drivers/clk/davinci/da8xx-cfgchip.c +++ b/drivers/clk/davinci/da8xx-cfgchip.c @@ -339,6 +339,349 @@ static int __init of_da850_async3_init(struct device *dev, struct regmap *regmap return of_da8xx_cfgchip_init_mux_clock(dev, _async3_info, regmap); } +/* --- USB 2.0 PHY clock --- */ + +struct da8xx_usb0_clk48 { + struct clk_hw hw; + struct clk *fck; + struct regmap *regmap; +}; + +#define to_da8xx_usb0_clk48(_hw) \ + container_of((_hw), struct da8xx_usb0_clk48, hw) + +static int da8xx_usb0_clk48_prepare(struct clk_hw *hw) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + + /* The USB 2.0 PSC clock is only needed temporarily during the USB 2.0 +* PHY clock enable, but since clk_prepare() can't be called in an +* atomic context (i.e. in clk_enable()), we have to prepare it here. +*/ + return clk_prepare(usb0->fck); +} + +static void da8xx_usb0_clk48_unprepare(struct clk_hw *hw) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + + clk_unprepare(usb0->fck); +} + +static int da8xx_usb0_clk48_enable(struct clk_hw *hw) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + unsigned int mask, val; + int ret; + + /* Locking the USB 2.O PLL requires that the USB 2.O PSC is enabled +* temporaily. It can be turned back off once the PLL is locked. +*/ + clk_enable(usb0->fck); + + /* Turn on the USB 2.0 PHY, but just the PLL, and not OTG. The USB 1.1 +* PHY may use the USB 2.0 PLL clock without USB 2.0 OTG being used. +*/ + mask = CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_PHY_PLLON; + val = CFGCHIP2_PHY_PLLON; + + regmap_write_bits(usb0->regmap, CFGCHIP(2), mask, val); + ret = regmap_read_poll_timeout(usb0->regmap, CFGCHIP(2), val, + val & CFGCHIP2_PHYCLKGD, 0, 50); + + clk_disable(usb0->fck); + + return ret; +} + +static void da8xx_usb0_clk48_disable(struct clk_hw *hw) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + unsigned int val; + + val = CFGCHIP2_PHYPWRDN; + regmap_write_bits(usb0->regmap, CFGCHIP(2), val, val); +} + +static int da8xx_usb0_clk48_is_enabled(struct clk_hw *hw) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + unsigned int val; + + regmap_read(usb0->regmap, CFGCHIP(2), ); + + return !!(val & CFGCHIP2_PHYCLKGD); +} + +static unsigned long da8xx_usb0_clk48_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + unsigned int mask, val; + + /* The parent clock rate must be one of the following */ + mask = CFGCHIP2_REFFREQ_MASK; + switch (parent_rate) { + case 1200: + val = CFGCHIP2_REFFREQ_12MHZ; + break; + case 1300: + val = CFGCHIP2_REFFREQ_13MHZ; + break; + case 1920: + val = CFGCHIP2_REFFREQ_19_2MHZ; + break; + case 2000: + val = CFGCHIP2_REFFREQ_20MHZ; + break; + case 2400: + val = CFGCHIP2_REFFREQ_24MHZ; + break; + case 2600: + val = CFGCHIP2_REFFREQ_26MHZ; + break; + case 3840: + val = CFGCHIP2_REFFREQ_38_4MHZ; + break; + case 4000: + val = CFGCHIP2_REFFREQ_40MHZ; + break; + case 4800: + val = CFGCHIP2_REFFREQ_48MHZ; + break; + default: + return 0; + } + + regmap_write_bits(usb0->regmap, CFGCHIP(2), mask, val); + + /* USB 2.0 PLL always supplies 48MHz */ + return 4800; +} + +static long da8xx_usb0_clk48_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate)
[PATCH v7 19/42] clk: davinci: cfgchip: Add TI DA8XX USB PHY clocks
This adds a new driver for the USB PHY clocks in the CFGCHIP2 syscon register on TI DA8XX-type SoCs. The USB0 (USB 2.0) PHY clock is an interesting case because it calls clk_enable() in a reentrant way. The USB 2.0 PSC only has to be enabled temporarily while we are locking the PLL, which takes place during the clk_enable() callback. Signed-off-by: David Lechner --- v7 changes: - convert to platform device - rename clk local variable to usb0/usb1 - put code in da8xx-cfgchip.c instead of creating a new file v6 changes: - rename clocks to usb{0,1}_clk48 - rename USB 2.0 PSC clock to "fck" - simplify {s,g}et_parent implementations - use pr_fmt macro drivers/clk/davinci/da8xx-cfgchip.c | 351 1 file changed, 351 insertions(+) diff --git a/drivers/clk/davinci/da8xx-cfgchip.c b/drivers/clk/davinci/da8xx-cfgchip.c index 386da99..7d5cf16 100644 --- a/drivers/clk/davinci/da8xx-cfgchip.c +++ b/drivers/clk/davinci/da8xx-cfgchip.c @@ -339,6 +339,349 @@ static int __init of_da850_async3_init(struct device *dev, struct regmap *regmap return of_da8xx_cfgchip_init_mux_clock(dev, _async3_info, regmap); } +/* --- USB 2.0 PHY clock --- */ + +struct da8xx_usb0_clk48 { + struct clk_hw hw; + struct clk *fck; + struct regmap *regmap; +}; + +#define to_da8xx_usb0_clk48(_hw) \ + container_of((_hw), struct da8xx_usb0_clk48, hw) + +static int da8xx_usb0_clk48_prepare(struct clk_hw *hw) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + + /* The USB 2.0 PSC clock is only needed temporarily during the USB 2.0 +* PHY clock enable, but since clk_prepare() can't be called in an +* atomic context (i.e. in clk_enable()), we have to prepare it here. +*/ + return clk_prepare(usb0->fck); +} + +static void da8xx_usb0_clk48_unprepare(struct clk_hw *hw) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + + clk_unprepare(usb0->fck); +} + +static int da8xx_usb0_clk48_enable(struct clk_hw *hw) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + unsigned int mask, val; + int ret; + + /* Locking the USB 2.O PLL requires that the USB 2.O PSC is enabled +* temporaily. It can be turned back off once the PLL is locked. +*/ + clk_enable(usb0->fck); + + /* Turn on the USB 2.0 PHY, but just the PLL, and not OTG. The USB 1.1 +* PHY may use the USB 2.0 PLL clock without USB 2.0 OTG being used. +*/ + mask = CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_PHY_PLLON; + val = CFGCHIP2_PHY_PLLON; + + regmap_write_bits(usb0->regmap, CFGCHIP(2), mask, val); + ret = regmap_read_poll_timeout(usb0->regmap, CFGCHIP(2), val, + val & CFGCHIP2_PHYCLKGD, 0, 50); + + clk_disable(usb0->fck); + + return ret; +} + +static void da8xx_usb0_clk48_disable(struct clk_hw *hw) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + unsigned int val; + + val = CFGCHIP2_PHYPWRDN; + regmap_write_bits(usb0->regmap, CFGCHIP(2), val, val); +} + +static int da8xx_usb0_clk48_is_enabled(struct clk_hw *hw) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + unsigned int val; + + regmap_read(usb0->regmap, CFGCHIP(2), ); + + return !!(val & CFGCHIP2_PHYCLKGD); +} + +static unsigned long da8xx_usb0_clk48_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + unsigned int mask, val; + + /* The parent clock rate must be one of the following */ + mask = CFGCHIP2_REFFREQ_MASK; + switch (parent_rate) { + case 1200: + val = CFGCHIP2_REFFREQ_12MHZ; + break; + case 1300: + val = CFGCHIP2_REFFREQ_13MHZ; + break; + case 1920: + val = CFGCHIP2_REFFREQ_19_2MHZ; + break; + case 2000: + val = CFGCHIP2_REFFREQ_20MHZ; + break; + case 2400: + val = CFGCHIP2_REFFREQ_24MHZ; + break; + case 2600: + val = CFGCHIP2_REFFREQ_26MHZ; + break; + case 3840: + val = CFGCHIP2_REFFREQ_38_4MHZ; + break; + case 4000: + val = CFGCHIP2_REFFREQ_40MHZ; + break; + case 4800: + val = CFGCHIP2_REFFREQ_48MHZ; + break; + default: + return 0; + } + + regmap_write_bits(usb0->regmap, CFGCHIP(2), mask, val); + + /* USB 2.0 PLL always supplies 48MHz */ + return 4800; +} + +static long da8xx_usb0_clk48_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + return