Input: uinput - mark as non-seekable
[safe/jmp/linux-2.6] / drivers / input / touchscreen / atmel_tsadcc.c
index eee126b..3d9b516 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <mach/board.h>
+#include <mach/cpu.h>
 
 /* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */
 
@@ -36,7 +38,9 @@
 #define          ATMEL_TSADCC_LOWRES   (1    <<  4)    /* Resolution selection */
 #define          ATMEL_TSADCC_SLEEP    (1    <<  5)    /* Sleep mode */
 #define          ATMEL_TSADCC_PENDET   (1    <<  6)    /* Pen Detect selection */
+#define          ATMEL_TSADCC_PRES     (1    <<  7)    /* Pressure Measurement Selection */
 #define          ATMEL_TSADCC_PRESCAL  (0x3f <<  8)    /* Prescalar Rate Selection */
+#define          ATMEL_TSADCC_EPRESCAL (0xff <<  8)    /* Prescalar Rate Selection (Extended) */
 #define          ATMEL_TSADCC_STARTUP  (0x7f << 16)    /* Start Up time */
 #define          ATMEL_TSADCC_SHTIM    (0xf  << 24)    /* Sample & Hold time */
 #define          ATMEL_TSADCC_PENDBC   (0xf  << 28)    /* Pen Detect debouncing time */
 #define ATMEL_TSADCC_CDR4      0x40    /* Channel Data 4 */
 #define ATMEL_TSADCC_CDR5      0x44    /* Channel Data 5 */
 
-#define ADC_CLOCK      1000000
+#define ATMEL_TSADCC_XPOS      0x50
+#define ATMEL_TSADCC_Z1DAT     0x54
+#define ATMEL_TSADCC_Z2DAT     0x58
+
+#define PRESCALER_VAL(x)       ((x) >> 8)
+
+#define ADC_DEFAULT_CLOCK      100000
 
 struct atmel_tsadcc {
        struct input_dev        *input;
        char                    phys[32];
        struct clk              *clk;
        int                     irq;
+       unsigned int            prev_absx;
+       unsigned int            prev_absy;
+       unsigned char           bufferedmeasure;
 };
 
 static void __iomem            *tsc_base;
@@ -100,10 +113,9 @@ static void __iomem                *tsc_base;
 
 static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
 {
-       struct input_dev *input_dev = ((struct atmel_tsadcc *)dev)->input;
+       struct atmel_tsadcc     *ts_dev = (struct atmel_tsadcc *)dev;
+       struct input_dev        *input_dev = ts_dev->input;
 
-       unsigned int absx;
-       unsigned int absy;
        unsigned int status;
        unsigned int reg;
 
@@ -121,6 +133,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
                atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
 
                input_report_key(input_dev, BTN_TOUCH, 0);
+               ts_dev->bufferedmeasure = 0;
                input_sync(input_dev);
 
        } else if (status & ATMEL_TSADCC_PENCNT) {
@@ -138,16 +151,23 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
        } else if (status & ATMEL_TSADCC_EOC(3)) {
                /* Conversion finished */
 
-               absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
-               absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
-
-               absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
-               absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
-
-               input_report_abs(input_dev, ABS_X, absx);
-               input_report_abs(input_dev, ABS_Y, absy);
-               input_report_key(input_dev, BTN_TOUCH, 1);
-               input_sync(input_dev);
+               if (ts_dev->bufferedmeasure) {
+                       /* Last measurement is always discarded, since it can
+                        * be erroneous.
+                        * Always report previous measurement */
+                       input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
+                       input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
+                       input_report_key(input_dev, BTN_TOUCH, 1);
+                       input_sync(input_dev);
+               } else
+                       ts_dev->bufferedmeasure = 1;
+
+               /* Now make new measurement */
+               ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
+               ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
+
+               ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
+               ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
        }
 
        return IRQ_HANDLED;
@@ -162,6 +182,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
        struct atmel_tsadcc     *ts_dev;
        struct input_dev        *input_dev;
        struct resource         *res;
+       struct at91_tsadcc_data *pdata = pdev->dev.platform_data;
        int             err = 0;
        unsigned int    prsc;
        unsigned int    reg;
@@ -194,14 +215,14 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
                goto err_free_dev;
        }
 
-       if (!request_mem_region(res->start, res->end - res->start + 1,
+       if (!request_mem_region(res->start, resource_size(res),
                                "atmel tsadcc regs")) {
                dev_err(&pdev->dev, "resources is unavailable.\n");
                err = -EBUSY;
                goto err_free_dev;
        }
 
-       tsc_base = ioremap(res->start, res->end - res->start + 1);
+       tsc_base = ioremap(res->start, resource_size(res));
        if (!tsc_base) {
                dev_err(&pdev->dev, "failed to map registers.\n");
                err = -ENOMEM;
@@ -223,39 +244,58 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
        }
 
        ts_dev->input = input_dev;
+       ts_dev->bufferedmeasure = 0;
 
        snprintf(ts_dev->phys, sizeof(ts_dev->phys),
-                "%s/input0", pdev->dev.bus_id);
+                "%s/input0", dev_name(&pdev->dev));
 
        input_dev->name = "atmel touch screen controller";
        input_dev->phys = ts_dev->phys;
        input_dev->dev.parent = &pdev->dev;
 
-       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-       input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
-
+       __set_bit(EV_ABS, input_dev->evbit);
        input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0);
        input_set_abs_params(input_dev, ABS_Y, 0, 0x3FF, 0, 0);
 
+       input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
+
        /* clk_enable() always returns 0, no need to check it */
        clk_enable(ts_dev->clk);
 
        prsc = clk_get_rate(ts_dev->clk);
        dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc);
 
-       prsc = prsc / ADC_CLOCK / 2 - 1;
+       if (!pdata)
+               goto err_fail;
+
+       if (!pdata->adc_clock)
+               pdata->adc_clock = ADC_DEFAULT_CLOCK;
+
+       prsc = (prsc / (2 * pdata->adc_clock)) - 1;
+
+       /* saturate if this value is too high */
+       if (cpu_is_at91sam9rl()) {
+               if (prsc > PRESCALER_VAL(ATMEL_TSADCC_PRESCAL))
+                       prsc = PRESCALER_VAL(ATMEL_TSADCC_PRESCAL);
+       } else {
+               if (prsc > PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL))
+                       prsc = PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL);
+       }
+
+       dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc);
 
        reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE          |
                ((0x00 << 5) & ATMEL_TSADCC_SLEEP)      |       /* Normal Mode */
                ((0x01 << 6) & ATMEL_TSADCC_PENDET)     |       /* Enable Pen Detect */
-               ((prsc << 8) & ATMEL_TSADCC_PRESCAL)    |       /* PRESCAL */
-               ((0x13 << 16) & ATMEL_TSADCC_STARTUP)   |       /* STARTUP */
-               ((0x0F << 28) & ATMEL_TSADCC_PENDBC);           /* PENDBC */
+               (prsc << 8)                             |
+               ((0x26 << 16) & ATMEL_TSADCC_STARTUP)   |
+               ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC);
 
        atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST);
        atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
        atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE);
-       atmel_tsadcc_write(ATMEL_TSADCC_TSR, (0x3 << 24) & ATMEL_TSADCC_TSSHTIM);
+       atmel_tsadcc_write(ATMEL_TSADCC_TSR,
+               (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);
 
        atmel_tsadcc_read(ATMEL_TSADCC_SR);
        atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
@@ -275,7 +315,7 @@ err_free_irq:
 err_unmap_regs:
        iounmap(tsc_base);
 err_release_mem:
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 err_free_dev:
        input_free_device(ts_dev->input);
 err_free_mem:
@@ -294,7 +334,7 @@ static int __devexit atmel_tsadcc_remove(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        iounmap(tsc_base);
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 
        clk_disable(ts_dev->clk);
        clk_put(ts_dev->clk);