linux/arch/arm/mach-davinci/clock.c
<<
>>
Prefs
   1/*
   2 * TI DaVinci clock config file
   3 *
   4 * Copyright (C) 2006 Texas Instruments.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/kernel.h>
  14#include <linux/init.h>
  15#include <linux/errno.h>
  16#include <linux/err.h>
  17#include <linux/mutex.h>
  18#include <linux/platform_device.h>
  19
  20#include <asm/hardware.h>
  21#include <asm/io.h>
  22
  23#include <asm/arch/psc.h>
  24#include "clock.h"
  25
  26/* PLL/Reset register offsets */
  27#define PLLM            0x110
  28
  29static LIST_HEAD(clocks);
  30static DEFINE_MUTEX(clocks_mutex);
  31static DEFINE_SPINLOCK(clockfw_lock);
  32
  33static unsigned int commonrate;
  34static unsigned int armrate;
  35static unsigned int fixedrate = 27000000;       /* 27 MHZ */
  36
  37extern void davinci_psc_config(unsigned int domain, unsigned int id, char enable);
  38
  39/*
  40 * Returns a clock. Note that we first try to use device id on the bus
  41 * and clock name. If this fails, we try to use clock name only.
  42 */
  43struct clk *clk_get(struct device *dev, const char *id)
  44{
  45        struct clk *p, *clk = ERR_PTR(-ENOENT);
  46        int idno;
  47
  48        if (dev == NULL || dev->bus != &platform_bus_type)
  49                idno = -1;
  50        else
  51                idno = to_platform_device(dev)->id;
  52
  53        mutex_lock(&clocks_mutex);
  54
  55        list_for_each_entry(p, &clocks, node) {
  56                if (p->id == idno &&
  57                    strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
  58                        clk = p;
  59                        goto found;
  60                }
  61        }
  62
  63        list_for_each_entry(p, &clocks, node) {
  64                if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
  65                        clk = p;
  66                        break;
  67                }
  68        }
  69
  70found:
  71        mutex_unlock(&clocks_mutex);
  72
  73        return clk;
  74}
  75EXPORT_SYMBOL(clk_get);
  76
  77void clk_put(struct clk *clk)
  78{
  79        if (clk && !IS_ERR(clk))
  80                module_put(clk->owner);
  81}
  82EXPORT_SYMBOL(clk_put);
  83
  84static int __clk_enable(struct clk *clk)
  85{
  86        if (clk->flags & ALWAYS_ENABLED)
  87                return 0;
  88
  89        davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, clk->lpsc, 1);
  90        return 0;
  91}
  92
  93static void __clk_disable(struct clk *clk)
  94{
  95        if (clk->usecount)
  96                return;
  97
  98        davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, clk->lpsc, 0);
  99}
 100
 101int clk_enable(struct clk *clk)
 102{
 103        unsigned long flags;
 104        int ret = 0;
 105
 106        if (clk == NULL || IS_ERR(clk))
 107                return -EINVAL;
 108
 109        if (clk->usecount++ == 0) {
 110                spin_lock_irqsave(&clockfw_lock, flags);
 111                ret = __clk_enable(clk);
 112                spin_unlock_irqrestore(&clockfw_lock, flags);
 113        }
 114
 115        return ret;
 116}
 117EXPORT_SYMBOL(clk_enable);
 118
 119void clk_disable(struct clk *clk)
 120{
 121        unsigned long flags;
 122
 123        if (clk == NULL || IS_ERR(clk))
 124                return;
 125
 126        if (clk->usecount > 0 && !(--clk->usecount)) {
 127                spin_lock_irqsave(&clockfw_lock, flags);
 128                __clk_disable(clk);
 129                spin_unlock_irqrestore(&clockfw_lock, flags);
 130        }
 131}
 132EXPORT_SYMBOL(clk_disable);
 133
 134unsigned long clk_get_rate(struct clk *clk)
 135{
 136        if (clk == NULL || IS_ERR(clk))
 137                return -EINVAL;
 138
 139        return *(clk->rate);
 140}
 141EXPORT_SYMBOL(clk_get_rate);
 142
 143long clk_round_rate(struct clk *clk, unsigned long rate)
 144{
 145        if (clk == NULL || IS_ERR(clk))
 146                return -EINVAL;
 147
 148        return *(clk->rate);
 149}
 150EXPORT_SYMBOL(clk_round_rate);
 151
 152int clk_set_rate(struct clk *clk, unsigned long rate)
 153{
 154        if (clk == NULL || IS_ERR(clk))
 155                return -EINVAL;
 156
 157        /* changing the clk rate is not supported */
 158        return -EINVAL;
 159}
 160EXPORT_SYMBOL(clk_set_rate);
 161
 162int clk_register(struct clk *clk)
 163{
 164        if (clk == NULL || IS_ERR(clk))
 165                return -EINVAL;
 166
 167        mutex_lock(&clocks_mutex);
 168        list_add(&clk->node, &clocks);
 169        mutex_unlock(&clocks_mutex);
 170
 171        return 0;
 172}
 173EXPORT_SYMBOL(clk_register);
 174
 175void clk_unregister(struct clk *clk)
 176{
 177        if (clk == NULL || IS_ERR(clk))
 178                return;
 179
 180        mutex_lock(&clocks_mutex);
 181        list_del(&clk->node);
 182        mutex_unlock(&clocks_mutex);
 183}
 184EXPORT_SYMBOL(clk_unregister);
 185
 186static struct clk davinci_clks[] = {
 187        {
 188                .name = "ARMCLK",
 189                .rate = &armrate,
 190                .lpsc = -1,
 191                .flags = ALWAYS_ENABLED,
 192        },
 193        {
 194                .name = "UART",
 195                .rate = &fixedrate,
 196                .lpsc = DAVINCI_LPSC_UART0,
 197        },
 198        {
 199                .name = "EMACCLK",
 200                .rate = &commonrate,
 201                .lpsc = DAVINCI_LPSC_EMAC_WRAPPER,
 202        },
 203        {
 204                .name = "I2CCLK",
 205                .rate = &fixedrate,
 206                .lpsc = DAVINCI_LPSC_I2C,
 207        },
 208        {
 209                .name = "IDECLK",
 210                .rate = &commonrate,
 211                .lpsc = DAVINCI_LPSC_ATA,
 212        },
 213        {
 214                .name = "McBSPCLK",
 215                .rate = &commonrate,
 216                .lpsc = DAVINCI_LPSC_McBSP,
 217        },
 218        {
 219                .name = "MMCSDCLK",
 220                .rate = &commonrate,
 221                .lpsc = DAVINCI_LPSC_MMC_SD,
 222        },
 223        {
 224                .name = "SPICLK",
 225                .rate = &commonrate,
 226                .lpsc = DAVINCI_LPSC_SPI,
 227        },
 228        {
 229                .name = "gpio",
 230                .rate = &commonrate,
 231                .lpsc = DAVINCI_LPSC_GPIO,
 232        },
 233        {
 234                .name = "AEMIFCLK",
 235                .rate = &commonrate,
 236                .lpsc = DAVINCI_LPSC_AEMIF,
 237                .usecount = 1,
 238        }
 239};
 240
 241int __init davinci_clk_init(void)
 242{
 243        struct clk *clkp;
 244        int count = 0;
 245        u32 pll_mult;
 246
 247        pll_mult = davinci_readl(DAVINCI_PLL_CNTRL0_BASE + PLLM);
 248        commonrate = ((pll_mult + 1) * 27000000) / 6;
 249        armrate = ((pll_mult + 1) * 27000000) / 2;
 250
 251        for (clkp = davinci_clks; count < ARRAY_SIZE(davinci_clks);
 252             count++, clkp++) {
 253                clk_register(clkp);
 254
 255                /* Turn on clocks that have been enabled in the
 256                 * table above */
 257                if (clkp->usecount)
 258                        clk_enable(clkp);
 259        }
 260
 261        return 0;
 262}
 263
 264#ifdef CONFIG_PROC_FS
 265#include <linux/proc_fs.h>
 266#include <linux/seq_file.h>
 267
 268static void *davinci_ck_start(struct seq_file *m, loff_t *pos)
 269{
 270        return *pos < 1 ? (void *)1 : NULL;
 271}
 272
 273static void *davinci_ck_next(struct seq_file *m, void *v, loff_t *pos)
 274{
 275        ++*pos;
 276        return NULL;
 277}
 278
 279static void davinci_ck_stop(struct seq_file *m, void *v)
 280{
 281}
 282
 283static int davinci_ck_show(struct seq_file *m, void *v)
 284{
 285        struct clk *cp;
 286
 287        list_for_each_entry(cp, &clocks, node)
 288                seq_printf(m,"%s %d %d\n", cp->name, *(cp->rate), cp->usecount);
 289
 290        return 0;
 291}
 292
 293static struct seq_operations davinci_ck_op = {
 294        .start  = davinci_ck_start,
 295        .next   = davinci_ck_next,
 296        .stop   = davinci_ck_stop,
 297        .show   = davinci_ck_show
 298};
 299
 300static int davinci_ck_open(struct inode *inode, struct file *file)
 301{
 302        return seq_open(file, &davinci_ck_op);
 303}
 304
 305static struct file_operations proc_davinci_ck_operations = {
 306        .open           = davinci_ck_open,
 307        .read           = seq_read,
 308        .llseek         = seq_lseek,
 309        .release        = seq_release,
 310};
 311
 312static int __init davinci_ck_proc_init(void)
 313{
 314        struct proc_dir_entry *entry;
 315
 316        entry = create_proc_entry("davinci_clocks", 0, NULL);
 317        if (entry)
 318                entry->proc_fops = &proc_davinci_ck_operations;
 319        return 0;
 320
 321}
 322__initcall(davinci_ck_proc_init);
 323#endif  /* CONFIG_DEBUG_PROC_FS */
 324