From 8098ff1bb2230ee8326c61ddfabace633b9319d2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Radek=20Pup=C3=A1k?= Date: Sun, 27 Apr 2008 13:08:04 +0200 Subject: [PATCH 1/1] Adding touchscreen driver source code into repository --- mx1_ts-driver.c | 594 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 594 insertions(+) create mode 100644 mx1_ts-driver.c diff --git a/mx1_ts-driver.c b/mx1_ts-driver.c new file mode 100644 index 0000000..2d4be95 --- /dev/null +++ b/mx1_ts-driver.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include //bonus XXX + +#include + + + +/* + * 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"); -- 2.39.2