#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/device.h> /* device_create()*/
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/map.h>
#include <plat/regs-adc.h>
#include <mach/map.h>
static void __iomem *base_addr;
#define __ADCREG(name) (*(volatile unsigned long *)(base_addr + name))
#define ADCCON __ADCREG(S3C_ADCCON) // ADC control
#define ADCDAT0 __ADCREG(S3C_ADCDAT0) // ADC conversion data 0
#define ADC_START (1 << 0)
#define ADC_SIZE 0x1000
#define ADC_MAJOR 240
static int adc_major = ADC_MAJOR;
struct adc_dev {
struct cdev cdev;
unsigned char mem[ADC_SIZE];
};
struct adc_dev *adc_devp;
static int adc_init(void)
{
unsigned int preScaler = 0XFF;
ADCCON = (1<<14) | (preScaler<<6) | (0<<3) | (0<<2);
ADCCON |= ADC_START;
return 0;
}
static int adc_open(struct inode *inode, struct file *filp)
{
printk("$$$$$%s$$$$$\n", __func__);
adc_init();
return 0;
}
static int adc_release(struct inode *inode, struct file *filp)
{
printk("$$$$$$%s$$$$$\n", __func__);
return 0;
}
static ssize_t adc_read(struct file *filp, char __user *buf, size_t size,
loff_t *ppos)
{
unsigned int count = size;
int ret = 0;
printk("$$$$$%s$$$$$\n", __func__);
ADCCON |= ADC_START;
while(ADCCON & 0x01);//check if Enable_start is low
while(!(ADCCON &0x8000));
ret = ADCDAT0 & 0x3ff;
count = copy_to_user(buf,(char *)&ret,sizeof(ret));
return sizeof(ret);
}
static const struct file_operations adc_fops = {
.owner = THIS_MODULE,
.read = adc_read,
.open = adc_open,
.release = adc_release,
};
static void adc_setup_cdev(struct adc_dev *dev, int index)
{
int err, devno = MKDEV(adc_major, index);
cdev_init(&dev->cdev, &adc_fops);
dev->cdev.owner = THIS_MODULE;
err = cdev_add(&dev->cdev, devno, 1);
if (err)
printk(KERN_NOTICE "Error %d adding LED%d", err, index);
}
struct class *myclass;
int adc_dev_init(void)
{
int result;
printk("$$$$$$%s$$$$$$\n", __func__);
dev_t devno = MKDEV(adc_major, 0);
if (adc_major)
result = register_chrdev_region(devno, 1, "adc");
else {
result = alloc_chrdev_region(&devno, 0, 1, "adc");
adc_major = MAJOR(devno);
}
if (result < 0)
return result;
adc_devp = kmalloc(sizeof(struct adc_dev), GFP_KERNEL);
if (!adc_devp) {
result = - ENOMEM;
goto fail_malloc;
}
memset(adc_devp, 0, sizeof(struct adc_dev));
adc_setup_cdev(adc_devp, 0);
myclass = class_create(THIS_MODULE,"test_char");
device_create(myclass, NULL, MKDEV(adc_major,0), NULL, "adc");
base_addr = ioremap(0x7E00B000,0X20);
if(base_addr == NULL)
{
printk("failed to remap\n");
return -ENOMEM;
}
return 0;
fail_malloc:
unregister_chrdev_region(devno, 1);
return result;
}
void adc_dev_exit(void)
{
cdev_del(&adc_devp->cdev);
kfree(adc_devp);
unregister_chrdev_region(MKDEV(adc_major, 0), 1);
class_destroy(myclass);
device_destroy(myclass,MKDEV(adc_major,0));
iounmap(base_addr);
}
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_LICENSE("Dual BSD/GPL");
module_param(adc_major, int, S_IRUGO);
module_init(adc_dev_init);
module_exit(adc_dev_exit);