Merge tag 'mfd-3.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd...
[pandora-kernel.git] / drivers / input / touchscreen / ti_am335x_tsc.c
index 449c0fb..e1c5300 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/input/ti_am335x_tsc.h>
 #include <linux/delay.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -121,11 +120,9 @@ static int titsc_config_wires(struct titsc *ts_dev)
 static void titsc_step_config(struct titsc *ts_dev)
 {
        unsigned int    config;
-       unsigned int    stepenable = 0;
-       int i, total_steps;
-
-       /* Configure the Step registers */
-       total_steps = 2 * ts_dev->coordinate_readouts;
+       int i;
+       int end_step;
+       u32 stepenable;
 
        config = STEPCONFIG_MODE_HWSYNC |
                        STEPCONFIG_AVG_16 | ts_dev->bit_xp;
@@ -143,7 +140,9 @@ static void titsc_step_config(struct titsc *ts_dev)
                break;
        }
 
-       for (i = 1; i <= ts_dev->coordinate_readouts; i++) {
+       /* 1 … coordinate_readouts is for X */
+       end_step = ts_dev->coordinate_readouts;
+       for (i = 0; i < end_step; i++) {
                titsc_writel(ts_dev, REG_STEPCONFIG(i), config);
                titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
        }
@@ -151,7 +150,7 @@ static void titsc_step_config(struct titsc *ts_dev)
        config = 0;
        config = STEPCONFIG_MODE_HWSYNC |
                        STEPCONFIG_AVG_16 | ts_dev->bit_yn |
-                       STEPCONFIG_INM_ADCREFM | STEPCONFIG_FIFO1;
+                       STEPCONFIG_INM_ADCREFM;
        switch (ts_dev->wires) {
        case 4:
                config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp);
@@ -165,12 +164,13 @@ static void titsc_step_config(struct titsc *ts_dev)
                break;
        }
 
-       for (i = (ts_dev->coordinate_readouts + 1); i <= total_steps; i++) {
+       /* coordinate_readouts … coordinate_readouts * 2 is for Y */
+       end_step = ts_dev->coordinate_readouts * 2;
+       for (i = ts_dev->coordinate_readouts; i < end_step; i++) {
                titsc_writel(ts_dev, REG_STEPCONFIG(i), config);
                titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
        }
 
-       config = 0;
        /* Charge step configuration */
        config = ts_dev->bit_xp | ts_dev->bit_yn |
                        STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR |
@@ -179,35 +179,39 @@ static void titsc_step_config(struct titsc *ts_dev)
        titsc_writel(ts_dev, REG_CHARGECONFIG, config);
        titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY);
 
-       config = 0;
-       /* Configure to calculate pressure */
+       /* coordinate_readouts * 2 … coordinate_readouts * 2 + 2 is for Z */
        config = STEPCONFIG_MODE_HWSYNC |
                        STEPCONFIG_AVG_16 | ts_dev->bit_yp |
                        ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM |
                        STEPCONFIG_INP(ts_dev->inp_xp);
-       titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 1), config);
-       titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 1),
+       titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config);
+       titsc_writel(ts_dev, REG_STEPDELAY(end_step),
                        STEPCONFIG_OPENDLY);
 
-       config |= STEPCONFIG_INP(ts_dev->inp_yn) | STEPCONFIG_FIFO1;
-       titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 2), config);
-       titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 2),
+       end_step++;
+       config |= STEPCONFIG_INP(ts_dev->inp_yn);
+       titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config);
+       titsc_writel(ts_dev, REG_STEPDELAY(end_step),
                        STEPCONFIG_OPENDLY);
 
        /* The steps1 … end and bit 0 for TS_Charge */
-       stepenable = (1 << (total_steps + 2)) - 1;
+       stepenable = (1 << (end_step + 2)) - 1;
        am335x_tsc_se_set(ts_dev->mfd_tscadc, stepenable);
 }
 
 static void titsc_read_coordinates(struct titsc *ts_dev,
-                                   unsigned int *x, unsigned int *y)
+               u32 *x, u32 *y, u32 *z1, u32 *z2)
 {
        unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT);
        unsigned int prev_val_x = ~0, prev_val_y = ~0;
        unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
        unsigned int read, diff;
        unsigned int i, channel;
+       unsigned int creads = ts_dev->coordinate_readouts;
 
+       *z1 = *z2 = 0;
+       if (fifocount % (creads * 2 + 2))
+               fifocount -= fifocount % (creads * 2 + 2);
        /*
         * Delta filter is used to remove large variations in sampled
         * values from ADC. The filter tries to predict where the next
@@ -216,32 +220,32 @@ static void titsc_read_coordinates(struct titsc *ts_dev,
         * algorithm compares the difference with that of a present value,
         * if true the value is reported to the sub system.
         */
-       for (i = 0; i < fifocount - 1; i++) {
+       for (i = 0; i < fifocount; i++) {
                read = titsc_readl(ts_dev, REG_FIFO0);
-               channel = read & 0xf0000;
-               channel = channel >> 0x10;
-               if ((channel >= 0) && (channel < ts_dev->coordinate_readouts)) {
-                       read &= 0xfff;
+
+               channel = (read & 0xf0000) >> 16;
+               read &= 0xfff;
+               if (channel < creads) {
                        diff = abs(read - prev_val_x);
                        if (diff < prev_diff_x) {
                                prev_diff_x = diff;
                                *x = read;
                        }
                        prev_val_x = read;
-               }
 
-               read = titsc_readl(ts_dev, REG_FIFO1);
-               channel = read & 0xf0000;
-               channel = channel >> 0x10;
-               if ((channel >= ts_dev->coordinate_readouts) &&
-                       (channel < (2 * ts_dev->coordinate_readouts - 1))) {
-                       read &= 0xfff;
+               } else if (channel < creads * 2) {
                        diff = abs(read - prev_val_y);
                        if (diff < prev_diff_y) {
                                prev_diff_y = diff;
                                *y = read;
                        }
                        prev_val_y = read;
+
+               } else if (channel < creads * 2 + 1) {
+                       *z1 = read;
+
+               } else if (channel < creads * 2 + 2) {
+                       *z2 = read;
                }
        }
 }
@@ -257,10 +261,8 @@ static irqreturn_t titsc_irq(int irq, void *dev)
 
        status = titsc_readl(ts_dev, REG_IRQSTATUS);
        if (status & IRQENB_FIFO0THRES) {
-               titsc_read_coordinates(ts_dev, &x, &y);
 
-               z1 = titsc_readl(ts_dev, REG_FIFO0) & 0xfff;
-               z2 = titsc_readl(ts_dev, REG_FIFO1) & 0xfff;
+               titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2);
 
                if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
                        /*
@@ -268,10 +270,10 @@ static irqreturn_t titsc_irq(int irq, void *dev)
                         * Resistance(touch) = x plate resistance *
                         * x postion/4096 * ((z2 / z1) - 1)
                         */
-                       z = z2 - z1;
+                       z = z1 - z2;
                        z *= x;
                        z *= ts_dev->x_plate_resistance;
-                       z /= z1;
+                       z /= z2;
                        z = (z + 2047) >> 12;
 
                        if (z <= MAX_12BIT) {
@@ -306,10 +308,18 @@ static irqreturn_t titsc_irq(int irq, void *dev)
                irqclr |= IRQENB_PENUP;
        }
 
-       titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
+       if (status & IRQENB_HW_PEN) {
 
-       am335x_tsc_se_update(ts_dev->mfd_tscadc);
-       return IRQ_HANDLED;
+               titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00);
+               titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN);
+       }
+
+       if (irqclr) {
+               titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
+               am335x_tsc_se_update(ts_dev->mfd_tscadc);
+               return IRQ_HANDLED;
+       }
+       return IRQ_NONE;
 }
 
 static int titsc_parse_dt(struct platform_device *pdev,
@@ -347,24 +357,6 @@ static int titsc_parse_dt(struct platform_device *pdev,
                        ts_dev->config_inp, ARRAY_SIZE(ts_dev->config_inp));
 }
 
-static int titsc_parse_pdata(struct ti_tscadc_dev *tscadc_dev,
-                                       struct titsc *ts_dev)
-{
-       struct mfd_tscadc_board *pdata = tscadc_dev->dev->platform_data;
-
-       if (!pdata)
-               return -EINVAL;
-
-       ts_dev->wires = pdata->tsc_init->wires;
-       ts_dev->x_plate_resistance =
-               pdata->tsc_init->x_plate_resistance;
-       ts_dev->steps_to_configure =
-               pdata->tsc_init->steps_to_configure;
-       memcpy(ts_dev->config_inp, pdata->tsc_init->wire_config,
-               sizeof(pdata->tsc_init->wire_config));
-       return 0;
-}
-
 /*
  * The functions for inserting/removing driver as a module.
  */
@@ -390,11 +382,7 @@ static int titsc_probe(struct platform_device *pdev)
        ts_dev->input = input_dev;
        ts_dev->irq = tscadc_dev->irq;
 
-       if (tscadc_dev->dev->platform_data)
-               err = titsc_parse_pdata(tscadc_dev, ts_dev);
-       else
-               err = titsc_parse_dt(pdev, ts_dev);
-
+       err = titsc_parse_dt(pdev, ts_dev);
        if (err) {
                dev_err(&pdev->dev, "Could not find valid DT data.\n");
                goto err_free_mem;
@@ -414,7 +402,8 @@ static int titsc_probe(struct platform_device *pdev)
                goto err_free_irq;
        }
        titsc_step_config(ts_dev);
-       titsc_writel(ts_dev, REG_FIFO0THR, ts_dev->coordinate_readouts);
+       titsc_writel(ts_dev, REG_FIFO0THR,
+                       ts_dev->coordinate_readouts * 2 + 2 - 1);
 
        input_dev->name = "ti-tsc";
        input_dev->dev.parent = &pdev->dev;
@@ -456,7 +445,6 @@ static int titsc_remove(struct platform_device *pdev)
 
        input_unregister_device(ts_dev->input);
 
-       platform_set_drvdata(pdev, NULL);
        kfree(ts_dev);
        return 0;
 }
@@ -491,7 +479,7 @@ static int titsc_resume(struct device *dev)
        }
        titsc_step_config(ts_dev);
        titsc_writel(ts_dev, REG_FIFO0THR,
-                       ts_dev->coordinate_readouts);
+                       ts_dev->coordinate_readouts * 2 + 2 - 1);
        return 0;
 }
 
@@ -514,7 +502,7 @@ static struct platform_driver ti_tsc_driver = {
        .probe  = titsc_probe,
        .remove = titsc_remove,
        .driver = {
-               .name   = "tsc",
+               .name   = "TI-am335x-tsc",
                .owner  = THIS_MODULE,
                .pm     = TITSC_PM_OPS,
                .of_match_table = of_match_ptr(ti_tsc_dt_ids),