Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1411396 > unrolled thread

[PATCH v3 0/8] Input: atmel_mxt_ts - output raw touch diagnostic data via V4L

Started byNick Dyer <nick.dyer@itdev.co.uk>
First post2016-06-01 18:50 +0200
Last post2016-06-02 17:20 +0200
Articles 14 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v3 0/8] Input: atmel_mxt_ts - output raw touch diagnostic data via V4L Nick Dyer <nick.dyer@itdev.co.uk> - 2016-06-01 18:50 +0200
    [PATCH v3 2/8] [media] Add signed 16-bit pixel format Nick Dyer <nick.dyer@itdev.co.uk> - 2016-06-01 18:50 +0200
    [PATCH v3 4/8] Input: atmel_mxt_ts - output diagnostic debug via v4l2 device Nick Dyer <nick.dyer@itdev.co.uk> - 2016-06-01 18:50 +0200
      Re: [PATCH v3 4/8] Input: atmel_mxt_ts - output diagnostic debug via  v4l2 device Dmitry Torokhov <dmitry.torokhov@gmail.com> - 2016-06-01 20:20 +0200
    [PATCH v3 7/8] Input: atmel_mxt_ts - add diagnostic data support for mXT1386 Nick Dyer <nick.dyer@itdev.co.uk> - 2016-06-01 18:50 +0200
      Re: [PATCH v3 7/8] Input: atmel_mxt_ts - add diagnostic data support  for mXT1386 Dmitry Torokhov <dmitry.torokhov@gmail.com> - 2016-06-01 20:20 +0200
    [PATCH v3 1/8] Input: atmel_mxt_ts - add support for T37 diagnostic data Nick Dyer <nick.dyer@itdev.co.uk> - 2016-06-01 18:50 +0200
      Re: [PATCH v3 1/8] Input: atmel_mxt_ts - add support for T37  diagnostic data Dmitry Torokhov <dmitry.torokhov@gmail.com> - 2016-06-01 20:20 +0200
    [PATCH v3 5/8] Input: atmel_mxt_ts - read touchscreen size Nick Dyer <nick.dyer@itdev.co.uk> - 2016-06-01 18:50 +0200
    [PATCH v3 3/8] [media] v4l2-core: Add VFL_TYPE_TOUCH_SENSOR Nick Dyer <nick.dyer@itdev.co.uk> - 2016-06-01 18:50 +0200
    [PATCH v3 6/8] Input: atmel_mxt_ts - handle diagnostic data orientation Nick Dyer <nick.dyer@itdev.co.uk> - 2016-06-01 18:50 +0200
    [PATCH v3 8/8] Input: atmel_mxt_ts - add support for reference data Nick Dyer <nick.dyer@itdev.co.uk> - 2016-06-01 18:50 +0200
    Re: [PATCH v3 0/8] Input: atmel_mxt_ts - output raw touch diagnostic  data via V4L Dmitry Torokhov <dmitry.torokhov@gmail.com> - 2016-06-01 20:20 +0200
      Re: [PATCH v3 0/8] Input: atmel_mxt_ts - output raw touch diagnostic  data via V4L Nick Dyer <nick.dyer@itdev.co.uk> - 2016-06-02 17:20 +0200

#1411396 — [PATCH v3 0/8] Input: atmel_mxt_ts - output raw touch diagnostic data via V4L

FromNick Dyer <nick.dyer@itdev.co.uk>
Date2016-06-01 18:50 +0200
Subject[PATCH v3 0/8] Input: atmel_mxt_ts - output raw touch diagnostic data via V4L
Message-ID<rFhvc-2p3-23@gated-at.bofh.it>
This is a series of patches to add diagnostic data support to the Atmel
maXTouch driver. It's a rewrite of the previous implementation which output via
debugfs: it now uses a V4L2 device in a similar way to the sur40 driver.

There are significant performance advantages to putting this code into the
driver.  The algorithm for retrieving the data has been fairly consistent
across a range of chips, with the exception of the mXT1386 series (see patch).

We have a utility which can read the data and display it in a useful format:
    https://github.com/ndyer/heatmap/commits/heatmap-v4l

These patches are also available from
    https://github.com/ndyer/linux/commits/diagnostic-v4l

Changes in v3:
- Address V4L2 review comments from Hans Verkuil
- Run v4l-compliance and fix all issues - needs minor patch here:
  https://github.com/ndyer/v4l-utils/commit/cf50469773f

Changes in v2:
- Split pixfmt changes into separate commit and add DocBook
- Introduce VFL_TYPE_TOUCH_SENSOR and /dev/v4l-touch
- Remove "single node" support for now, it may be better to treat it as metadata later
- Explicitly set VFL_DIR_RX
- Fix Kconfig

[toc] | [next] | [standalone]


#1411397 — [PATCH v3 2/8] [media] Add signed 16-bit pixel format

FromNick Dyer <nick.dyer@itdev.co.uk>
Date2016-06-01 18:50 +0200
Subject[PATCH v3 2/8] [media] Add signed 16-bit pixel format
Message-ID<rFhvc-2p3-35@gated-at.bofh.it>
In reply to#1411396
This will be used for output of raw touch delta data. This format is
used by Atmel maXTouch (atmel_mxt_ts) and also Synaptics RMI4.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 Documentation/DocBook/media/v4l/pixfmt-ys16.xml | 79 +++++++++++++++++++++++++
 Documentation/DocBook/media/v4l/pixfmt.xml      |  1 +
 drivers/media/v4l2-core/v4l2-ioctl.c            |  1 +
 include/uapi/linux/videodev2.h                  |  1 +
 4 files changed, 82 insertions(+)
 create mode 100644 Documentation/DocBook/media/v4l/pixfmt-ys16.xml

diff --git a/Documentation/DocBook/media/v4l/pixfmt-ys16.xml b/Documentation/DocBook/media/v4l/pixfmt-ys16.xml
new file mode 100644
index 0000000..f92d65e
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/pixfmt-ys16.xml
@@ -0,0 +1,79 @@
+<refentry id="V4L2-PIX-FMT-YS16">
+  <refmeta>
+    <refentrytitle>V4L2_PIX_FMT_YS16 ('YS16')</refentrytitle>
+    &manvol;
+  </refmeta>
+  <refnamediv>
+    <refname><constant>V4L2_PIX_FMT_YS16</constant></refname>
+    <refpurpose>Grey-scale image</refpurpose>
+  </refnamediv>
+  <refsect1>
+    <title>Description</title>
+
+    <para>This is a signed grey-scale image with a depth of 16 bits per
+pixel. The most significant byte is stored at higher memory addresses
+(little-endian).</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_YS16</constant> 4 &times; 4
+pixel image</title>
+
+      <formalpara>
+	<title>Byte Order.</title>
+	<para>Each cell is one byte.
+	  <informaltable frame="none">
+	    <tgroup cols="9" align="center">
+	      <colspec align="left" colwidth="2*" />
+	      <tbody valign="top">
+		<row>
+		  <entry>start&nbsp;+&nbsp;0:</entry>
+		  <entry>Y'<subscript>00low</subscript></entry>
+		  <entry>Y'<subscript>00high</subscript></entry>
+		  <entry>Y'<subscript>01low</subscript></entry>
+		  <entry>Y'<subscript>01high</subscript></entry>
+		  <entry>Y'<subscript>02low</subscript></entry>
+		  <entry>Y'<subscript>02high</subscript></entry>
+		  <entry>Y'<subscript>03low</subscript></entry>
+		  <entry>Y'<subscript>03high</subscript></entry>
+		</row>
+		<row>
+		  <entry>start&nbsp;+&nbsp;8:</entry>
+		  <entry>Y'<subscript>10low</subscript></entry>
+		  <entry>Y'<subscript>10high</subscript></entry>
+		  <entry>Y'<subscript>11low</subscript></entry>
+		  <entry>Y'<subscript>11high</subscript></entry>
+		  <entry>Y'<subscript>12low</subscript></entry>
+		  <entry>Y'<subscript>12high</subscript></entry>
+		  <entry>Y'<subscript>13low</subscript></entry>
+		  <entry>Y'<subscript>13high</subscript></entry>
+		</row>
+		<row>
+		  <entry>start&nbsp;+&nbsp;16:</entry>
+		  <entry>Y'<subscript>20low</subscript></entry>
+		  <entry>Y'<subscript>20high</subscript></entry>
+		  <entry>Y'<subscript>21low</subscript></entry>
+		  <entry>Y'<subscript>21high</subscript></entry>
+		  <entry>Y'<subscript>22low</subscript></entry>
+		  <entry>Y'<subscript>22high</subscript></entry>
+		  <entry>Y'<subscript>23low</subscript></entry>
+		  <entry>Y'<subscript>23high</subscript></entry>
+		</row>
+		<row>
+		  <entry>start&nbsp;+&nbsp;24:</entry>
+		  <entry>Y'<subscript>30low</subscript></entry>
+		  <entry>Y'<subscript>30high</subscript></entry>
+		  <entry>Y'<subscript>31low</subscript></entry>
+		  <entry>Y'<subscript>31high</subscript></entry>
+		  <entry>Y'<subscript>32low</subscript></entry>
+		  <entry>Y'<subscript>32high</subscript></entry>
+		  <entry>Y'<subscript>33low</subscript></entry>
+		  <entry>Y'<subscript>33high</subscript></entry>
+		</row>
+	      </tbody>
+	    </tgroup>
+	  </informaltable>
+	</para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml
index 5a08aee..f3e3e6d 100644
--- a/Documentation/DocBook/media/v4l/pixfmt.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt.xml
@@ -1619,6 +1619,7 @@ information.</para>
     &sub-y12;
     &sub-y10b;
     &sub-y16;
+    &sub-ys16;
     &sub-y16-be;
     &sub-y8i;
     &sub-y12i;
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 28e5be2..ecf7e0b 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1164,6 +1164,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
 	case V4L2_PIX_FMT_Y10:		descr = "10-bit Greyscale"; break;
 	case V4L2_PIX_FMT_Y12:		descr = "12-bit Greyscale"; break;
 	case V4L2_PIX_FMT_Y16:		descr = "16-bit Greyscale"; break;
+	case V4L2_PIX_FMT_YS16:		descr = "16-bit Greyscale (Signed)"; break;
 	case V4L2_PIX_FMT_Y16_BE:	descr = "16-bit Greyscale BE"; break;
 	case V4L2_PIX_FMT_Y10BPACK:	descr = "10-bit Greyscale (Packed)"; break;
 	case V4L2_PIX_FMT_PAL8:		descr = "8-bit Palette"; break;
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 8f95191..e0125cf 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -493,6 +493,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_Y12     v4l2_fourcc('Y', '1', '2', ' ') /* 12  Greyscale     */
 #define V4L2_PIX_FMT_Y16     v4l2_fourcc('Y', '1', '6', ' ') /* 16  Greyscale     */
 #define V4L2_PIX_FMT_Y16_BE  v4l2_fourcc_be('Y', '1', '6', ' ') /* 16  Greyscale BE  */
+#define V4L2_PIX_FMT_YS16    v4l2_fourcc('Y', 'S', '1', '6') /* signed 16-bit Greyscale */
 
 /* Grey bit-packed formats */
 #define V4L2_PIX_FMT_Y10BPACK    v4l2_fourcc('Y', '1', '0', 'B') /* 10  Greyscale bit-packed */
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1411399 — [PATCH v3 4/8] Input: atmel_mxt_ts - output diagnostic debug via v4l2 device

FromNick Dyer <nick.dyer@itdev.co.uk>
Date2016-06-01 18:50 +0200
Subject[PATCH v3 4/8] Input: atmel_mxt_ts - output diagnostic debug via v4l2 device
Message-ID<rFhvd-2p3-61@gated-at.bofh.it>
In reply to#1411396
Register a video device to output T37 diagnostic data.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/Kconfig        |   2 +
 drivers/input/touchscreen/atmel_mxt_ts.c | 247 +++++++++++++++++++++++++++++++
 2 files changed, 249 insertions(+)

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 8ecdc38..73154b6 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -105,6 +105,8 @@ config TOUCHSCREEN_AR1021_I2C
 config TOUCHSCREEN_ATMEL_MXT
 	tristate "Atmel mXT I2C Touchscreen"
 	depends on I2C
+	depends on VIDEO_V4L2
+	select VIDEOBUF2_VMALLOC
 	select FW_LOADER
 	help
 	  Say Y here if you have Atmel mXT series I2C touchscreen,
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 21f42ed..8608cb1 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -28,6 +28,10 @@
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <asm/unaligned.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-vmalloc.h>
 
 /* Firmware files */
 #define MXT_FW_NAME		"maxtouch.fw"
@@ -222,6 +226,23 @@ struct mxt_dbg {
 	struct t37_debug *t37_buf;
 	unsigned int t37_pages;
 	unsigned int t37_nodes;
+
+	struct v4l2_device v4l2;
+	struct v4l2_pix_format format;
+	struct video_device vdev;
+	struct vb2_queue queue;
+	struct mutex lock;
+	int input;
+};
+
+static const struct v4l2_file_operations mxt_video_fops = {
+	.owner = THIS_MODULE,
+	.open = v4l2_fh_open,
+	.release = vb2_fop_release,
+	.unlocked_ioctl = video_ioctl2,
+	.read = vb2_fop_read,
+	.mmap = vb2_fop_mmap,
+	.poll = vb2_fop_poll,
 };
 
 /* Each client has this additional data */
@@ -277,6 +298,11 @@ struct mxt_data {
 	struct completion crc_completion;
 };
 
+struct mxt_vb2_buffer {
+	struct vb2_buffer	vb;
+	struct list_head	list;
+};
+
 static size_t mxt_obj_size(const struct mxt_object *obj)
 {
 	return obj->size_minus_one + 1;
@@ -1523,6 +1549,9 @@ static void mxt_free_input_device(struct mxt_data *data)
 
 static void mxt_free_object_table(struct mxt_data *data)
 {
+	video_unregister_device(&data->dbg.vdev);
+	v4l2_device_unregister(&data->dbg.v4l2);
+
 	kfree(data->object_table);
 	data->object_table = NULL;
 	kfree(data->msg_buf);
@@ -2154,10 +2183,191 @@ wait_cmd:
 	return mxt_convert_debug_pages(data, outbuf);
 }
 
+static int mxt_queue_setup(struct vb2_queue *q,
+		       unsigned int *nbuffers, unsigned int *nplanes,
+		       unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct mxt_data *data = q->drv_priv;
+	size_t size = data->dbg.t37_nodes * sizeof(u16);
+
+	if (*nplanes)
+		return sizes[0] < size ? -EINVAL : 0;
+
+	*nplanes = 1;
+	sizes[0] = size;
+
+	return 0;
+}
+
+static void mxt_buffer_queue(struct vb2_buffer *vb)
+{
+	struct mxt_data *data = vb2_get_drv_priv(vb->vb2_queue);
+	u16 *ptr;
+	int ret;
+
+	ptr = vb2_plane_vaddr(vb, 0);
+	if (!ptr) {
+		dev_err(&data->client->dev, "Error acquiring frame ptr\n");
+		goto fault;
+	}
+
+	ret = mxt_read_diagnostic_debug(data, MXT_DIAGNOSTIC_DELTAS, ptr);
+	if (ret)
+		goto fault;
+
+	vb2_set_plane_payload(vb, 0, data->dbg.t37_nodes * sizeof(u16));
+	vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+	return;
+
+fault:
+	vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+}
+
+/* V4L2 structures */
+static const struct vb2_ops mxt_queue_ops = {
+	.queue_setup		= mxt_queue_setup,
+	.buf_queue		= mxt_buffer_queue,
+	.wait_prepare		= vb2_ops_wait_prepare,
+	.wait_finish		= vb2_ops_wait_finish,
+};
+
+static const struct vb2_queue mxt_queue = {
+	.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+	.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ,
+	.buf_struct_size = sizeof(struct mxt_vb2_buffer),
+	.ops = &mxt_queue_ops,
+	.mem_ops = &vb2_vmalloc_memops,
+	.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC,
+	.min_buffers_needed = 1,
+};
+
+static int mxt_vidioc_querycap(struct file *file, void *priv,
+				 struct v4l2_capability *cap)
+{
+	struct mxt_data *data = video_drvdata(file);
+
+	strlcpy(cap->driver, "atmel_mxt_ts", sizeof(cap->driver));
+	strlcpy(cap->card, "atmel_mxt_ts touch", sizeof(cap->card));
+	snprintf(cap->bus_info, sizeof(cap->bus_info),
+		 "I2C:%s", dev_name(&data->client->dev));
+	return 0;
+}
+
+static int mxt_vidioc_enum_input(struct file *file, void *priv,
+				   struct v4l2_input *i)
+{
+	if (i->index > 0)
+		return -EINVAL;
+
+	i->type = V4L2_INPUT_TYPE_TOUCH_SENSOR;
+	strlcpy(i->name, "Mutual References", sizeof(i->name));
+	return 0;
+}
+
+static int mxt_set_input(struct mxt_data *data, unsigned int i)
+{
+	struct v4l2_pix_format *f = &data->dbg.format;
+
+	if (i > 0)
+		return -EINVAL;
+
+	f->width = data->info.matrix_xsize;
+	f->height = data->info.matrix_ysize;
+	f->pixelformat = V4L2_PIX_FMT_YS16;
+	f->field = V4L2_FIELD_NONE;
+	f->colorspace = V4L2_COLORSPACE_RAW;
+	f->bytesperline = f->width * sizeof(u16);
+	f->sizeimage = f->width * f->height * sizeof(u16);
+
+	data->dbg.input = i;
+
+	return 0;
+}
+
+static int mxt_vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	return mxt_set_input(video_drvdata(file), i);
+}
+
+static int mxt_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct mxt_data *data = video_drvdata(file);
+
+	*i = data->dbg.input;
+
+	return 0;
+}
+
+static int mxt_vidioc_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct mxt_data *data = video_drvdata(file);
+
+	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	f->fmt.pix = data->dbg.format;
+
+	return 0;
+}
+
+static int mxt_vidioc_enum_fmt(struct file *file, void *priv,
+				 struct v4l2_fmtdesc *fmt)
+{
+	if (fmt->index > 0 || fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	fmt->pixelformat = V4L2_PIX_FMT_YS16;
+	return 0;
+}
+
+static int mxt_vidioc_g_parm(struct file *file, void *fh,
+			     struct v4l2_streamparm *a)
+{
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	a->parm.capture.readbuffers = 1;
+	a->parm.capture.timeperframe.numerator = 1;
+	a->parm.capture.timeperframe.denominator = 10;
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops mxt_video_ioctl_ops = {
+	.vidioc_querycap        = mxt_vidioc_querycap,
+
+	.vidioc_enum_fmt_vid_cap = mxt_vidioc_enum_fmt,
+	.vidioc_s_fmt_vid_cap   = mxt_vidioc_fmt,
+	.vidioc_g_fmt_vid_cap   = mxt_vidioc_fmt,
+	.vidioc_try_fmt_vid_cap	= mxt_vidioc_fmt,
+	.vidioc_g_parm		= mxt_vidioc_g_parm,
+
+	.vidioc_enum_input      = mxt_vidioc_enum_input,
+	.vidioc_g_input         = mxt_vidioc_g_input,
+	.vidioc_s_input         = mxt_vidioc_s_input,
+
+	.vidioc_reqbufs         = vb2_ioctl_reqbufs,
+	.vidioc_create_bufs     = vb2_ioctl_create_bufs,
+	.vidioc_querybuf        = vb2_ioctl_querybuf,
+	.vidioc_qbuf            = vb2_ioctl_qbuf,
+	.vidioc_dqbuf           = vb2_ioctl_dqbuf,
+	.vidioc_expbuf          = vb2_ioctl_expbuf,
+
+	.vidioc_streamon        = vb2_ioctl_streamon,
+	.vidioc_streamoff       = vb2_ioctl_streamoff,
+};
+
+static const struct video_device mxt_video_device = {
+	.name = "Atmel maxTouch",
+	.fops = &mxt_video_fops,
+	.ioctl_ops = &mxt_video_ioctl_ops,
+	.release = video_device_release_empty,
+	.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+		       V4L2_CAP_STREAMING,
+};
+
 static void mxt_debug_init(struct mxt_data *data)
 {
 	struct mxt_dbg *dbg = &data->dbg;
 	struct mxt_object *object;
+	int error;
 
 	object = mxt_get_object(data, MXT_GEN_COMMAND_T6);
 	if (!object)
@@ -2187,8 +2397,45 @@ static void mxt_debug_init(struct mxt_data *data)
 	if (!dbg->t37_buf)
 		goto error;
 
+	/* init channel to zero */
+	mxt_set_input(data, 0);
+
+	/* register video device */
+	snprintf(dbg->v4l2.name, sizeof(dbg->v4l2.name), "%s", "atmel_mxt_ts");
+	error = v4l2_device_register(&data->client->dev, &dbg->v4l2);
+	if (error) {
+		dev_err(&data->client->dev, "Unable to register video master device.");
+		goto error;
+	}
+
+	/* initialize the queue */
+	mutex_init(&dbg->lock);
+	dbg->queue = mxt_queue;
+	dbg->queue.drv_priv = data;
+	dbg->queue.lock = &dbg->lock;
+
+	error = vb2_queue_init(&dbg->queue);
+	if (error)
+		goto error_unreg_v4l2;
+
+	dbg->vdev = mxt_video_device;
+	dbg->vdev.v4l2_dev = &dbg->v4l2;
+	dbg->vdev.lock = &dbg->lock;
+	dbg->vdev.vfl_dir = VFL_DIR_RX;
+	dbg->vdev.queue = &dbg->queue;
+	video_set_drvdata(&dbg->vdev, data);
+
+	error = video_register_device(&dbg->vdev, VFL_TYPE_TOUCH_SENSOR, -1);
+	if (error) {
+		dev_err(&data->client->dev,
+				"Unable to register video subdevice.");
+		goto error_unreg_v4l2;
+	}
+
 	return;
 
+error_unreg_v4l2:
+	v4l2_device_unregister(&dbg->v4l2);
 error:
 	dev_err(&data->client->dev, "Error initialising T37 diagnostic data\n");
 }
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1411455 — Re: [PATCH v3 4/8] Input: atmel_mxt_ts - output diagnostic debug via v4l2 device

FromDmitry Torokhov <dmitry.torokhov@gmail.com>
Date2016-06-01 20:20 +0200
SubjectRe: [PATCH v3 4/8] Input: atmel_mxt_ts - output diagnostic debug via v4l2 device
Message-ID<rFiUi-3wl-23@gated-at.bofh.it>
In reply to#1411399
On Wed, Jun 01, 2016 at 05:39:48PM +0100, Nick Dyer wrote:
> Register a video device to output T37 diagnostic data.
> 
> Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
> ---
>  drivers/input/touchscreen/Kconfig        |   2 +
>  drivers/input/touchscreen/atmel_mxt_ts.c | 247 +++++++++++++++++++++++++++++++
>  2 files changed, 249 insertions(+)
> 
> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
> index 8ecdc38..73154b6 100644
> --- a/drivers/input/touchscreen/Kconfig
> +++ b/drivers/input/touchscreen/Kconfig
> @@ -105,6 +105,8 @@ config TOUCHSCREEN_AR1021_I2C
>  config TOUCHSCREEN_ATMEL_MXT
>  	tristate "Atmel mXT I2C Touchscreen"
>  	depends on I2C
> +	depends on VIDEO_V4L2

Hmm.. can we possibly stub this out? I do not think we want to depend on
V4L2 unconditionally.

> +	select VIDEOBUF2_VMALLOC
>  	select FW_LOADER
>  	help
>  	  Say Y here if you have Atmel mXT series I2C touchscreen,
> diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
> index 21f42ed..8608cb1 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -28,6 +28,10 @@
>  #include <linux/of.h>
>  #include <linux/slab.h>
>  #include <asm/unaligned.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/videobuf2-v4l2.h>
> +#include <media/videobuf2-vmalloc.h>
>  
>  /* Firmware files */
>  #define MXT_FW_NAME		"maxtouch.fw"
> @@ -222,6 +226,23 @@ struct mxt_dbg {
>  	struct t37_debug *t37_buf;
>  	unsigned int t37_pages;
>  	unsigned int t37_nodes;
> +
> +	struct v4l2_device v4l2;
> +	struct v4l2_pix_format format;
> +	struct video_device vdev;
> +	struct vb2_queue queue;
> +	struct mutex lock;
> +	int input;
> +};
> +
> +static const struct v4l2_file_operations mxt_video_fops = {
> +	.owner = THIS_MODULE,
> +	.open = v4l2_fh_open,
> +	.release = vb2_fop_release,
> +	.unlocked_ioctl = video_ioctl2,
> +	.read = vb2_fop_read,
> +	.mmap = vb2_fop_mmap,
> +	.poll = vb2_fop_poll,
>  };
>  
>  /* Each client has this additional data */
> @@ -277,6 +298,11 @@ struct mxt_data {
>  	struct completion crc_completion;
>  };
>  
> +struct mxt_vb2_buffer {
> +	struct vb2_buffer	vb;
> +	struct list_head	list;
> +};
> +
>  static size_t mxt_obj_size(const struct mxt_object *obj)
>  {
>  	return obj->size_minus_one + 1;
> @@ -1523,6 +1549,9 @@ static void mxt_free_input_device(struct mxt_data *data)
>  
>  static void mxt_free_object_table(struct mxt_data *data)
>  {
> +	video_unregister_device(&data->dbg.vdev);
> +	v4l2_device_unregister(&data->dbg.v4l2);
> +
>  	kfree(data->object_table);
>  	data->object_table = NULL;
>  	kfree(data->msg_buf);
> @@ -2154,10 +2183,191 @@ wait_cmd:
>  	return mxt_convert_debug_pages(data, outbuf);
>  }
>  
> +static int mxt_queue_setup(struct vb2_queue *q,
> +		       unsigned int *nbuffers, unsigned int *nplanes,
> +		       unsigned int sizes[], void *alloc_ctxs[])
> +{
> +	struct mxt_data *data = q->drv_priv;
> +	size_t size = data->dbg.t37_nodes * sizeof(u16);
> +
> +	if (*nplanes)
> +		return sizes[0] < size ? -EINVAL : 0;
> +
> +	*nplanes = 1;
> +	sizes[0] = size;
> +
> +	return 0;
> +}
> +
> +static void mxt_buffer_queue(struct vb2_buffer *vb)
> +{
> +	struct mxt_data *data = vb2_get_drv_priv(vb->vb2_queue);
> +	u16 *ptr;
> +	int ret;
> +
> +	ptr = vb2_plane_vaddr(vb, 0);
> +	if (!ptr) {
> +		dev_err(&data->client->dev, "Error acquiring frame ptr\n");
> +		goto fault;
> +	}
> +
> +	ret = mxt_read_diagnostic_debug(data, MXT_DIAGNOSTIC_DELTAS, ptr);
> +	if (ret)
> +		goto fault;
> +
> +	vb2_set_plane_payload(vb, 0, data->dbg.t37_nodes * sizeof(u16));
> +	vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
> +	return;
> +
> +fault:
> +	vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
> +}
> +
> +/* V4L2 structures */
> +static const struct vb2_ops mxt_queue_ops = {
> +	.queue_setup		= mxt_queue_setup,
> +	.buf_queue		= mxt_buffer_queue,
> +	.wait_prepare		= vb2_ops_wait_prepare,
> +	.wait_finish		= vb2_ops_wait_finish,
> +};
> +
> +static const struct vb2_queue mxt_queue = {
> +	.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
> +	.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ,
> +	.buf_struct_size = sizeof(struct mxt_vb2_buffer),
> +	.ops = &mxt_queue_ops,
> +	.mem_ops = &vb2_vmalloc_memops,
> +	.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC,
> +	.min_buffers_needed = 1,
> +};
> +
> +static int mxt_vidioc_querycap(struct file *file, void *priv,
> +				 struct v4l2_capability *cap)
> +{
> +	struct mxt_data *data = video_drvdata(file);
> +
> +	strlcpy(cap->driver, "atmel_mxt_ts", sizeof(cap->driver));
> +	strlcpy(cap->card, "atmel_mxt_ts touch", sizeof(cap->card));
> +	snprintf(cap->bus_info, sizeof(cap->bus_info),
> +		 "I2C:%s", dev_name(&data->client->dev));
> +	return 0;
> +}
> +
> +static int mxt_vidioc_enum_input(struct file *file, void *priv,
> +				   struct v4l2_input *i)
> +{
> +	if (i->index > 0)
> +		return -EINVAL;
> +
> +	i->type = V4L2_INPUT_TYPE_TOUCH_SENSOR;
> +	strlcpy(i->name, "Mutual References", sizeof(i->name));
> +	return 0;
> +}
> +
> +static int mxt_set_input(struct mxt_data *data, unsigned int i)
> +{
> +	struct v4l2_pix_format *f = &data->dbg.format;
> +
> +	if (i > 0)
> +		return -EINVAL;
> +
> +	f->width = data->info.matrix_xsize;
> +	f->height = data->info.matrix_ysize;
> +	f->pixelformat = V4L2_PIX_FMT_YS16;
> +	f->field = V4L2_FIELD_NONE;
> +	f->colorspace = V4L2_COLORSPACE_RAW;
> +	f->bytesperline = f->width * sizeof(u16);
> +	f->sizeimage = f->width * f->height * sizeof(u16);
> +
> +	data->dbg.input = i;
> +
> +	return 0;
> +}
> +
> +static int mxt_vidioc_s_input(struct file *file, void *priv, unsigned int i)
> +{
> +	return mxt_set_input(video_drvdata(file), i);
> +}
> +
> +static int mxt_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
> +{
> +	struct mxt_data *data = video_drvdata(file);
> +
> +	*i = data->dbg.input;
> +
> +	return 0;
> +}
> +
> +static int mxt_vidioc_fmt(struct file *file, void *priv, struct v4l2_format *f)
> +{
> +	struct mxt_data *data = video_drvdata(file);
> +
> +	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +	f->fmt.pix = data->dbg.format;
> +
> +	return 0;
> +}
> +
> +static int mxt_vidioc_enum_fmt(struct file *file, void *priv,
> +				 struct v4l2_fmtdesc *fmt)
> +{
> +	if (fmt->index > 0 || fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
> +		return -EINVAL;
> +
> +	fmt->pixelformat = V4L2_PIX_FMT_YS16;
> +	return 0;
> +}
> +
> +static int mxt_vidioc_g_parm(struct file *file, void *fh,
> +			     struct v4l2_streamparm *a)
> +{
> +	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
> +		return -EINVAL;
> +
> +	a->parm.capture.readbuffers = 1;
> +	a->parm.capture.timeperframe.numerator = 1;
> +	a->parm.capture.timeperframe.denominator = 10;
> +	return 0;
> +}
> +
> +static const struct v4l2_ioctl_ops mxt_video_ioctl_ops = {
> +	.vidioc_querycap        = mxt_vidioc_querycap,
> +
> +	.vidioc_enum_fmt_vid_cap = mxt_vidioc_enum_fmt,
> +	.vidioc_s_fmt_vid_cap   = mxt_vidioc_fmt,
> +	.vidioc_g_fmt_vid_cap   = mxt_vidioc_fmt,
> +	.vidioc_try_fmt_vid_cap	= mxt_vidioc_fmt,
> +	.vidioc_g_parm		= mxt_vidioc_g_parm,
> +
> +	.vidioc_enum_input      = mxt_vidioc_enum_input,
> +	.vidioc_g_input         = mxt_vidioc_g_input,
> +	.vidioc_s_input         = mxt_vidioc_s_input,
> +
> +	.vidioc_reqbufs         = vb2_ioctl_reqbufs,
> +	.vidioc_create_bufs     = vb2_ioctl_create_bufs,
> +	.vidioc_querybuf        = vb2_ioctl_querybuf,
> +	.vidioc_qbuf            = vb2_ioctl_qbuf,
> +	.vidioc_dqbuf           = vb2_ioctl_dqbuf,
> +	.vidioc_expbuf          = vb2_ioctl_expbuf,
> +
> +	.vidioc_streamon        = vb2_ioctl_streamon,
> +	.vidioc_streamoff       = vb2_ioctl_streamoff,
> +};
> +
> +static const struct video_device mxt_video_device = {
> +	.name = "Atmel maxTouch",
> +	.fops = &mxt_video_fops,
> +	.ioctl_ops = &mxt_video_ioctl_ops,
> +	.release = video_device_release_empty,
> +	.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
> +		       V4L2_CAP_STREAMING,
> +};
> +
>  static void mxt_debug_init(struct mxt_data *data)
>  {
>  	struct mxt_dbg *dbg = &data->dbg;
>  	struct mxt_object *object;
> +	int error;
>  
>  	object = mxt_get_object(data, MXT_GEN_COMMAND_T6);
>  	if (!object)
> @@ -2187,8 +2397,45 @@ static void mxt_debug_init(struct mxt_data *data)
>  	if (!dbg->t37_buf)
>  		goto error;
>  
> +	/* init channel to zero */
> +	mxt_set_input(data, 0);
> +
> +	/* register video device */
> +	snprintf(dbg->v4l2.name, sizeof(dbg->v4l2.name), "%s", "atmel_mxt_ts");
> +	error = v4l2_device_register(&data->client->dev, &dbg->v4l2);
> +	if (error) {
> +		dev_err(&data->client->dev, "Unable to register video master device.");
> +		goto error;
> +	}
> +
> +	/* initialize the queue */
> +	mutex_init(&dbg->lock);
> +	dbg->queue = mxt_queue;
> +	dbg->queue.drv_priv = data;
> +	dbg->queue.lock = &dbg->lock;
> +
> +	error = vb2_queue_init(&dbg->queue);
> +	if (error)
> +		goto error_unreg_v4l2;
> +
> +	dbg->vdev = mxt_video_device;
> +	dbg->vdev.v4l2_dev = &dbg->v4l2;
> +	dbg->vdev.lock = &dbg->lock;
> +	dbg->vdev.vfl_dir = VFL_DIR_RX;
> +	dbg->vdev.queue = &dbg->queue;
> +	video_set_drvdata(&dbg->vdev, data);
> +
> +	error = video_register_device(&dbg->vdev, VFL_TYPE_TOUCH_SENSOR, -1);
> +	if (error) {
> +		dev_err(&data->client->dev,
> +				"Unable to register video subdevice.");
> +		goto error_unreg_v4l2;
> +	}
> +
>  	return;
>  
> +error_unreg_v4l2:
> +	v4l2_device_unregister(&dbg->v4l2);
>  error:
>  	dev_err(&data->client->dev, "Error initialising T37 diagnostic data\n");
>  }
> -- 
> 2.5.0
> 

-- 
Dmitry

[toc] | [prev] | [next] | [standalone]


#1411400 — [PATCH v3 7/8] Input: atmel_mxt_ts - add diagnostic data support for mXT1386

FromNick Dyer <nick.dyer@itdev.co.uk>
Date2016-06-01 18:50 +0200
Subject[PATCH v3 7/8] Input: atmel_mxt_ts - add diagnostic data support for mXT1386
Message-ID<rFhve-2p3-77@gated-at.bofh.it>
In reply to#1411396
The mXT1386 family of chips have a different architecture which splits
the diagnostic data into 3 columns.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c | 29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index eced661..7d8002d 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -137,6 +137,10 @@ struct t9_range {
 #define MXT_DIAGNOSTIC_DELTAS	0x10
 #define MXT_DIAGNOSTIC_SIZE	128
 
+#define MXT_FAMILY_1386			160
+#define MXT1386_COLUMNS			3
+#define MXT1386_PAGES_PER_COLUMN	8
+
 struct t37_debug {
 	u8 mode;
 	u8 page;
@@ -2135,13 +2139,27 @@ recheck:
 static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x,
 			       unsigned int y)
 {
+	struct mxt_info *info = &data->info;
 	struct mxt_dbg *dbg = &data->dbg;
 	unsigned int ofs, page;
+	unsigned int col = 0;
+	unsigned int col_width;
+
+	if (info->family_id == MXT_FAMILY_1386) {
+		col_width = info->matrix_ysize / MXT1386_COLUMNS;
+		col = y / col_width;
+		y = y % col_width;
+	} else {
+		col_width = info->matrix_ysize;
+	}
 
-	ofs = (y + (x * data->info.matrix_ysize)) * sizeof(u16);
+	ofs = (y + (x * col_width)) * sizeof(u16);
 	page = ofs / MXT_DIAGNOSTIC_SIZE;
 	ofs %= MXT_DIAGNOSTIC_SIZE;
 
+	if (info->family_id == MXT_FAMILY_1386)
+		page += col * MXT1386_PAGES_PER_COLUMN;
+
 	return get_unaligned_le16(&dbg->t37_buf[page].data[ofs]);
 }
 
@@ -2411,6 +2429,7 @@ static const struct video_device mxt_video_device = {
 
 static void mxt_debug_init(struct mxt_data *data)
 {
+	struct mxt_info *info = &data->info;
 	struct mxt_dbg *dbg = &data->dbg;
 	struct mxt_object *object;
 	int error;
@@ -2434,9 +2453,13 @@ static void mxt_debug_init(struct mxt_data *data)
 
 	/* Calculate size of data and allocate buffer */
 	dbg->t37_nodes = data->xsize * data->ysize;
-	dbg->t37_pages = ((data->xsize * data->info.matrix_ysize)
-			  * sizeof(u16) / sizeof(dbg->t37_buf->data)) + 1;
 
+	if (info->family_id == MXT_FAMILY_1386)
+		dbg->t37_pages = MXT1386_COLUMNS * MXT1386_PAGES_PER_COLUMN;
+	else
+		dbg->t37_pages = ((data->xsize * info->matrix_ysize)
+				   * sizeof(u16) / sizeof(dbg->t37_buf->data))
+				   + 1;
 
 	dbg->t37_buf = devm_kzalloc(&data->client->dev,
 				     sizeof(struct t37_debug) * dbg->t37_pages,
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1411450 — Re: [PATCH v3 7/8] Input: atmel_mxt_ts - add diagnostic data support for mXT1386

FromDmitry Torokhov <dmitry.torokhov@gmail.com>
Date2016-06-01 20:20 +0200
SubjectRe: [PATCH v3 7/8] Input: atmel_mxt_ts - add diagnostic data support for mXT1386
Message-ID<rFiUi-3wl-5@gated-at.bofh.it>
In reply to#1411400
On Wed, Jun 01, 2016 at 05:39:51PM +0100, Nick Dyer wrote:
> The mXT1386 family of chips have a different architecture which splits
> the diagnostic data into 3 columns.
> 
> Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
> ---
>  drivers/input/touchscreen/atmel_mxt_ts.c | 29 ++++++++++++++++++++++++++---
>  1 file changed, 26 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
> index eced661..7d8002d 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -137,6 +137,10 @@ struct t9_range {
>  #define MXT_DIAGNOSTIC_DELTAS	0x10
>  #define MXT_DIAGNOSTIC_SIZE	128
>  
> +#define MXT_FAMILY_1386			160
> +#define MXT1386_COLUMNS			3
> +#define MXT1386_PAGES_PER_COLUMN	8
> +
>  struct t37_debug {
>  	u8 mode;
>  	u8 page;
> @@ -2135,13 +2139,27 @@ recheck:
>  static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x,
>  			       unsigned int y)
>  {
> +	struct mxt_info *info = &data->info;
>  	struct mxt_dbg *dbg = &data->dbg;
>  	unsigned int ofs, page;
> +	unsigned int col = 0;
> +	unsigned int col_width;
> +
> +	if (info->family_id == MXT_FAMILY_1386) {
> +		col_width = info->matrix_ysize / MXT1386_COLUMNS;
> +		col = y / col_width;
> +		y = y % col_width;
> +	} else {
> +		col_width = info->matrix_ysize;
> +	}
>  
> -	ofs = (y + (x * data->info.matrix_ysize)) * sizeof(u16);
> +	ofs = (y + (x * col_width)) * sizeof(u16);
>  	page = ofs / MXT_DIAGNOSTIC_SIZE;
>  	ofs %= MXT_DIAGNOSTIC_SIZE;
>  
> +	if (info->family_id == MXT_FAMILY_1386)
> +		page += col * MXT1386_PAGES_PER_COLUMN;
> +
>  	return get_unaligned_le16(&dbg->t37_buf[page].data[ofs]);
>  }
>  
> @@ -2411,6 +2429,7 @@ static const struct video_device mxt_video_device = {
>  
>  static void mxt_debug_init(struct mxt_data *data)
>  {
> +	struct mxt_info *info = &data->info;
>  	struct mxt_dbg *dbg = &data->dbg;
>  	struct mxt_object *object;
>  	int error;
> @@ -2434,9 +2453,13 @@ static void mxt_debug_init(struct mxt_data *data)
>  
>  	/* Calculate size of data and allocate buffer */
>  	dbg->t37_nodes = data->xsize * data->ysize;
> -	dbg->t37_pages = ((data->xsize * data->info.matrix_ysize)
> -			  * sizeof(u16) / sizeof(dbg->t37_buf->data)) + 1;
>  
> +	if (info->family_id == MXT_FAMILY_1386)
> +		dbg->t37_pages = MXT1386_COLUMNS * MXT1386_PAGES_PER_COLUMN;
> +	else
> +		dbg->t37_pages = ((data->xsize * info->matrix_ysize)
> +				   * sizeof(u16) / sizeof(dbg->t37_buf->data))
> +				   + 1;

Won't this result in an extra page in some cases. DIV_ROUND_UP instead?

>  
>  	dbg->t37_buf = devm_kzalloc(&data->client->dev,
>  				     sizeof(struct t37_debug) * dbg->t37_pages,
> -- 
> 2.5.0
> 

-- 
Dmitry

[toc] | [prev] | [next] | [standalone]


#1411401 — [PATCH v3 1/8] Input: atmel_mxt_ts - add support for T37 diagnostic data

FromNick Dyer <nick.dyer@itdev.co.uk>
Date2016-06-01 18:50 +0200
Subject[PATCH v3 1/8] Input: atmel_mxt_ts - add support for T37 diagnostic data
Message-ID<rFhve-2p3-91@gated-at.bofh.it>
In reply to#1411396
Atmel maXTouch devices have a T37 object which can be used to read raw
touch deltas from the device. This consists of an array of 16-bit
integers, one for each node on the touchscreen matrix.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c | 152 +++++++++++++++++++++++++++++++
 1 file changed, 152 insertions(+)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 5af7907..21f42ed 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -124,6 +124,17 @@ struct t9_range {
 #define MXT_COMMS_CTRL		0
 #define MXT_COMMS_CMD		1
 
+/* MXT_DEBUG_DIAGNOSTIC_T37 */
+#define MXT_DIAGNOSTIC_PAGEUP	0x01
+#define MXT_DIAGNOSTIC_DELTAS	0x10
+#define MXT_DIAGNOSTIC_SIZE	128
+
+struct t37_debug {
+	u8 mode;
+	u8 page;
+	u8 data[MXT_DIAGNOSTIC_SIZE];
+};
+
 /* Define for MXT_GEN_COMMAND_T6 */
 #define MXT_BOOT_VALUE		0xa5
 #define MXT_RESET_VALUE		0x01
@@ -205,6 +216,14 @@ struct mxt_object {
 	u8 num_report_ids;
 } __packed;
 
+struct mxt_dbg {
+	u16 t37_address;
+	u16 diag_cmd_address;
+	struct t37_debug *t37_buf;
+	unsigned int t37_pages;
+	unsigned int t37_nodes;
+};
+
 /* Each client has this additional data */
 struct mxt_data {
 	struct i2c_client *client;
@@ -233,6 +252,7 @@ struct mxt_data {
 	u8 num_touchids;
 	u8 multitouch;
 	struct t7_config t7_cfg;
+	struct mxt_dbg dbg;
 
 	/* Cached parameters from object table */
 	u16 T5_address;
@@ -2043,6 +2063,136 @@ recheck:
 	return 0;
 }
 
+static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x,
+			       unsigned int y)
+{
+	struct mxt_dbg *dbg = &data->dbg;
+	unsigned int ofs, page;
+
+	ofs = (y + (x * data->info.matrix_ysize)) * sizeof(u16);
+	page = ofs / MXT_DIAGNOSTIC_SIZE;
+	ofs %= MXT_DIAGNOSTIC_SIZE;
+
+	return get_unaligned_le16(&dbg->t37_buf[page].data[ofs]);
+}
+
+static int mxt_convert_debug_pages(struct mxt_data *data, u16 *outbuf)
+{
+	struct mxt_dbg *dbg = &data->dbg;
+	unsigned int x = 0;
+	unsigned int y = 0;
+	unsigned int i;
+
+	for (i = 0; i < dbg->t37_nodes; i++) {
+		outbuf[i] = mxt_get_debug_value(data, x, y);
+
+		/* Next value */
+		if (++x >= data->info.matrix_xsize) {
+			x = 0;
+			y++;
+		}
+	}
+
+	return 0;
+}
+
+static int mxt_read_diagnostic_debug(struct mxt_data *data, u8 mode,
+				     u16 *outbuf)
+{
+	struct mxt_dbg *dbg = &data->dbg;
+	int retries = 0;
+	int page;
+	int ret;
+	u8 cmd = mode;
+	struct t37_debug *p;
+	u8 cmd_poll;
+
+	for (page = 0; page < dbg->t37_pages; page++) {
+		p = dbg->t37_buf + page;
+
+		ret = mxt_write_reg(data->client, dbg->diag_cmd_address,
+				    cmd);
+		if (ret)
+			return ret;
+
+		retries = 0;
+		msleep(20);
+wait_cmd:
+		/* Read back command byte */
+		ret = __mxt_read_reg(data->client, dbg->diag_cmd_address,
+				     sizeof(cmd_poll), &cmd_poll);
+		if (ret)
+			return ret;
+
+		/* Field is cleared once the command has been processed */
+		if (cmd_poll) {
+			if (retries++ > 100)
+				return -EINVAL;
+
+			msleep(20);
+			goto wait_cmd;
+		}
+
+		/* Read T37 page */
+		ret = __mxt_read_reg(data->client, dbg->t37_address,
+				sizeof(struct t37_debug), p);
+		if (ret)
+			return ret;
+
+		if ((p->mode != mode) || (p->page != page)) {
+			dev_err(&data->client->dev, "T37 page mismatch\n");
+			return -EINVAL;
+		}
+
+		dev_dbg(&data->client->dev, "%s page:%d retries:%d\n",
+			__func__, page, retries);
+
+		/* For remaining pages, write PAGEUP rather than mode */
+		cmd = MXT_DIAGNOSTIC_PAGEUP;
+	}
+
+	return mxt_convert_debug_pages(data, outbuf);
+}
+
+static void mxt_debug_init(struct mxt_data *data)
+{
+	struct mxt_dbg *dbg = &data->dbg;
+	struct mxt_object *object;
+
+	object = mxt_get_object(data, MXT_GEN_COMMAND_T6);
+	if (!object)
+		return;
+
+	dbg->diag_cmd_address = object->start_address + MXT_COMMAND_DIAGNOSTIC;
+
+	object = mxt_get_object(data, MXT_DEBUG_DIAGNOSTIC_T37);
+	if (!object)
+		return;
+
+	if (mxt_obj_size(object) != sizeof(struct t37_debug)) {
+		dev_warn(&data->client->dev, "Bad T37 size");
+		return;
+	}
+
+	dbg->t37_address = object->start_address;
+
+	/* Calculate size of data and allocate buffer */
+	dbg->t37_nodes = data->info.matrix_xsize * data->info.matrix_ysize;
+	dbg->t37_pages = dbg->t37_nodes * sizeof(u16)
+					/ sizeof(dbg->t37_buf->data) + 1;
+
+	dbg->t37_buf = devm_kzalloc(&data->client->dev,
+				     sizeof(struct t37_debug) * dbg->t37_pages,
+				     GFP_KERNEL);
+	if (!dbg->t37_buf)
+		goto error;
+
+	return;
+
+error:
+	dev_err(&data->client->dev, "Error initialising T37 diagnostic data\n");
+}
+
 static int mxt_configure_objects(struct mxt_data *data,
 				 const struct firmware *cfg)
 {
@@ -2070,6 +2220,8 @@ static int mxt_configure_objects(struct mxt_data *data,
 		dev_warn(dev, "No touch object detected\n");
 	}
 
+	mxt_debug_init(data);
+
 	dev_info(dev,
 		 "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
 		 info->family_id, info->variant_id, info->version >> 4,
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1411454 — Re: [PATCH v3 1/8] Input: atmel_mxt_ts - add support for T37 diagnostic data

FromDmitry Torokhov <dmitry.torokhov@gmail.com>
Date2016-06-01 20:20 +0200
SubjectRe: [PATCH v3 1/8] Input: atmel_mxt_ts - add support for T37 diagnostic data
Message-ID<rFiUi-3wl-29@gated-at.bofh.it>
In reply to#1411401
Hi Nick,

On Wed, Jun 01, 2016 at 05:39:45PM +0100, Nick Dyer wrote:
> Atmel maXTouch devices have a T37 object which can be used to read raw
> touch deltas from the device. This consists of an array of 16-bit
> integers, one for each node on the touchscreen matrix.
> 
> Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
> ---
>  drivers/input/touchscreen/atmel_mxt_ts.c | 152 +++++++++++++++++++++++++++++++
>  1 file changed, 152 insertions(+)
> 
> diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
> index 5af7907..21f42ed 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -124,6 +124,17 @@ struct t9_range {
>  #define MXT_COMMS_CTRL		0
>  #define MXT_COMMS_CMD		1
>  
> +/* MXT_DEBUG_DIAGNOSTIC_T37 */
> +#define MXT_DIAGNOSTIC_PAGEUP	0x01
> +#define MXT_DIAGNOSTIC_DELTAS	0x10
> +#define MXT_DIAGNOSTIC_SIZE	128
> +
> +struct t37_debug {
> +	u8 mode;
> +	u8 page;
> +	u8 data[MXT_DIAGNOSTIC_SIZE];
> +};
> +
>  /* Define for MXT_GEN_COMMAND_T6 */
>  #define MXT_BOOT_VALUE		0xa5
>  #define MXT_RESET_VALUE		0x01
> @@ -205,6 +216,14 @@ struct mxt_object {
>  	u8 num_report_ids;
>  } __packed;
>  
> +struct mxt_dbg {
> +	u16 t37_address;
> +	u16 diag_cmd_address;
> +	struct t37_debug *t37_buf;
> +	unsigned int t37_pages;
> +	unsigned int t37_nodes;
> +};
> +
>  /* Each client has this additional data */
>  struct mxt_data {
>  	struct i2c_client *client;
> @@ -233,6 +252,7 @@ struct mxt_data {
>  	u8 num_touchids;
>  	u8 multitouch;
>  	struct t7_config t7_cfg;
> +	struct mxt_dbg dbg;
>  
>  	/* Cached parameters from object table */
>  	u16 T5_address;
> @@ -2043,6 +2063,136 @@ recheck:
>  	return 0;
>  }
>  
> +static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x,
> +			       unsigned int y)
> +{
> +	struct mxt_dbg *dbg = &data->dbg;
> +	unsigned int ofs, page;
> +
> +	ofs = (y + (x * data->info.matrix_ysize)) * sizeof(u16);
> +	page = ofs / MXT_DIAGNOSTIC_SIZE;
> +	ofs %= MXT_DIAGNOSTIC_SIZE;
> +
> +	return get_unaligned_le16(&dbg->t37_buf[page].data[ofs]);
> +}
> +
> +static int mxt_convert_debug_pages(struct mxt_data *data, u16 *outbuf)
> +{
> +	struct mxt_dbg *dbg = &data->dbg;
> +	unsigned int x = 0;
> +	unsigned int y = 0;
> +	unsigned int i;
> +
> +	for (i = 0; i < dbg->t37_nodes; i++) {
> +		outbuf[i] = mxt_get_debug_value(data, x, y);
> +
> +		/* Next value */
> +		if (++x >= data->info.matrix_xsize) {
> +			x = 0;
> +			y++;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int mxt_read_diagnostic_debug(struct mxt_data *data, u8 mode,
> +				     u16 *outbuf)
> +{
> +	struct mxt_dbg *dbg = &data->dbg;
> +	int retries = 0;
> +	int page;
> +	int ret;
> +	u8 cmd = mode;
> +	struct t37_debug *p;
> +	u8 cmd_poll;
> +
> +	for (page = 0; page < dbg->t37_pages; page++) {
> +		p = dbg->t37_buf + page;
> +
> +		ret = mxt_write_reg(data->client, dbg->diag_cmd_address,
> +				    cmd);
> +		if (ret)
> +			return ret;
> +
> +		retries = 0;
> +		msleep(20);
> +wait_cmd:
> +		/* Read back command byte */
> +		ret = __mxt_read_reg(data->client, dbg->diag_cmd_address,
> +				     sizeof(cmd_poll), &cmd_poll);
> +		if (ret)
> +			return ret;
> +
> +		/* Field is cleared once the command has been processed */
> +		if (cmd_poll) {
> +			if (retries++ > 100)
> +				return -EINVAL;
> +
> +			msleep(20);
> +			goto wait_cmd;
> +		}
> +
> +		/* Read T37 page */
> +		ret = __mxt_read_reg(data->client, dbg->t37_address,
> +				sizeof(struct t37_debug), p);
> +		if (ret)
> +			return ret;
> +
> +		if ((p->mode != mode) || (p->page != page)) {

No need for extra parenthesis.

> +			dev_err(&data->client->dev, "T37 page mismatch\n");
> +			return -EINVAL;
> +		}
> +
> +		dev_dbg(&data->client->dev, "%s page:%d retries:%d\n",
> +			__func__, page, retries);
> +
> +		/* For remaining pages, write PAGEUP rather than mode */
> +		cmd = MXT_DIAGNOSTIC_PAGEUP;
> +	}
> +
> +	return mxt_convert_debug_pages(data, outbuf);
> +}
> +
> +static void mxt_debug_init(struct mxt_data *data)
> +{
> +	struct mxt_dbg *dbg = &data->dbg;
> +	struct mxt_object *object;
> +
> +	object = mxt_get_object(data, MXT_GEN_COMMAND_T6);
> +	if (!object)
> +		return;
> +
> +	dbg->diag_cmd_address = object->start_address + MXT_COMMAND_DIAGNOSTIC;
> +
> +	object = mxt_get_object(data, MXT_DEBUG_DIAGNOSTIC_T37);
> +	if (!object)
> +		return;
> +
> +	if (mxt_obj_size(object) != sizeof(struct t37_debug)) {
> +		dev_warn(&data->client->dev, "Bad T37 size");
> +		return;
> +	}
> +
> +	dbg->t37_address = object->start_address;
> +
> +	/* Calculate size of data and allocate buffer */
> +	dbg->t37_nodes = data->info.matrix_xsize * data->info.matrix_ysize;
> +	dbg->t37_pages = dbg->t37_nodes * sizeof(u16)
> +					/ sizeof(dbg->t37_buf->data) + 1;
> +
> +	dbg->t37_buf = devm_kzalloc(&data->client->dev,
> +				     sizeof(struct t37_debug) * dbg->t37_pages,
> +				     GFP_KERNEL);

devm_kcalloc() or devm_kmalloc_array() if memory does not need to be
zeroed out.

> +	if (!dbg->t37_buf)
> +		goto error;
> +
> +	return;
> +
> +error:
> +	dev_err(&data->client->dev, "Error initialising T37 diagnostic data\n");

Why do we only emit this message if memory allocation fails? And if it
is intentional why don't we do it inline?

> +}
> +
>  static int mxt_configure_objects(struct mxt_data *data,
>  				 const struct firmware *cfg)
>  {
> @@ -2070,6 +2220,8 @@ static int mxt_configure_objects(struct mxt_data *data,
>  		dev_warn(dev, "No touch object detected\n");
>  	}
>  
> +	mxt_debug_init(data);
> +
>  	dev_info(dev,
>  		 "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
>  		 info->family_id, info->variant_id, info->version >> 4,
> -- 
> 2.5.0
> 

Thanks.

-- 
Dmitry

[toc] | [prev] | [next] | [standalone]


#1411402 — [PATCH v3 5/8] Input: atmel_mxt_ts - read touchscreen size

FromNick Dyer <nick.dyer@itdev.co.uk>
Date2016-06-01 18:50 +0200
Subject[PATCH v3 5/8] Input: atmel_mxt_ts - read touchscreen size
Message-ID<rFhvf-2p3-109@gated-at.bofh.it>
In reply to#1411396
The touchscreen may have a margin where not all the matrix is used. Read
the parameters from T9 and T100 and take account of the difference.

Note: this does not read the XORIGIN/YORIGIN fields so it assumes that
the touchscreen starts at (0,0)

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c | 43 +++++++++++++++++++++++++++-----
 1 file changed, 37 insertions(+), 6 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 8608cb1..ac4126c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -103,6 +103,8 @@ struct t7_config {
 
 /* MXT_TOUCH_MULTI_T9 field */
 #define MXT_T9_CTRL		0
+#define MXT_T9_XSIZE		3
+#define MXT_T9_YSIZE		4
 #define MXT_T9_ORIENT		9
 #define MXT_T9_RANGE		18
 
@@ -148,7 +150,9 @@ struct t37_debug {
 #define MXT_T100_CTRL		0
 #define MXT_T100_CFG1		1
 #define MXT_T100_TCHAUX		3
+#define MXT_T100_XSIZE		9
 #define MXT_T100_XRANGE		13
+#define MXT_T100_YSIZE		20
 #define MXT_T100_YRANGE		24
 
 #define MXT_T100_CFG_SWITCHXY	BIT(5)
@@ -257,6 +261,8 @@ struct mxt_data {
 	unsigned int max_x;
 	unsigned int max_y;
 	bool xy_switch;
+	u8 xsize;
+	u8 ysize;
 	bool in_bootloader;
 	u16 mem_size;
 	u8 t100_aux_ampl;
@@ -1710,6 +1716,18 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
 		return -EINVAL;
 
 	error = __mxt_read_reg(client,
+			       object->start_address + MXT_T9_XSIZE,
+			       sizeof(data->xsize), &data->xsize);
+	if (error)
+		return error;
+
+	error = __mxt_read_reg(client,
+			       object->start_address + MXT_T9_YSIZE,
+			       sizeof(data->ysize), &data->ysize);
+	if (error)
+		return error;
+
+	error = __mxt_read_reg(client,
 			       object->start_address + MXT_T9_RANGE,
 			       sizeof(range), &range);
 	if (error)
@@ -1759,6 +1777,18 @@ static int mxt_read_t100_config(struct mxt_data *data)
 
 	data->max_y = get_unaligned_le16(&range_y);
 
+	error = __mxt_read_reg(client,
+			       object->start_address + MXT_T100_XSIZE,
+			       sizeof(data->xsize), &data->xsize);
+	if (error)
+		return error;
+
+	error = __mxt_read_reg(client,
+			       object->start_address + MXT_T100_YSIZE,
+			       sizeof(data->ysize), &data->ysize);
+	if (error)
+		return error;
+
 	/* read orientation config */
 	error =  __mxt_read_reg(client,
 				object->start_address + MXT_T100_CFG1,
@@ -2116,7 +2146,7 @@ static int mxt_convert_debug_pages(struct mxt_data *data, u16 *outbuf)
 		outbuf[i] = mxt_get_debug_value(data, x, y);
 
 		/* Next value */
-		if (++x >= data->info.matrix_xsize) {
+		if (++x >= data->xsize) {
 			x = 0;
 			y++;
 		}
@@ -2271,8 +2301,8 @@ static int mxt_set_input(struct mxt_data *data, unsigned int i)
 	if (i > 0)
 		return -EINVAL;
 
-	f->width = data->info.matrix_xsize;
-	f->height = data->info.matrix_ysize;
+	f->width = data->xsize;
+	f->height = data->ysize;
 	f->pixelformat = V4L2_PIX_FMT_YS16;
 	f->field = V4L2_FIELD_NONE;
 	f->colorspace = V4L2_COLORSPACE_RAW;
@@ -2387,9 +2417,10 @@ static void mxt_debug_init(struct mxt_data *data)
 	dbg->t37_address = object->start_address;
 
 	/* Calculate size of data and allocate buffer */
-	dbg->t37_nodes = data->info.matrix_xsize * data->info.matrix_ysize;
-	dbg->t37_pages = dbg->t37_nodes * sizeof(u16)
-					/ sizeof(dbg->t37_buf->data) + 1;
+	dbg->t37_nodes = data->xsize * data->ysize;
+	dbg->t37_pages = ((data->xsize * data->info.matrix_ysize)
+			  * sizeof(u16) / sizeof(dbg->t37_buf->data)) + 1;
+
 
 	dbg->t37_buf = devm_kzalloc(&data->client->dev,
 				     sizeof(struct t37_debug) * dbg->t37_pages,
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1411403 — [PATCH v3 3/8] [media] v4l2-core: Add VFL_TYPE_TOUCH_SENSOR

FromNick Dyer <nick.dyer@itdev.co.uk>
Date2016-06-01 18:50 +0200
Subject[PATCH v3 3/8] [media] v4l2-core: Add VFL_TYPE_TOUCH_SENSOR
Message-ID<rFhvf-2p3-115@gated-at.bofh.it>
In reply to#1411396
Some touch controllers send out raw touch data in a similar way to a
greyscale frame grabber. Add a new device type for these devices.

Use a new device prefix v4l-touch for these devices, to stop generic
capture software from treating them as webcams.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/sur40.c    |  2 +-
 drivers/media/v4l2-core/v4l2-dev.c   | 13 ++++++++++---
 drivers/media/v4l2-core/v4l2-ioctl.c | 15 ++++++++++-----
 include/media/v4l2-dev.h             |  3 ++-
 include/uapi/linux/videodev2.h       |  1 +
 5 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index 880c40b..7e5fe2b 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -599,7 +599,7 @@ static int sur40_probe(struct usb_interface *interface,
 	sur40->vdev.queue = &sur40->queue;
 	video_set_drvdata(&sur40->vdev, sur40);
 
-	error = video_register_device(&sur40->vdev, VFL_TYPE_GRABBER, -1);
+	error = video_register_device(&sur40->vdev, VFL_TYPE_TOUCH_SENSOR, -1);
 	if (error) {
 		dev_err(&interface->dev,
 			"Unable to register video subdevice.");
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 70b559d..7068e12 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -529,6 +529,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
 	bool is_sdr = vdev->vfl_type == VFL_TYPE_SDR;
 	bool is_rx = vdev->vfl_dir != VFL_DIR_TX;
 	bool is_tx = vdev->vfl_dir != VFL_DIR_RX;
+	bool is_touch = vdev->vfl_type == VFL_TYPE_TOUCH_SENSOR;
 
 	bitmap_zero(valid_ioctls, BASE_VIDIOC_PRIVATE);
 
@@ -573,7 +574,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
 	if (ops->vidioc_enum_freq_bands || ops->vidioc_g_tuner || ops->vidioc_g_modulator)
 		set_bit(_IOC_NR(VIDIOC_ENUM_FREQ_BANDS), valid_ioctls);
 
-	if (is_vid) {
+	if (is_vid || is_touch) {
 		/* video specific ioctls */
 		if ((is_rx && (ops->vidioc_enum_fmt_vid_cap ||
 			       ops->vidioc_enum_fmt_vid_cap_mplane ||
@@ -662,7 +663,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
 			set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls);
 	}
 
-	if (is_vid || is_vbi || is_sdr) {
+	if (is_vid || is_vbi || is_sdr || is_touch) {
 		/* ioctls valid for video, vbi or sdr */
 		SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs);
 		SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf);
@@ -675,7 +676,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
 		SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff);
 	}
 
-	if (is_vid || is_vbi) {
+	if (is_vid || is_vbi || is_touch) {
 		/* ioctls valid for video or vbi */
 		if (ops->vidioc_s_std)
 			set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls);
@@ -739,6 +740,7 @@ static int video_register_media_controller(struct video_device *vdev, int type)
 	vdev->entity.function = MEDIA_ENT_F_UNKNOWN;
 
 	switch (type) {
+	case VFL_TYPE_TOUCH_SENSOR:
 	case VFL_TYPE_GRABBER:
 		intf_type = MEDIA_INTF_T_V4L_VIDEO;
 		vdev->entity.function = MEDIA_ENT_F_IO_V4L;
@@ -845,6 +847,8 @@ static int video_register_media_controller(struct video_device *vdev, int type)
  *	%VFL_TYPE_SUBDEV - A subdevice
  *
  *	%VFL_TYPE_SDR - Software Defined Radio
+ *
+ *	%VFL_TYPE_TOUCH_SENSOR - A touch sensor
  */
 int __video_register_device(struct video_device *vdev, int type, int nr,
 		int warn_if_nr_in_use, struct module *owner)
@@ -888,6 +892,9 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
 		/* Use device name 'swradio' because 'sdr' was already taken. */
 		name_base = "swradio";
 		break;
+	case VFL_TYPE_TOUCH_SENSOR:
+		name_base = "v4l-touch";
+		break;
 	default:
 		printk(KERN_ERR "%s called with unknown type: %d\n",
 		       __func__, type);
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index ecf7e0b..352c4d0 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -924,6 +924,7 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type)
 	bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
 	bool is_vbi = vfd->vfl_type == VFL_TYPE_VBI;
 	bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
+	bool is_touch = vfd->vfl_type == VFL_TYPE_TOUCH_SENSOR;
 	bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
 	bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
 
@@ -932,7 +933,7 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type)
 
 	switch (type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (is_vid && is_rx &&
+		if ((is_vid || is_touch) && is_rx &&
 		    (ops->vidioc_g_fmt_vid_cap || ops->vidioc_g_fmt_vid_cap_mplane))
 			return 0;
 		break;
@@ -1310,13 +1311,14 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,
 	struct video_device *vfd = video_devdata(file);
 	bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
 	bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
+	bool is_touch = vfd->vfl_type == VFL_TYPE_TOUCH_SENSOR;
 	bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
 	bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
 	int ret = -EINVAL;
 
 	switch (p->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (unlikely(!is_rx || !is_vid || !ops->vidioc_enum_fmt_vid_cap))
+		if (unlikely(!is_rx || (!is_vid && !is_touch) || !ops->vidioc_enum_fmt_vid_cap))
 			break;
 		ret = ops->vidioc_enum_fmt_vid_cap(file, fh, arg);
 		break;
@@ -1363,6 +1365,7 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
 	struct video_device *vfd = video_devdata(file);
 	bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
 	bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
+	bool is_touch = vfd->vfl_type == VFL_TYPE_TOUCH_SENSOR;
 	bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
 	bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
 	int ret;
@@ -1393,7 +1396,7 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
 
 	switch (p->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_vid_cap))
+		if (unlikely(!is_rx || (!is_vid && !is_touch) || !ops->vidioc_g_fmt_vid_cap))
 			break;
 		p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
 		ret = ops->vidioc_g_fmt_vid_cap(file, fh, arg);
@@ -1459,6 +1462,7 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
 	struct video_device *vfd = video_devdata(file);
 	bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
 	bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
+	bool is_touch = vfd->vfl_type == VFL_TYPE_TOUCH_SENSOR;
 	bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
 	bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
 	int ret;
@@ -1470,7 +1474,7 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
 
 	switch (p->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_cap))
+		if (unlikely(!is_rx || (!is_vid && !is_touch) || !ops->vidioc_s_fmt_vid_cap))
 			break;
 		CLEAR_AFTER_FIELD(p, fmt.pix);
 		ret = ops->vidioc_s_fmt_vid_cap(file, fh, arg);
@@ -1546,6 +1550,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
 	struct video_device *vfd = video_devdata(file);
 	bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
 	bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
+	bool is_touch = vfd->vfl_type == VFL_TYPE_TOUCH_SENSOR;
 	bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
 	bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
 	int ret;
@@ -1554,7 +1559,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
 
 	switch (p->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_vid_cap))
+		if (unlikely(!is_rx || (!is_vid && !is_touch) || !ops->vidioc_try_fmt_vid_cap))
 			break;
 		CLEAR_AFTER_FIELD(p, fmt.pix);
 		ret = ops->vidioc_try_fmt_vid_cap(file, fh, arg);
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 25a3190..99eb87a 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -25,7 +25,8 @@
 #define VFL_TYPE_RADIO		2
 #define VFL_TYPE_SUBDEV		3
 #define VFL_TYPE_SDR		4
-#define VFL_TYPE_MAX		5
+#define VFL_TYPE_TOUCH_SENSOR	5
+#define VFL_TYPE_MAX		6
 
 /* Is this a receiver, transmitter or mem-to-mem? */
 /* Ignored for VFL_TYPE_SUBDEV. */
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index e0125cf..765a6cb 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1400,6 +1400,7 @@ struct v4l2_input {
 /*  Values for the 'type' field */
 #define V4L2_INPUT_TYPE_TUNER		1
 #define V4L2_INPUT_TYPE_CAMERA		2
+#define V4L2_INPUT_TYPE_TOUCH_SENSOR	3
 
 /* field 'status' - general */
 #define V4L2_IN_ST_NO_POWER    0x00000001  /* Attached device is off */
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1411405 — [PATCH v3 6/8] Input: atmel_mxt_ts - handle diagnostic data orientation

FromNick Dyer <nick.dyer@itdev.co.uk>
Date2016-06-01 18:50 +0200
Subject[PATCH v3 6/8] Input: atmel_mxt_ts - handle diagnostic data orientation
Message-ID<rFhvg-2p3-133@gated-at.bofh.it>
In reply to#1411396
Invert the diagnostic data to match the orientation of the input device.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c | 26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index ac4126c..eced661 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -125,6 +125,8 @@ struct t9_range {
 
 /* MXT_TOUCH_MULTI_T9 orient */
 #define MXT_T9_ORIENT_SWITCH	(1 << 0)
+#define MXT_T9_ORIENT_INVERTX	(1 << 1)
+#define MXT_T9_ORIENT_INVERTY	(1 << 2)
 
 /* MXT_SPT_COMMSCONFIG_T18 */
 #define MXT_COMMS_CTRL		0
@@ -156,6 +158,8 @@ struct t37_debug {
 #define MXT_T100_YRANGE		24
 
 #define MXT_T100_CFG_SWITCHXY	BIT(5)
+#define MXT_T100_CFG_INVERTY	BIT(6)
+#define MXT_T100_CFG_INVERTX	BIT(7)
 
 #define MXT_T100_TCHAUX_VECT	BIT(0)
 #define MXT_T100_TCHAUX_AMPL	BIT(1)
@@ -260,6 +264,8 @@ struct mxt_data {
 	unsigned int irq;
 	unsigned int max_x;
 	unsigned int max_y;
+	bool invertx;
+	bool inverty;
 	bool xy_switch;
 	u8 xsize;
 	u8 ysize;
@@ -1743,6 +1749,8 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
 		return error;
 
 	data->xy_switch = orient & MXT_T9_ORIENT_SWITCH;
+	data->invertx = orient & MXT_T9_ORIENT_INVERTX;
+	data->inverty = orient & MXT_T9_ORIENT_INVERTY;
 
 	return 0;
 }
@@ -1797,6 +1805,8 @@ static int mxt_read_t100_config(struct mxt_data *data)
 		return error;
 
 	data->xy_switch = cfg & MXT_T100_CFG_SWITCHXY;
+	data->invertx = cfg & MXT_T100_CFG_INVERTX;
+	data->inverty = cfg & MXT_T100_CFG_INVERTY;
 
 	/* allocate aux bytes */
 	error =  __mxt_read_reg(client,
@@ -2140,13 +2150,19 @@ static int mxt_convert_debug_pages(struct mxt_data *data, u16 *outbuf)
 	struct mxt_dbg *dbg = &data->dbg;
 	unsigned int x = 0;
 	unsigned int y = 0;
-	unsigned int i;
+	unsigned int i, rx, ry;
 
 	for (i = 0; i < dbg->t37_nodes; i++) {
-		outbuf[i] = mxt_get_debug_value(data, x, y);
+		/* Handle orientation */
+		rx = data->xy_switch ? y : x;
+		ry = data->xy_switch ? x : y;
+		rx = data->invertx ? (data->xsize - 1 - rx) : rx;
+		ry = data->inverty ? (data->ysize - 1 - ry) : ry;
+
+		outbuf[i] = mxt_get_debug_value(data, rx, ry);
 
 		/* Next value */
-		if (++x >= data->xsize) {
+		if (++x >= (data->xy_switch ? data->ysize : data->xsize)) {
 			x = 0;
 			y++;
 		}
@@ -2301,8 +2317,8 @@ static int mxt_set_input(struct mxt_data *data, unsigned int i)
 	if (i > 0)
 		return -EINVAL;
 
-	f->width = data->xsize;
-	f->height = data->ysize;
+	f->width = data->xy_switch ? data->ysize : data->xsize;
+	f->height = data->xy_switch ? data->xsize : data->ysize;
 	f->pixelformat = V4L2_PIX_FMT_YS16;
 	f->field = V4L2_FIELD_NONE;
 	f->colorspace = V4L2_COLORSPACE_RAW;
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1411408 — [PATCH v3 8/8] Input: atmel_mxt_ts - add support for reference data

FromNick Dyer <nick.dyer@itdev.co.uk>
Date2016-06-01 18:50 +0200
Subject[PATCH v3 8/8] Input: atmel_mxt_ts - add support for reference data
Message-ID<rFhvh-2p3-145@gated-at.bofh.it>
In reply to#1411396
There are different datatypes available from a maXTouch chip. Add
support to retrieve reference data as well.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c | 58 ++++++++++++++++++++++++++++----
 1 file changed, 51 insertions(+), 7 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 7d8002d..d9e0906 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -135,6 +135,7 @@ struct t9_range {
 /* MXT_DEBUG_DIAGNOSTIC_T37 */
 #define MXT_DIAGNOSTIC_PAGEUP	0x01
 #define MXT_DIAGNOSTIC_DELTAS	0x10
+#define MXT_DIAGNOSTIC_REFS	0x11
 #define MXT_DIAGNOSTIC_SIZE	128
 
 #define MXT_FAMILY_1386			160
@@ -247,6 +248,12 @@ struct mxt_dbg {
 	int input;
 };
 
+enum v4l_dbg_inputs {
+	MXT_V4L_INPUT_DELTAS,
+	MXT_V4L_INPUT_REFS,
+	MXT_V4L_INPUT_MAX,
+};
+
 static const struct v4l2_file_operations mxt_video_fops = {
 	.owner = THIS_MODULE,
 	.open = v4l2_fh_open,
@@ -2268,6 +2275,7 @@ static void mxt_buffer_queue(struct vb2_buffer *vb)
 	struct mxt_data *data = vb2_get_drv_priv(vb->vb2_queue);
 	u16 *ptr;
 	int ret;
+	u8 mode;
 
 	ptr = vb2_plane_vaddr(vb, 0);
 	if (!ptr) {
@@ -2275,7 +2283,18 @@ static void mxt_buffer_queue(struct vb2_buffer *vb)
 		goto fault;
 	}
 
-	ret = mxt_read_diagnostic_debug(data, MXT_DIAGNOSTIC_DELTAS, ptr);
+	switch (data->dbg.input) {
+	case MXT_V4L_INPUT_DELTAS:
+	default:
+		mode = MXT_DIAGNOSTIC_DELTAS;
+		break;
+
+	case MXT_V4L_INPUT_REFS:
+		mode = MXT_DIAGNOSTIC_REFS;
+		break;
+	}
+
+	ret = mxt_read_diagnostic_debug(data, mode, ptr);
 	if (ret)
 		goto fault;
 
@@ -2320,11 +2339,20 @@ static int mxt_vidioc_querycap(struct file *file, void *priv,
 static int mxt_vidioc_enum_input(struct file *file, void *priv,
 				   struct v4l2_input *i)
 {
-	if (i->index > 0)
+	if (i->index >= MXT_V4L_INPUT_MAX)
 		return -EINVAL;
 
 	i->type = V4L2_INPUT_TYPE_TOUCH_SENSOR;
-	strlcpy(i->name, "Mutual References", sizeof(i->name));
+
+	switch (i->index) {
+	case MXT_V4L_INPUT_REFS:
+		strlcpy(i->name, "Mutual References", sizeof(i->name));
+		break;
+	case MXT_V4L_INPUT_DELTAS:
+		strlcpy(i->name, "Mutual Deltas", sizeof(i->name));
+		break;
+	}
+
 	return 0;
 }
 
@@ -2332,12 +2360,16 @@ static int mxt_set_input(struct mxt_data *data, unsigned int i)
 {
 	struct v4l2_pix_format *f = &data->dbg.format;
 
-	if (i > 0)
+	if (i >= MXT_V4L_INPUT_MAX)
 		return -EINVAL;
 
+	if (i == MXT_V4L_INPUT_DELTAS)
+		f->pixelformat = V4L2_PIX_FMT_YS16;
+	else
+		f->pixelformat = V4L2_PIX_FMT_Y16;
+
 	f->width = data->xy_switch ? data->ysize : data->xsize;
 	f->height = data->xy_switch ? data->xsize : data->ysize;
-	f->pixelformat = V4L2_PIX_FMT_YS16;
 	f->field = V4L2_FIELD_NONE;
 	f->colorspace = V4L2_COLORSPACE_RAW;
 	f->bytesperline = f->width * sizeof(u16);
@@ -2375,10 +2407,22 @@ static int mxt_vidioc_fmt(struct file *file, void *priv, struct v4l2_format *f)
 static int mxt_vidioc_enum_fmt(struct file *file, void *priv,
 				 struct v4l2_fmtdesc *fmt)
 {
-	if (fmt->index > 0 || fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	switch (fmt->index) {
+	case 0:
+		fmt->pixelformat = V4L2_PIX_FMT_Y16;
+		break;
+
+	case 1:
+		fmt->pixelformat = V4L2_PIX_FMT_YS16;
+		break;
+
+	default:
 		return -EINVAL;
+	}
 
-	fmt->pixelformat = V4L2_PIX_FMT_YS16;
 	return 0;
 }
 
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1411453 — Re: [PATCH v3 0/8] Input: atmel_mxt_ts - output raw touch diagnostic data via V4L

FromDmitry Torokhov <dmitry.torokhov@gmail.com>
Date2016-06-01 20:20 +0200
SubjectRe: [PATCH v3 0/8] Input: atmel_mxt_ts - output raw touch diagnostic data via V4L
Message-ID<rFiUi-3wl-25@gated-at.bofh.it>
In reply to#1411396
On Wed, Jun 01, 2016 at 05:39:44PM +0100, Nick Dyer wrote:
> This is a series of patches to add diagnostic data support to the Atmel
> maXTouch driver. It's a rewrite of the previous implementation which output via
> debugfs: it now uses a V4L2 device in a similar way to the sur40 driver.
> 
> There are significant performance advantages to putting this code into the
> driver.  The algorithm for retrieving the data has been fairly consistent
> across a range of chips, with the exception of the mXT1386 series (see patch).
> 
> We have a utility which can read the data and display it in a useful format:
>     https://github.com/ndyer/heatmap/commits/heatmap-v4l
> 
> These patches are also available from
>     https://github.com/ndyer/linux/commits/diagnostic-v4l
> 
> Changes in v3:
> - Address V4L2 review comments from Hans Verkuil
> - Run v4l-compliance and fix all issues - needs minor patch here:
>   https://github.com/ndyer/v4l-utils/commit/cf50469773f
> 
> Changes in v2:
> - Split pixfmt changes into separate commit and add DocBook
> - Introduce VFL_TYPE_TOUCH_SENSOR and /dev/v4l-touch
> - Remove "single node" support for now, it may be better to treat it as metadata later
> - Explicitly set VFL_DIR_RX
> - Fix Kconfig
> 

I do not have any objections other than some nits form the input side;
majority of the review should come from V4L2 side here...

-- 
Dmitry

[toc] | [prev] | [next] | [standalone]


#1412341 — Re: [PATCH v3 0/8] Input: atmel_mxt_ts - output raw touch diagnostic data via V4L

FromNick Dyer <nick.dyer@itdev.co.uk>
Date2016-06-02 17:20 +0200
SubjectRe: [PATCH v3 0/8] Input: atmel_mxt_ts - output raw touch diagnostic data via V4L
Message-ID<rFCzD-7xa-13@gated-at.bofh.it>
In reply to#1411453
Hi Dmitry-

On 01/06/2016 19:17, Dmitry Torokhov wrote:
> On Wed, Jun 01, 2016 at 05:39:44PM +0100, Nick Dyer wrote:
>> This is a series of patches to add diagnostic data support to the Atmel
>> maXTouch driver. It's a rewrite of the previous implementation which output via
>> debugfs: it now uses a V4L2 device in a similar way to the sur40 driver.
>
> I do not have any objections other than some nits form the input side;
> majority of the review should come from V4L2 side here...

Thanks for the review. I've hopefully fixed the issues you raised and
pushed it to
    https://github.com/ndyer/linux/commits/diagnostic-v4l-20160602

I will wait for the V4L2 folks to comment before posting a [PATCH v4]

cheers

Nick

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web