Commit a2c09c12 authored by Stephen Boyd's avatar Stephen Boyd

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
...@@ -49,6 +49,7 @@ Optional child node properties: ...@@ -49,6 +49,7 @@ Optional child node properties:
- silabs,multisynth-source: source pll A(0) or B(1) of corresponding multisynth - silabs,multisynth-source: source pll A(0) or B(1) of corresponding multisynth
divider. divider.
- silabs,pll-master: boolean, multisynth can change pll frequency. - 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 - silabs,disable-state : clock output disable state, shall be
0 = clock output is driven LOW when disabled 0 = clock output is driven LOW when disabled
1 = clock output is driven HIGH when disabled 1 = clock output is driven HIGH when disabled
......
...@@ -204,6 +204,8 @@ at91_clk_register_programmable(struct regmap *regmap, ...@@ -204,6 +204,8 @@ at91_clk_register_programmable(struct regmap *regmap,
if (ret) { if (ret) {
kfree(prog); kfree(prog);
hw = ERR_PTR(ret); hw = ERR_PTR(ret);
} else {
pmc_register_pck(id);
} }
return hw; return hw;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "pmc.h" #include "pmc.h"
#define PMC_MAX_IDS 128 #define PMC_MAX_IDS 128
#define PMC_MAX_PCKS 8
int of_at91_get_clk_range(struct device_node *np, const char *propname, int of_at91_get_clk_range(struct device_node *np, const char *propname,
struct clk_range *range) struct clk_range *range)
...@@ -50,6 +51,7 @@ EXPORT_SYMBOL_GPL(of_at91_get_clk_range); ...@@ -50,6 +51,7 @@ EXPORT_SYMBOL_GPL(of_at91_get_clk_range);
static struct regmap *pmcreg; static struct regmap *pmcreg;
static u8 registered_ids[PMC_MAX_IDS]; static u8 registered_ids[PMC_MAX_IDS];
static u8 registered_pcks[PMC_MAX_PCKS];
static struct static struct
{ {
...@@ -66,8 +68,13 @@ static struct ...@@ -66,8 +68,13 @@ static struct
u32 pcr[PMC_MAX_IDS]; u32 pcr[PMC_MAX_IDS];
u32 audio_pll0; u32 audio_pll0;
u32 audio_pll1; u32 audio_pll1;
u32 pckr[PMC_MAX_PCKS];
} pmc_cache; } 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) void pmc_register_id(u8 id)
{ {
int i; int i;
...@@ -82,11 +89,30 @@ void pmc_register_id(u8 id) ...@@ -82,11 +89,30 @@ void pmc_register_id(u8 id)
} }
} }
/*
* 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;
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) static int pmc_suspend(void)
{ {
int i; int i;
u8 num;
regmap_read(pmcreg, AT91_PMC_IMR, &pmc_cache.scsr); regmap_read(pmcreg, AT91_PMC_SCSR, &pmc_cache.scsr);
regmap_read(pmcreg, AT91_PMC_PCSR, &pmc_cache.pcsr0); regmap_read(pmcreg, AT91_PMC_PCSR, &pmc_cache.pcsr0);
regmap_read(pmcreg, AT91_CKGR_UCKR, &pmc_cache.uckr); regmap_read(pmcreg, AT91_CKGR_UCKR, &pmc_cache.uckr);
regmap_read(pmcreg, AT91_CKGR_MOR, &pmc_cache.mor); regmap_read(pmcreg, AT91_CKGR_MOR, &pmc_cache.mor);
...@@ -103,14 +129,29 @@ static int pmc_suspend(void) ...@@ -103,14 +129,29 @@ static int pmc_suspend(void)
regmap_read(pmcreg, AT91_PMC_PCR, regmap_read(pmcreg, AT91_PMC_PCR,
&pmc_cache.pcr[registered_ids[i]]); &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; 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) static void pmc_resume(void)
{ {
int i, ret = 0; int i;
u8 num;
u32 tmp; u32 tmp;
u32 mask = AT91_PMC_MCKRDY | AT91_PMC_LOCKA;
regmap_read(pmcreg, AT91_PMC_MCKR, &tmp); regmap_read(pmcreg, AT91_PMC_MCKR, &tmp);
if (pmc_cache.mckr != tmp) if (pmc_cache.mckr != tmp)
...@@ -119,7 +160,7 @@ static void pmc_resume(void) ...@@ -119,7 +160,7 @@ static void pmc_resume(void)
if (pmc_cache.pllar != tmp) if (pmc_cache.pllar != tmp)
pr_warn("PLLAR was not configured properly by the firmware\n"); 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_PMC_PCER, pmc_cache.pcsr0);
regmap_write(pmcreg, AT91_CKGR_UCKR, pmc_cache.uckr); regmap_write(pmcreg, AT91_CKGR_UCKR, pmc_cache.uckr);
regmap_write(pmcreg, AT91_CKGR_MOR, pmc_cache.mor); regmap_write(pmcreg, AT91_CKGR_MOR, pmc_cache.mor);
...@@ -133,14 +174,16 @@ static void pmc_resume(void) ...@@ -133,14 +174,16 @@ static void pmc_resume(void)
pmc_cache.pcr[registered_ids[i]] | pmc_cache.pcr[registered_ids[i]] |
AT91_PMC_PCR_CMD); AT91_PMC_PCR_CMD);
} }
for (i = 0; registered_pcks[i]; i++) {
if (pmc_cache.uckr & AT91_PMC_UPLLEN) { num = registered_pcks[i] - 1;
ret = regmap_read_poll_timeout(pmcreg, AT91_PMC_SR, tmp, regmap_write(pmcreg, AT91_PMC_PCKR(num), pmc_cache.pckr[num]);
!(tmp & AT91_PMC_LOCKU),
10, 5000);
if (ret)
pr_crit("USB PLL didn't lock when resuming\n");
} }
if (pmc_cache.uckr & AT91_PMC_UPLLEN)
mask |= AT91_PMC_LOCKU;
while (!pmc_ready(mask))
cpu_relax();
} }
static struct syscore_ops pmc_syscore_ops = { static struct syscore_ops pmc_syscore_ops = {
......
...@@ -31,8 +31,10 @@ int of_at91_get_clk_range(struct device_node *np, const char *propname, ...@@ -31,8 +31,10 @@ int of_at91_get_clk_range(struct device_node *np, const char *propname,
#ifdef CONFIG_PM #ifdef CONFIG_PM
void pmc_register_id(u8 id); void pmc_register_id(u8 id);
void pmc_register_pck(u8 pck);
#else #else
static inline void pmc_register_id(u8 id) {} static inline void pmc_register_id(u8 id) {}
static inline void pmc_register_pck(u8 pck) {}
#endif #endif
#endif /* __PMC_H_ */ #endif /* __PMC_H_ */
...@@ -40,6 +40,10 @@ ...@@ -40,6 +40,10 @@
#define MMCM_REG_FILTER1 0x4e #define MMCM_REG_FILTER1 0x4e
#define MMCM_REG_FILTER2 0x4f #define MMCM_REG_FILTER2 0x4f
#define MMCM_CLKOUT_NOCOUNT BIT(6)
#define MMCM_CLK_DIV_NOCOUNT BIT(12)
struct axi_clkgen { struct axi_clkgen {
void __iomem *base; void __iomem *base;
struct clk_hw clk_hw; struct clk_hw clk_hw;
...@@ -298,13 +302,17 @@ static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -298,13 +302,17 @@ static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate) unsigned long *parent_rate)
{ {
unsigned int d, m, dout; unsigned int d, m, dout;
unsigned long long tmp;
axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout); axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout);
if (d == 0 || dout == 0 || m == 0) if (d == 0 || dout == 0 || m == 0)
return -EINVAL; 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, 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, ...@@ -315,18 +323,33 @@ static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw,
unsigned int reg; unsigned int reg;
unsigned long long tmp; unsigned long long tmp;
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_2, &reg);
if (reg & MMCM_CLKOUT_NOCOUNT) {
dout = 1;
} else {
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, &reg); axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, &reg);
dout = (reg & 0x3f) + ((reg >> 6) & 0x3f); dout = (reg & 0x3f) + ((reg >> 6) & 0x3f);
}
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_DIV, &reg); axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_DIV, &reg);
if (reg & MMCM_CLK_DIV_NOCOUNT)
d = 1;
else
d = (reg & 0x3f) + ((reg >> 6) & 0x3f); d = (reg & 0x3f) + ((reg >> 6) & 0x3f);
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB2, &reg);
if (reg & MMCM_CLKOUT_NOCOUNT) {
m = 1;
} else {
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, &reg); axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, &reg);
m = (reg & 0x3f) + ((reg >> 6) & 0x3f); m = (reg & 0x3f) + ((reg >> 6) & 0x3f);
}
if (d == 0 || dout == 0) if (d == 0 || dout == 0)
return 0; return 0;
tmp = (unsigned long long)(parent_rate / d) * m; tmp = (unsigned long long)parent_rate * m;
do_div(tmp, dout); tmp = DIV_ROUND_CLOSEST_ULL(tmp, dout * d);
return min_t(unsigned long long, tmp, ULONG_MAX); return min_t(unsigned long long, tmp, ULONG_MAX);
} }
......
...@@ -72,7 +72,7 @@ static const char * const si5351_input_names[] = { ...@@ -72,7 +72,7 @@ static const char * const si5351_input_names[] = {
"xtal", "clkin" "xtal", "clkin"
}; };
static const char * const si5351_pll_names[] = { static const char * const si5351_pll_names[] = {
"plla", "pllb", "vxco" "si5351_plla", "si5351_pllb", "si5351_vxco"
}; };
static const char * const si5351_msynth_names[] = { static const char * const si5351_msynth_names[] = {
"ms0", "ms1", "ms2", "ms3", "ms4", "ms5", "ms6", "ms7" "ms0", "ms1", "ms2", "ms3", "ms4", "ms5", "ms6", "ms7"
...@@ -903,13 +903,42 @@ static int _si5351_clkout_set_disable_state( ...@@ -903,13 +903,42 @@ static int _si5351_clkout_set_disable_state(
return 0; 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) static int si5351_clkout_prepare(struct clk_hw *hw)
{ {
struct si5351_hw_data *hwdata = struct si5351_hw_data *hwdata =
container_of(hw, struct si5351_hw_data, hw); 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_set_bits(hwdata->drvdata, SI5351_CLK0_CTRL + hwdata->num,
SI5351_CLK_POWERDOWN, 0); 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, si5351_set_bits(hwdata->drvdata, SI5351_OUTPUT_ENABLE_CTRL,
(1 << hwdata->num), 0); (1 << hwdata->num), 0);
return 0; return 0;
...@@ -1297,6 +1326,9 @@ static int si5351_dt_parse(struct i2c_client *client, ...@@ -1297,6 +1326,9 @@ static int si5351_dt_parse(struct i2c_client *client,
pdata->clkout[num].pll_master = pdata->clkout[num].pll_master =
of_property_read_bool(child, "silabs,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; client->dev.platform_data = pdata;
...@@ -1437,11 +1469,6 @@ static int si5351_i2c_probe(struct i2c_client *client, ...@@ -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 */ /* register xtal input clock gate */
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));
init.name = si5351_input_names[0]; init.name = si5351_input_names[0];
...@@ -1456,7 +1483,7 @@ static int si5351_i2c_probe(struct i2c_client *client, ...@@ -1456,7 +1483,7 @@ static int si5351_i2c_probe(struct i2c_client *client,
ret = devm_clk_hw_register(&client->dev, &drvdata->xtal); ret = devm_clk_hw_register(&client->dev, &drvdata->xtal);
if (ret) { if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name); dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk; return ret;
} }
/* register clkin input clock gate */ /* register clkin input clock gate */
...@@ -1474,7 +1501,7 @@ static int si5351_i2c_probe(struct i2c_client *client, ...@@ -1474,7 +1501,7 @@ static int si5351_i2c_probe(struct i2c_client *client,
if (ret) { if (ret) {
dev_err(&client->dev, "unable to register %s\n", dev_err(&client->dev, "unable to register %s\n",
init.name); init.name);
goto err_clk; return ret;
} }
} }
...@@ -1496,7 +1523,7 @@ static int si5351_i2c_probe(struct i2c_client *client, ...@@ -1496,7 +1523,7 @@ static int si5351_i2c_probe(struct i2c_client *client,
ret = devm_clk_hw_register(&client->dev, &drvdata->pll[0].hw); ret = devm_clk_hw_register(&client->dev, &drvdata->pll[0].hw);
if (ret) { if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name); dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk; return ret;
} }
/* register PLLB or VXCO (Si5351B) */ /* register PLLB or VXCO (Si5351B) */
...@@ -1520,7 +1547,7 @@ static int si5351_i2c_probe(struct i2c_client *client, ...@@ -1520,7 +1547,7 @@ static int si5351_i2c_probe(struct i2c_client *client,
ret = devm_clk_hw_register(&client->dev, &drvdata->pll[1].hw); ret = devm_clk_hw_register(&client->dev, &drvdata->pll[1].hw);
if (ret) { if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name); dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk; return ret;
} }
/* register clk multisync and clk out divider */ /* register clk multisync and clk out divider */
...@@ -1539,7 +1566,7 @@ static int si5351_i2c_probe(struct i2c_client *client, ...@@ -1539,7 +1566,7 @@ static int si5351_i2c_probe(struct i2c_client *client,
if (WARN_ON(!drvdata->msynth || !drvdata->clkout)) { if (WARN_ON(!drvdata->msynth || !drvdata->clkout)) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_clk; return ret;
} }
for (n = 0; n < num_clocks; n++) { for (n = 0; n < num_clocks; n++) {
...@@ -1559,7 +1586,7 @@ static int si5351_i2c_probe(struct i2c_client *client, ...@@ -1559,7 +1586,7 @@ static int si5351_i2c_probe(struct i2c_client *client,
if (ret) { if (ret) {
dev_err(&client->dev, "unable to register %s\n", dev_err(&client->dev, "unable to register %s\n",
init.name); init.name);
goto err_clk; return ret;
} }
} }
...@@ -1587,7 +1614,7 @@ static int si5351_i2c_probe(struct i2c_client *client, ...@@ -1587,7 +1614,7 @@ static int si5351_i2c_probe(struct i2c_client *client,
if (ret) { if (ret) {
dev_err(&client->dev, "unable to register %s\n", dev_err(&client->dev, "unable to register %s\n",
init.name); init.name);
goto err_clk; return ret;
} }
/* set initial clkout rate */ /* set initial clkout rate */
...@@ -1606,17 +1633,17 @@ static int si5351_i2c_probe(struct i2c_client *client, ...@@ -1606,17 +1633,17 @@ static int si5351_i2c_probe(struct i2c_client *client,
drvdata); drvdata);
if (ret) { if (ret) {
dev_err(&client->dev, "unable to add clk provider\n"); dev_err(&client->dev, "unable to add clk provider\n");
goto err_clk; return ret;
} }
return 0; return 0;
}
err_clk: static int si5351_i2c_remove(struct i2c_client *client)
if (!IS_ERR(drvdata->pxtal)) {
clk_disable_unprepare(drvdata->pxtal); of_clk_del_provider(client->dev.of_node);
if (!IS_ERR(drvdata->pclkin))
clk_disable_unprepare(drvdata->pclkin); return 0;
return ret;
} }
static const struct i2c_device_id si5351_i2c_ids[] = { static const struct i2c_device_id si5351_i2c_ids[] = {
...@@ -1634,6 +1661,7 @@ static struct i2c_driver si5351_driver = { ...@@ -1634,6 +1661,7 @@ static struct i2c_driver si5351_driver = {
.of_match_table = of_match_ptr(si5351_dt_ids), .of_match_table = of_match_ptr(si5351_dt_ids),
}, },
.probe = si5351_i2c_probe, .probe = si5351_i2c_probe,
.remove = si5351_i2c_remove,
.id_table = si5351_i2c_ids, .id_table = si5351_i2c_ids,
}; };
module_i2c_driver(si5351_driver); module_i2c_driver(si5351_driver);
......
...@@ -2917,14 +2917,17 @@ static int __clk_core_init(struct clk_core *core) ...@@ -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) { hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
struct clk_core *parent = __clk_init_parent(orphan); struct clk_core *parent = __clk_init_parent(orphan);
unsigned long flags;
/* /*
* we could call __clk_set_parent, but that would result in a * we could call __clk_set_parent, but that would result in a
* redundant call to the .set_rate op, if it exists * redundant call to the .set_rate op, if it exists
*/ */
if (parent) { if (parent) {
__clk_set_parent_before(orphan, parent); /* update the clk tree topology */
__clk_set_parent_after(orphan, parent, NULL); flags = clk_enable_lock();
clk_reparent(orphan, parent);
clk_enable_unlock(flags);
__clk_recalc_accuracies(orphan); __clk_recalc_accuracies(orphan);
__clk_recalc_rates(orphan, 0); __clk_recalc_rates(orphan, 0);
} }
......
...@@ -329,12 +329,16 @@ static void __init pxa3xx_dummy_clocks_init(void) ...@@ -329,12 +329,16 @@ static void __init pxa3xx_dummy_clocks_init(void)
static void __init pxa3xx_base_clocks_init(void) static void __init pxa3xx_base_clocks_init(void)
{ {
struct clk *clk;
pxa3xx_register_plls(); pxa3xx_register_plls();
pxa3xx_register_core(); pxa3xx_register_core();
clk_register_clk_pxa3xx_system_bus(); clk_register_clk_pxa3xx_system_bus();
clk_register_clk_pxa3xx_ac97(); clk_register_clk_pxa3xx_ac97();
clk_register_clk_pxa3xx_smemc(); 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, clkdev_pxa_register(CLK_OSTIMER, "OSTIMER0", NULL,
clk_register_fixed_factor(NULL, "os-timer0", clk_register_fixed_factor(NULL, "os-timer0",
"osc_13mhz", 0, 1, 4)); "osc_13mhz", 0, 1, 4));
......
...@@ -86,6 +86,7 @@ enum si5351_disable_state { ...@@ -86,6 +86,7 @@ enum si5351_disable_state {
* @multisynth_src: multisynth source clock * @multisynth_src: multisynth source clock
* @clkout_src: clkout source clock * @clkout_src: clkout source clock
* @pll_master: if true, clkout can also change pll rate * @pll_master: if true, clkout can also change pll rate
* @pll_reset: if true, clkout can reset its pll
* @drive: output drive strength * @drive: output drive strength
* @rate: initial clkout rate, or default if 0 * @rate: initial clkout rate, or default if 0
*/ */
...@@ -95,6 +96,7 @@ struct si5351_clkout_config { ...@@ -95,6 +96,7 @@ struct si5351_clkout_config {
enum si5351_drive_strength drive; enum si5351_drive_strength drive;
enum si5351_disable_state disable_state; enum si5351_disable_state disable_state;
bool pll_master; bool pll_master;
bool pll_reset;
unsigned long rate; unsigned long rate;
}; };
......
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