/*
* linux/arch/arm/mach-omap/clock.c
*
* Copyright (C) 2004 Nokia corporation
* Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <asm/semaphore.h>
#include <asm/hardware/clock.h>
#include <asm/arch/board.h>
#include <asm/arch/usb.h>
#include "clock.h"
static LIST_HEAD(clocks);
static DECLARE_MUTEX(clocks_sem);
static DEFINE_SPINLOCK(clockfw_lock);
static void propagate_rate(struct clk * clk);
/* External clock (MCLK & BCLK) functions */
static int set_ext_clk_rate(struct clk * clk, unsigned long rate);
static long round_ext_clk_rate(struct clk * clk, unsigned long rate);
static void init_ext_clk(struct clk * clk);
/* MPU virtual clock functions */
static int select_table_rate(struct clk * clk, unsigned long rate);
static long round_to_table_rate(struct clk * clk, unsigned long rate);
void clk_setdpll(__u16, __u16);
struct mpu_rate rate_table[] = {
/* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL
* armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv
*/
#if defined(CONFIG_OMAP_ARM_216MHZ)
{ 216000000, 12000000, 216000000, 0x050d, 0x2910 }, /* 1/1/2/2/2/8 */
#endif
#if defined(CONFIG_OMAP_ARM_195MHZ)
{ 195000000, 13000000, 195000000, 0x050e, 0x2790 }, /* 1/1/2/2/4/8 */
#endif
#if defined(CONFIG_OMAP_ARM_192MHZ)
{ 192000000, 19200000, 192000000, 0x050f, 0x2510 }, /* 1/1/2/2/8/8 */
{ 192000000, 12000000, 192000000, 0x050f, 0x2810 }, /* 1/1/2/2/8/8 */
{ 96000000, 12000000, 192000000, 0x055f, 0x2810 }, /* 2/2/2/2/8/8 */
{ 48000000, 12000000, 192000000, 0x0ccf, 0x2810 }, /* 4/4/4/4/8/8 */
{ 24000000, 12000000, 192000000, 0x0fff, 0x2810 }, /* 8/8/8/8/8/8 */
#endif
#if defined(CONFIG_OMAP_ARM_182MHZ)
{ 182000000, 13000000, 182000000, 0x050e, 0x2710 }, /* 1/1/2/2/4/8 */
#endif
#if defined(CONFIG_OMAP_ARM_168MHZ)
{ 168000000, 12000000, 168000000, 0x010f, 0x2710 }, /* 1/1/1/2/8/8 */
#endif
#if defined(CONFIG_OMAP_ARM_150MHZ)
{ 150000000, 12000000, 150000000, 0x150a, 0x2cb0 }, /* 0/0/1/1/2/2 */
#endif
#if defined(CONFIG_OMAP_ARM_120MHZ)
{ 120000000, 12000000, 120000000, 0x010a, 0x2510 }, /* 1/1/1/2/4/4 */
#endif
#if defined(CONFIG_OMAP_ARM_96MHZ)
{ 96000000, 12000000, 96000000, 0x0005, 0x2410 }, /* 1/1/1/1/2/2 */
#endif
#if defined(CONFIG_OMAP_ARM_60MHZ)
{ 60000000, 12000000, 60000000, 0x0005, 0x2290 }, /* 1/1/1/1/2/2 */
#endif
#if defined(CONFIG_OMAP_ARM_30MHZ)
{ 30000000, 12000000, 60000000, 0x0555, 0x2290 }, /* 2/2/2/2/2/2 */
#endif
{ 0, 0, 0, 0, 0 },
};
static void ckctl_recalc(struct clk * clk)
{
int dsor;
/* Calculate divisor encoded as 2-bit exponent */
dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
if (unlikely(clk->rate == clk->parent->rate / dsor))
return; /* No change, quick exit */
clk->rate = clk->parent->rate / dsor;
if (unlikely(clk->flags & RATE_PROPAGATES))
propagate_rate(clk);
}
static void followparent_recalc(struct clk * clk)
{
clk->rate = clk->parent->rate;
}
static void watchdog_recalc(struct clk * clk)
{
clk->rate = clk->parent->rate / 14;
}
static struct clk ck_ref = {
.name = "ck_ref",
.rate = 12000000,
.flags