/* beepdrv.c beep driver. GUANGZHOU ZHIYUAN
Copyright (c) 2009 GUANGZHOU ZHIYUAN ELECTRONICS CO.LTD
By Chenxibing
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/cdev.h>
#include <asm/arch/hardware.h>
#include <asm/uaccess.h>
#include <asm/arch/irq.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <mach/hardware.h>
#include <mach/platform.h>
#include <asm/arch/lpc32xx_gpio.h>
#include "beepdrv.h"
#define DEV_NAME "beep"
struct cdev *beep_cdev;
#define BEEP_MAJOR 231
#define BEEP_MINOR 0
int beep_major = BEEP_MAJOR;
int beep_minor = BEEP_MINOR;
module_param(beep_major, int, 0);
module_param(beep_minor, int, 0);
#define GPIO_IOBASE io_p2v(GPIO_BASE)
static struct semaphore beep_sem;
static int beep_open(struct inode *inode, struct file *filp)
{
__raw_writel(_BIT(5), GPIO_P3_OUTP_SET(GPIO_IOBASE));//SET GPIO_05 BEEP OFF
try_module_get(THIS_MODULE);
printk( KERN_INFO DEV_NAME " opened!\n");
return 0;
}
static int beep_release(struct inode *inode, struct file *filp)
{
__raw_writel(_BIT(5), GPIO_P3_OUTP_SET(GPIO_IOBASE));//SET GPIO_05 BEEP OFF
module_put(THIS_MODULE);
printk(KERN_INFO DEV_NAME " released!\n");
return 0;
}
static int beep_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
int level;
if (_IOC_TYPE(cmd) != BEEP_IOC_MAGIC) {
return -ENOTTY;
}
if (_IOC_NR(cmd) >= BEEP_IOC_MAXNR) {
return -ENOTTY;
}
// printk("arg=0x%x\n", arg);
switch (cmd) {
case SET_BEEP_ON:
__raw_writel(_BIT(5), GPIO_P3_OUTP_CLR(GPIO_IOBASE));//CLR GPIO_05
udelay(10);
break;
case SET_BEEP_OFF:
__raw_writel(_BIT(5), GPIO_P3_OUTP_SET(GPIO_IOBASE));//SET GPIO_05
udelay(10);
break;
default:
__raw_writel(_BIT(5), GPIO_P3_OUTP_SET(GPIO_IOBASE));//SET GPIO_05
break;
}
return 0;
}
static struct file_operations beep_fops = {
.owner = THIS_MODULE,
.ioctl = beep_ioctl,
.open = beep_open,
.release = beep_release,
};
static void beep_setup_cdev(struct cdev *dev)
{
int err, devno = MKDEV(beep_major, beep_minor);
cdev_init(dev, &beep_fops);
dev->owner = THIS_MODULE;
dev->ops = &beep_fops;
err = cdev_add (dev, devno, 1);
/* Fail gracefully if need be */
if (err)
printk(KERN_NOTICE "Error %d adding gpio.\n", err);
}
static int __init beep_init(void)
{
int result;
printk(DEV_NAME " init starting......\n");
__raw_writel(_BIT(5), GPIO_P3_OUTP_SET(GPIO_IOBASE));//SET GPIO_05 BEEP OFF
dev_t dev = 0;// MKDEV(gpio_major, 0);
/*
* Register your major, and accept a dynamic number.
*/
if (beep_major)
result = register_chrdev_region(beep_minor, 1, DEV_NAME);
else {
result = alloc_chrdev_region(&dev, 0, 1, DEV_NAME);
beep_major = MAJOR(dev);
}
if (result < 0)
return result;
beep_cdev = cdev_alloc();
if (!beep_cdev) {
result = -ENOMEM;
goto fail; /* Make this more graceful */
}
beep_setup_cdev(&beep_cdev);
printk(DEV_NAME " registered OK.\n");
return 0;
fail:
cdev_del(&beep_cdev);
unregister_chrdev_region(MKDEV(beep_major, beep_minor), 1);
// beep_exit();
return result;
}
static int __exit beep_exit(void)
{
cdev_del(&beep_cdev);
unregister_chrdev_region(MKDEV(beep_major, beep_minor), 1);
printk(DEV_NAME " unregistered.\n");
}
module_init(beep_init);
module_exit(beep_exit);
MODULE_AUTHOR("Abing ");
MODULE_DESCRIPTION("ZHIYUAN tp-beep Driver");
MODULE_LICENSE("GPL");
|