--- /dev/null
+/*
+ * 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");