Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1411396 > unrolled thread
| Started by | Nick Dyer <nick.dyer@itdev.co.uk> |
|---|---|
| First post | 2016-06-01 18:50 +0200 |
| Last post | 2016-06-02 17:20 +0200 |
| Articles | 14 — 2 participants |
Back to article view | Back to linux.kernel
[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
| From | Nick Dyer <nick.dyer@itdev.co.uk> |
|---|---|
| Date | 2016-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]
| From | Nick Dyer <nick.dyer@itdev.co.uk> |
|---|---|
| Date | 2016-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 × 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 + 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 + 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 + 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 + 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]
| From | Nick Dyer <nick.dyer@itdev.co.uk> |
|---|---|
| Date | 2016-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]
| From | Dmitry Torokhov <dmitry.torokhov@gmail.com> |
|---|---|
| Date | 2016-06-01 20:20 +0200 |
| Subject | Re: [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]
| From | Nick Dyer <nick.dyer@itdev.co.uk> |
|---|---|
| Date | 2016-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]
| From | Dmitry Torokhov <dmitry.torokhov@gmail.com> |
|---|---|
| Date | 2016-06-01 20:20 +0200 |
| Subject | Re: [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]
| From | Nick Dyer <nick.dyer@itdev.co.uk> |
|---|---|
| Date | 2016-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]
| From | Dmitry Torokhov <dmitry.torokhov@gmail.com> |
|---|---|
| Date | 2016-06-01 20:20 +0200 |
| Subject | Re: [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]
| From | Nick Dyer <nick.dyer@itdev.co.uk> |
|---|---|
| Date | 2016-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]
| From | Nick Dyer <nick.dyer@itdev.co.uk> |
|---|---|
| Date | 2016-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]
| From | Nick Dyer <nick.dyer@itdev.co.uk> |
|---|---|
| Date | 2016-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]
| From | Nick Dyer <nick.dyer@itdev.co.uk> |
|---|---|
| Date | 2016-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]
| From | Dmitry Torokhov <dmitry.torokhov@gmail.com> |
|---|---|
| Date | 2016-06-01 20:20 +0200 |
| Subject | Re: [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]
| From | Nick Dyer <nick.dyer@itdev.co.uk> |
|---|---|
| Date | 2016-06-02 17:20 +0200 |
| Subject | Re: [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