/*
* main.c -- the bare test char module
*
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
* Copyright (C) 2001 O'Reilly & Associates
*
* The source code in this file can be freely used, adapted,
* and redistributed in source or binary form, so long as an
* acknowledgment appears in derived source files. The citation
* should list that the code comes from the book "Linux Device
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
* by O'Reilly & Associates. No warranty is attached;
* we cannot take responsibility for errors or fitness for use.
*
*/
//#include
#include
#include
#include
#include // tasklet
#include /* printk() */
#include /* kmalloc() */
#include /* everything... */
#include /* error codes */
#include /* size_t */
#include
#include /* O_ACCMODE */
#include
#include
#include
//#include
#include
#include // wait_event_interruptible, wake_up_interruptible
#include
#include /* cli(), *_flags */
#include /* copy_*_user */
#include
#include
#include
#include
#include
#include
int test_major = 220;
int test_minor = 0;
int test_nr_devs = 1; /* number of bare test devices */
static struct cdev *test_devices;
static struct semaphore sem;
static wait_queue_head_t mywait;
module_param(test_major, int, S_IRUGO);
module_param(test_minor, int, S_IRUGO);
module_param(test_nr_devs, int, S_IRUGO);
MODULE_AUTHOR("Alessandro Rubini, Jonathan Corbet");
MODULE_LICENSE("Dual BSD/GPL");
void __iomem * base_addr;
#define WAIT4INT(x) (((x)<<8) | S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | S3C2410_ADCTSC_XY_PST(3))
#define AUTOPST (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0))
#define AD_COUNT 5
unsigned int Gabs[AD_COUNT];
unsigned long xp;
unsigned long yp;
void Startad(void)
{
writel((S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST), base_addr+S3C2410_ADCTSC);
writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
printk("<1> start ad conveting\n");
}
irqreturn_t stylus_updown(int irq,void * dev_id,struct pt_regs * regs)
{
int temp_updown;
temp_updown=__raw_readl(base_addr+S3C2410_ADCDAT0)&(1<<15);
if (temp_updown==0) // stylus down
{
printk("<1>the stylus is down,state=%d\n",temp_updown);
Startad();
}
else
{
printk("<1>the stylus is up,state=%d\n",temp_updown);
writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
}
printk("<1> in interrupt\n");
return IRQ_HANDLED;
}
irqreturn_t ad_action(int irq,void * dev_id,struct pt_regs * regs)
{
unsigned long data0;
unsigned long data1;
static char counter=0; // AD计算次数
data0 = readl(base_addr+S3C2410_ADCDAT0);
data1 = readl(base_addr+S3C2410_ADCDAT1);
counter++;
xp+=(data1&0x3ff);
yp+=(data0&0x3ff);
if (counter>AD_COUNT)
{
xp=xp/AD_COUNT;
yp=yp/AD_COUNT;
writel(WAIT4INT(1), base_addr+S3C2410_ADCTSC);
//此处若不添加触摸笔抬起状态,只要触摸笔点击就会一直连续的计算坐标值,添加后就只计算5次
printk("<1> xp_average=%d,yp_average=%d,counter=%d\n",xp,yp,counter);
counter=0;
xp=0;
yp=0;
return IRQ_HANDLED;
}
printk("<1> xp=%d,yp=%d,\n",xp,yp);
Startad();
return IRQ_HANDLED;
}
int test_open(struct inode *inode, struct file *filp)
{
struct clk *clk;
clk=clk_get(NULL,"adc");
if(IS_ERR(clk)) panic("error to get adc clock\n");
clk_enable(clk);
try_module_get(THIS_MODULE);
printk(KERN_EMERG"device opening\n");
s3c2410_gpio_cfgpin(S3C2410_GPF4,S3C2410_GPIO_OUTPUT); // LED
s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_XMON);
s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPG13_nXPON);
s3c2410_gpio_cfgpin(S3C2410_GPG14, S3C2410_GPG14_YMON);
s3c2410_gpio_cfgpin(S3C2410_GPG15, S3C2410_GPG15_nYPON);
base_addr=ioremap(S3C2410_PA_ADC,0X100);
if (base_addr == NULL) {
printk(KERN_ERR "Failed to remap register block\n");
return -ENOMEM;
}
__raw_writel(1<<14|55<<6,base_addr+S3C2410_ADCCON); // prescale
__raw_writel(20000,base_addr+S3C2410_ADCDLY); // adcdly
writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC); // 设置updown=0,等待触摸笔点击状态
printk(KERN_EMERG"device opening over \n");
return 0; /* success */
}
int test_release(struct inode *inode, struct file *filp)
{
module_put(THIS_MODULE);
iounmap(base_addr);
printk(KERN_EMERG"device closeing now\n");
return 0;
}
/*
* Follow the list
*/
ssize_t test_read(struct file *filp, int __user *buf, size_t count,
loff_t *f_pos)
{
ssize_t retval = 0;
char b[5]={0};
if (down_interruptible(&sem))
return -ERESTARTSYS;
/*
if (copy_to_user(buf, &test_value, sizeof(test_value))) {
retval = -EFAULT;
printk("<1> read error");
goto out;
}
*/
retval = count;
printk(KERN_EMERG"device reading\n,b[0]=%d,b[1]=%d\n",b[0],b[1]);
out:
up(&sem);
return retval;
}
struct file_operations test_fops = {
.owner = THIS_MODULE,
.read = test_read,
.open = test_open,
.release = test_release,
};
/*
* Finally, the module stuff
*/
/*
* The cleanup function is used to handle initialization failures as well.
* Thefore, it must be careful to work correctly even if some of the items
* have not been initialized
*/
void test_cleanup_module(void)
{
dev_t devno = MKDEV(test_major, test_minor);
if (test_devices) {
cdev_del(test_devices);
}
free_irq(IRQ_TC,NULL);
free_irq(IRQ_ADC,NULL);
unregister_chrdev_region(devno, 1);
}
/*
* Set up the char_dev structure for this device.
*/
static void test_setup_cdev(struct cdev *dev, int index)
{
int err, devno = MKDEV(test_major, test_minor + index);
dev=cdev_alloc();
cdev_init(dev, &test_fops);
dev->owner = THIS_MODULE;
dev->ops = &test_fops;
err = cdev_add (dev, devno, 1);
if (err)
printk(KERN_NOTICE "Error %d adding test%d", err, index);
}
int test_init_module(void)
{
int result;
dev_t dev = 0;
if (test_major)
{
dev = MKDEV (test_major,test_minor);
result = register_chrdev_region(dev, 1, "test");
}
else
{
result = alloc_chrdev_region(&dev, test_minor, 1,
"test");
test_major = MAJOR(dev);
}
if (result < 0) {
printk(KERN_WARNING "test: can't get major %d\n", test_major);
return result;
}
init_MUTEX(&sem);
test_setup_cdev(test_devices, 0);
init_waitqueue_head(&mywait);
/* At this point call the init function for any friend device */
dev = MKDEV(test_major, test_minor);
printk("<1>hello,i am coming\n");
if (request_irq(IRQ_ADC, ad_action,IRQF_SAMPLE_RANDOM, "s3c2410_action", NULL))
{
printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC !\n");
iounmap(base_addr);
return -EIO;
}
if (request_irq(IRQ_TC, stylus_updown,IRQF_SAMPLE_RANDOM, "s3c2410_action", NULL))
{
printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !\n");
iounmap(base_addr);
return -EIO;
}
return 0; /* succeed */
fail:
test_cleanup_module();
return result;
}
module_init(test_init_module);
module_exit(test_cleanup_module);