Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1520241 > unrolled thread
| Started by | Jonathan Cameron <jic23@kernel.org> |
|---|---|
| First post | 2016-11-12 15:10 +0100 |
| Last post | 2016-11-19 21:20 +0100 |
| Articles | 5 — 4 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: [PATCH v7 4/9] drivers:input:tsc2007: add iio interface to read external ADC input and temperature Jonathan Cameron <jic23@kernel.org> - 2016-11-12 15:10 +0100
Re: [PATCH v7 4/9] drivers:input:tsc2007: add iio interface to read external ADC input and temperature Jonathan Cameron <jic23@kernel.org> - 2016-11-12 15:20 +0100
Re: [PATCH v7 4/9] drivers:input:tsc2007: add iio interface to read external ADC input and temperature "H. Nikolaus Schaller" <hns@goldelico.com> - 2016-11-12 20:30 +0100
Re: [PATCH v7 4/9] drivers:input:tsc2007: add iio interface to read external ADC input and temperature Dmitry Torokhov <dmitry.torokhov@gmail.com> - 2016-11-19 19:40 +0100
Re: [PATCH v7 4/9] drivers:input:tsc2007: add iio interface to read external ADC input and temperature Jonathan Cameron <jic23@jic23.retrosnub.co.uk> - 2016-11-19 21:20 +0100
| From | Jonathan Cameron <jic23@kernel.org> |
|---|---|
| Date | 2016-11-12 15:10 +0100 |
| Subject | Re: [PATCH v7 4/9] drivers:input:tsc2007: add iio interface to read external ADC input and temperature |
| Message-ID | <sCHah-35Y-15@gated-at.bofh.it> |
On 11/11/16 19:02, H. Nikolaus Schaller wrote:
> The tsc2007 chip not only has a resistive touch screen controller but
> also an external AUX adc imput which can be used for an ambient
> light sensor, battery voltage monitoring or any general purpose.
>
> Additionally it can measure the chip temperature.
>
> This extension provides an iio interface for these adc channels.
>
> Since it is not wasting much resources and is very straightforward,
> we simply provide all other adc channels as optional iio interfaces
> as weel. This can be used for debugging or special applications.
>
> This patch also splits the tsc2007 driver in several source files:
> tsc2007.h -- constants, structs and stubs
> tsc2007_core.c -- functional parts of the original driver
> tsc2007_iio.c -- the optional iio stuff
>
> Makefile magic allows to conditionally link the iio
> stuff if CONFIG_IIO=y in a way that it works with
> CONFIG_TOUCHSCREEN_TSC2007=m.
>
I ran a quick build test and it blows up in a number of ways related to
the #ifdef CONFIG_IIO.
I'm not entirely sure why but
#if IS_ENABLED(CONFIG_IIO) works fine.
Otherwise looks good to me
> Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
Reviewed-by: Jonathan Cameron <jic23@kernel.org>
> ---
> drivers/input/touchscreen/Makefile | 2 +
> drivers/input/touchscreen/tsc2007.h | 118 ++++++++++++++++
> .../touchscreen/{tsc2007.c => tsc2007_core.c} | 119 ++++++----------
> drivers/input/touchscreen/tsc2007_iio.c | 152 +++++++++++++++++++++
> 4 files changed, 310 insertions(+), 81 deletions(-)
> create mode 100644 drivers/input/touchscreen/tsc2007.h
> rename drivers/input/touchscreen/{tsc2007.c => tsc2007_core.c} (85%)
> create mode 100644 drivers/input/touchscreen/tsc2007_iio.c
>
> diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
> index 81b8645..d932e2d 100644
> --- a/drivers/input/touchscreen/Makefile
> +++ b/drivers/input/touchscreen/Makefile
> @@ -80,6 +80,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_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
> index 0000000..5049bf8
> --- /dev/null
> +++ b/drivers/input/touchscreen/tsc2007.h
> @@ -0,0 +1,118 @@
> +/*
> + * drivers/input/touchscreen/tsc2007.h
> + *
> + * 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.
> + */
> +
> +#include <linux/input/touchscreen.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;
> +
> + struct touchscreen_properties prop;
> +
> + bool report_resistance;
> + u16 min_x;
> + u16 min_y;
> + u16 max_x;
> + u16 max_y;
> + 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;
> + bool pendown;
> +
> + int (*get_pendown_state)(struct device *);
> + void (*clear_penirq)(void);
> +
> + struct mutex mlock;
> + struct iio_dev *iio_dev; /* optional */
> +};
> +
> +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);
> +
> +#ifdef CONFIG_IIO
> +
> +/* defined in tsc2007_iio.c */
> +int tsc2007_iio_configure(struct tsc2007 *ts);
> +void tsc2007_iio_unconfigure(struct tsc2007 *ts);
> +
> +#else /* CONFIG_IIO */
> +
> +static inline int tsc2007_iio_configure(struct tsc2007 *ts)
> +{
> + return 0;
> +}
> +static inline void tsc2007_iio_unconfigure(struct tsc2007 *ts)
> +{
> +}
> +
> +#endif /* CONFIG_IIO */
> diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007_core.c
> similarity index 85%
> rename from drivers/input/touchscreen/tsc2007.c
> rename to drivers/input/touchscreen/tsc2007_core.c
> index 5e3c4bf..72775ae 100644
> --- a/drivers/input/touchscreen/tsc2007.c
> +++ b/drivers/input/touchscreen/tsc2007_core.c
> @@ -27,80 +27,10 @@
> #include <linux/i2c.h>
> #include <linux/i2c/tsc2007.h>
> #include <linux/of_device.h>
> -#include <linux/of.h>
> #include <linux/of_gpio.h>
> -#include <linux/input/touchscreen.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;
> -
> - struct touchscreen_properties prop;
> -
> - bool report_resistance;
> - u16 min_x;
> - u16 min_y;
> - u16 max_x;
> - u16 max_y;
> - u16 max_rt;
> - unsigned long poll_period; /* in jiffies */
> - int fuzzx;
> - int fuzzy;
> - int fuzzz;
> +#include "tsc2007.h"
>
> - unsigned gpio;
> - int irq;
> -
> - wait_queue_head_t wait;
> - bool stopped;
> - bool pendown;
> -
> - 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;
> @@ -121,6 +51,7 @@ static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
>
> return val;
> }
> +EXPORT_SYMBOL(tsc2007_xfer);
>
> static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
> {
> @@ -138,7 +69,7 @@ static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
> tsc2007_xfer(tsc, PWRDOWN);
> }
>
> -static u32 tsc2007_calculate_resistance(struct tsc2007 *tsc,
> +u32 tsc2007_calculate_resistance(struct tsc2007 *tsc,
> struct ts_event *tc)
> {
> u32 rt = 0;
> @@ -158,8 +89,9 @@ static u32 tsc2007_calculate_resistance(struct tsc2007 *tsc,
>
> return rt;
> }
> +EXPORT_SYMBOL(tsc2007_calculate_resistance);
>
> -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,6 +112,7 @@ static bool tsc2007_is_pen_down(struct tsc2007 *ts)
>
> return ts->get_pendown_state(&ts->client->dev);
> }
> +EXPORT_SYMBOL(tsc2007_is_pen_down);
>
> static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
> {
> @@ -192,7 +125,10 @@ 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_resistance(ts, &tc);
>
> @@ -450,7 +386,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;
> @@ -472,7 +409,13 @@ static int tsc2007_probe(struct i2c_client *client,
> ts->client = client;
> ts->irq = client->irq;
> ts->input = input_dev;
> +
> + err = tsc2007_iio_configure(ts);
> + if (err < 0)
> + return err;
> +
> init_waitqueue_head(&ts->wait);
> + mutex_init(&ts->mlock);
>
> snprintf(ts->phys, sizeof(ts->phys),
> "%s/input0", dev_name(&client->dev));
> @@ -494,7 +437,7 @@ static int tsc2007_probe(struct i2c_client *client,
> if (pdata) {
> err = tsc2007_probe_pdev(client, ts, pdata, id);
> if (err)
> - return err;
> + goto probe_err;
> input_set_abs_params(input_dev, ABS_X, 0, ts->max_x-ts->min_x,
> ts->fuzzx, 0);
> input_set_abs_params(input_dev, ABS_Y, 0, ts->max_y-ts->min_y,
> @@ -504,7 +447,7 @@ static int tsc2007_probe(struct i2c_client *client,
> } else {
> err = tsc2007_probe_dt(client, ts);
> if (err)
> - return err;
> + goto probe_err;
> }
>
> if (pdata) {
> @@ -516,7 +459,7 @@ static int tsc2007_probe(struct i2c_client *client,
> dev_err(&client->dev,
> "Failed to register exit_platform_hw action, %d\n",
> err);
> - return err;
> + goto probe_err;
> }
> }
>
> @@ -533,7 +476,7 @@ static int tsc2007_probe(struct i2c_client *client,
> if (err) {
> dev_err(&client->dev, "Failed to request irq %d: %d\n",
> ts->irq, err);
> - return err;
> + goto probe_err;
> }
>
> tsc2007_stop(ts);
> @@ -543,17 +486,30 @@ static int tsc2007_probe(struct i2c_client *client,
> if (err < 0) {
> dev_err(&client->dev,
> "Failed to setup chip: %d\n", err);
> - return err; /* usually, chip does not respond */
> + goto probe_err; /* chip does not respond */
> }
>
> err = input_register_device(input_dev);
> if (err) {
> dev_err(&client->dev,
> "Failed to register input device: %d\n", err);
> - return err;
> + goto probe_err;
> }
>
> return 0;
> +
> +probe_err:
> + tsc2007_iio_unconfigure(ts);
> + return err;
> +}
> +
> +static int tsc2007_remove(struct i2c_client *client)
> +{
> + struct tsc2007 *ts = i2c_get_clientdata(client);
> +
> + tsc2007_iio_unconfigure(ts);
> + input_unregister_device(ts->input);
> + return 0;
> }
>
> static const struct i2c_device_id tsc2007_idtable[] = {
> @@ -578,6 +534,7 @@ static struct i2c_driver tsc2007_driver = {
> },
> .id_table = tsc2007_idtable,
> .probe = tsc2007_probe,
> + .remove = tsc2007_remove,
> };
>
> module_i2c_driver(tsc2007_driver);
> diff --git a/drivers/input/touchscreen/tsc2007_iio.c b/drivers/input/touchscreen/tsc2007_iio.c
> new file mode 100644
> index 0000000..e492bba
> --- /dev/null
> +++ b/drivers/input/touchscreen/tsc2007_iio.c
> @@ -0,0 +1,152 @@
> +/*
> + * drivers/input/touchscreen/tsc2007_iio.c
> + *
> + * 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)
> +{
> + int err;
> + struct iio_dev *indio_dev;
> + struct tsc2007_iio *iio;
> +
> + indio_dev = devm_iio_device_alloc(&ts->client->dev,
> + sizeof(struct tsc2007_iio));
> + if (!indio_dev) {
> + dev_err(&ts->client->dev, "iio_device_alloc failed\n");
> + return -ENOMEM;
> + }
> +
> + iio = iio_priv(indio_dev);
> + iio->ts = ts;
> + ts->iio_dev = (void *) indio_dev;
> +
> + 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);
> +
> + err = iio_device_register(indio_dev);
> + if (err < 0) {
> + dev_err(&ts->client->dev, "iio_device_register() failed: %d\n",
> + err);
> + return err;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(tsc2007_iio_configure);
> +
> +void tsc2007_iio_unconfigure(struct tsc2007 *ts)
> +{
> + struct iio_dev *indio_dev = ts->iio_dev;
> +
> + iio_device_unregister(indio_dev);
> +}
> +EXPORT_SYMBOL(tsc2007_iio_unconfigure);
>
[toc] | [next] | [standalone]
| From | Jonathan Cameron <jic23@kernel.org> |
|---|---|
| Date | 2016-11-12 15:20 +0100 |
| Message-ID | <sCHjX-3aw-1@gated-at.bofh.it> |
| In reply to | #1520241 |
On 12/11/16 14:04, Jonathan Cameron wrote:
> On 11/11/16 19:02, H. Nikolaus Schaller wrote:
>> The tsc2007 chip not only has a resistive touch screen controller but
>> also an external AUX adc imput which can be used for an ambient
>> light sensor, battery voltage monitoring or any general purpose.
>>
>> Additionally it can measure the chip temperature.
>>
>> This extension provides an iio interface for these adc channels.
>>
>> Since it is not wasting much resources and is very straightforward,
>> we simply provide all other adc channels as optional iio interfaces
>> as weel. This can be used for debugging or special applications.
>>
>> This patch also splits the tsc2007 driver in several source files:
>> tsc2007.h -- constants, structs and stubs
>> tsc2007_core.c -- functional parts of the original driver
>> tsc2007_iio.c -- the optional iio stuff
>>
>> Makefile magic allows to conditionally link the iio
>> stuff if CONFIG_IIO=y in a way that it works with
>> CONFIG_TOUCHSCREEN_TSC2007=m.
>>
>
> I ran a quick build test and it blows up in a number of ways related to
> the #ifdef CONFIG_IIO.
>
> I'm not entirely sure why but
> #if IS_ENABLED(CONFIG_IIO) works fine.
Ah, I'm being sleepy today. It's because I'm building IIO as a module
and the symbol defined would therefore be CONFIG_IIO_MODULE.
The IS_ENABLED macro takes care of both cases.
>
> Otherwise looks good to me
>> Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
> Reviewed-by: Jonathan Cameron <jic23@kernel.org>
>> ---
>> drivers/input/touchscreen/Makefile | 2 +
>> drivers/input/touchscreen/tsc2007.h | 118 ++++++++++++++++
>> .../touchscreen/{tsc2007.c => tsc2007_core.c} | 119 ++++++----------
>> drivers/input/touchscreen/tsc2007_iio.c | 152 +++++++++++++++++++++
>> 4 files changed, 310 insertions(+), 81 deletions(-)
>> create mode 100644 drivers/input/touchscreen/tsc2007.h
>> rename drivers/input/touchscreen/{tsc2007.c => tsc2007_core.c} (85%)
>> create mode 100644 drivers/input/touchscreen/tsc2007_iio.c
>>
>> diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
>> index 81b8645..d932e2d 100644
>> --- a/drivers/input/touchscreen/Makefile
>> +++ b/drivers/input/touchscreen/Makefile
>> @@ -80,6 +80,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_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
>> index 0000000..5049bf8
>> --- /dev/null
>> +++ b/drivers/input/touchscreen/tsc2007.h
>> @@ -0,0 +1,118 @@
>> +/*
>> + * drivers/input/touchscreen/tsc2007.h
>> + *
>> + * 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.
>> + */
>> +
>> +#include <linux/input/touchscreen.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;
>> +
>> + struct touchscreen_properties prop;
>> +
>> + bool report_resistance;
>> + u16 min_x;
>> + u16 min_y;
>> + u16 max_x;
>> + u16 max_y;
>> + 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;
>> + bool pendown;
>> +
>> + int (*get_pendown_state)(struct device *);
>> + void (*clear_penirq)(void);
>> +
>> + struct mutex mlock;
>> + struct iio_dev *iio_dev; /* optional */
>> +};
>> +
>> +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);
>> +
>> +#ifdef CONFIG_IIO
>> +
>> +/* defined in tsc2007_iio.c */
>> +int tsc2007_iio_configure(struct tsc2007 *ts);
>> +void tsc2007_iio_unconfigure(struct tsc2007 *ts);
>> +
>> +#else /* CONFIG_IIO */
>> +
>> +static inline int tsc2007_iio_configure(struct tsc2007 *ts)
>> +{
>> + return 0;
>> +}
>> +static inline void tsc2007_iio_unconfigure(struct tsc2007 *ts)
>> +{
>> +}
>> +
>> +#endif /* CONFIG_IIO */
>> diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007_core.c
>> similarity index 85%
>> rename from drivers/input/touchscreen/tsc2007.c
>> rename to drivers/input/touchscreen/tsc2007_core.c
>> index 5e3c4bf..72775ae 100644
>> --- a/drivers/input/touchscreen/tsc2007.c
>> +++ b/drivers/input/touchscreen/tsc2007_core.c
>> @@ -27,80 +27,10 @@
>> #include <linux/i2c.h>
>> #include <linux/i2c/tsc2007.h>
>> #include <linux/of_device.h>
>> -#include <linux/of.h>
>> #include <linux/of_gpio.h>
>> -#include <linux/input/touchscreen.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;
>> -
>> - struct touchscreen_properties prop;
>> -
>> - bool report_resistance;
>> - u16 min_x;
>> - u16 min_y;
>> - u16 max_x;
>> - u16 max_y;
>> - u16 max_rt;
>> - unsigned long poll_period; /* in jiffies */
>> - int fuzzx;
>> - int fuzzy;
>> - int fuzzz;
>> +#include "tsc2007.h"
>>
>> - unsigned gpio;
>> - int irq;
>> -
>> - wait_queue_head_t wait;
>> - bool stopped;
>> - bool pendown;
>> -
>> - 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;
>> @@ -121,6 +51,7 @@ static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
>>
>> return val;
>> }
>> +EXPORT_SYMBOL(tsc2007_xfer);
>>
>> static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
>> {
>> @@ -138,7 +69,7 @@ static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
>> tsc2007_xfer(tsc, PWRDOWN);
>> }
>>
>> -static u32 tsc2007_calculate_resistance(struct tsc2007 *tsc,
>> +u32 tsc2007_calculate_resistance(struct tsc2007 *tsc,
>> struct ts_event *tc)
>> {
>> u32 rt = 0;
>> @@ -158,8 +89,9 @@ static u32 tsc2007_calculate_resistance(struct tsc2007 *tsc,
>>
>> return rt;
>> }
>> +EXPORT_SYMBOL(tsc2007_calculate_resistance);
>>
>> -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,6 +112,7 @@ static bool tsc2007_is_pen_down(struct tsc2007 *ts)
>>
>> return ts->get_pendown_state(&ts->client->dev);
>> }
>> +EXPORT_SYMBOL(tsc2007_is_pen_down);
>>
>> static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
>> {
>> @@ -192,7 +125,10 @@ 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_resistance(ts, &tc);
>>
>> @@ -450,7 +386,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;
>> @@ -472,7 +409,13 @@ static int tsc2007_probe(struct i2c_client *client,
>> ts->client = client;
>> ts->irq = client->irq;
>> ts->input = input_dev;
>> +
>> + err = tsc2007_iio_configure(ts);
>> + if (err < 0)
>> + return err;
>> +
>> init_waitqueue_head(&ts->wait);
>> + mutex_init(&ts->mlock);
>>
>> snprintf(ts->phys, sizeof(ts->phys),
>> "%s/input0", dev_name(&client->dev));
>> @@ -494,7 +437,7 @@ static int tsc2007_probe(struct i2c_client *client,
>> if (pdata) {
>> err = tsc2007_probe_pdev(client, ts, pdata, id);
>> if (err)
>> - return err;
>> + goto probe_err;
>> input_set_abs_params(input_dev, ABS_X, 0, ts->max_x-ts->min_x,
>> ts->fuzzx, 0);
>> input_set_abs_params(input_dev, ABS_Y, 0, ts->max_y-ts->min_y,
>> @@ -504,7 +447,7 @@ static int tsc2007_probe(struct i2c_client *client,
>> } else {
>> err = tsc2007_probe_dt(client, ts);
>> if (err)
>> - return err;
>> + goto probe_err;
>> }
>>
>> if (pdata) {
>> @@ -516,7 +459,7 @@ static int tsc2007_probe(struct i2c_client *client,
>> dev_err(&client->dev,
>> "Failed to register exit_platform_hw action, %d\n",
>> err);
>> - return err;
>> + goto probe_err;
>> }
>> }
>>
>> @@ -533,7 +476,7 @@ static int tsc2007_probe(struct i2c_client *client,
>> if (err) {
>> dev_err(&client->dev, "Failed to request irq %d: %d\n",
>> ts->irq, err);
>> - return err;
>> + goto probe_err;
>> }
>>
>> tsc2007_stop(ts);
>> @@ -543,17 +486,30 @@ static int tsc2007_probe(struct i2c_client *client,
>> if (err < 0) {
>> dev_err(&client->dev,
>> "Failed to setup chip: %d\n", err);
>> - return err; /* usually, chip does not respond */
>> + goto probe_err; /* chip does not respond */
>> }
>>
>> err = input_register_device(input_dev);
>> if (err) {
>> dev_err(&client->dev,
>> "Failed to register input device: %d\n", err);
>> - return err;
>> + goto probe_err;
>> }
>>
>> return 0;
>> +
>> +probe_err:
>> + tsc2007_iio_unconfigure(ts);
>> + return err;
>> +}
>> +
>> +static int tsc2007_remove(struct i2c_client *client)
>> +{
>> + struct tsc2007 *ts = i2c_get_clientdata(client);
>> +
>> + tsc2007_iio_unconfigure(ts);
>> + input_unregister_device(ts->input);
>> + return 0;
>> }
>>
>> static const struct i2c_device_id tsc2007_idtable[] = {
>> @@ -578,6 +534,7 @@ static struct i2c_driver tsc2007_driver = {
>> },
>> .id_table = tsc2007_idtable,
>> .probe = tsc2007_probe,
>> + .remove = tsc2007_remove,
>> };
>>
>> module_i2c_driver(tsc2007_driver);
>> diff --git a/drivers/input/touchscreen/tsc2007_iio.c b/drivers/input/touchscreen/tsc2007_iio.c
>> new file mode 100644
>> index 0000000..e492bba
>> --- /dev/null
>> +++ b/drivers/input/touchscreen/tsc2007_iio.c
>> @@ -0,0 +1,152 @@
>> +/*
>> + * drivers/input/touchscreen/tsc2007_iio.c
>> + *
>> + * 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)
>> +{
>> + int err;
>> + struct iio_dev *indio_dev;
>> + struct tsc2007_iio *iio;
>> +
>> + indio_dev = devm_iio_device_alloc(&ts->client->dev,
>> + sizeof(struct tsc2007_iio));
>> + if (!indio_dev) {
>> + dev_err(&ts->client->dev, "iio_device_alloc failed\n");
>> + return -ENOMEM;
>> + }
>> +
>> + iio = iio_priv(indio_dev);
>> + iio->ts = ts;
>> + ts->iio_dev = (void *) indio_dev;
>> +
>> + 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);
>> +
>> + err = iio_device_register(indio_dev);
>> + if (err < 0) {
>> + dev_err(&ts->client->dev, "iio_device_register() failed: %d\n",
>> + err);
>> + return err;
>> + }
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL(tsc2007_iio_configure);
>> +
>> +void tsc2007_iio_unconfigure(struct tsc2007 *ts)
>> +{
>> + struct iio_dev *indio_dev = ts->iio_dev;
>> +
>> + iio_device_unregister(indio_dev);
>> +}
>> +EXPORT_SYMBOL(tsc2007_iio_unconfigure);
>>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
[toc] | [prev] | [next] | [standalone]
| From | "H. Nikolaus Schaller" <hns@goldelico.com> |
|---|---|
| Date | 2016-11-12 20:30 +0100 |
| Subject | Re: [PATCH v7 4/9] drivers:input:tsc2007: add iio interface to read external ADC input and temperature |
| Message-ID | <sCM9X-6lD-1@gated-at.bofh.it> |
| In reply to | #1520242 |
> Am 12.11.2016 um 15:19 schrieb Jonathan Cameron <jic23@kernel.org>: > > On 12/11/16 14:04, Jonathan Cameron wrote: >> On 11/11/16 19:02, H. Nikolaus Schaller wrote: >>> The tsc2007 chip not only has a resistive touch screen controller but >>> also an external AUX adc imput which can be used for an ambient >>> light sensor, battery voltage monitoring or any general purpose. >>> >>> Additionally it can measure the chip temperature. >>> >>> This extension provides an iio interface for these adc channels. >>> >>> Since it is not wasting much resources and is very straightforward, >>> we simply provide all other adc channels as optional iio interfaces >>> as weel. This can be used for debugging or special applications. >>> >>> This patch also splits the tsc2007 driver in several source files: >>> tsc2007.h -- constants, structs and stubs >>> tsc2007_core.c -- functional parts of the original driver >>> tsc2007_iio.c -- the optional iio stuff >>> >>> Makefile magic allows to conditionally link the iio >>> stuff if CONFIG_IIO=y in a way that it works with >>> CONFIG_TOUCHSCREEN_TSC2007=m. >>> >> >> I ran a quick build test and it blows up in a number of ways related to >> the #ifdef CONFIG_IIO. >> >> I'm not entirely sure why but >> #if IS_ENABLED(CONFIG_IIO) works fine. > Ah, I'm being sleepy today. It's because I'm building IIO as a module > and the symbol defined would therefore be CONFIG_IIO_MODULE. > > The IS_ENABLED macro takes care of both cases. Ah, yes. I wasn't aware that CONFIG_IIO is tristate at all. We have it as "y" and therefore didn't notice. I will collect this fix for V8. >> >> Otherwise looks good to me >>> Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> >> Reviewed-by: Jonathan Cameron <jic23@kernel.org> Will add this as well. Thanks for the detailled review! BR, Nikolaus
[toc] | [prev] | [next] | [standalone]
| From | Dmitry Torokhov <dmitry.torokhov@gmail.com> |
|---|---|
| Date | 2016-11-19 19:40 +0100 |
| Message-ID | <sFiIp-8M-7@gated-at.bofh.it> |
| In reply to | #1520242 |
On Sat, Nov 12, 2016 at 02:19:30PM +0000, Jonathan Cameron wrote:
> On 12/11/16 14:04, Jonathan Cameron wrote:
> > On 11/11/16 19:02, H. Nikolaus Schaller wrote:
> >> The tsc2007 chip not only has a resistive touch screen controller but
> >> also an external AUX adc imput which can be used for an ambient
> >> light sensor, battery voltage monitoring or any general purpose.
> >>
> >> Additionally it can measure the chip temperature.
> >>
> >> This extension provides an iio interface for these adc channels.
> >>
> >> Since it is not wasting much resources and is very straightforward,
> >> we simply provide all other adc channels as optional iio interfaces
> >> as weel. This can be used for debugging or special applications.
> >>
> >> This patch also splits the tsc2007 driver in several source files:
> >> tsc2007.h -- constants, structs and stubs
> >> tsc2007_core.c -- functional parts of the original driver
> >> tsc2007_iio.c -- the optional iio stuff
> >>
> >> Makefile magic allows to conditionally link the iio
> >> stuff if CONFIG_IIO=y in a way that it works with
> >> CONFIG_TOUCHSCREEN_TSC2007=m.
> >>
> >
> > I ran a quick build test and it blows up in a number of ways related to
> > the #ifdef CONFIG_IIO.
> >
> > I'm not entirely sure why but
> > #if IS_ENABLED(CONFIG_IIO) works fine.
> Ah, I'm being sleepy today. It's because I'm building IIO as a module
> and the symbol defined would therefore be CONFIG_IIO_MODULE.
>
> The IS_ENABLED macro takes care of both cases.
No it doesn't. Have you tried building the driver into the kernel with
IIO as a module?
> >
> > Otherwise looks good to me
> >> Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
> > Reviewed-by: Jonathan Cameron <jic23@kernel.org>
> >> ---
> >> drivers/input/touchscreen/Makefile | 2 +
> >> drivers/input/touchscreen/tsc2007.h | 118 ++++++++++++++++
> >> .../touchscreen/{tsc2007.c => tsc2007_core.c} | 119 ++++++----------
> >> drivers/input/touchscreen/tsc2007_iio.c | 152 +++++++++++++++++++++
> >> 4 files changed, 310 insertions(+), 81 deletions(-)
> >> create mode 100644 drivers/input/touchscreen/tsc2007.h
> >> rename drivers/input/touchscreen/{tsc2007.c => tsc2007_core.c} (85%)
> >> create mode 100644 drivers/input/touchscreen/tsc2007_iio.c
> >>
> >> diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
> >> index 81b8645..d932e2d 100644
> >> --- a/drivers/input/touchscreen/Makefile
> >> +++ b/drivers/input/touchscreen/Makefile
> >> @@ -80,6 +80,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_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
> >> index 0000000..5049bf8
> >> --- /dev/null
> >> +++ b/drivers/input/touchscreen/tsc2007.h
> >> @@ -0,0 +1,118 @@
> >> +/*
> >> + * drivers/input/touchscreen/tsc2007.h
> >> + *
> >> + * 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.
> >> + */
> >> +
> >> +#include <linux/input/touchscreen.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;
> >> +
> >> + struct touchscreen_properties prop;
> >> +
> >> + bool report_resistance;
> >> + u16 min_x;
> >> + u16 min_y;
> >> + u16 max_x;
> >> + u16 max_y;
> >> + 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;
> >> + bool pendown;
> >> +
> >> + int (*get_pendown_state)(struct device *);
> >> + void (*clear_penirq)(void);
> >> +
> >> + struct mutex mlock;
> >> + struct iio_dev *iio_dev; /* optional */
> >> +};
> >> +
> >> +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);
> >> +
> >> +#ifdef CONFIG_IIO
> >> +
> >> +/* defined in tsc2007_iio.c */
> >> +int tsc2007_iio_configure(struct tsc2007 *ts);
> >> +void tsc2007_iio_unconfigure(struct tsc2007 *ts);
> >> +
> >> +#else /* CONFIG_IIO */
> >> +
> >> +static inline int tsc2007_iio_configure(struct tsc2007 *ts)
> >> +{
> >> + return 0;
> >> +}
> >> +static inline void tsc2007_iio_unconfigure(struct tsc2007 *ts)
> >> +{
> >> +}
> >> +
> >> +#endif /* CONFIG_IIO */
> >> diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007_core.c
> >> similarity index 85%
> >> rename from drivers/input/touchscreen/tsc2007.c
> >> rename to drivers/input/touchscreen/tsc2007_core.c
> >> index 5e3c4bf..72775ae 100644
> >> --- a/drivers/input/touchscreen/tsc2007.c
> >> +++ b/drivers/input/touchscreen/tsc2007_core.c
> >> @@ -27,80 +27,10 @@
> >> #include <linux/i2c.h>
> >> #include <linux/i2c/tsc2007.h>
> >> #include <linux/of_device.h>
> >> -#include <linux/of.h>
> >> #include <linux/of_gpio.h>
> >> -#include <linux/input/touchscreen.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;
> >> -
> >> - struct touchscreen_properties prop;
> >> -
> >> - bool report_resistance;
> >> - u16 min_x;
> >> - u16 min_y;
> >> - u16 max_x;
> >> - u16 max_y;
> >> - u16 max_rt;
> >> - unsigned long poll_period; /* in jiffies */
> >> - int fuzzx;
> >> - int fuzzy;
> >> - int fuzzz;
> >> +#include "tsc2007.h"
> >>
> >> - unsigned gpio;
> >> - int irq;
> >> -
> >> - wait_queue_head_t wait;
> >> - bool stopped;
> >> - bool pendown;
> >> -
> >> - 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;
> >> @@ -121,6 +51,7 @@ static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
> >>
> >> return val;
> >> }
> >> +EXPORT_SYMBOL(tsc2007_xfer);
> >>
> >> static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
> >> {
> >> @@ -138,7 +69,7 @@ static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
> >> tsc2007_xfer(tsc, PWRDOWN);
> >> }
> >>
> >> -static u32 tsc2007_calculate_resistance(struct tsc2007 *tsc,
> >> +u32 tsc2007_calculate_resistance(struct tsc2007 *tsc,
> >> struct ts_event *tc)
> >> {
> >> u32 rt = 0;
> >> @@ -158,8 +89,9 @@ static u32 tsc2007_calculate_resistance(struct tsc2007 *tsc,
> >>
> >> return rt;
> >> }
> >> +EXPORT_SYMBOL(tsc2007_calculate_resistance);
> >>
> >> -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,6 +112,7 @@ static bool tsc2007_is_pen_down(struct tsc2007 *ts)
> >>
> >> return ts->get_pendown_state(&ts->client->dev);
> >> }
> >> +EXPORT_SYMBOL(tsc2007_is_pen_down);
> >>
> >> static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
> >> {
> >> @@ -192,7 +125,10 @@ 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_resistance(ts, &tc);
> >>
> >> @@ -450,7 +386,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;
> >> @@ -472,7 +409,13 @@ static int tsc2007_probe(struct i2c_client *client,
> >> ts->client = client;
> >> ts->irq = client->irq;
> >> ts->input = input_dev;
> >> +
> >> + err = tsc2007_iio_configure(ts);
> >> + if (err < 0)
> >> + return err;
> >> +
> >> init_waitqueue_head(&ts->wait);
> >> + mutex_init(&ts->mlock);
> >>
> >> snprintf(ts->phys, sizeof(ts->phys),
> >> "%s/input0", dev_name(&client->dev));
> >> @@ -494,7 +437,7 @@ static int tsc2007_probe(struct i2c_client *client,
> >> if (pdata) {
> >> err = tsc2007_probe_pdev(client, ts, pdata, id);
> >> if (err)
> >> - return err;
> >> + goto probe_err;
> >> input_set_abs_params(input_dev, ABS_X, 0, ts->max_x-ts->min_x,
> >> ts->fuzzx, 0);
> >> input_set_abs_params(input_dev, ABS_Y, 0, ts->max_y-ts->min_y,
> >> @@ -504,7 +447,7 @@ static int tsc2007_probe(struct i2c_client *client,
> >> } else {
> >> err = tsc2007_probe_dt(client, ts);
> >> if (err)
> >> - return err;
> >> + goto probe_err;
> >> }
> >>
> >> if (pdata) {
> >> @@ -516,7 +459,7 @@ static int tsc2007_probe(struct i2c_client *client,
> >> dev_err(&client->dev,
> >> "Failed to register exit_platform_hw action, %d\n",
> >> err);
> >> - return err;
> >> + goto probe_err;
> >> }
> >> }
> >>
> >> @@ -533,7 +476,7 @@ static int tsc2007_probe(struct i2c_client *client,
> >> if (err) {
> >> dev_err(&client->dev, "Failed to request irq %d: %d\n",
> >> ts->irq, err);
> >> - return err;
> >> + goto probe_err;
> >> }
> >>
> >> tsc2007_stop(ts);
> >> @@ -543,17 +486,30 @@ static int tsc2007_probe(struct i2c_client *client,
> >> if (err < 0) {
> >> dev_err(&client->dev,
> >> "Failed to setup chip: %d\n", err);
> >> - return err; /* usually, chip does not respond */
> >> + goto probe_err; /* chip does not respond */
> >> }
> >>
> >> err = input_register_device(input_dev);
> >> if (err) {
> >> dev_err(&client->dev,
> >> "Failed to register input device: %d\n", err);
> >> - return err;
> >> + goto probe_err;
> >> }
> >>
> >> return 0;
> >> +
> >> +probe_err:
> >> + tsc2007_iio_unconfigure(ts);
> >> + return err;
> >> +}
> >> +
> >> +static int tsc2007_remove(struct i2c_client *client)
> >> +{
> >> + struct tsc2007 *ts = i2c_get_clientdata(client);
> >> +
> >> + tsc2007_iio_unconfigure(ts);
> >> + input_unregister_device(ts->input);
> >> + return 0;
> >> }
> >>
> >> static const struct i2c_device_id tsc2007_idtable[] = {
> >> @@ -578,6 +534,7 @@ static struct i2c_driver tsc2007_driver = {
> >> },
> >> .id_table = tsc2007_idtable,
> >> .probe = tsc2007_probe,
> >> + .remove = tsc2007_remove,
> >> };
> >>
> >> module_i2c_driver(tsc2007_driver);
> >> diff --git a/drivers/input/touchscreen/tsc2007_iio.c b/drivers/input/touchscreen/tsc2007_iio.c
> >> new file mode 100644
> >> index 0000000..e492bba
> >> --- /dev/null
> >> +++ b/drivers/input/touchscreen/tsc2007_iio.c
> >> @@ -0,0 +1,152 @@
> >> +/*
> >> + * drivers/input/touchscreen/tsc2007_iio.c
> >> + *
> >> + * 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)
> >> +{
> >> + int err;
> >> + struct iio_dev *indio_dev;
> >> + struct tsc2007_iio *iio;
> >> +
> >> + indio_dev = devm_iio_device_alloc(&ts->client->dev,
> >> + sizeof(struct tsc2007_iio));
> >> + if (!indio_dev) {
> >> + dev_err(&ts->client->dev, "iio_device_alloc failed\n");
> >> + return -ENOMEM;
> >> + }
> >> +
> >> + iio = iio_priv(indio_dev);
> >> + iio->ts = ts;
> >> + ts->iio_dev = (void *) indio_dev;
> >> +
> >> + 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);
> >> +
> >> + err = iio_device_register(indio_dev);
> >> + if (err < 0) {
> >> + dev_err(&ts->client->dev, "iio_device_register() failed: %d\n",
> >> + err);
> >> + return err;
> >> + }
> >> +
> >> + return 0;
> >> +}
> >> +EXPORT_SYMBOL(tsc2007_iio_configure);
> >> +
> >> +void tsc2007_iio_unconfigure(struct tsc2007 *ts)
> >> +{
> >> + struct iio_dev *indio_dev = ts->iio_dev;
> >> +
> >> + iio_device_unregister(indio_dev);
> >> +}
> >> +EXPORT_SYMBOL(tsc2007_iio_unconfigure);
> >>
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> >
>
--
Dmitry
[toc] | [prev] | [next] | [standalone]
| From | Jonathan Cameron <jic23@jic23.retrosnub.co.uk> |
|---|---|
| Date | 2016-11-19 21:20 +0100 |
| Subject | Re: [PATCH v7 4/9] drivers:input:tsc2007: add iio interface to read external ADC input and temperature |
| Message-ID | <sFkhc-1dA-9@gated-at.bofh.it> |
| In reply to | #1526115 |
On 19 November 2016 18:38:49 GMT+00:00, Dmitry Torokhov <dmitry.torokhov@gmail.com> wrote:
>On Sat, Nov 12, 2016 at 02:19:30PM +0000, Jonathan Cameron wrote:
>> On 12/11/16 14:04, Jonathan Cameron wrote:
>> > On 11/11/16 19:02, H. Nikolaus Schaller wrote:
>> >> The tsc2007 chip not only has a resistive touch screen controller
>but
>> >> also an external AUX adc imput which can be used for an ambient
>> >> light sensor, battery voltage monitoring or any general purpose.
>> >>
>> >> Additionally it can measure the chip temperature.
>> >>
>> >> This extension provides an iio interface for these adc channels.
>> >>
>> >> Since it is not wasting much resources and is very
>straightforward,
>> >> we simply provide all other adc channels as optional iio
>interfaces
>> >> as weel. This can be used for debugging or special applications.
>> >>
>> >> This patch also splits the tsc2007 driver in several source files:
>> >> tsc2007.h -- constants, structs and stubs
>> >> tsc2007_core.c -- functional parts of the original driver
>> >> tsc2007_iio.c -- the optional iio stuff
>> >>
>> >> Makefile magic allows to conditionally link the iio
>> >> stuff if CONFIG_IIO=y in a way that it works with
>> >> CONFIG_TOUCHSCREEN_TSC2007=m.
>> >>
>> >
>> > I ran a quick build test and it blows up in a number of ways
>related to
>> > the #ifdef CONFIG_IIO.
>> >
>> > I'm not entirely sure why but
>> > #if IS_ENABLED(CONFIG_IIO) works fine.
>> Ah, I'm being sleepy today. It's because I'm building IIO as a
>module
>> and the symbol defined would therefore be CONFIG_IIO_MODULE.
>>
>> The IS_ENABLED macro takes care of both cases.
>
>No it doesn't. Have you tried building the driver into the kernel with
>IIO as a module?
Fair point. Is there a clean way of handling this?
>
>> >
>> > Otherwise looks good to me
>> >> Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
>> > Reviewed-by: Jonathan Cameron <jic23@kernel.org>
>> >> ---
>> >> drivers/input/touchscreen/Makefile | 2 +
>> >> drivers/input/touchscreen/tsc2007.h | 118
>++++++++++++++++
>> >> .../touchscreen/{tsc2007.c => tsc2007_core.c} | 119
>++++++----------
>> >> drivers/input/touchscreen/tsc2007_iio.c | 152
>+++++++++++++++++++++
>> >> 4 files changed, 310 insertions(+), 81 deletions(-)
>> >> create mode 100644 drivers/input/touchscreen/tsc2007.h
>> >> rename drivers/input/touchscreen/{tsc2007.c => tsc2007_core.c}
>(85%)
>> >> create mode 100644 drivers/input/touchscreen/tsc2007_iio.c
>> >>
>> >> diff --git a/drivers/input/touchscreen/Makefile
>b/drivers/input/touchscreen/Makefile
>> >> index 81b8645..d932e2d 100644
>> >> --- a/drivers/input/touchscreen/Makefile
>> >> +++ b/drivers/input/touchscreen/Makefile
>> >> @@ -80,6 +80,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_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
>> >> index 0000000..5049bf8
>> >> --- /dev/null
>> >> +++ b/drivers/input/touchscreen/tsc2007.h
>> >> @@ -0,0 +1,118 @@
>> >> +/*
>> >> + * drivers/input/touchscreen/tsc2007.h
>> >> + *
>> >> + * 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.
>> >> + */
>> >> +
>> >> +#include <linux/input/touchscreen.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;
>> >> +
>> >> + struct touchscreen_properties prop;
>> >> +
>> >> + bool report_resistance;
>> >> + u16 min_x;
>> >> + u16 min_y;
>> >> + u16 max_x;
>> >> + u16 max_y;
>> >> + 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;
>> >> + bool pendown;
>> >> +
>> >> + int (*get_pendown_state)(struct device *);
>> >> + void (*clear_penirq)(void);
>> >> +
>> >> + struct mutex mlock;
>> >> + struct iio_dev *iio_dev; /* optional */
>> >> +};
>> >> +
>> >> +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);
>> >> +
>> >> +#ifdef CONFIG_IIO
>> >> +
>> >> +/* defined in tsc2007_iio.c */
>> >> +int tsc2007_iio_configure(struct tsc2007 *ts);
>> >> +void tsc2007_iio_unconfigure(struct tsc2007 *ts);
>> >> +
>> >> +#else /* CONFIG_IIO */
>> >> +
>> >> +static inline int tsc2007_iio_configure(struct tsc2007 *ts)
>> >> +{
>> >> + return 0;
>> >> +}
>> >> +static inline void tsc2007_iio_unconfigure(struct tsc2007 *ts)
>> >> +{
>> >> +}
>> >> +
>> >> +#endif /* CONFIG_IIO */
>> >> diff --git a/drivers/input/touchscreen/tsc2007.c
>b/drivers/input/touchscreen/tsc2007_core.c
>> >> similarity index 85%
>> >> rename from drivers/input/touchscreen/tsc2007.c
>> >> rename to drivers/input/touchscreen/tsc2007_core.c
>> >> index 5e3c4bf..72775ae 100644
>> >> --- a/drivers/input/touchscreen/tsc2007.c
>> >> +++ b/drivers/input/touchscreen/tsc2007_core.c
>> >> @@ -27,80 +27,10 @@
>> >> #include <linux/i2c.h>
>> >> #include <linux/i2c/tsc2007.h>
>> >> #include <linux/of_device.h>
>> >> -#include <linux/of.h>
>> >> #include <linux/of_gpio.h>
>> >> -#include <linux/input/touchscreen.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;
>> >> -
>> >> - struct touchscreen_properties prop;
>> >> -
>> >> - bool report_resistance;
>> >> - u16 min_x;
>> >> - u16 min_y;
>> >> - u16 max_x;
>> >> - u16 max_y;
>> >> - u16 max_rt;
>> >> - unsigned long poll_period; /* in jiffies */
>> >> - int fuzzx;
>> >> - int fuzzy;
>> >> - int fuzzz;
>> >> +#include "tsc2007.h"
>> >>
>> >> - unsigned gpio;
>> >> - int irq;
>> >> -
>> >> - wait_queue_head_t wait;
>> >> - bool stopped;
>> >> - bool pendown;
>> >> -
>> >> - 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;
>> >> @@ -121,6 +51,7 @@ static inline int tsc2007_xfer(struct tsc2007
>*tsc, u8 cmd)
>> >>
>> >> return val;
>> >> }
>> >> +EXPORT_SYMBOL(tsc2007_xfer);
>> >>
>> >> static void tsc2007_read_values(struct tsc2007 *tsc, struct
>ts_event *tc)
>> >> {
>> >> @@ -138,7 +69,7 @@ static void tsc2007_read_values(struct tsc2007
>*tsc, struct ts_event *tc)
>> >> tsc2007_xfer(tsc, PWRDOWN);
>> >> }
>> >>
>> >> -static u32 tsc2007_calculate_resistance(struct tsc2007 *tsc,
>> >> +u32 tsc2007_calculate_resistance(struct tsc2007 *tsc,
>> >> struct ts_event *tc)
>> >> {
>> >> u32 rt = 0;
>> >> @@ -158,8 +89,9 @@ static u32 tsc2007_calculate_resistance(struct
>tsc2007 *tsc,
>> >>
>> >> return rt;
>> >> }
>> >> +EXPORT_SYMBOL(tsc2007_calculate_resistance);
>> >>
>> >> -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,6 +112,7 @@ static bool tsc2007_is_pen_down(struct tsc2007
>*ts)
>> >>
>> >> return ts->get_pendown_state(&ts->client->dev);
>> >> }
>> >> +EXPORT_SYMBOL(tsc2007_is_pen_down);
>> >>
>> >> static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
>> >> {
>> >> @@ -192,7 +125,10 @@ 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_resistance(ts, &tc);
>> >>
>> >> @@ -450,7 +386,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;
>> >> @@ -472,7 +409,13 @@ static int tsc2007_probe(struct i2c_client
>*client,
>> >> ts->client = client;
>> >> ts->irq = client->irq;
>> >> ts->input = input_dev;
>> >> +
>> >> + err = tsc2007_iio_configure(ts);
>> >> + if (err < 0)
>> >> + return err;
>> >> +
>> >> init_waitqueue_head(&ts->wait);
>> >> + mutex_init(&ts->mlock);
>> >>
>> >> snprintf(ts->phys, sizeof(ts->phys),
>> >> "%s/input0", dev_name(&client->dev));
>> >> @@ -494,7 +437,7 @@ static int tsc2007_probe(struct i2c_client
>*client,
>> >> if (pdata) {
>> >> err = tsc2007_probe_pdev(client, ts, pdata, id);
>> >> if (err)
>> >> - return err;
>> >> + goto probe_err;
>> >> input_set_abs_params(input_dev, ABS_X, 0, ts->max_x-ts->min_x,
>> >> ts->fuzzx, 0);
>> >> input_set_abs_params(input_dev, ABS_Y, 0, ts->max_y-ts->min_y,
>> >> @@ -504,7 +447,7 @@ static int tsc2007_probe(struct i2c_client
>*client,
>> >> } else {
>> >> err = tsc2007_probe_dt(client, ts);
>> >> if (err)
>> >> - return err;
>> >> + goto probe_err;
>> >> }
>> >>
>> >> if (pdata) {
>> >> @@ -516,7 +459,7 @@ static int tsc2007_probe(struct i2c_client
>*client,
>> >> dev_err(&client->dev,
>> >> "Failed to register exit_platform_hw action, %d\n",
>> >> err);
>> >> - return err;
>> >> + goto probe_err;
>> >> }
>> >> }
>> >>
>> >> @@ -533,7 +476,7 @@ static int tsc2007_probe(struct i2c_client
>*client,
>> >> if (err) {
>> >> dev_err(&client->dev, "Failed to request irq %d: %d\n",
>> >> ts->irq, err);
>> >> - return err;
>> >> + goto probe_err;
>> >> }
>> >>
>> >> tsc2007_stop(ts);
>> >> @@ -543,17 +486,30 @@ static int tsc2007_probe(struct i2c_client
>*client,
>> >> if (err < 0) {
>> >> dev_err(&client->dev,
>> >> "Failed to setup chip: %d\n", err);
>> >> - return err; /* usually, chip does not respond */
>> >> + goto probe_err; /* chip does not respond */
>> >> }
>> >>
>> >> err = input_register_device(input_dev);
>> >> if (err) {
>> >> dev_err(&client->dev,
>> >> "Failed to register input device: %d\n", err);
>> >> - return err;
>> >> + goto probe_err;
>> >> }
>> >>
>> >> return 0;
>> >> +
>> >> +probe_err:
>> >> + tsc2007_iio_unconfigure(ts);
>> >> + return err;
>> >> +}
>> >> +
>> >> +static int tsc2007_remove(struct i2c_client *client)
>> >> +{
>> >> + struct tsc2007 *ts = i2c_get_clientdata(client);
>> >> +
>> >> + tsc2007_iio_unconfigure(ts);
>> >> + input_unregister_device(ts->input);
>> >> + return 0;
>> >> }
>> >>
>> >> static const struct i2c_device_id tsc2007_idtable[] = {
>> >> @@ -578,6 +534,7 @@ static struct i2c_driver tsc2007_driver = {
>> >> },
>> >> .id_table = tsc2007_idtable,
>> >> .probe = tsc2007_probe,
>> >> + .remove = tsc2007_remove,
>> >> };
>> >>
>> >> module_i2c_driver(tsc2007_driver);
>> >> diff --git a/drivers/input/touchscreen/tsc2007_iio.c
>b/drivers/input/touchscreen/tsc2007_iio.c
>> >> new file mode 100644
>> >> index 0000000..e492bba
>> >> --- /dev/null
>> >> +++ b/drivers/input/touchscreen/tsc2007_iio.c
>> >> @@ -0,0 +1,152 @@
>> >> +/*
>> >> + * drivers/input/touchscreen/tsc2007_iio.c
>> >> + *
>> >> + * 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)
>> >> +{
>> >> + int err;
>> >> + struct iio_dev *indio_dev;
>> >> + struct tsc2007_iio *iio;
>> >> +
>> >> + indio_dev = devm_iio_device_alloc(&ts->client->dev,
>> >> + sizeof(struct tsc2007_iio));
>> >> + if (!indio_dev) {
>> >> + dev_err(&ts->client->dev, "iio_device_alloc failed\n");
>> >> + return -ENOMEM;
>> >> + }
>> >> +
>> >> + iio = iio_priv(indio_dev);
>> >> + iio->ts = ts;
>> >> + ts->iio_dev = (void *) indio_dev;
>> >> +
>> >> + 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);
>> >> +
>> >> + err = iio_device_register(indio_dev);
>> >> + if (err < 0) {
>> >> + dev_err(&ts->client->dev, "iio_device_register() failed: %d\n",
>> >> + err);
>> >> + return err;
>> >> + }
>> >> +
>> >> + return 0;
>> >> +}
>> >> +EXPORT_SYMBOL(tsc2007_iio_configure);
>> >> +
>> >> +void tsc2007_iio_unconfigure(struct tsc2007 *ts)
>> >> +{
>> >> + struct iio_dev *indio_dev = ts->iio_dev;
>> >> +
>> >> + iio_device_unregister(indio_dev);
>> >> +}
>> >> +EXPORT_SYMBOL(tsc2007_iio_unconfigure);
>> >>
>> >
>> > --
>> > To unsubscribe from this list: send the line "unsubscribe
>linux-iio" in
>> > the body of a message to majordomo@vger.kernel.org
>> > More majordomo info at http://vger.kernel.org/majordomo-info.html
>> >
>>
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web