linux/drivers/misc/hdpuftrs/hdpu_cpustate.c
<<
>>
Prefs
   1/*
   2 *      Sky CPU State Driver
   3 *
   4 *      Copyright (C) 2002 Brian Waite
   5 *
   6 *      This driver allows use of the CPU state bits
   7 *      It exports the /dev/sky_cpustate and also
   8 *      /proc/sky_cpustate pseudo-file for status information.
   9 *
  10 *      This program is free software; you can redistribute it and/or
  11 *      modify it under the terms of the GNU General Public License
  12 *      as published by the Free Software Foundation; either version
  13 *      2 of the License, or (at your option) any later version.
  14 *
  15 */
  16
  17#include <linux/module.h>
  18#include <linux/kernel.h>
  19#include <linux/spinlock.h>
  20#include <linux/smp_lock.h>
  21#include <linux/miscdevice.h>
  22#include <linux/proc_fs.h>
  23#include <linux/hdpu_features.h>
  24#include <linux/platform_device.h>
  25#include <asm/uaccess.h>
  26#include <linux/seq_file.h>
  27#include <asm/io.h>
  28
  29#define SKY_CPUSTATE_VERSION            "1.1"
  30
  31static int hdpu_cpustate_probe(struct platform_device *pdev);
  32static int hdpu_cpustate_remove(struct platform_device *pdev);
  33
  34static unsigned char cpustate_get_state(void);
  35static int cpustate_proc_open(struct inode *inode, struct file *file);
  36static int cpustate_proc_read(struct seq_file *seq, void *offset);
  37
  38static struct cpustate_t cpustate;
  39
  40static const struct file_operations proc_cpustate = {
  41        .open = cpustate_proc_open,
  42        .read = seq_read,
  43        .llseek = seq_lseek,
  44        .release = single_release,
  45        .owner = THIS_MODULE,
  46};
  47
  48static int cpustate_proc_open(struct inode *inode, struct file *file)
  49{
  50        return single_open(file, cpustate_proc_read, NULL);
  51}
  52
  53static int cpustate_proc_read(struct seq_file *seq, void *offset)
  54{
  55        seq_printf(seq, "CPU State: %04x\n", cpustate_get_state());
  56        return 0;
  57}
  58
  59static int cpustate_get_ref(int excl)
  60{
  61
  62        int retval = -EBUSY;
  63
  64        spin_lock(&cpustate.lock);
  65
  66        if (cpustate.excl)
  67                goto out_busy;
  68
  69        if (excl) {
  70                if (cpustate.open_count)
  71                        goto out_busy;
  72                cpustate.excl = 1;
  73        }
  74
  75        cpustate.open_count++;
  76        retval = 0;
  77
  78      out_busy:
  79        spin_unlock(&cpustate.lock);
  80        return retval;
  81}
  82
  83static int cpustate_free_ref(void)
  84{
  85
  86        spin_lock(&cpustate.lock);
  87
  88        cpustate.excl = 0;
  89        cpustate.open_count--;
  90
  91        spin_unlock(&cpustate.lock);
  92        return 0;
  93}
  94
  95static unsigned char cpustate_get_state(void)
  96{
  97
  98        return cpustate.cached_val;
  99}
 100
 101static void cpustate_set_state(unsigned char new_state)
 102{
 103        unsigned int state = (new_state << 21);
 104
 105#ifdef DEBUG_CPUSTATE
 106        printk("CPUSTATE -> 0x%x\n", new_state);
 107#endif
 108        spin_lock(&cpustate.lock);
 109        cpustate.cached_val = new_state;
 110        writel((0xff << 21), cpustate.clr_addr);
 111        writel(state, cpustate.set_addr);
 112        spin_unlock(&cpustate.lock);
 113}
 114
 115/*
 116 *      Now all the various file operations that we export.
 117 */
 118
 119static ssize_t cpustate_read(struct file *file, char *buf,
 120                             size_t count, loff_t * ppos)
 121{
 122        unsigned char data;
 123
 124        if (count < 0)
 125                return -EFAULT;
 126        if (count == 0)
 127                return 0;
 128
 129        data = cpustate_get_state();
 130        if (copy_to_user(buf, &data, sizeof(unsigned char)))
 131                return -EFAULT;
 132        return sizeof(unsigned char);
 133}
 134
 135static ssize_t cpustate_write(struct file *file, const char *buf,
 136                              size_t count, loff_t * ppos)
 137{
 138        unsigned char data;
 139
 140        if (count < 0)
 141                return -EFAULT;
 142
 143        if (count == 0)
 144                return 0;
 145
 146        if (copy_from_user((unsigned char *)&data, buf, sizeof(unsigned char)))
 147                return -EFAULT;
 148
 149        cpustate_set_state(data);
 150        return sizeof(unsigned char);
 151}
 152
 153static int cpustate_open(struct inode *inode, struct file *file)
 154{
 155        int ret;
 156
 157        lock_kernel();
 158        ret = cpustate_get_ref((file->f_flags & O_EXCL));
 159        unlock_kernel();
 160
 161        return ret;
 162}
 163
 164static int cpustate_release(struct inode *inode, struct file *file)
 165{
 166        return cpustate_free_ref();
 167}
 168
 169static struct platform_driver hdpu_cpustate_driver = {
 170        .probe = hdpu_cpustate_probe,
 171        .remove = hdpu_cpustate_remove,
 172        .driver = {
 173                .name = HDPU_CPUSTATE_NAME,
 174                .owner = THIS_MODULE,
 175        },
 176};
 177
 178/*
 179 *      The various file operations we support.
 180 */
 181static const struct file_operations cpustate_fops = {
 182      .owner    = THIS_MODULE,
 183      .open     = cpustate_open,
 184      .release  = cpustate_release,
 185      .read     = cpustate_read,
 186      .write    = cpustate_write,
 187      .llseek   = no_llseek,
 188};
 189
 190static struct miscdevice cpustate_dev = {
 191        .minor  = MISC_DYNAMIC_MINOR,
 192        .name   = "sky_cpustate",
 193        .fops   = &cpustate_fops,
 194};
 195
 196static int hdpu_cpustate_probe(struct platform_device *pdev)
 197{
 198        struct resource *res;
 199        struct proc_dir_entry *proc_de;
 200        int ret;
 201
 202        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 203        if (!res) {
 204                printk(KERN_ERR "sky_cpustate: "
 205                       "Invalid memory resource.\n");
 206                return -EINVAL;
 207        }
 208        cpustate.set_addr = (unsigned long *)res->start;
 209        cpustate.clr_addr = (unsigned long *)res->end - 1;
 210
 211        ret = misc_register(&cpustate_dev);
 212        if (ret) {
 213                printk(KERN_WARNING "sky_cpustate: "
 214                       "Unable to register misc device.\n");
 215                cpustate.set_addr = NULL;
 216                cpustate.clr_addr = NULL;
 217                return ret;
 218        }
 219
 220        proc_de = proc_create("sky_cpustate", 0666, NULL, &proc_cpustate);
 221        if (!proc_de) {
 222                printk(KERN_WARNING "sky_cpustate: "
 223                       "Unable to create proc entry\n");
 224        }
 225
 226        printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n");
 227        return 0;
 228}
 229
 230static int hdpu_cpustate_remove(struct platform_device *pdev)
 231{
 232        cpustate.set_addr = NULL;
 233        cpustate.clr_addr = NULL;
 234
 235        remove_proc_entry("sky_cpustate", NULL);
 236        misc_deregister(&cpustate_dev);
 237
 238        return 0;
 239}
 240
 241static int __init cpustate_init(void)
 242{
 243        return platform_driver_register(&hdpu_cpustate_driver);
 244}
 245
 246static void __exit cpustate_exit(void)
 247{
 248        platform_driver_unregister(&hdpu_cpustate_driver);
 249}
 250
 251module_init(cpustate_init);
 252module_exit(cpustate_exit);
 253
 254MODULE_AUTHOR("Brian Waite");
 255MODULE_LICENSE("GPL");
 256MODULE_ALIAS("platform:" HDPU_CPUSTATE_NAME);
 257