]> rtime.felk.cvut.cz Git - mx1ts.git/commitdiff
Adding touchscreen driver source code into repository
authorRadek Pupák <pupakr1@fel.cvut.cz>
Sun, 27 Apr 2008 11:08:04 +0000 (13:08 +0200)
committerRadek Pupák <pupakr1@fel.cvut.cz>
Sun, 27 Apr 2008 11:08:04 +0000 (13:08 +0200)
mx1_ts-driver.c [new file with mode: 0644]

diff --git a/mx1_ts-driver.c b/mx1_ts-driver.c
new file mode 100644 (file)
index 0000000..2d4be95
--- /dev/null
@@ -0,0 +1,594 @@
+/*
+ *  MX1 touchscreen driver
+ *
+ *  Author:    Nicolas Pitre
+ *  Created:   September 25, 2006
+ *  Copyright: MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This code is heavily based on ucb1x00-*.c copyrighted by Russell King
+ * covering the UCB1100, UCB1200 and UCB1300..  Support for the UCB1400 has
+ * been made separate from ucb1x00-core/ucb1x00-ts on Russell's request.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/suspend.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/io.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/ac97_codec.h>
+
+#include <linux/gameport.h>            //bonus XXX
+
+#include <linux/platform_device.h>
+
+
+
+/*
+ * originaly from
+ * linux/drivers/misc/mx1ts.h
+ *
+ * Copyright (C) 2003 Blue Mug, Inc. for Motorola, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+/* Interrupt numbers */
+#define ASP_COMPARE_IRQ         5
+#define ASP_PENDATA_IRQ         33
+#define ASP_TOUCH_IRQ           46
+
+/* Analog signal processor (ASP) control registers */
+#define ASP_BASE_ADDR          0x00215000
+
+#define ASP_ACNTLCR            (0x10)     /* Control register */
+#define ASP_PSMPLRG            (0x14)     /* Pen A/D sampe rate control */
+#define ASP_CMPCNTL            (0x30)     /* Compare control register */
+#define ASP_ICNTLR             (0x18)     /* Interrupt control register */
+#define ASP_ISTATR             (0x1C)     /* Interrupt status register */
+#define ASP_PADFIFO            (0x00)     /* Pen sample FIFO */
+#define ASP_CLKDIV             (0x2C)     /* Clock divide register */
+
+/* ASP control register bits */
+#define ASP_CLKEN               (1 << 25)       /* Clock enable */
+#define ASP_SWRST               (1 << 23)       /* Software reset */
+#define ASP_U_SEL               (1 << 21)       /* U-channel resistor select */
+#define ASP_AZ_SEL              (1 << 20)       /* Auto-zero position select */
+#define ASP_LVM                 (1 << 19)       /* Low voltage output */
+#define ASP_NM                  (1 << 18)       /* Normal voltage output */
+#define ASP_HPM                 (1 << 17)       /* High voltage output */
+#define ASP_GLO                 (1 << 16)       /* Low gain enable */
+#define ASP_AZE                 (1 << 15)       /* Auto-zero enable */
+#define ASP_AUTO                (1 << 14)       /* Auto sampling */
+#define ASP_SW8                 (1 << 11)       /* Switch control 8 */
+#define ASP_SW7                 (1 << 10)
+#define ASP_SW6                 (1 << 9)
+#define ASP_SW5                 (1 << 8)
+#define ASP_SW4                 (1 << 7)
+#define ASP_SW3                 (1 << 6)
+#define ASP_SW2                 (1 << 5)
+#define ASP_SW1                 (1 << 4)        /* Switch control 1 */
+#define ASP_VDAE                (1 << 3)        /* Voice D/A enable */
+#define ASP_VADE                (1 << 2)        /* Voice A/D enable */
+#define ASP_PADE                (1 << 1)        /* Pen A/D enable */
+#define ASP_BGE                 (1 << 0)        /* Bandgap enable */
+
+#define ASP_MODE_MASK           0x00003000
+#define ASP_MODE_NONE           0x00000000
+#define ASP_MODE_ONLY_X         0x00001000
+#define ASP_MODE_ONLY_Y         0x00002000
+#define ASP_MODE_ONLY_U         0x00003000
+
+/* ASP Pen A/D sample rate control register */
+#define ASP_DMCNT_MASK          (0x00007000)    /* Decimation ratio count */
+#define ASP_DMCNT_SCALE         (12)
+#define ASP_BIT_SELECT_MASK     (0x00000C00)    /* Bit select */
+#define ASP_BIT_SELECT_SCALE    (10)
+#define ASP_IDLECNT_MASK        (0x000003F0)    /* Idle count */
+#define ASP_IDLECNT_SCALE       (4)
+#define ASP_DSCNT_MASK          (0x0000000F)    /* Data setup count */
+#define ASP_DSCNT_SCALE         (0)
+
+/* ASP compare control register */
+#define ASP_INT                 (1 << 19)       /* Interrupt status */
+#define ASP_CC                  (1 << 18)       /* Trigger on greater than */
+#define ASP_INSEL_MASK          (0x00030000)
+#define ASP_INSEL_DISABLE       (0x00000000)
+#define ASP_INSEL_X             (0x00010000)
+#define ASP_INSEL_Y             (0x00020000)
+#define ASP_INSEL_U             (0x00030000)
+#define ASP_COMPARE_VAL_MASK    (0x0000FFFF)
+#define ASP_COMPARE_VAL_SCALE   (0)
+
+/* ASP interrupt control register bits */
+#define ASP_PUIE                (1 << 10)       /* Pen up XXX undocumented */
+#define ASP_VDDMAE              (1 << 8)        /* VDAC FIFO empty DMA */
+#define ASP_VADMAE              (1 << 7)        /* VADC FIFO full DMA */
+#define ASP_POL                 (1 << 6)        /* Pen interrupt polarity */
+#define ASP_EDGE                (1 << 5)        /* Edge trigger enable */
+#define ASP_PIRQE               (1 << 4)        /* Pen interrupt enable */
+#define ASP_VDAFEE              (1 << 3)        /* VDAC FIFO empty interrupt */
+#define ASP_VADFFE              (1 << 2)        /* VADC FIFO full interrupt */
+#define ASP_PFFE                (1 << 1)        /* Pen FIFO full interrupt */
+#define ASP_PDRE                (1 << 0)        /* Pen data ready interrupt */
+
+/* ASP interrupt/error status register bits */
+#define ASP_PUIS                 (1 << 10)       /* Pen-up Status,event-> clear by 1 */
+#define ASP_BGR                 (1 << 9)        /* Bandgap ready */
+#define ASP_VOV                 (1 << 8)        /* Voice sample data overflow */
+#define ASP_POV                 (1 << 7)        /* Pen sample data overflow */
+#define ASP_PEN                 (1 << 6)        /* Pen interrupt */
+#define ASP_VDAFF               (1 << 5)        /* VDAC FIFO full */
+#define ASP_VDAFE               (1 << 4)        /* VDAC FIFO empty */
+#define ASP_VADFF               (1 << 3)        /* VADC FIFO full */
+#define ASP_VADDR               (1 << 2)        /* VADC data ready */
+#define ASP_PFF                 (1 << 1)        /* Pen sample FIFO full */
+#define ASP_PDR                 (1 << 0)        /* Pen data ready */
+
+/* ASP Clock divide register */
+#define ASP_PADC_CLK_MASK       (0x0000001F)
+#define ASP_PADC_CLK_SCALE      (0)
+#define ASP_VADC_CLK_MASK       (0x000003E0)
+#define ASP_VADC_CLK_SCALE      (5)
+#define ASP_VDAC_CLK_MASK       (0x00003C00)
+#define ASP_VDAC_CLK_SCALE      (10)
+
+#define DEV_IRQ_ID     "mx1-ts"
+
+struct mx1ts {
+       struct input_dev        *ts_idev;
+       struct resource         pamet;
+       int                     irq;
+
+       wait_queue_head_t       ts_wait;
+       struct task_struct      *ts_task;
+
+       unsigned int            irq_pending;    
+       unsigned int            ts_restart:1;
+       unsigned int            adcsync:1;
+       void __iomem*           mx1ts_mem;
+       
+       u16                     x_res;          
+       u16                     y_res;
+
+}; 
+
+
+struct mx1ts mx1_ts;
+
+static inline void mx1ts_reg_set_mask(struct mx1ts *mts , unsigned int reg, u32 mask)
+{      
+       u32 val;
+       val = __raw_readl(mts->mx1ts_mem+reg);
+       val |= mask;
+       __raw_writel(val, mts->mx1ts_mem+reg );
+}
+
+static inline void mx1ts_reg_write(struct mx1ts *mts, unsigned int reg, unsigned int val)
+{      
+       __raw_writel(val, mts->mx1ts_mem+reg);
+       printk("mx1_touchscreen: zapisuji do : %p  hodnotu %d\n",mts->mx1ts_mem+reg, val);
+       
+}
+
+static inline unsigned int mx1ts_reg_read(struct mx1ts *mts, unsigned int reg)
+{
+       unsigned int out;
+
+       out =  __raw_readl( mts->mx1ts_mem + reg );     
+       printk("mx1_touchscreen: ctu z %p : %d \n",mts->mx1ts_mem + reg, out);
+               
+       return out;
+}
+
+static irqreturn_t mx1ts_pendata_irq(int irq, void *dev_id)
+{
+       struct mx1_ts *mts = (struct mx1_ts *) dev_id;
+       printk("<1> mx1_touchscreen: mx1_pendata_irq interrupt recived from struct %p\n", mts);
+       
+       //mx1ts_reg_write(mts, ASP_ICNTLR , ASP_PUIE | /* ASP_EDGE |*/ ASP_PIRQE);
+
+       mx1ts_reg_set_mask(mts, ASP_ISTATR, ASP_PUIS);
+       
+       unsigned int data = mx1ts_reg_read(mts, ASP_PADFIFO);
+printk("<1> mx1_touchscreen: FIFO data %i\n", data);
+
+
+       static unsigned int auto_zero, pen_x, pen_y, pen_u;
+/*
+       if (mx1_reg_read(ASP_ISTATR) & 0x400) {
+               mx1_reg_set_bit(ASP_ISTATR, 0x400);
+
+               mx1ts_disable_auto_sample();
+               mx1ts_disable_pen_up_interrupt();
+               mx1ts_enable_pen_touch_interrupt();
+
+               mx1ts_evt_add(&mx1ts, 0, pen_x, pen_y);
+
+               mx1ts_flush_fifo();
+
+               return;
+       }
+
+       if (mx1_performing_auto_calibration) {
+               unsigned int value;
+
+               mx1_cal_auto_zero = mx1_reg_read(ASP_PADFIFO) & 0xFFFF;
+               mx1_cal_range_x = mx1_reg_read(ASP_PADFIFO) & 0xFFFF;
+               mx1_cal_range_y = mx1_reg_read(ASP_PADFIFO) & 0xFFFF;
+
+               if ((mx1_cal_auto_zero >= mx1_cal_range_x) ||
+                   (mx1_cal_auto_zero >= mx1_cal_range_y)) {
+                       // Invalid data. 
+                       mx1ts_start_auto_calibration();
+                       return;
+               }
+
+               mx1_cal_range_x -= mx1_cal_auto_zero;
+               mx1_cal_range_y -= mx1_cal_auto_zero;
+
+               value = mx1_reg_read(ASP_ACNTLCR);
+               value &= ~0x04000000; // Undocumented. 
+               mx1_reg_write(ASP_ACNTLCR, value);
+
+               mx1_performing_auto_calibration = 0;
+
+               mx1ts_enable_auto_sample();
+       } else {
+               // There could be more than one sample in the FIFO, but we're
+               // only going to read one per call. The interrupt will be
+               // generated as long as there is data in the FIFO. 
+
+               if ((mx1_reg_read(ASP_ISTATR) & ASP_PDR) != ASP_PDR) {
+                       return;
+               }
+
+               auto_zero = mx1_reg_read(ASP_PADFIFO);
+               if (auto_zero > (mx1_cal_auto_zero + 0x200)) {
+                       return;
+               }
+
+               pen_x = mx1_reg_read(ASP_PADFIFO);
+               pen_y = mx1_reg_read(ASP_PADFIFO);
+               pen_u = mx1_reg_read(ASP_PADFIFO);
+
+               pen_x = (u32)(((pen_x - mx1_cal_auto_zero) << 16) /
+                             mx1_cal_range_x);
+               pen_y = (u32)(((pen_y - mx1_cal_auto_zero) << 16) /
+                             mx1_cal_range_y);
+
+               mx1ts_evt_add(&mx1ts, pen_u, pen_x, pen_y);
+       }*/
+       return IRQ_HANDLED;
+}
+
+static void mx1ts_pokus_zapnout(struct mx1ts *mts) {
+       mx1ts_reg_write(mts, ASP_CLKDIV, 0x1F); //clok divide register
+       mx1ts_reg_write(mts, ASP_ICNTLR , ASP_PUIE | ASP_PDRE | ASP_PFFE |/* ASP_EDGE |*/ ASP_PIRQE);   //interupt control register //0X00000833
+       mx1ts_reg_write(mts, ASP_PSMPLRG, 0x0000487F);  //pen a/d sample rate control register 
+       mx1ts_reg_write(mts,ASP_ACNTLCR, ASP_CLKEN | ASP_AZE | ASP_AUTO | (10<<12) | 3);        //control register
+
+}
+
+static void mx1ts_enable_pen_up_irq(struct mx1ts *mts)
+{
+       unsigned int value;
+       printk(KERN_ERR "Pen up irq.\n");       
+
+       //value = mx1ts_reg_read(mts, ASP_ICNTLR);
+       //value |= ASP_PUIE;
+       //mx1ts_reg_write(mts, ASP_ICNTLR, value);
+       //printk(KERN_ERR "Mely probehnout nejake zapisy.\n");
+       //printk(KERN_ERR "Na adresu %i\n",ASP_ICNTLR );
+       //printk(KERN_ERR "Hodnota %i\n",value );
+}
+
+static irqreturn_t mx1ts_touch_irq(int irq, void *dev_id)
+{
+       struct mx1ts *mts = (struct mx1ts *) dev_id;
+       
+       /* Clear the interrupt. */
+       mx1ts_reg_set_mask(mts, ASP_ISTATR, ASP_PEN);
+
+//     mx1ts_disable_pen_touch_interrupt();
+//     mx1ts_start_auto_calibration();
+//     mx1ts_enable_pen_up_irq(mts);
+       return IRQ_HANDLED;
+}
+
+static inline int mx1ts_enable_irqs(struct mx1ts *mts) //zaregistruje preruseni
+{
+       int result;
+// int request_irq(unsigned int irq,  void (*handler)(int, struct pt_regs *),  unsigned long flags,  const char *device); 
+//static void mx1ts_pendata_int(int irq, void *dev_id, struct pt_regs *regs);
+//request_irq (irq, soc_intr, IRQF_SHARED, "SOC", (void *)s))
+       result = request_irq(ASP_PENDATA_IRQ,
+                            mx1ts_pendata_irq,
+                            /*IRQF_*/ 0,
+                            DEV_IRQ_ID,
+                            mts);
+       if (result) {
+               printk(KERN_ERR "Couldn't request pen data IRQ.\n");
+               return result;
+       }
+
+       result = request_irq(ASP_TOUCH_IRQ,
+                            mx1ts_touch_irq,
+                            /*IRQF_*/ 0,
+                            DEV_IRQ_ID,
+                            mts);
+       if (result) {
+               printk(KERN_ERR "Couldn't request pen touch IRQ.\n");
+               free_irq(ASP_PENDATA_IRQ, mts);
+               return result;
+       }
+       return result;
+}
+
+static void mx1ts_evt_add(struct input_dev *idev, u16 pressure, u16 x, u16 y)
+{
+       input_report_abs(idev, ABS_X, x);
+       input_report_abs(idev, ABS_Y, y);
+       input_report_abs(idev, ABS_PRESSURE, pressure);
+       input_sync(idev);
+}
+
+static int mx1ts_on(struct mx1ts *mts)
+{
+       int ret = 0;
+       int err;                //k check_region
+       
+       if(!request_mem_region(ASP_BASE_ADDR, 0x38 , "mx1ts")) {
+               printk(KERN_ERR "mx1ts: request_mem_region \tFAILED\n");        
+       }
+
+       printk("<1>mx1ts: request_mem_region \tOK\n");  
+
+       mts->mx1ts_mem = ioremap ( ASP_BASE_ADDR, 0x38);
+       
+       printk("<1>mx1ts: memory remaped on %p \n", mts->mx1ts_mem);
+       //mx1ts_reset_asp();
+
+       printk("<1>mx1ts: enabling irqs\n");
+       if ((ret = mx1ts_enable_irqs(mts)))
+               return ret;
+       printk("<1>mx1ts: irqs enabled \tOK\n");        
+
+       mx1ts_pokus_zapnout(mts);
+       printk("<1>mx1ts: vypada ze zapisy probehly\n");        
+
+       //mx1ts_evt_add(mts->ts_idev, 1, 2,3);
+
+       return 0;
+}
+
+static int mx1ts_close(struct platform_dev *dev)
+{
+       return 0;
+}
+
+static int mx1ts_open(struct platform_dev *dev)
+{
+       return 0;
+}
+
+static int mx1ts_probe(struct platform_device *dev)
+{
+               
+       //struct mx1ts *mts= &mx1_ts;
+       struct mx1ts *mts;              
+       struct input_dev *idev;
+       int error, id, x_res, y_res;
+
+//     mx1ts_disable_pen_touch_interrupt();
+//     mx1ts_start_auto_calibration();
+//     mx1ts_enable_pen_up_interrupt();
+
+       mts = kzalloc(sizeof(struct mx1ts), GFP_KERNEL);        //alokuje pamet
+       idev = input_allocate_device();                         
+       if (!mts || !idev) {
+               error = -ENOMEM;
+               goto err_free_devs;
+               return error;   //XXX
+       }
+       mx1_ts = *mts;
+
+       
+       mx1ts_on(mts);  
+       
+       return 0;
+
+       mts->ts_idev = idev;
+       //ucb->adcsync = adcsync;
+       //ucb->ac97 = to_ac97_t(dev);
+       init_waitqueue_head(&mts->ts_wait);
+
+/*     id = mx1ts_reg_read(ucb, UCB_ID);
+       if (id != UCB_ID_1400) {
+               error = -ENODEV;
+               goto err_free_devs;
+       }
+
+       error = mx1ts_detect_irq(ucb);
+       if (error) {
+               printk(KERN_ERR "UCB1400: IRQ probe failed\n");
+               goto err_free_devs;
+       }
+
+       error = request_irq(ucb->irq, mx1ts_hard_irq, IRQF_TRIGGER_RISING,
+                               "UCB1400", ucb);
+       if (error) {
+               printk(KERN_ERR "mx1ts: unable to grab irq%d: %d\n",
+                               ucb->irq, error);
+               goto err_free_devs;
+       }
+       printk(KERN_DEBUG "UCB1400: found IRQ %d\n", ucb->irq);*/
+
+//     input_set_drvdata(idev, mx1_ts);
+
+       idev->dev.parent        = &dev->dev;
+       idev->name              = "MX1 touchscreen interface";
+       idev->id.vendor         = (unsigned int) 345;//mx1ts_reg_read(mx1_ts, AC97_VENDOR_ID1);
+       idev->id.product        = id;
+       idev->open              = mx1ts_open;
+       idev->close             = mx1ts_close;
+       idev->evbit[0]          = BIT(EV_ABS); //BIT_MASK(EV_ABS);
+       //idev->bustype         = BUS_HOST;
+
+       printk("<1> mx1ts: setting idev struct \tOK\t");
+       
+/*     mx1ts_adc_enable(ucb);
+       x_res = mx1ts_read_xres(ucb);
+       y_res = mx1ts_read_yres(ucb);
+       mx1ts_adc_disable(ucb);
+       printk(KERN_DEBUG "UCB1400: x/y = %d/%d\n", x_res, y_res);*/
+
+       input_set_abs_params(idev, ABS_X, 0, x_res, 0, 0);
+       input_set_abs_params(idev, ABS_Y, 0, y_res, 0, 0);
+       input_set_abs_params(idev, ABS_PRESSURE, 0, 0, 0, 0);
+
+//     error = input_register_device(idev);
+//     if (error)
+//             goto err_free_irq;
+
+//     dev_set_drvdata(dev, ucb);
+       return 0;
+
+// err_free_irq:
+//     free_irq(ucb->irq, ucb);
+ err_free_devs:
+       input_free_device(idev);
+       kfree(mts);
+       return error;
+
+} 
+
+
+
+
+static int mx1ts_remove(struct platform_device *dev)
+{
+       struct mx1_ts *mts = &mx1_ts;
+       
+       release_mem_region(ASP_BASE_ADDR, 0x40);
+       iounmap(mx1_ts.mx1ts_mem);
+       free_irq(ASP_PENDATA_IRQ, mts);
+       free_irq(ASP_TOUCH_IRQ, mts);
+
+       //input_free_device(mts->ts_idev);
+       kfree(mts);
+
+       printk("<1> Removing driver \tOK\n");
+       return 0;
+}
+
+
+
+static int mx1ts_resume(struct platform_device *dev)
+{
+       return 0;
+}
+
+/* inicializace ovladace a driveru (insmod, rmmmod ) */
+
+static struct platform_driver mx1ts_driver = {
+       .probe = mx1ts_probe,
+       .remove = mx1ts_remove,
+       .resume = mx1ts_resume,
+       .driver = {
+               .name           = "mx1ts",
+               .owner          = THIS_MODULE,
+               },
+};
+
+static struct resource mx1ts_resources[] = {
+       [0] = {
+               .start  = ASP_BASE_ADDR + 0,
+               .end    = ASP_BASE_ADDR + 0x37,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = ASP_PENDATA_IRQ,
+               .end    = ASP_PENDATA_IRQ,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = ASP_TOUCH_IRQ,
+               .end    = ASP_TOUCH_IRQ,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mx1ts_device = {
+       .name           = "mx1ts",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(mx1ts_resources),
+       .resource       = mx1ts_resources,
+};
+
+
+
+
+static int __init mx1ts_init(void)
+{
+
+       int error;
+       error = platform_device_register(&mx1ts_device);
+       if(error) {
+               printk(KERN_ERR "PiMX1_touchsceen: device registration failed\n");
+               return error;
+       }
+
+
+       error = platform_driver_register(&mx1ts_driver);
+       if (error) {
+               printk(KERN_ERR "mx1_touchscreen: failed to register touchscreen driver, error: %d\n", error);
+               platform_device_unregister(&mx1ts_device);
+               return error;
+       }
+       
+               
+       return 0;
+       
+}
+
+static void __exit mx1ts_exit(void)
+{
+       platform_driver_unregister(&mx1ts_driver);              
+       platform_device_unregister(&mx1ts_device);
+       
+       return;
+}                           
+
+//module_param(adcsync, bool, 0444);
+//MODULE_PARM_DESC(adcsync, "Synchronize touch readings with ADCSYNC pin.");
+
+//module_param(ts_delay, int, 0444);
+//MODULE_PARM_DESC(ts_delay, "Delay between panel setup and position read. Default = 55us.");
+
+//module_param(ts_delay_pressure, int, 0444);
+//MODULE_PARM_DESC(ts_delay_pressure,
+//               "delay between panel setup and pressure read.  Default = 0us.");
+
+module_init(mx1ts_init);
+module_exit(mx1ts_exit);
+
+MODULE_DESCRIPTION("MX1 touchscreen driver");
+MODULE_LICENSE("GPL");