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#include <linux/list.h>
  19
  20#include <mach/chip.h>
  21
  22#include "clock.h"
  23
  24/* at32 clock list */
  25static LIST_HEAD(at32_clock_list);
  26
  27static DEFINE_SPINLOCK(clk_lock);
  28static DEFINE_SPINLOCK(clk_list_lock);
  29
  30void at32_clk_register(struct clk *clk)
  31{
  32        spin_lock(&clk_list_lock);
  33        /* add the new item to the end of the list */
  34        list_add_tail(&clk->list, &at32_clock_list);
  35        spin_unlock(&clk_list_lock);
  36}
  37
  38struct clk *clk_get(struct device *dev, const char *id)
  39{
  40        struct clk *clk;
  41
  42        spin_lock(&clk_list_lock);
  43
  44        list_for_each_entry(clk, &at32_clock_list, list) {
  45                if (clk->dev == dev && strcmp(id, clk->name) == 0) {
  46                        spin_unlock(&clk_list_lock);
  47                        return clk;
  48                }
  49        }
  50
  51        spin_unlock(&clk_list_lock);
  52        return ERR_PTR(-ENOENT);
  53}
  54EXPORT_SYMBOL(clk_get);
  55
  56void clk_put(struct clk *clk)
  57{
  58        /* clocks are static for now, we can't free them */
  59}
  60EXPORT_SYMBOL(clk_put);
  61
  62static void __clk_enable(struct clk *clk)
  63{
  64        if (clk->parent)
  65                __clk_enable(clk->parent);
  66        if (clk->users++ == 0 && clk->mode)
  67                clk->mode(clk, 1);
  68}
  69
  70int clk_enable(struct clk *clk)
  71{
  72        unsigned long flags;
  73
  74        spin_lock_irqsave(&clk_lock, flags);
  75        __clk_enable(clk);
  76        spin_unlock_irqrestore(&clk_lock, flags);
  77
  78        return 0;
  79}
  80EXPORT_SYMBOL(clk_enable);
  81
  82static void __clk_disable(struct clk *clk)
  83{
  84        if (clk->users == 0) {
  85                printk(KERN_ERR "%s: mismatched disable\n", clk->name);
  86                WARN_ON(1);
  87                return;
  88        }
  89
  90        if (--clk->users == 0 && clk->mode)
  91                clk->mode(clk, 0);
  92        if (clk->parent)
  93                __clk_disable(clk->parent);
  94}
  95
  96void clk_disable(struct clk *clk)
  97{
  98        unsigned long flags;
  99
 100        spin_lock_irqsave(&clk_lock, flags);
 101        __clk_disable(clk);
 102        spin_unlock_irqrestore(&clk_lock, flags);
 103}
 104EXPORT_SYMBOL(clk_disable);
 105
 106unsigned long clk_get_rate(struct clk *clk)
 107{
 108        unsigned long flags;
 109        unsigned long rate;
 110
 111        spin_lock_irqsave(&clk_lock, flags);
 112        rate = clk->get_rate(clk);
 113        spin_unlock_irqrestore(&clk_lock, flags);
 114
 115        return rate;
 116}
 117EXPORT_SYMBOL(clk_get_rate);
 118
 119long clk_round_rate(struct clk *clk, unsigned long rate)
 120{
 121        unsigned long flags, actual_rate;
 122
 123        if (!clk->set_rate)
 124                return -ENOSYS;
 125
 126        spin_lock_irqsave(&clk_lock, flags);
 127        actual_rate = clk->set_rate(clk, rate, 0);
 128        spin_unlock_irqrestore(&clk_lock, flags);
 129
 130        return actual_rate;
 131}
 132EXPORT_SYMBOL(clk_round_rate);
 133
 134int clk_set_rate(struct clk *clk, unsigned long rate)
 135{
 136        unsigned long flags;
 137        long ret;
 138
 139        if (!clk->set_rate)
 140                return -ENOSYS;
 141
 142        spin_lock_irqsave(&clk_lock, flags);
 143        ret = clk->set_rate(clk, rate, 1);
 144        spin_unlock_irqrestore(&clk_lock, flags);
 145
 146        return (ret < 0) ? ret : 0;
 147}
 148EXPORT_SYMBOL(clk_set_rate);
 149
 150int clk_set_parent(struct clk *clk, struct clk *parent)
 151{
 152        unsigned long flags;
 153        int ret;
 154
 155        if (!clk->set_parent)
 156                return -ENOSYS;
 157
 158        spin_lock_irqsave(&clk_lock, flags);
 159        ret = clk->set_parent(clk, parent);
 160        spin_unlock_irqrestore(&clk_lock, flags);
 161
 162        return ret;
 163}
 164EXPORT_SYMBOL(clk_set_parent);
 165
 166struct clk *clk_get_parent(struct clk *clk)
 167{
 168        return clk->parent;
 169}
 170EXPORT_SYMBOL(clk_get_parent);
 171
 172
 173
 174#ifdef CONFIG_DEBUG_FS
 175
 176/* /sys/kernel/debug/at32ap_clk */
 177
 178#include <linux/io.h>
 179#include <linux/debugfs.h>
 180#include <linux/seq_file.h>
 181#include "pm.h"
 182
 183
 184#define NEST_DELTA      2
 185#define NEST_MAX        6
 186
 187struct clkinf {
 188        struct seq_file *s;
 189        unsigned        nest;
 190};
 191
 192static void
 193dump_clock(struct clk *parent, struct clkinf *r)
 194{
 195        unsigned        nest = r->nest;
 196        char            buf[16 + NEST_MAX];
 197        struct clk      *clk;
 198        unsigned        i;
 199
 200        /* skip clocks coupled to devices that aren't registered */
 201        if (parent->dev && !dev_name(parent->dev) && !parent->users)
 202                return;
 203
 204        /* <nest spaces> name <pad to end> */
 205        memset(buf, ' ', sizeof(buf) - 1);
 206        buf[sizeof(buf) - 1] = 0;
 207        i = strlen(parent->name);
 208        memcpy(buf + nest, parent->name,
 209                        min(i, (unsigned)(sizeof(buf) - 1 - nest)));
 210
 211        seq_printf(r->s, "%s%c users=%2d %-3s %9ld Hz",
 212                buf, parent->set_parent ? '*' : ' ',
 213                parent->users,
 214                parent->users ? "on" : "off",   /* NOTE: not-paranoid!! */
 215                clk_get_rate(parent));
 216        if (parent->dev)
 217                seq_printf(r->s, ", for %s", dev_name(parent->dev));
 218        seq_printf(r->s, "\n");
 219
 220        /* cost of this scan is small, but not linear... */
 221        r->nest = nest + NEST_DELTA;
 222
 223        list_for_each_entry(clk, &at32_clock_list, list) {
 224                if (clk->parent == parent)
 225                        dump_clock(clk, r);
 226        }
 227        r->nest = nest;
 228}
 229
 230static int clk_show(struct seq_file *s, void *unused)
 231{
 232        struct clkinf   r;
 233        int             i;
 234        struct clk      *clk;
 235
 236        /* show all the power manager registers */
 237        seq_printf(s, "MCCTRL  = %8x\n", pm_readl(MCCTRL));
 238        seq_printf(s, "CKSEL   = %8x\n", pm_readl(CKSEL));
 239        seq_printf(s, "CPUMASK = %8x\n", pm_readl(CPU_MASK));
 240        seq_printf(s, "HSBMASK = %8x\n", pm_readl(HSB_MASK));
 241        seq_printf(s, "PBAMASK = %8x\n", pm_readl(PBA_MASK));
 242        seq_printf(s, "PBBMASK = %8x\n", pm_readl(PBB_MASK));
 243        seq_printf(s, "PLL0    = %8x\n", pm_readl(PLL0));
 244        seq_printf(s, "PLL1    = %8x\n", pm_readl(PLL1));
 245        seq_printf(s, "IMR     = %8x\n", pm_readl(IMR));
 246        for (i = 0; i < 8; i++) {
 247                if (i == 5)
 248                        continue;
 249                seq_printf(s, "GCCTRL%d = %8x\n", i, pm_readl(GCCTRL(i)));
 250        }
 251
 252        seq_printf(s, "\n");
 253
 254        r.s = s;
 255        r.nest = 0;
 256        /* protected from changes on the list while dumping */
 257        spin_lock(&clk_list_lock);
 258
 259        /* show clock tree as derived from the three oscillators */
 260        clk = clk_get(NULL, "osc32k");
 261        dump_clock(clk, &r);
 262        clk_put(clk);
 263
 264        clk = clk_get(NULL, "osc0");
 265        dump_clock(clk, &r);
 266        clk_put(clk);
 267
 268        clk = clk_get(NULL, "osc1");
 269        dump_clock(clk, &r);
 270        clk_put(clk);
 271
 272        spin_unlock(&clk_list_lock);
 273
 274        return 0;
 275}
 276
 277static int clk_open(struct inode *inode, struct file *file)
 278{
 279        return single_open(file, clk_show, NULL);
 280}
 281
 282static const struct file_operations clk_operations = {
 283        .open           = clk_open,
 284        .read           = seq_read,
 285        .llseek         = seq_lseek,
 286        .release        = single_release,
 287};
 288
 289static int __init clk_debugfs_init(void)
 290{
 291        (void) debugfs_create_file("at32ap_clk", S_IFREG | S_IRUGO,
 292                        NULL, NULL, &clk_operations);
 293
 294        return 0;
 295}
 296postcore_initcall(clk_debugfs_init);
 297
 298#endif
 299
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.