]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'tsc2007' into next
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Thu, 23 Feb 2017 17:22:10 +0000 (09:22 -0800)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Thu, 23 Feb 2017 17:22:10 +0000 (09:22 -0800)
Bring in TSC2007 improvements.

drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/tsc2007.h [new file with mode: 0644]
drivers/input/touchscreen/tsc2007_core.c [moved from drivers/input/touchscreen/tsc2007.c with 83% similarity]
drivers/input/touchscreen/tsc2007_iio.c [new file with mode: 0644]

index 574400ba1cb6c7407cfd0688475a7eef7c920565..6515e649e204d7723cd4fafd6beecbb19247bbcb 100644 (file)
@@ -1025,6 +1025,16 @@ config TOUCHSCREEN_TSC2007
          To compile this driver as a module, choose M here: the
          module will be called tsc2007.
 
+config TOUCHSCREEN_TSC2007_IIO
+       bool "IIO interface for external ADC input and temperature"
+       depends on TOUCHSCREEN_TSC2007
+       depends on IIO=y || IIO=TOUCHSCREEN_TSC2007
+       help
+         Saying Y here adds an iio interface to the tsc2007 which
+         provides values for the AUX input (used for e.g. battery
+         or ambient light monitoring), temperature and raw input
+         values.
+
 config TOUCHSCREEN_W90X900
        tristate "W90P910 touchscreen driver"
        depends on ARCH_W90X900
index b622e53441376a7261fe42b1f82598b0aeb3126a..ad5c896222bc6f72df5971c6fcc4856594971050 100644 (file)
@@ -79,6 +79,8 @@ obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO)   += tsc40.o
 obj-$(CONFIG_TOUCHSCREEN_TSC200X_CORE) += tsc200x-core.o
 obj-$(CONFIG_TOUCHSCREEN_TSC2004)      += tsc2004.o
 obj-$(CONFIG_TOUCHSCREEN_TSC2005)      += tsc2005.o
+tsc2007-y := tsc2007_core.o
+tsc2007-$(CONFIG_TOUCHSCREEN_TSC2007_IIO)      += tsc2007_iio.o
 obj-$(CONFIG_TOUCHSCREEN_TSC2007)      += tsc2007.o
 obj-$(CONFIG_TOUCHSCREEN_UCB1400)      += ucb1400_ts.o
 obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001)  += wacom_w8001.o
diff --git a/drivers/input/touchscreen/tsc2007.h b/drivers/input/touchscreen/tsc2007.h
new file mode 100644 (file)
index 0000000..30fdf5b
--- /dev/null
@@ -0,0 +1,101 @@
+
+/*
+ * Copyright (c) 2008 MtekVision Co., Ltd.
+ *     Kwangwoo Lee <kwlee@mtekvision.com>
+ *
+ * Using code from:
+ *  - ads7846.c
+ *     Copyright (c) 2005 David Brownell
+ *     Copyright (c) 2006 Nokia Corporation
+ *  - corgi_ts.c
+ *     Copyright (C) 2004-2005 Richard Purdie
+ *  - omap_ts.[hc], ads7846.h, ts_osk.c
+ *     Copyright (C) 2002 MontaVista Software
+ *     Copyright (C) 2004 Texas Instruments
+ *     Copyright (C) 2005 Dirk Behme
+ *
+ *  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.
+ */
+
+#ifndef _TSC2007_H
+#define _TSC2007_H
+
+#define TSC2007_MEASURE_TEMP0          (0x0 << 4)
+#define TSC2007_MEASURE_AUX            (0x2 << 4)
+#define TSC2007_MEASURE_TEMP1          (0x4 << 4)
+#define TSC2007_ACTIVATE_XN            (0x8 << 4)
+#define TSC2007_ACTIVATE_YN            (0x9 << 4)
+#define TSC2007_ACTIVATE_YP_XN         (0xa << 4)
+#define TSC2007_SETUP                  (0xb << 4)
+#define TSC2007_MEASURE_X              (0xc << 4)
+#define TSC2007_MEASURE_Y              (0xd << 4)
+#define TSC2007_MEASURE_Z1             (0xe << 4)
+#define TSC2007_MEASURE_Z2             (0xf << 4)
+
+#define TSC2007_POWER_OFF_IRQ_EN       (0x0 << 2)
+#define TSC2007_ADC_ON_IRQ_DIS0                (0x1 << 2)
+#define TSC2007_ADC_OFF_IRQ_EN         (0x2 << 2)
+#define TSC2007_ADC_ON_IRQ_DIS1                (0x3 << 2)
+
+#define TSC2007_12BIT                  (0x0 << 1)
+#define TSC2007_8BIT                   (0x1 << 1)
+
+#define MAX_12BIT                      ((1 << 12) - 1)
+
+#define ADC_ON_12BIT   (TSC2007_12BIT | TSC2007_ADC_ON_IRQ_DIS0)
+
+#define READ_Y         (ADC_ON_12BIT | TSC2007_MEASURE_Y)
+#define READ_Z1                (ADC_ON_12BIT | TSC2007_MEASURE_Z1)
+#define READ_Z2                (ADC_ON_12BIT | TSC2007_MEASURE_Z2)
+#define READ_X         (ADC_ON_12BIT | TSC2007_MEASURE_X)
+#define PWRDOWN                (TSC2007_12BIT | TSC2007_POWER_OFF_IRQ_EN)
+
+struct ts_event {
+       u16     x;
+       u16     y;
+       u16     z1, z2;
+};
+
+struct tsc2007 {
+       struct input_dev        *input;
+       char                    phys[32];
+
+       struct i2c_client       *client;
+
+       u16                     model;
+       u16                     x_plate_ohms;
+       u16                     max_rt;
+       unsigned long           poll_period; /* in jiffies */
+       int                     fuzzx;
+       int                     fuzzy;
+       int                     fuzzz;
+
+       unsigned int            gpio;
+       int                     irq;
+
+       wait_queue_head_t       wait;
+       bool                    stopped;
+
+       int                     (*get_pendown_state)(struct device *);
+       void                    (*clear_penirq)(void);
+
+       struct mutex            mlock;
+};
+
+int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd);
+u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc);
+bool tsc2007_is_pen_down(struct tsc2007 *ts);
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_TSC2007_IIO)
+/* defined in tsc2007_iio.c */
+int tsc2007_iio_configure(struct tsc2007 *ts);
+#else
+static inline int tsc2007_iio_configure(struct tsc2007 *ts)
+{
+       return 0;
+}
+#endif /* CONFIG_TOUCHSCREEN_TSC2007_IIO */
+
+#endif /* _TSC2007_H */
similarity index 83%
rename from drivers/input/touchscreen/tsc2007.c
rename to drivers/input/touchscreen/tsc2007_core.c
index 5d0cd51c6f41d126beef0e6e4bc7580288129cf6..fc7384936011dce48ba6d7c96d83bcc358409df8 100644 (file)
 #include <linux/i2c.h>
 #include <linux/i2c/tsc2007.h>
 #include <linux/of_device.h>
-#include <linux/of.h>
 #include <linux/of_gpio.h>
+#include "tsc2007.h"
 
-#define TSC2007_MEASURE_TEMP0          (0x0 << 4)
-#define TSC2007_MEASURE_AUX            (0x2 << 4)
-#define TSC2007_MEASURE_TEMP1          (0x4 << 4)
-#define TSC2007_ACTIVATE_XN            (0x8 << 4)
-#define TSC2007_ACTIVATE_YN            (0x9 << 4)
-#define TSC2007_ACTIVATE_YP_XN         (0xa << 4)
-#define TSC2007_SETUP                  (0xb << 4)
-#define TSC2007_MEASURE_X              (0xc << 4)
-#define TSC2007_MEASURE_Y              (0xd << 4)
-#define TSC2007_MEASURE_Z1             (0xe << 4)
-#define TSC2007_MEASURE_Z2             (0xf << 4)
-
-#define TSC2007_POWER_OFF_IRQ_EN       (0x0 << 2)
-#define TSC2007_ADC_ON_IRQ_DIS0                (0x1 << 2)
-#define TSC2007_ADC_OFF_IRQ_EN         (0x2 << 2)
-#define TSC2007_ADC_ON_IRQ_DIS1                (0x3 << 2)
-
-#define TSC2007_12BIT                  (0x0 << 1)
-#define TSC2007_8BIT                   (0x1 << 1)
-
-#define        MAX_12BIT                       ((1 << 12) - 1)
-
-#define ADC_ON_12BIT   (TSC2007_12BIT | TSC2007_ADC_ON_IRQ_DIS0)
-
-#define READ_Y         (ADC_ON_12BIT | TSC2007_MEASURE_Y)
-#define READ_Z1                (ADC_ON_12BIT | TSC2007_MEASURE_Z1)
-#define READ_Z2                (ADC_ON_12BIT | TSC2007_MEASURE_Z2)
-#define READ_X         (ADC_ON_12BIT | TSC2007_MEASURE_X)
-#define PWRDOWN                (TSC2007_12BIT | TSC2007_POWER_OFF_IRQ_EN)
-
-struct ts_event {
-       u16     x;
-       u16     y;
-       u16     z1, z2;
-};
-
-struct tsc2007 {
-       struct input_dev        *input;
-       char                    phys[32];
-
-       struct i2c_client       *client;
-
-       u16                     model;
-       u16                     x_plate_ohms;
-       u16                     max_rt;
-       unsigned long           poll_period; /* in jiffies */
-       int                     fuzzx;
-       int                     fuzzy;
-       int                     fuzzz;
-
-       unsigned                gpio;
-       int                     irq;
-
-       wait_queue_head_t       wait;
-       bool                    stopped;
-
-       int                     (*get_pendown_state)(struct device *);
-       void                    (*clear_penirq)(void);
-};
-
-static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
+int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
 {
        s32 data;
        u16 val;
@@ -128,7 +68,7 @@ static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
        tsc2007_xfer(tsc, PWRDOWN);
 }
 
-static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
+u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc)
 {
        u32 rt = 0;
 
@@ -137,7 +77,7 @@ static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
                tc->x = 0;
 
        if (likely(tc->x && tc->z1)) {
-               /* compute touch pressure resistance using equation #1 */
+               /* compute touch resistance using equation #1 */
                rt = tc->z2 - tc->z1;
                rt *= tc->x;
                rt *= tsc->x_plate_ohms;
@@ -148,7 +88,7 @@ static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
        return rt;
 }
 
-static bool tsc2007_is_pen_down(struct tsc2007 *ts)
+bool tsc2007_is_pen_down(struct tsc2007 *ts)
 {
        /*
         * NOTE: We can't rely on the pressure to determine the pen down
@@ -180,9 +120,12 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
        while (!ts->stopped && tsc2007_is_pen_down(ts)) {
 
                /* pen is down, continue with the measurement */
+
+               mutex_lock(&ts->mlock);
                tsc2007_read_values(ts, &tc);
+               mutex_unlock(&ts->mlock);
 
-               rt = tsc2007_calculate_pressure(ts, &tc);
+               rt = tsc2007_calculate_resistance(ts, &tc);
 
                if (!rt && !ts->get_pendown_state) {
                        /*
@@ -195,9 +138,11 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
 
                if (rt <= ts->max_rt) {
                        dev_dbg(&ts->client->dev,
-                               "DOWN point(%4d,%4d), pressure (%4u)\n",
+                               "DOWN point(%4d,%4d), resistance (%4u)\n",
                                tc.x, tc.y, rt);
 
+                       rt = ts->max_rt - rt;
+
                        input_report_key(input, BTN_TOUCH, 1);
                        input_report_abs(input, ABS_X, tc.x);
                        input_report_abs(input, ABS_Y, tc.y);
@@ -375,7 +320,8 @@ static void tsc2007_call_exit_platform_hw(void *data)
 static int tsc2007_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
-       const struct tsc2007_platform_data *pdata = dev_get_platdata(&client->dev);
+       const struct tsc2007_platform_data *pdata =
+               dev_get_platdata(&client->dev);
        struct tsc2007 *ts;
        struct input_dev *input_dev;
        int err;
@@ -404,7 +350,9 @@ static int tsc2007_probe(struct i2c_client *client,
        ts->client = client;
        ts->irq = client->irq;
        ts->input = input_dev;
+
        init_waitqueue_head(&ts->wait);
+       mutex_init(&ts->mlock);
 
        snprintf(ts->phys, sizeof(ts->phys),
                 "%s/input0", dev_name(&client->dev));
@@ -418,8 +366,7 @@ static int tsc2007_probe(struct i2c_client *client,
 
        input_set_drvdata(input_dev, ts);
 
-       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-       input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+       input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
 
        input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0);
        input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0);
@@ -455,6 +402,14 @@ static int tsc2007_probe(struct i2c_client *client,
 
        tsc2007_stop(ts);
 
+       /* power down the chip (TSC2007_SETUP does not ACK on I2C) */
+       err = tsc2007_xfer(ts, PWRDOWN);
+       if (err < 0) {
+               dev_err(&client->dev,
+                       "Failed to setup chip: %d\n", err);
+               return err;     /* chip does not respond */
+       }
+
        err = input_register_device(input_dev);
        if (err) {
                dev_err(&client->dev,
@@ -462,6 +417,13 @@ static int tsc2007_probe(struct i2c_client *client,
                return err;
        }
 
+       err =  tsc2007_iio_configure(ts);
+       if (err) {
+               dev_err(&client->dev,
+                       "Failed to register with IIO: %d\n", err);
+               return err;
+       }
+
        return 0;
 }
 
diff --git a/drivers/input/touchscreen/tsc2007_iio.c b/drivers/input/touchscreen/tsc2007_iio.c
new file mode 100644 (file)
index 0000000..27b25a9
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2016 Golden Delicious Comp. GmbH&Co. KG
+ *     Nikolaus Schaller <hns@goldelico.com>
+ *
+ *  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.
+ */
+
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include "tsc2007.h"
+
+struct tsc2007_iio {
+       struct tsc2007 *ts;
+};
+
+#define TSC2007_CHAN_IIO(_chan, _name, _type, _chan_info) \
+{ \
+       .datasheet_name = _name, \
+       .type = _type, \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |  \
+                       BIT(_chan_info), \
+       .indexed = 1, \
+       .channel = _chan, \
+}
+
+static const struct iio_chan_spec tsc2007_iio_channel[] = {
+       TSC2007_CHAN_IIO(0, "x", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
+       TSC2007_CHAN_IIO(1, "y", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
+       TSC2007_CHAN_IIO(2, "z1", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
+       TSC2007_CHAN_IIO(3, "z2", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
+       TSC2007_CHAN_IIO(4, "adc", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
+       TSC2007_CHAN_IIO(5, "rt", IIO_VOLTAGE, IIO_CHAN_INFO_RAW), /* Ohms? */
+       TSC2007_CHAN_IIO(6, "pen", IIO_PRESSURE, IIO_CHAN_INFO_RAW),
+       TSC2007_CHAN_IIO(7, "temp0", IIO_TEMP, IIO_CHAN_INFO_RAW),
+       TSC2007_CHAN_IIO(8, "temp1", IIO_TEMP, IIO_CHAN_INFO_RAW),
+};
+
+static int tsc2007_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int *val, int *val2, long mask)
+{
+       struct tsc2007_iio *iio = iio_priv(indio_dev);
+       struct tsc2007 *tsc = iio->ts;
+       int adc_chan = chan->channel;
+       int ret = 0;
+
+       if (adc_chan >= ARRAY_SIZE(tsc2007_iio_channel))
+               return -EINVAL;
+
+       if (mask != IIO_CHAN_INFO_RAW)
+               return -EINVAL;
+
+       mutex_lock(&tsc->mlock);
+
+       switch (chan->channel) {
+       case 0:
+               *val = tsc2007_xfer(tsc, READ_X);
+               break;
+       case 1:
+               *val = tsc2007_xfer(tsc, READ_Y);
+               break;
+       case 2:
+               *val = tsc2007_xfer(tsc, READ_Z1);
+               break;
+       case 3:
+               *val = tsc2007_xfer(tsc, READ_Z2);
+               break;
+       case 4:
+               *val = tsc2007_xfer(tsc, (ADC_ON_12BIT | TSC2007_MEASURE_AUX));
+               break;
+       case 5: {
+               struct ts_event tc;
+
+               tc.x = tsc2007_xfer(tsc, READ_X);
+               tc.z1 = tsc2007_xfer(tsc, READ_Z1);
+               tc.z2 = tsc2007_xfer(tsc, READ_Z2);
+               *val = tsc2007_calculate_resistance(tsc, &tc);
+               break;
+       }
+       case 6:
+               *val = tsc2007_is_pen_down(tsc);
+               break;
+       case 7:
+               *val = tsc2007_xfer(tsc,
+                                   (ADC_ON_12BIT | TSC2007_MEASURE_TEMP0));
+               break;
+       case 8:
+               *val = tsc2007_xfer(tsc,
+                                   (ADC_ON_12BIT | TSC2007_MEASURE_TEMP1));
+               break;
+       }
+
+       /* Prepare for next touch reading - power down ADC, enable PENIRQ */
+       tsc2007_xfer(tsc, PWRDOWN);
+
+       mutex_unlock(&tsc->mlock);
+
+       ret = IIO_VAL_INT;
+
+       return ret;
+}
+
+static const struct iio_info tsc2007_iio_info = {
+       .read_raw = tsc2007_read_raw,
+       .driver_module = THIS_MODULE,
+};
+
+int tsc2007_iio_configure(struct tsc2007 *ts)
+{
+       struct iio_dev *indio_dev;
+       struct tsc2007_iio *iio;
+       int error;
+
+       indio_dev = devm_iio_device_alloc(&ts->client->dev, sizeof(*iio));
+       if (!indio_dev) {
+               dev_err(&ts->client->dev, "iio_device_alloc failed\n");
+               return -ENOMEM;
+       }
+
+       iio = iio_priv(indio_dev);
+       iio->ts = ts;
+
+       indio_dev->name = "tsc2007";
+       indio_dev->dev.parent = &ts->client->dev;
+       indio_dev->info = &tsc2007_iio_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->channels = tsc2007_iio_channel;
+       indio_dev->num_channels = ARRAY_SIZE(tsc2007_iio_channel);
+
+       error = devm_iio_device_register(&ts->client->dev, indio_dev);
+       if (error) {
+               dev_err(&ts->client->dev,
+                       "iio_device_register() failed: %d\n", error);
+               return error;
+       }
+
+       return 0;
+}