RFC [PATCH 4/9] Added lpc32xx clock handler

Russell King - ARM Linux linux at arm.linux.org.uk
Fri Nov 20 09:10:35 EST 2009


On Fri, Nov 20, 2009 at 02:11:24AM +0100, Kevin Wells wrote:
> +static int local_onoff_set_rate(struct clk *clk, u32 rate)
> +{
> +       u32 tmp;
> +
> +       tmp = readl(clk->enable_reg);
> +
> +       if (rate == 0)
> +               tmp &= ~clk->enable_mask;
> +       else
> +               tmp |= clk->enable_mask;
> +
> +       writel(tmp, clk->enable_reg);
> +
> +       return 0;
> +}

Definitely need to get PNX well away from this invalid usage - the clock
enable state is not supposed to be controlled by setting the rate to
zero vs non-zero.  That's what clk_enable/clk_disable are supposed to
do.

Yes, PNX4008 is a right mess in this respect, but I now have a set of
patches which fixes some of that (at least the stuff which is exposed
to drivers.)

> +static int local_clk_enable(struct clk *clk)
> +{
> +       int ret = 0;
> +
> +       if (clk->parent != NULL)
> +               ret = local_clk_enable(clk->parent);
> +
> +       if (clk->usecount == 0)
> +               clk->enable(clk, 1);

This takes no account of what may happen if the parent clock returns
failure.

Also, with parented clocks, you really don't want to enable the parent
every time a child is enabled - it makes reparenting unnecessarily
difficult.  Just enable the parent if it's the first time the child is
being enabled.

> +/*
> + * clk_enable - inform the system when the clock source should be running.
> + */
> +int clk_enable(struct clk *clk)
> +{
> +       int ret;
> +
> +       if ((IS_ERR(clk)) || (clk == NULL))
> +               return -ENODEV;

These checks should not be necessary.

> +/*
> + * clk_disable - inform the system when the clock source is no longer required
> + */
> +void clk_disable(struct clk *clk)
> +{
> +       if ((IS_ERR(clk)) || (clk == NULL))
> +               return;

Ditto.

> +/*
> + * clk_get_rate - obtain the current clock rate (in Hz) for a clock source.
> + *               This is only valid once the clock source has been enabled
> + */
> +unsigned long clk_get_rate(struct clk *clk)
> +{
> +       unsigned long rate = 0;
> +
> +       if (!IS_ERR(clk))

Ditto.

> +/*
> + * clk_round_rate - adjust a rate to the exact rate a clock can provide
> + */
> +long clk_round_rate(struct clk *clk, unsigned long rate)
> +{
> +       if (!IS_ERR(clk)) {

Ditto.

> +/*
> + * clk_set_rate - set the clock rate for a clock source
> + */
> +int clk_set_rate(struct clk *clk, unsigned long rate)
> +{
> +       int ret = -ENODEV;
> +
> +       if (!IS_ERR(clk)) {

Ditto.

> +/*
> + * clk_set_parent - set the parent clock source for this clock
> + */
> +int clk_set_parent(struct clk *clk, struct clk *parent)
> +{
> +       int ret = -ENODEV;
> +
> +       if (!IS_ERR(clk)) {

Ditto.

> +static void clk_inc_counts(struct clk *clk)
> +{
> +       clk->usecount++;
> +
> +       if (clk->parent != NULL)
> +               clk_inc_counts(clk->parent);
> +}
> +
> +int __init clk_init(void)
> +{
> +       u32 reg;
> +       int i;
> +
> +       /* Set initial rates for PLL397 and main oscillator */
> +       reg = readl(CLKPWR_PLL397_CTRL(CLKPWR_IOBASE));
> +       if ((reg & CLKPWR_SYSCTRL_PLL397_DIS) != 0)
> +               osc_pll397.rate = 0;
> +       else {
> +               osc_pll397.rate = 397 * osc_32KHz.rate;
> +               clk_inc_counts(&osc_32KHz);

Is there a reason clk_enable() can't do this?

> +       }
> +       reg = readl(CLKPWR_MAIN_OSC_CTRL(CLKPWR_IOBASE));
> +       if ((reg & CLKPWR_MOSC_DISABLE) != 0)
> +               osc_main.rate = 0;
> +       else
> +               osc_main.rate = MAIN_OSC_FREQ;
> +
> +       /* Update PLL397 or main osc use count and parent based on
> +          current SYSCLK selection */
> +       if (clk_is_sysclk_mainosc() != 0)
> +               clk_sys.parent = &osc_main;
> +       else
> +               clk_sys.parent = &osc_pll397;
> +       clk_sys.rate = clk_sys.parent->rate;
> +
> +       /* Compute the ARM PLL and USB PLL frequencies */
> +       local_update_armpll_rate();
> +       local_update_usbpll_rate();
> +       if (clk_usbpll.rate != 0)
> +               clk_inc_counts(&osc_main);
> +
> +       /* HCLK and PCLKs are always on and use the ARM PLL clock*/
> +       clk_inc_counts(clk_hclk.parent);
> +       clk_inc_counts(clk_pclk.parent);
> +
> +       /* Timer 0 is used for the system clock tick. It was pre-initialized
> +          prior to this elsewhere */
> +       clk_inc_counts(clk_timer0.parent);

Ditto for these.



More information about the linux-arm-kernel mailing list