/*
* Clock manipulation routines for Freescale STMP37XX/STMP378X
*
* Author: Vitaly Wool <vital@embeddedalley.com>
*
* Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#define DEBUG
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <asm/mach-types.h>
#include <asm/clkdev.h>
#include <mach/platform.h>
#include <mach/regs-clkctrl.h>
#include "clock.h"
static DEFINE_SPINLOCK(clocks_lock);
static struct clk osc_24M;
static struct clk pll_clk;
static struct clk cpu_clk;
static struct clk hclk;
static int propagate_rate(struct clk *);
static inline int clk_is_busy(struct clk *clk)
{
return __raw_readl(clk->busy_reg) & (1 << clk->busy_bit);
}
static inline int clk_good(struct clk *clk)
{
return clk && !IS_ERR(clk) && clk->ops;
}
static int std_clk_enable(struct clk *clk)
{
if (clk->enable_reg) {
u32 clk_reg = __raw_readl(clk->enable_reg);
if (clk->enable_negate)
clk_reg &= ~(1 << clk->enable_shift);
else
clk_reg |= (1 << clk->enable_shift);
__raw_writel(clk_reg, clk->enable_reg);
if (clk->enable_wait)
udelay(clk->enable_wait);
return 0;
} else
return -EINVAL;
}
static int std_clk_disable(struct clk *clk)
{
if (clk->enable_reg) {
u32 clk_reg = __raw_readl(clk->enable_reg);
if (clk->enable_negate)
clk_reg |= (1 << clk->enable_shift);
else
clk_reg &= ~(1 << clk->enable_shift);
__raw_writel(clk_reg, clk->enable_reg);
return 0;
} else
return -EINVAL;
}
static int io_set_rate(struct clk *clk, u32 rate)
{
u32 reg_frac, clkctrl_frac;
int i, ret = 0, mask = 0x1f;
clkctrl_frac = (clk->parent->rate * 18 + rate - 1) / rate;
if (clkctrl_frac < 18 || clkctrl_frac > 35) {
ret = -EINVAL;
goto out;
}
reg_frac = __raw_readl(clk->scale_reg);
reg_frac &= ~(mask << clk->scale_shift);
__raw_writel(reg_frac | (clkctrl_frac << clk->scale_shift),
clk->scale_reg);
if (clk->busy_reg) {
for (i = 10000; i; i--)
if (!clk_is_busy(clk))
break;
if (!i)
ret = -ETIMEDOUT;
else
ret = 0;
}
out:
return ret;
}
static long io_get_rate(struct clk *clk)
{
long rate = clk->parent->