linux/arch/avr32/mach-at32ap/clock.c
<<
>>
Prefs
   1/*
   2 * Clock management for AT32AP CPUs
   3 *
   4 * Copyright (C) 2006 Atmel Corporation
   5 *
   6 * Based on arch/arm/mach-at91/clock.c
   7 *   Copyright (C) 2005 David Brownell
   8 *   Copyright (C) 2005 Ivan Kokshaysky
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as
  12 * published by the Free Software Foundation.
  13 */
  14#include <linux/clk.h>
  15#include <linux/err.h>
  16#include <linux/device.h>
  17#include <linux/string.h>
  18
  19#include <mach/chip.h>
  20
  21#include "clock.h"
  22
  23static DEFINE_SPINLOCK(clk_lock);
  24
  25struct clk *clk_get(struct device *dev, const char *id)
  26{
  27        int i;
  28
  29        for (i = 0; i < at32_nr_clocks; i++) {
  30                struct clk *clk = at32_clock_list[i];
  31
  32                if (clk->dev == dev && strcmp(id, clk->name) == 0)
  33                        return clk;
  34        }
  35
  36        return ERR_PTR(-ENOENT);
  37}
  38EXPORT_SYMBOL(clk_get);
  39
  40void clk_put(struct clk *clk)
  41{
  42        /* clocks are static for now, we can't free them */
  43}
  44EXPORT_SYMBOL(clk_put);
  45
  46static void __clk_enable(struct clk *clk)
  47{
  48        if (clk->parent)
  49                __clk_enable(clk->parent);
  50        if (clk->users++ == 0 && clk->mode)
  51                clk->mode(clk, 1);
  52}
  53
  54int clk_enable(struct clk *clk)
  55{
  56        unsigned long flags;
  57
  58        spin_lock_irqsave(&clk_lock, flags);
  59        __clk_enable(clk);
  60        spin_unlock_irqrestore(&clk_lock, flags);
  61
  62        return 0;
  63}
  64EXPORT_SYMBOL(clk_enable);
  65
  66static void __clk_disable(struct clk *clk)
  67{
  68        if (clk->users == 0) {
  69                printk(KERN_ERR "%s: mismatched disable\n", clk->name);
  70                WARN_ON(1);
  71                return;
  72        }
  73
  74        if (--clk->users == 0 && clk->mode)
  75                clk->mode(clk, 0);
  76        if (clk->parent)
  77                __clk_disable(clk->parent);
  78}
  79
  80void clk_disable(struct clk *clk)
  81{
  82        unsigned long flags;
  83
  84        spin_lock_irqsave(&clk_lock, flags);
  85        __clk_disable(clk);
  86        spin_unlock_irqrestore(&clk_lock, flags);
  87}
  88EXPORT_SYMBOL(clk_disable);
  89
  90unsigned long clk_get_rate(struct clk *clk)
  91{
  92        unsigned long flags;
  93        unsigned long rate;
  94
  95        spin_lock_irqsave(&clk_lock, flags);
  96        rate = clk->get_rate(clk);
  97        spin_unlock_irqrestore(&clk_lock, flags);
  98
  99        return rate;
 100}
 101EXPORT_SYMBOL(clk_get_rate);
 102
 103long clk_round_rate(struct clk *clk, unsigned long rate)
 104{
 105        unsigned long flags, actual_rate;
 106
 107        if (!clk->set_rate)
 108                return -ENOSYS;
 109
 110        spin_lock_irqsave(&clk_lock, flags);
 111        actual_rate = clk->set_rate(clk, rate, 0);
 112        spin_unlock_irqrestore(&clk_lock, flags);
 113
 114        return actual_rate;
 115}
 116EXPORT_SYMBOL(clk_round_rate);
 117
 118int clk_set_rate(struct clk *clk, unsigned long rate)
 119{
 120        unsigned long flags;
 121        long ret;
 122
 123        if (!clk->set_rate)
 124                return -ENOSYS;
 125
 126        spin_lock_irqsave(&clk_lock, flags);
 127        ret = clk->set_rate(clk, rate, 1);
 128        spin_unlock_irqrestore(&clk_lock, flags);
 129
 130        return (ret < 0) ? ret : 0;
 131}
 132EXPORT_SYMBOL(clk_set_rate);
 133
 134int clk_set_parent(struct clk *clk, struct clk *parent)
 135{
 136        unsigned long flags;
 137        int ret;
 138
 139        if (!clk->set_parent)
 140                return -ENOSYS;
 141
 142        spin_lock_irqsave(&clk_lock, flags);
 143        ret = clk->set_parent(clk, parent);
 144        spin_unlock_irqrestore(&clk_lock, flags);
 145
 146        return ret;
 147}
 148EXPORT_SYMBOL(clk_set_parent);
 149
 150struct clk *clk_get_parent(struct clk *clk)
 151{
 152        return clk->parent;
 153}
 154EXPORT_SYMBOL(clk_get_parent);
 155
 156
 157
 158#ifdef CONFIG_DEBUG_FS
 159
 160/* /sys/kernel/debug/at32ap_clk */
 161
 162#include <linux/io.h>
 163#include <linux/debugfs.h>
 164#include <linux/seq_file.h>
 165#include "pm.h"
 166
 167
 168#define NEST_DELTA      2
 169#define NEST_MAX        6
 170
 171struct clkinf {
 172        struct seq_file *s;
 173        unsigned        nest;
 174};
 175
 176static void
 177dump_clock(struct clk *parent, struct clkinf *r)
 178{
 179        unsigned        nest = r->nest;
 180        char            buf[16 + NEST_MAX];
 181        struct clk      *clk;
 182        unsigned        i;
 183
 184        /* skip clocks coupled to devices that aren't registered */
 185        if (parent->dev && !parent->dev->bus_id[0] && !parent->users)
 186                return;
 187
 188        /* <nest spaces> name <pad to end> */
 189        memset(buf, ' ', sizeof(buf) - 1);
 190        buf[sizeof(buf) - 1] = 0;
 191        i = strlen(parent->name);
 192        memcpy(buf + nest, parent->name,
 193                        min(i, (unsigned)(sizeof(buf) - 1 - nest)));
 194
 195        seq_printf(r->s, "%s%c users=%2d %-3s %9ld Hz",
 196                buf, parent->set_parent ? '*' : ' ',
 197                parent->users,
 198                parent->users ? "on" : "off",   /* NOTE: not-paranoid!! */
 199                clk_get_rate(parent));
 200        if (parent->dev)
 201                seq_printf(r->s, ", for %s", parent->dev->bus_id);
 202        seq_printf(r->s, "\n");
 203
 204        /* cost of this scan is small, but not linear... */
 205        r->nest = nest + NEST_DELTA;
 206        for (i = 3; i < at32_nr_clocks; i++) {
 207                clk = at32_clock_list[i];
 208                if (clk->parent == parent)
 209                        dump_clock(clk, r);
 210        }
 211        r->nest = nest;
 212}
 213
 214static int clk_show(struct seq_file *s, void *unused)
 215{
 216        struct clkinf   r;
 217        int             i;
 218
 219        /* show all the power manager registers */
 220        seq_printf(s, "MCCTRL  = %8x\n", pm_readl(MCCTRL));
 221        seq_printf(s, "CKSEL   = %8x\n", pm_readl(CKSEL));
 222        seq_printf(s, "CPUMASK = %8x\n", pm_readl(CPU_MASK));
 223        seq_printf(s, "HSBMASK = %8x\n", pm_readl(HSB_MASK));
 224        seq_printf(s, "PBAMASK = %8x\n", pm_readl(PBA_MASK));
 225        seq_printf(s, "PBBMASK = %8x\n", pm_readl(PBB_MASK));
 226        seq_printf(s, "PLL0    = %8x\n", pm_readl(PLL0));
 227        seq_printf(s, "PLL1    = %8x\n", pm_readl(PLL1));
 228        seq_printf(s, "IMR     = %8x\n", pm_readl(IMR));
 229        for (i = 0; i < 8; i++) {
 230                if (i == 5)
 231                        continue;
 232                seq_printf(s, "GCCTRL%d = %8x\n", i, pm_readl(GCCTRL(i)));
 233        }
 234
 235        seq_printf(s, "\n");
 236
 237        /* show clock tree as derived from the three oscillators
 238         * we "know" are at the head of the list
 239         */
 240        r.s = s;
 241        r.nest = 0;
 242        dump_clock(at32_clock_list[0], &r);
 243        dump_clock(at32_clock_list[1], &r);
 244        dump_clock(at32_clock_list[2], &r);
 245
 246        return 0;
 247}
 248
 249static int clk_open(struct inode *inode, struct file *file)
 250{
 251        return single_open(file, clk_show, NULL);
 252}
 253
 254static const struct file_operations clk_operations = {
 255        .open           = clk_open,
 256        .read           = seq_read,
 257        .llseek         = seq_lseek,
 258        .release        = single_release,
 259};
 260
 261static int __init clk_debugfs_init(void)
 262{
 263        (void) debugfs_create_file("at32ap_clk", S_IFREG | S_IRUGO,
 264                        NULL, NULL, &clk_operations);
 265
 266        return 0;
 267}
 268postcore_initcall(clk_debugfs_init);
 269
 270#endif
 271