EVM PWM.c

From eLinux.org
Revision as of 14:03, 22 May 2007 by SpaceMonkey (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

<per>

// PWM driver - Andrew Armstrong 2007

// Used a skeleton from somewhere, cannot remember where tho!

  1. include <linux/config.h>
  2. include <linux/kernel.h>
  3. include <linux/module.h>
  4. include <linux/init.h>
  5. include <linux/fs.h>
  6. include <linux/major.h>
  7. include <linux/root_dev.h>
  8. include <asm/uaccess.h> /* for put_user */
  9. include <asm/setup.h>
  10. include <asm/semaphore.h>
  11. include <asm/hardware/clock.h>
  12. include <asm/io.h>
  13. include <asm/mach-types.h>
  1. include <asm/mach/arch.h>
  2. include <asm/mach/map.h>
  1. include <asm/arch/hardware.h>

/*

*  Prototypes - this would normally go in a .h file
*/

int init_module(void); void cleanup_module(void); static int device_open(struct inode *, struct file *); static int device_release(struct inode *, struct file *); static ssize_t device_read(struct file *, char *, size_t, loff_t *); static ssize_t device_write(struct file *, const char *, size_t, loff_t *);

  1. define SUCCESS 0
  2. define DEVICE_NAME "fb3_pwm" /* Dev name as it appears in /proc/devices */
  3. define BUF_LEN 80 /* Max length of the message from the device */

/*

* Global variables are declared as static, so are global within the file. 
*/

static int Major; /* Major number assigned to our device driver */ static int Device_Open = 0; /* Is device open? * Used to prevent multiple access to device */ static char msg[BUF_LEN]; /* The msg the device will give when asked */ static char *msg_Ptr;

static struct file_operations fops = { .read = device_read, .write = device_write, .open = device_open, .release = device_release };

//********************************************************************************

static int PWMStatus=1; //1 = on 2 = off

//********************************************************************************

  1. define PWM0_BASE __REG(0x01C22000)
  1. define PWM0_PID __REG(0x01C22000)
  1. define PWM0_PCR __REG(0x01C22004)
  1. define PWM0_CFG __REG(0x01C22008)
  1. define PWM0_START __REG(0x01C2200C)
  1. define PWM0_RPT __REG(0x01C22010)
  1. define PWM0_PER __REG(0x01C22014)
  1. define PWM0_PH1D __REG(0x01C22018)

void pwm_power(int option) {

if(option==0) { PWM0_CFG = 0x00000000; PWMStatus = 0; } else { PWM0_PCR = 0x00000001; PWM0_CFG = 0x00000001; PWM0_RPT = 0x99999999; PWM0_PER = 0x00002000; PWM0_PH1D = 0x00001000; PWM0_START = 0x00000001; PWMStatus = 1; } }

//AA07 Checks a character for a boolean 0 or 1 returns appropriately, returns 999 on error int checkchar(char s) {

if (s >= '0' && s <= '1') { if (s == '0') { return 0; } else { return 1; } } else { return 999; }

}

int init_module(void) {

       Major = register_chrdev(0, DEVICE_NAME, &fops);

if (Major < 0) { printk(KERN_ALERT "Registering char device failed with %d\n", Major); return Major; }

printk(KERN_INFO "Create driver node:- 'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major); printk(KERN_INFO "[cat] to see status and [echo 0] for off and [1] for on\n");

printk(KERN_ALERT "Turning PWM on (default setting)\n"); pwm_power(0); pwm_power(1);

return 0; }

/*

* This function is called when the module is unloaded
*/

void cleanup_module(void) { /* * Unregister the device */ int ret = unregister_chrdev(Major, DEVICE_NAME); if (ret < 0) printk(KERN_ALERT "Error in unregister_chrdev: %d\n", ret); }

/*

* Methods
*/

/*

* Called when a process tries to open the device file, like
* "cat /dev/mycharfile"
*/

static int device_open(struct inode *inode, struct file *file) { if (Device_Open) return -EBUSY;

Device_Open++; sprintf(msg, "%d\n", PWMStatus); msg_Ptr = msg; try_module_get(THIS_MODULE);

return SUCCESS; }

/*

* Called when a process closes the device file.
*/

static int device_release(struct inode *inode, struct file *file) { Device_Open--; /* We're now ready for our next caller */

/* * Decrement the usage count, or else once you opened the file, you'll * never get get rid of the module. */ module_put(THIS_MODULE);

return 0; }

/*

* Called when a process, which already opened the dev file, attempts to
* read from it.
*/

static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */ char *buffer, /* buffer to fill with data */ size_t length, /* length of the buffer */ loff_t * offset) { /* * Number of bytes actually written to the buffer */ int bytes_read = 0;

/* * If we're at the end of the message, * return 0 signifying end of file */ if (*msg_Ptr == 0) return 0;

/* * Actually put the data into the buffer */ while (length && *msg_Ptr) {

/* * The buffer is in the user data segment, not the kernel * segment so "*" assignment won't work. We have to use * put_user which copies data from the kernel data segment to * the user data segment. */ put_user(*(msg_Ptr++), buffer++);

length--; bytes_read++; }

/* * Most read functions return the number of bytes put into the buffer */ return bytes_read; }

/*

* Called when a process writes to dev file: echo "hi" > /dev/hello 
*/

static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * off) { int i = checkchar(buff[0]);

if (i == 999) { printk(KERN_ALERT "Error in option, use 0 (off) or 1 (on)\n"); } else { printk(KERN_ALERT "Setting value %d :- 0 (off) or 1 (on)\n",i); pwm_power(i); }

return len;

}


</per>