Merge branches 'clk-at91', 'clk-imx7ulp', 'clk-axigen', 'clk-si5351' and 'clk-pxa' into clk-next
* clk-at91: clk: at91: pmc: Support backup for programmable clocks clk: at91: pmc: Save SCSR during suspend clk: at91: pmc: Wait for clocks when resuming * clk-imx7ulp: clk: Don't touch hardware when reparenting during registration * clk-axigen: clk: axi-clkgen: Round closest in round_rate() and recalc_rate() clk: axi-clkgen: Correctly handle nocount bit in recalc_rate() * clk-si5351: clk: si5351: _si5351_clkout_reset_pll() can be static clk: si5351: Do not enable parent clocks on probe clk: si5351: Rename internal plls to avoid name collisions clk: si5351: Apply PLL soft reset before enabling the outputs clk: si5351: Add DT property to enable PLL reset clk: si5351: implement remove handler * clk-pxa: clk: pxa: unbreak lookup of CLK_POUT
This commit is contained in:
commit
a2c09c12d4
@ -49,6 +49,7 @@ Optional child node properties:
|
||||
- silabs,multisynth-source: source pll A(0) or B(1) of corresponding multisynth
|
||||
divider.
|
||||
- silabs,pll-master: boolean, multisynth can change pll frequency.
|
||||
- silabs,pll-reset: boolean, clock output can reset its pll.
|
||||
- silabs,disable-state : clock output disable state, shall be
|
||||
0 = clock output is driven LOW when disabled
|
||||
1 = clock output is driven HIGH when disabled
|
||||
|
@ -204,6 +204,8 @@ at91_clk_register_programmable(struct regmap *regmap,
|
||||
if (ret) {
|
||||
kfree(prog);
|
||||
hw = ERR_PTR(ret);
|
||||
} else {
|
||||
pmc_register_pck(id);
|
||||
}
|
||||
|
||||
return hw;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "pmc.h"
|
||||
|
||||
#define PMC_MAX_IDS 128
|
||||
#define PMC_MAX_PCKS 8
|
||||
|
||||
int of_at91_get_clk_range(struct device_node *np, const char *propname,
|
||||
struct clk_range *range)
|
||||
@ -50,6 +51,7 @@ EXPORT_SYMBOL_GPL(of_at91_get_clk_range);
|
||||
static struct regmap *pmcreg;
|
||||
|
||||
static u8 registered_ids[PMC_MAX_IDS];
|
||||
static u8 registered_pcks[PMC_MAX_PCKS];
|
||||
|
||||
static struct
|
||||
{
|
||||
@ -66,8 +68,13 @@ static struct
|
||||
u32 pcr[PMC_MAX_IDS];
|
||||
u32 audio_pll0;
|
||||
u32 audio_pll1;
|
||||
u32 pckr[PMC_MAX_PCKS];
|
||||
} pmc_cache;
|
||||
|
||||
/*
|
||||
* As Peripheral ID 0 is invalid on AT91 chips, the identifier is stored
|
||||
* without alteration in the table, and 0 is for unused clocks.
|
||||
*/
|
||||
void pmc_register_id(u8 id)
|
||||
{
|
||||
int i;
|
||||
@ -82,11 +89,30 @@ void pmc_register_id(u8 id)
|
||||
}
|
||||
}
|
||||
|
||||
static int pmc_suspend(void)
|
||||
/*
|
||||
* As Programmable Clock 0 is valid on AT91 chips, there is an offset
|
||||
* of 1 between the stored value and the real clock ID.
|
||||
*/
|
||||
void pmc_register_pck(u8 pck)
|
||||
{
|
||||
int i;
|
||||
|
||||
regmap_read(pmcreg, AT91_PMC_IMR, &pmc_cache.scsr);
|
||||
for (i = 0; i < PMC_MAX_PCKS; i++) {
|
||||
if (registered_pcks[i] == 0) {
|
||||
registered_pcks[i] = pck + 1;
|
||||
break;
|
||||
}
|
||||
if (registered_pcks[i] == (pck + 1))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int pmc_suspend(void)
|
||||
{
|
||||
int i;
|
||||
u8 num;
|
||||
|
||||
regmap_read(pmcreg, AT91_PMC_SCSR, &pmc_cache.scsr);
|
||||
regmap_read(pmcreg, AT91_PMC_PCSR, &pmc_cache.pcsr0);
|
||||
regmap_read(pmcreg, AT91_CKGR_UCKR, &pmc_cache.uckr);
|
||||
regmap_read(pmcreg, AT91_CKGR_MOR, &pmc_cache.mor);
|
||||
@ -103,14 +129,29 @@ static int pmc_suspend(void)
|
||||
regmap_read(pmcreg, AT91_PMC_PCR,
|
||||
&pmc_cache.pcr[registered_ids[i]]);
|
||||
}
|
||||
for (i = 0; registered_pcks[i]; i++) {
|
||||
num = registered_pcks[i] - 1;
|
||||
regmap_read(pmcreg, AT91_PMC_PCKR(num), &pmc_cache.pckr[num]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool pmc_ready(unsigned int mask)
|
||||
{
|
||||
unsigned int status;
|
||||
|
||||
regmap_read(pmcreg, AT91_PMC_SR, &status);
|
||||
|
||||
return ((status & mask) == mask) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void pmc_resume(void)
|
||||
{
|
||||
int i, ret = 0;
|
||||
int i;
|
||||
u8 num;
|
||||
u32 tmp;
|
||||
u32 mask = AT91_PMC_MCKRDY | AT91_PMC_LOCKA;
|
||||
|
||||
regmap_read(pmcreg, AT91_PMC_MCKR, &tmp);
|
||||
if (pmc_cache.mckr != tmp)
|
||||
@ -119,7 +160,7 @@ static void pmc_resume(void)
|
||||
if (pmc_cache.pllar != tmp)
|
||||
pr_warn("PLLAR was not configured properly by the firmware\n");
|
||||
|
||||
regmap_write(pmcreg, AT91_PMC_IMR, pmc_cache.scsr);
|
||||
regmap_write(pmcreg, AT91_PMC_SCER, pmc_cache.scsr);
|
||||
regmap_write(pmcreg, AT91_PMC_PCER, pmc_cache.pcsr0);
|
||||
regmap_write(pmcreg, AT91_CKGR_UCKR, pmc_cache.uckr);
|
||||
regmap_write(pmcreg, AT91_CKGR_MOR, pmc_cache.mor);
|
||||
@ -133,14 +174,16 @@ static void pmc_resume(void)
|
||||
pmc_cache.pcr[registered_ids[i]] |
|
||||
AT91_PMC_PCR_CMD);
|
||||
}
|
||||
|
||||
if (pmc_cache.uckr & AT91_PMC_UPLLEN) {
|
||||
ret = regmap_read_poll_timeout(pmcreg, AT91_PMC_SR, tmp,
|
||||
!(tmp & AT91_PMC_LOCKU),
|
||||
10, 5000);
|
||||
if (ret)
|
||||
pr_crit("USB PLL didn't lock when resuming\n");
|
||||
for (i = 0; registered_pcks[i]; i++) {
|
||||
num = registered_pcks[i] - 1;
|
||||
regmap_write(pmcreg, AT91_PMC_PCKR(num), pmc_cache.pckr[num]);
|
||||
}
|
||||
|
||||
if (pmc_cache.uckr & AT91_PMC_UPLLEN)
|
||||
mask |= AT91_PMC_LOCKU;
|
||||
|
||||
while (!pmc_ready(mask))
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
static struct syscore_ops pmc_syscore_ops = {
|
||||
|
@ -31,8 +31,10 @@ int of_at91_get_clk_range(struct device_node *np, const char *propname,
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
void pmc_register_id(u8 id);
|
||||
void pmc_register_pck(u8 pck);
|
||||
#else
|
||||
static inline void pmc_register_id(u8 id) {}
|
||||
static inline void pmc_register_pck(u8 pck) {}
|
||||
#endif
|
||||
|
||||
#endif /* __PMC_H_ */
|
||||
|
@ -40,6 +40,10 @@
|
||||
#define MMCM_REG_FILTER1 0x4e
|
||||
#define MMCM_REG_FILTER2 0x4f
|
||||
|
||||
#define MMCM_CLKOUT_NOCOUNT BIT(6)
|
||||
|
||||
#define MMCM_CLK_DIV_NOCOUNT BIT(12)
|
||||
|
||||
struct axi_clkgen {
|
||||
void __iomem *base;
|
||||
struct clk_hw clk_hw;
|
||||
@ -298,13 +302,17 @@ static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
unsigned int d, m, dout;
|
||||
unsigned long long tmp;
|
||||
|
||||
axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout);
|
||||
|
||||
if (d == 0 || dout == 0 || m == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return *parent_rate / d * m / dout;
|
||||
tmp = (unsigned long long)*parent_rate * m;
|
||||
tmp = DIV_ROUND_CLOSEST_ULL(tmp, dout * d);
|
||||
|
||||
return min_t(unsigned long long, tmp, LONG_MAX);
|
||||
}
|
||||
|
||||
static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw,
|
||||
@ -315,18 +323,33 @@ static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw,
|
||||
unsigned int reg;
|
||||
unsigned long long tmp;
|
||||
|
||||
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, ®);
|
||||
dout = (reg & 0x3f) + ((reg >> 6) & 0x3f);
|
||||
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_2, ®);
|
||||
if (reg & MMCM_CLKOUT_NOCOUNT) {
|
||||
dout = 1;
|
||||
} else {
|
||||
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, ®);
|
||||
dout = (reg & 0x3f) + ((reg >> 6) & 0x3f);
|
||||
}
|
||||
|
||||
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_DIV, ®);
|
||||
d = (reg & 0x3f) + ((reg >> 6) & 0x3f);
|
||||
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, ®);
|
||||
m = (reg & 0x3f) + ((reg >> 6) & 0x3f);
|
||||
if (reg & MMCM_CLK_DIV_NOCOUNT)
|
||||
d = 1;
|
||||
else
|
||||
d = (reg & 0x3f) + ((reg >> 6) & 0x3f);
|
||||
|
||||
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB2, ®);
|
||||
if (reg & MMCM_CLKOUT_NOCOUNT) {
|
||||
m = 1;
|
||||
} else {
|
||||
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, ®);
|
||||
m = (reg & 0x3f) + ((reg >> 6) & 0x3f);
|
||||
}
|
||||
|
||||
if (d == 0 || dout == 0)
|
||||
return 0;
|
||||
|
||||
tmp = (unsigned long long)(parent_rate / d) * m;
|
||||
do_div(tmp, dout);
|
||||
tmp = (unsigned long long)parent_rate * m;
|
||||
tmp = DIV_ROUND_CLOSEST_ULL(tmp, dout * d);
|
||||
|
||||
return min_t(unsigned long long, tmp, ULONG_MAX);
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ static const char * const si5351_input_names[] = {
|
||||
"xtal", "clkin"
|
||||
};
|
||||
static const char * const si5351_pll_names[] = {
|
||||
"plla", "pllb", "vxco"
|
||||
"si5351_plla", "si5351_pllb", "si5351_vxco"
|
||||
};
|
||||
static const char * const si5351_msynth_names[] = {
|
||||
"ms0", "ms1", "ms2", "ms3", "ms4", "ms5", "ms6", "ms7"
|
||||
@ -903,13 +903,42 @@ static int _si5351_clkout_set_disable_state(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num)
|
||||
{
|
||||
u8 val = si5351_reg_read(drvdata, SI5351_CLK0_CTRL + num);
|
||||
|
||||
switch (val & SI5351_CLK_INPUT_MASK) {
|
||||
case SI5351_CLK_INPUT_XTAL:
|
||||
case SI5351_CLK_INPUT_CLKIN:
|
||||
return; /* pll not used, no need to reset */
|
||||
}
|
||||
|
||||
si5351_reg_write(drvdata, SI5351_PLL_RESET,
|
||||
val & SI5351_CLK_PLL_SELECT ? SI5351_PLL_RESET_B :
|
||||
SI5351_PLL_RESET_A);
|
||||
|
||||
dev_dbg(&drvdata->client->dev, "%s - %s: pll = %d\n",
|
||||
__func__, clk_hw_get_name(&drvdata->clkout[num].hw),
|
||||
(val & SI5351_CLK_PLL_SELECT) ? 1 : 0);
|
||||
}
|
||||
|
||||
static int si5351_clkout_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct si5351_hw_data *hwdata =
|
||||
container_of(hw, struct si5351_hw_data, hw);
|
||||
struct si5351_platform_data *pdata =
|
||||
hwdata->drvdata->client->dev.platform_data;
|
||||
|
||||
si5351_set_bits(hwdata->drvdata, SI5351_CLK0_CTRL + hwdata->num,
|
||||
SI5351_CLK_POWERDOWN, 0);
|
||||
|
||||
/*
|
||||
* Do a pll soft reset on the parent pll -- needed to get a
|
||||
* deterministic phase relationship between the output clocks.
|
||||
*/
|
||||
if (pdata->clkout[hwdata->num].pll_reset)
|
||||
_si5351_clkout_reset_pll(hwdata->drvdata, hwdata->num);
|
||||
|
||||
si5351_set_bits(hwdata->drvdata, SI5351_OUTPUT_ENABLE_CTRL,
|
||||
(1 << hwdata->num), 0);
|
||||
return 0;
|
||||
@ -1297,6 +1326,9 @@ static int si5351_dt_parse(struct i2c_client *client,
|
||||
|
||||
pdata->clkout[num].pll_master =
|
||||
of_property_read_bool(child, "silabs,pll-master");
|
||||
|
||||
pdata->clkout[num].pll_reset =
|
||||
of_property_read_bool(child, "silabs,pll-reset");
|
||||
}
|
||||
client->dev.platform_data = pdata;
|
||||
|
||||
@ -1437,11 +1469,6 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
}
|
||||
}
|
||||
|
||||
if (!IS_ERR(drvdata->pxtal))
|
||||
clk_prepare_enable(drvdata->pxtal);
|
||||
if (!IS_ERR(drvdata->pclkin))
|
||||
clk_prepare_enable(drvdata->pclkin);
|
||||
|
||||
/* register xtal input clock gate */
|
||||
memset(&init, 0, sizeof(init));
|
||||
init.name = si5351_input_names[0];
|
||||
@ -1456,7 +1483,7 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
ret = devm_clk_hw_register(&client->dev, &drvdata->xtal);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to register %s\n", init.name);
|
||||
goto err_clk;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* register clkin input clock gate */
|
||||
@ -1474,7 +1501,7 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to register %s\n",
|
||||
init.name);
|
||||
goto err_clk;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1496,7 +1523,7 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
ret = devm_clk_hw_register(&client->dev, &drvdata->pll[0].hw);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to register %s\n", init.name);
|
||||
goto err_clk;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* register PLLB or VXCO (Si5351B) */
|
||||
@ -1520,7 +1547,7 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
ret = devm_clk_hw_register(&client->dev, &drvdata->pll[1].hw);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to register %s\n", init.name);
|
||||
goto err_clk;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* register clk multisync and clk out divider */
|
||||
@ -1539,7 +1566,7 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
|
||||
if (WARN_ON(!drvdata->msynth || !drvdata->clkout)) {
|
||||
ret = -ENOMEM;
|
||||
goto err_clk;
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (n = 0; n < num_clocks; n++) {
|
||||
@ -1559,7 +1586,7 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to register %s\n",
|
||||
init.name);
|
||||
goto err_clk;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1587,7 +1614,7 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to register %s\n",
|
||||
init.name);
|
||||
goto err_clk;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set initial clkout rate */
|
||||
@ -1606,17 +1633,17 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
drvdata);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to add clk provider\n");
|
||||
goto err_clk;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
err_clk:
|
||||
if (!IS_ERR(drvdata->pxtal))
|
||||
clk_disable_unprepare(drvdata->pxtal);
|
||||
if (!IS_ERR(drvdata->pclkin))
|
||||
clk_disable_unprepare(drvdata->pclkin);
|
||||
return ret;
|
||||
static int si5351_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
of_clk_del_provider(client->dev.of_node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id si5351_i2c_ids[] = {
|
||||
@ -1634,6 +1661,7 @@ static struct i2c_driver si5351_driver = {
|
||||
.of_match_table = of_match_ptr(si5351_dt_ids),
|
||||
},
|
||||
.probe = si5351_i2c_probe,
|
||||
.remove = si5351_i2c_remove,
|
||||
.id_table = si5351_i2c_ids,
|
||||
};
|
||||
module_i2c_driver(si5351_driver);
|
||||
|
@ -2917,14 +2917,17 @@ static int __clk_core_init(struct clk_core *core)
|
||||
*/
|
||||
hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
|
||||
struct clk_core *parent = __clk_init_parent(orphan);
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* we could call __clk_set_parent, but that would result in a
|
||||
* redundant call to the .set_rate op, if it exists
|
||||
*/
|
||||
if (parent) {
|
||||
__clk_set_parent_before(orphan, parent);
|
||||
__clk_set_parent_after(orphan, parent, NULL);
|
||||
/* update the clk tree topology */
|
||||
flags = clk_enable_lock();
|
||||
clk_reparent(orphan, parent);
|
||||
clk_enable_unlock(flags);
|
||||
__clk_recalc_accuracies(orphan);
|
||||
__clk_recalc_rates(orphan, 0);
|
||||
}
|
||||
|
@ -329,12 +329,16 @@ static void __init pxa3xx_dummy_clocks_init(void)
|
||||
|
||||
static void __init pxa3xx_base_clocks_init(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
pxa3xx_register_plls();
|
||||
pxa3xx_register_core();
|
||||
clk_register_clk_pxa3xx_system_bus();
|
||||
clk_register_clk_pxa3xx_ac97();
|
||||
clk_register_clk_pxa3xx_smemc();
|
||||
clk_register_gate(NULL, "CLK_POUT", "osc_13mhz", 0, OSCC, 11, 0, NULL);
|
||||
clk = clk_register_gate(NULL, "CLK_POUT",
|
||||
"osc_13mhz", 0, OSCC, 11, 0, NULL);
|
||||
clk_register_clkdev(clk, "CLK_POUT", NULL);
|
||||
clkdev_pxa_register(CLK_OSTIMER, "OSTIMER0", NULL,
|
||||
clk_register_fixed_factor(NULL, "os-timer0",
|
||||
"osc_13mhz", 0, 1, 4));
|
||||
|
@ -86,6 +86,7 @@ enum si5351_disable_state {
|
||||
* @multisynth_src: multisynth source clock
|
||||
* @clkout_src: clkout source clock
|
||||
* @pll_master: if true, clkout can also change pll rate
|
||||
* @pll_reset: if true, clkout can reset its pll
|
||||
* @drive: output drive strength
|
||||
* @rate: initial clkout rate, or default if 0
|
||||
*/
|
||||
@ -95,6 +96,7 @@ struct si5351_clkout_config {
|
||||
enum si5351_drive_strength drive;
|
||||
enum si5351_disable_state disable_state;
|
||||
bool pll_master;
|
||||
bool pll_reset;
|
||||
unsigned long rate;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user