#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h> // error codes
#include <linux/types.h> // size_t
#include <linux/delay.h> // mdelay
#include <linux/proc_fs.h>
#include <asm/uaccess.h> // to copy to/from userspace
#include <asm/hardware.h>
#include <asm/arch-s3c2410/s3c2410.h>
#include <asm-arm/arch-s3c2410/irqs.h>
#include <linux/wait.h>
#include <linux/signal.h>
#include <linux/ioctl.h>
#define adc_CTL_BASE io_p2v(0x58000000)
#define S3C2410_ADCCON (adc_CTL_BASE + 0x0)
#define S3C2410_ADCDAT (adc_CTL_BASE + 0xC)
#define PCLK 50700000
#define ADC_FREQ 2500000
#define START_ADC 0x0304 // the command of starting adc
#define MY_ADC_SIG 51
static int global; // recieve the value of adc
struct unit {
u32 *ADC_CON;
u32 *ADC_DAT;
};
static struct unit adc_unit = {
.ADC_CON = (u32 *)S3C2410_ADCCON,
.ADC_DAT = (u32 *)S3C2410_ADCDAT,
};
static void adcdone_int_handler(int irq, void *dev_id, struct pt_regs *reg)
{
global =( (int)*adc_unit.ADC_DAT & 0x3FF);
}
ssize_t adc_open(struct inode * inode, struct file * file)
{
MOD_INC_USE_COUNT;
file->private_data = &adc_unit;
return 0;
}
ssize_t adc_release(struct inode * inode, struct file * file)
{
MOD_DEC_USE_COUNT;
return 0;
}
ssize_t adc_read(struct file * file, char * buf, size_t count, loff_t * offset)
{
int ret;
int temp;
temp = global;
ret = copy_to_user(buf, &temp, count);
if(ret!=0)
{
printk("The copy to user error!\n");
return -EFAULT;
}
return ret;
}
ssize_t adc_write(struct file * file, const char * buf, size_t count, loff_t * offset)
{
return 0;
}
int adc_ioctl(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)
{
switch(cmd)
{
case START_ADC: *adc_unit.ADC_CON |= 0x1; break;
default:
{
printk("the ioctl error!\n");
break;
}
}
return 0;
}
struct file_operations adc_Ctl_ops =
{
open: adc_open,
read: adc_read,
write: adc_write,
ioctl: adc_ioctl,
release: adc_release,
};
static devfs_handle_t devfs_handle,devfs_adc_dir;
static void __init init_hardware(struct unit *unit)
{
char preScaler = PCLK/ADC_FREQ - 1;
*unit->ADC_CON = (1<<14) | (preScaler<<6) | (1<<4);
*unit->ADC_DAT = 0x0;
}
static int __init init_adc()
{
int res;
printk("This is my Adc driver!\n");
devfs_register_chrdev(224, "adc", &adc_Ctl_ops);
devfs_adc_dir = devfs_mk_dir(NULL, "adc", NULL);
devfs_handle = devfs_register(devfs_adc_dir, "0", DEVFS_FL_DEFAULT,
224, 0,S_IFCHR | S_IRUSR | S_IWUSR,&adc_Ctl_ops, NULL);
res = request_irq(IRQ_ADC_DONE, adcdone_int_handler, SA_INTERRUPT , "adc", NULL);
if(res < 0)
printk("The IRQ Wrong!\n");
init_hardware(&adc_unit);
return res;
}
static void __exit clean_adc()
{
devfs_unregister_chrdev(224,"adc");
devfs_unregister(devfs_handle);
devfs_unregister(devfs_adc_dir);
free_irq(IRQ_ADC_DONE,NULL);
}
module_init(init_adc);
module_exit(clean_adc);
MODULE_DESCRIPTION("EduKitII-2410 adc driver");
MODULE_AUTHOR("Embest tech&info Co.,Ltd. <www.embedinfo.com>");
MODULE_LICENSE("GPL");