mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 1/1] input: add qt1070 touch keyboard support
@ 2012-11-01 13:22 Jean-Christophe PLAGNIOL-VILLARD
  2012-11-01 13:52 ` [PATCH 1/1 v2] " Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 1 reply; 5+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-01 13:22 UTC (permalink / raw)
  To: barebox

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
 drivers/input/Kconfig  |    7 ++
 drivers/input/Makefile |    1 +
 drivers/input/qt1070.c |  228 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/input/qt1070.h |   17 ++++
 4 files changed, 253 insertions(+)
 create mode 100644 drivers/input/qt1070.c
 create mode 100644 include/input/qt1070.h

diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 15979a2..8c528b4 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -30,4 +30,11 @@ config KEYBOARD_IMX_KEYPAD
 	  setup logic must also provide a 'matrix_keymap_data' structure,
 	  defining the used keys.
 
+config KEYBOARD_QT1070
+	tristate "Atmel AT42QT1070 Touch Sensor Chip"
+	depends on I2C
+	help
+	  Say Y here if you want to use Atmel AT42QT1070 QTouch
+	  Sensor chip as input device.
+
 endmenu
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 3d105cc..d042980 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
 obj-$(CONFIG_KEYBOARD_IMX_KEYPAD) += imx_keypad.o
+obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o
diff --git a/drivers/input/qt1070.c b/drivers/input/qt1070.c
new file mode 100644
index 0000000..cd9c5a6
--- /dev/null
+++ b/drivers/input/qt1070.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <init.h>
+#include <clock.h>
+#include <poller.h>
+#include <kfifo.h>
+#include <i2c/i2c.h>
+#include <malloc.h>
+#include <readkey.h>
+#include <input/qt1070.h>
+
+#define QT1070_CHIP_ID		0x2e
+
+#define QT1070_READ_CHIP_ID	0x00
+#define QT1070_FW_VERSION	0x01
+#define QT1070_DET_STATUS	0x02
+#define QT1070_KEY_STATUS	0x03
+
+/* Calibrate */
+#define QT1070_CALIBRATE_CMD	0x38
+#define QT1070_CAL_TIME		200
+
+/* Reset */
+#define QT1070_RESET		0x39
+#define QT1070_RESET_TIME	255
+
+static int default_code[QT1070_NB_BUTTONS] = {
+	KEY_ENTER, KEY_HOME, KEY_UP, KEY_DOWN,
+	KEY_RIGHT, KEY_LEFT, KEY_CLEAR_SCREEN };
+
+struct qt1070_data {
+	int code[QT1070_NB_BUTTONS];
+
+	/* optional */
+	int fifo_size;
+
+	struct i2c_client *client;
+	u8 button_state[QT1070_NB_BUTTONS];
+	u8 previous_state;
+
+	struct kfifo *recv_fifo;
+	struct poller_struct poller;
+	struct console_device cdev;
+};
+
+static inline struct qt1070_data *
+poller_to_qt_data(struct poller_struct *poller)
+{
+	return container_of(poller, struct qt1070_data, poller);
+}
+
+static inline struct qt1070_data *
+cdev_to_qt_data(struct console_device *cdev)
+{
+	return container_of(cdev, struct qt1070_data, cdev);
+}
+
+static bool qt1070_read(struct qt1070_data *data, u8 reg, u8 *val)
+{
+	int ret;
+
+	ret = i2c_read_reg(data->client, reg, val, 1);
+
+	if (ret < 0)
+		return ret;
+	if (ret != 1)
+		return -EIO;
+	return 0;
+}
+
+static bool qt1070_write(struct qt1070_data *data, u8 reg, const u8 val)
+{
+	int ret;
+
+	ret = i2c_write_reg(data->client, reg, &val, 1);
+	if (ret < 0)
+		return ret;
+	if (ret != 1)
+		return -EIO;
+	return 0;
+}
+
+static void qt1070_poller(struct poller_struct *poller)
+{
+	struct qt1070_data *data = poller_to_qt_data(poller);
+	int i;
+	u8 buf, bt;
+	u8 mask = 0x1;
+
+	qt1070_read(data, QT1070_DET_STATUS, &buf);
+
+	if (qt1070_read(data, QT1070_KEY_STATUS, &buf))
+		return;
+
+	if (!buf & !data->previous_state)
+		return;
+
+	for (i = 0; i < QT1070_NB_BUTTONS; i++) {
+		bt = buf & mask;
+
+		if (!bt && data->button_state[i]) {
+			debug("release key(%d) as %d\n", i, data->code[i]);
+			kfifo_put(data->recv_fifo, (u_char*)&data->code[i], sizeof(int));
+		} else if (bt) {
+			debug("pressed key(%d) as %d\n", i, data->code[i]);
+		}
+
+		data->button_state[i] = bt;
+		mask <<= 1;
+	}
+
+	data->previous_state = buf;
+}
+
+static int qt1070_tstc(struct console_device *cdev)
+{
+	struct qt1070_data *data = cdev_to_qt_data(cdev);
+
+	return (kfifo_len(data->recv_fifo) == 0) ? 0 : 1;
+}
+
+static int qt1070_getc(struct console_device *cdev)
+{
+	int code = 0;
+	struct qt1070_data *data = cdev_to_qt_data(cdev);
+
+	kfifo_get(data->recv_fifo, (u_char*)&code, sizeof(int));
+	return code;
+}
+
+static int __init qt1070_probe(struct device_d *dev)
+{
+	struct console_device *cdev;
+	struct qt1070_data *data;
+	u8 fw_version, chip_id;
+	int ret;
+	char buf[6];
+
+	data = xzalloc(sizeof(*data));
+	data->client = to_i2c_client(dev);
+
+	ret = qt1070_read(data, QT1070_READ_CHIP_ID, &chip_id);
+	if (ret) {
+		dev_err(dev, "can not read chip id (%d)\n", ret);
+		goto err;
+	}
+
+	if (chip_id != QT1070_CHIP_ID) {
+		dev_err(dev, "unsupported id 0x%x\n", chip_id);
+		ret = -ENXIO;
+		goto err;
+	}
+
+	ret = qt1070_read(data, QT1070_FW_VERSION, &fw_version);
+	if (ret) {
+		dev_err(dev, "can not read firmware version (%d)\n", ret);
+		goto err;
+	}
+
+	sprintf(buf, "0x%x", fw_version);
+	dev_add_param_fixed(dev, "fw_version", buf);
+	sprintf(buf, "0x%x", chip_id);
+	dev_add_param_fixed(dev, "chip_ip", buf);
+
+	/* Calibrate device */
+	qt1070_write(data, QT1070_CALIBRATE_CMD, 1);
+	if (ret) {
+		dev_err(dev, "can not calibreate the chip (%d)\n", ret);
+		goto err;
+	}
+	mdelay(QT1070_CAL_TIME);
+
+	/* Soft reset */
+	ret = qt1070_write(data, QT1070_RESET, 1);
+	if (ret) {
+		dev_err(dev, "can not reset the chip (%d)\n", ret);
+		goto err;
+	}
+	mdelay(QT1070_RESET_TIME);
+
+	memcpy(data->code, default_code, sizeof(int) * ARRAY_SIZE(default_code));
+	if (dev->platform_data) {
+		struct qt1070_platform_data pdata = dev->platform_data;
+
+		memcpy(data->code, pdata->code, sizeof(int) * pdata->nb_code);
+	}
+
+	data->fifo_size = 50;
+	data->recv_fifo = kfifo_alloc(data->fifo_size);
+
+	data->poller.func = qt1070_poller;
+
+	cdev = &data->cdev;
+	dev->type_data = cdev;
+	cdev->dev = dev;
+	cdev->f_caps = CONSOLE_STDIN;
+	cdev->tstc = qt1070_tstc;
+	cdev->getc = qt1070_getc;
+
+	console_register(&data->cdev);
+
+	ret = poller_register(&data->poller);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	free(data);
+	return ret;
+}
+
+static struct driver_d qt1070_driver = {
+	.name	= "qt1070",
+	.probe	= qt1070_probe,
+};
+
+static int qt1070_init(void)
+{
+	i2c_register_driver(&qt1070_driver);
+	return 0;
+}
+device_initcall(qt1070_init);
diff --git a/include/input/qt1070.h b/include/input/qt1070.h
new file mode 100644
index 0000000..8a29559
--- /dev/null
+++ b/include/input/qt1070.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2
+ */
+
+#ifndef __QT1070_H__
+#define __QT1070_H__
+
+#define QT1070_NB_BUTTONS	7
+
+struct qt1070_platform_data {
+	int code[QT1070_NB_BUTTONS];
+	int nb_code;
+};
+
+#endif /* __QT1070_H__ */
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/1 v2] input: add qt1070 touch keyboard support
  2012-11-01 13:22 [PATCH 1/1] input: add qt1070 touch keyboard support Jean-Christophe PLAGNIOL-VILLARD
@ 2012-11-01 13:52 ` Jean-Christophe PLAGNIOL-VILLARD
  2012-11-02 20:15   ` Sascha Hauer
  2012-11-03 11:26   ` [PATCH 1/1 v3] " Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 2 replies; 5+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-01 13:52 UTC (permalink / raw)
  To: barebox

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
fix typo add when checking the patch

Best Regards,
J.
 drivers/input/Kconfig  |    7 ++
 drivers/input/Makefile |    1 +
 drivers/input/qt1070.c |  228 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/input/qt1070.h |   17 ++++
 4 files changed, 253 insertions(+)
 create mode 100644 drivers/input/qt1070.c
 create mode 100644 include/input/qt1070.h

diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 15979a2..8c528b4 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -30,4 +30,11 @@ config KEYBOARD_IMX_KEYPAD
 	  setup logic must also provide a 'matrix_keymap_data' structure,
 	  defining the used keys.
 
+config KEYBOARD_QT1070
+	tristate "Atmel AT42QT1070 Touch Sensor Chip"
+	depends on I2C
+	help
+	  Say Y here if you want to use Atmel AT42QT1070 QTouch
+	  Sensor chip as input device.
+
 endmenu
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 3d105cc..d042980 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
 obj-$(CONFIG_KEYBOARD_IMX_KEYPAD) += imx_keypad.o
+obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o
diff --git a/drivers/input/qt1070.c b/drivers/input/qt1070.c
new file mode 100644
index 0000000..49cd836
--- /dev/null
+++ b/drivers/input/qt1070.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <init.h>
+#include <clock.h>
+#include <poller.h>
+#include <kfifo.h>
+#include <i2c/i2c.h>
+#include <malloc.h>
+#include <readkey.h>
+#include <input/qt1070.h>
+
+#define QT1070_CHIP_ID		0x2e
+
+#define QT1070_READ_CHIP_ID	0x00
+#define QT1070_FW_VERSION	0x01
+#define QT1070_DET_STATUS	0x02
+#define QT1070_KEY_STATUS	0x03
+
+/* Calibrate */
+#define QT1070_CALIBRATE_CMD	0x38
+#define QT1070_CAL_TIME		200
+
+/* Reset */
+#define QT1070_RESET		0x39
+#define QT1070_RESET_TIME	255
+
+static int default_code[QT1070_NB_BUTTONS] = {
+	KEY_ENTER, KEY_HOME, KEY_UP, KEY_DOWN,
+	KEY_RIGHT, KEY_LEFT, KEY_CLEAR_SCREEN };
+
+struct qt1070_data {
+	int code[QT1070_NB_BUTTONS];
+
+	/* optional */
+	int fifo_size;
+
+	struct i2c_client *client;
+	u8 button_state[QT1070_NB_BUTTONS];
+	u8 previous_state;
+
+	struct kfifo *recv_fifo;
+	struct poller_struct poller;
+	struct console_device cdev;
+};
+
+static inline struct qt1070_data *
+poller_to_qt_data(struct poller_struct *poller)
+{
+	return container_of(poller, struct qt1070_data, poller);
+}
+
+static inline struct qt1070_data *
+cdev_to_qt_data(struct console_device *cdev)
+{
+	return container_of(cdev, struct qt1070_data, cdev);
+}
+
+static bool qt1070_read(struct qt1070_data *data, u8 reg, u8 *val)
+{
+	int ret;
+
+	ret = i2c_read_reg(data->client, reg, val, 1);
+
+	if (ret < 0)
+		return ret;
+	if (ret != 1)
+		return -EIO;
+	return 0;
+}
+
+static bool qt1070_write(struct qt1070_data *data, u8 reg, const u8 val)
+{
+	int ret;
+
+	ret = i2c_write_reg(data->client, reg, &val, 1);
+	if (ret < 0)
+		return ret;
+	if (ret != 1)
+		return -EIO;
+	return 0;
+}
+
+static void qt1070_poller(struct poller_struct *poller)
+{
+	struct qt1070_data *data = poller_to_qt_data(poller);
+	int i;
+	u8 buf, bt;
+	u8 mask = 0x1;
+
+	qt1070_read(data, QT1070_DET_STATUS, &buf);
+
+	if (qt1070_read(data, QT1070_KEY_STATUS, &buf))
+		return;
+
+	if (!buf & !data->previous_state)
+		return;
+
+	for (i = 0; i < QT1070_NB_BUTTONS; i++) {
+		bt = buf & mask;
+
+		if (!bt && data->button_state[i]) {
+			debug("release key(%d) as %d\n", i, data->code[i]);
+			kfifo_put(data->recv_fifo, (u_char*)&data->code[i], sizeof(int));
+		} else if (bt) {
+			debug("pressed key(%d) as %d\n", i, data->code[i]);
+		}
+
+		data->button_state[i] = bt;
+		mask <<= 1;
+	}
+
+	data->previous_state = buf;
+}
+
+static int qt1070_tstc(struct console_device *cdev)
+{
+	struct qt1070_data *data = cdev_to_qt_data(cdev);
+
+	return (kfifo_len(data->recv_fifo) == 0) ? 0 : 1;
+}
+
+static int qt1070_getc(struct console_device *cdev)
+{
+	int code = 0;
+	struct qt1070_data *data = cdev_to_qt_data(cdev);
+
+	kfifo_get(data->recv_fifo, (u_char*)&code, sizeof(int));
+	return code;
+}
+
+static int __init qt1070_probe(struct device_d *dev)
+{
+	struct console_device *cdev;
+	struct qt1070_data *data;
+	u8 fw_version, chip_id;
+	int ret;
+	char buf[6];
+
+	data = xzalloc(sizeof(*data));
+	data->client = to_i2c_client(dev);
+
+	ret = qt1070_read(data, QT1070_READ_CHIP_ID, &chip_id);
+	if (ret) {
+		dev_err(dev, "can not read chip id (%d)\n", ret);
+		goto err;
+	}
+
+	if (chip_id != QT1070_CHIP_ID) {
+		dev_err(dev, "unsupported id 0x%x\n", chip_id);
+		ret = -ENXIO;
+		goto err;
+	}
+
+	ret = qt1070_read(data, QT1070_FW_VERSION, &fw_version);
+	if (ret) {
+		dev_err(dev, "can not read firmware version (%d)\n", ret);
+		goto err;
+	}
+
+	sprintf(buf, "0x%x", fw_version);
+	dev_add_param_fixed(dev, "fw_version", buf);
+	sprintf(buf, "0x%x", chip_id);
+	dev_add_param_fixed(dev, "chip_ip", buf);
+
+	/* Calibrate device */
+	qt1070_write(data, QT1070_CALIBRATE_CMD, 1);
+	if (ret) {
+		dev_err(dev, "can not calibreate the chip (%d)\n", ret);
+		goto err;
+	}
+	mdelay(QT1070_CAL_TIME);
+
+	/* Soft reset */
+	ret = qt1070_write(data, QT1070_RESET, 1);
+	if (ret) {
+		dev_err(dev, "can not reset the chip (%d)\n", ret);
+		goto err;
+	}
+	mdelay(QT1070_RESET_TIME);
+
+	memcpy(data->code, default_code, sizeof(int) * ARRAY_SIZE(default_code));
+	if (dev->platform_data) {
+		struct qt1070_platform_data *pdata = dev->platform_data;
+
+		memcpy(data->code, pdata->code, sizeof(int) * pdata->nb_code);
+	}
+
+	data->fifo_size = 50;
+	data->recv_fifo = kfifo_alloc(data->fifo_size);
+
+	data->poller.func = qt1070_poller;
+
+	cdev = &data->cdev;
+	dev->type_data = cdev;
+	cdev->dev = dev;
+	cdev->f_caps = CONSOLE_STDIN;
+	cdev->tstc = qt1070_tstc;
+	cdev->getc = qt1070_getc;
+
+	console_register(&data->cdev);
+
+	ret = poller_register(&data->poller);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	free(data);
+	return ret;
+}
+
+static struct driver_d qt1070_driver = {
+	.name	= "qt1070",
+	.probe	= qt1070_probe,
+};
+
+static int qt1070_init(void)
+{
+	i2c_register_driver(&qt1070_driver);
+	return 0;
+}
+device_initcall(qt1070_init);
diff --git a/include/input/qt1070.h b/include/input/qt1070.h
new file mode 100644
index 0000000..8a29559
--- /dev/null
+++ b/include/input/qt1070.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2
+ */
+
+#ifndef __QT1070_H__
+#define __QT1070_H__
+
+#define QT1070_NB_BUTTONS	7
+
+struct qt1070_platform_data {
+	int code[QT1070_NB_BUTTONS];
+	int nb_code;
+};
+
+#endif /* __QT1070_H__ */
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/1 v2] input: add qt1070 touch keyboard support
  2012-11-01 13:52 ` [PATCH 1/1 v2] " Jean-Christophe PLAGNIOL-VILLARD
@ 2012-11-02 20:15   ` Sascha Hauer
  2012-11-03  7:32     ` Jean-Christophe PLAGNIOL-VILLARD
  2012-11-03 11:26   ` [PATCH 1/1 v3] " Jean-Christophe PLAGNIOL-VILLARD
  1 sibling, 1 reply; 5+ messages in thread
From: Sascha Hauer @ 2012-11-02 20:15 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox

On Thu, Nov 01, 2012 at 02:52:53PM +0100, Jean-Christophe PLAGNIOL-VILLARD wrote:
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> ---
> fix typo add when checking the patch
>

select POLLER missing in Kconfig

> +static void qt1070_poller(struct poller_struct *poller)
> +{
> +	struct qt1070_data *data = poller_to_qt_data(poller);
> +	int i;
> +	u8 buf, bt;
> +	u8 mask = 0x1;
> +
> +	qt1070_read(data, QT1070_DET_STATUS, &buf);
> +
> +	if (qt1070_read(data, QT1070_KEY_STATUS, &buf))
> +		return;
> +
> +	if (!buf & !data->previous_state)
> +		return;
> +
> +	for (i = 0; i < QT1070_NB_BUTTONS; i++) {
> +		bt = buf & mask;
> +
> +		if (!bt && data->button_state[i]) {
> +			debug("release key(%d) as %d\n", i, data->code[i]);
> +			kfifo_put(data->recv_fifo, (u_char*)&data->code[i], sizeof(int));
> +		} else if (bt) {
> +			debug("pressed key(%d) as %d\n", i, data->code[i]);
> +		}
> +
> +		data->button_state[i] = bt;
> +		mask <<= 1;
> +	}
> +
> +	data->previous_state = buf;
> +}
> +
> +static int qt1070_tstc(struct console_device *cdev)
> +{
> +	struct qt1070_data *data = cdev_to_qt_data(cdev);
> +
> +	return (kfifo_len(data->recv_fifo) == 0) ? 0 : 1;
> +}
> +
> +static int qt1070_getc(struct console_device *cdev)
> +{
> +	int code = 0;
> +	struct qt1070_data *data = cdev_to_qt_data(cdev);
> +
> +	kfifo_get(data->recv_fifo, (u_char*)&code, sizeof(int));
> +	return code;
> +}
> +
> +static int __init qt1070_probe(struct device_d *dev)
> +{
> +	struct console_device *cdev;
> +	struct qt1070_data *data;
> +	u8 fw_version, chip_id;
> +	int ret;
> +	char buf[6];
> +
> +	data = xzalloc(sizeof(*data));
> +	data->client = to_i2c_client(dev);
> +
> +	ret = qt1070_read(data, QT1070_READ_CHIP_ID, &chip_id);
> +	if (ret) {
> +		dev_err(dev, "can not read chip id (%d)\n", ret);
> +		goto err;
> +	}
> +
> +	if (chip_id != QT1070_CHIP_ID) {
> +		dev_err(dev, "unsupported id 0x%x\n", chip_id);
> +		ret = -ENXIO;
> +		goto err;
> +	}
> +
> +	ret = qt1070_read(data, QT1070_FW_VERSION, &fw_version);
> +	if (ret) {
> +		dev_err(dev, "can not read firmware version (%d)\n", ret);
> +		goto err;
> +	}
> +
> +	sprintf(buf, "0x%x", fw_version);
> +	dev_add_param_fixed(dev, "fw_version", buf);
> +	sprintf(buf, "0x%x", chip_id);
> +	dev_add_param_fixed(dev, "chip_ip", buf);
> +
> +	/* Calibrate device */
> +	qt1070_write(data, QT1070_CALIBRATE_CMD, 1);
> +	if (ret) {
> +		dev_err(dev, "can not calibreate the chip (%d)\n", ret);

s/calibreate/calibrate/

> +		goto err;
> +	}
> +	mdelay(QT1070_CAL_TIME);
> +
> +	/* Soft reset */
> +	ret = qt1070_write(data, QT1070_RESET, 1);
> +	if (ret) {
> +		dev_err(dev, "can not reset the chip (%d)\n", ret);
> +		goto err;
> +	}
> +	mdelay(QT1070_RESET_TIME);
> +

This delays the boot by about half a second. If you register
a poller anyway you could use it to wait until the reset finished.

> +	memcpy(data->code, default_code, sizeof(int) * ARRAY_SIZE(default_code));
> +	if (dev->platform_data) {
> +		struct qt1070_platform_data *pdata = dev->platform_data;
> +
> +		memcpy(data->code, pdata->code, sizeof(int) * pdata->nb_code);
> +	}
> +
> +	data->fifo_size = 50;

I wonder if such a deep fifo is useful. If the user
plays with the buttons when and nobody empties the fifo
at that time you will end up with 50 old button presses
in the fifo. It may be better to just store the last button
in a variable. This would also fix the problem that when
the fifo is full you discard the newest buttons. It's
better to drop the oldest buttons.

> +	data->recv_fifo = kfifo_alloc(data->fifo_size);
> +
> +	data->poller.func = qt1070_poller;
> +
> +	cdev = &data->cdev;
> +	dev->type_data = cdev;

This is unused in the console layer. Please drop.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/1 v2] input: add qt1070 touch keyboard support
  2012-11-02 20:15   ` Sascha Hauer
@ 2012-11-03  7:32     ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 5+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-03  7:32 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox

> > +}
> > +
> > +static int __init qt1070_probe(struct device_d *dev)
> > +{
> > +	struct console_device *cdev;
> > +	struct qt1070_data *data;
> > +	u8 fw_version, chip_id;
> > +	int ret;
> > +	char buf[6];
> > +
> > +	data = xzalloc(sizeof(*data));
> > +	data->client = to_i2c_client(dev);
> > +
> > +	ret = qt1070_read(data, QT1070_READ_CHIP_ID, &chip_id);
> > +	if (ret) {
> > +		dev_err(dev, "can not read chip id (%d)\n", ret);
> > +		goto err;
> > +	}
> > +
> > +	if (chip_id != QT1070_CHIP_ID) {
> > +		dev_err(dev, "unsupported id 0x%x\n", chip_id);
> > +		ret = -ENXIO;
> > +		goto err;
> > +	}
> > +
> > +	ret = qt1070_read(data, QT1070_FW_VERSION, &fw_version);
> > +	if (ret) {
> > +		dev_err(dev, "can not read firmware version (%d)\n", ret);
> > +		goto err;
> > +	}
> > +
> > +	sprintf(buf, "0x%x", fw_version);
> > +	dev_add_param_fixed(dev, "fw_version", buf);
> > +	sprintf(buf, "0x%x", chip_id);
> > +	dev_add_param_fixed(dev, "chip_ip", buf);
> > +
> > +	/* Calibrate device */
> > +	qt1070_write(data, QT1070_CALIBRATE_CMD, 1);
> > +	if (ret) {
> > +		dev_err(dev, "can not calibreate the chip (%d)\n", ret);
> 
> s/calibreate/calibrate/
> 
> > +		goto err;
> > +	}
> > +	mdelay(QT1070_CAL_TIME);
> > +
> > +	/* Soft reset */
> > +	ret = qt1070_write(data, QT1070_RESET, 1);
> > +	if (ret) {
> > +		dev_err(dev, "can not reset the chip (%d)\n", ret);
> > +		goto err;
> > +	}
> > +	mdelay(QT1070_RESET_TIME);
> > +
> 
> This delays the boot by about half a second. If you register
> a poller anyway you could use it to wait until the reset finished.
ok
> 
> > +	memcpy(data->code, default_code, sizeof(int) * ARRAY_SIZE(default_code));
> > +	if (dev->platform_data) {
> > +		struct qt1070_platform_data *pdata = dev->platform_data;
> > +
> > +		memcpy(data->code, pdata->code, sizeof(int) * pdata->nb_code);
> > +	}
> > +
> > +	data->fifo_size = 50;
> 
> I wonder if such a deep fifo is useful. If the user
> plays with the buttons when and nobody empties the fifo
> at that time you will end up with 50 old button presses
> in the fifo. It may be better to just store the last button
> in a variable. This would also fix the problem that when
> the fifo is full you discard the newest buttons. It's
> better to drop the oldest buttons.
no the touch can report 7 keys at the same time so I put 50.

If we pessed 2 times 7 keys before barebox read we have 14 * sifeod(int) = 56
bytes so I think 50 is ok

Best Regards,
J.

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/1 v3] input: add qt1070 touch keyboard support
  2012-11-01 13:52 ` [PATCH 1/1 v2] " Jean-Christophe PLAGNIOL-VILLARD
  2012-11-02 20:15   ` Sascha Hauer
@ 2012-11-03 11:26   ` Jean-Christophe PLAGNIOL-VILLARD
  1 sibling, 0 replies; 5+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-03 11:26 UTC (permalink / raw)
  To: barebox

use irq pin as the pin is asserted untill we clear it
This will allow to do not poll on i2c which slow down barebox

If no irq_pin is provided fall back on i2c polling

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
v3:

	add irq_pin support
	use different poll function to wait for calibration and reset
	so we do not endup with a delay of nearly 500ms at boot time

Best Regards,
J.
 drivers/input/Kconfig  |    8 ++
 drivers/input/Makefile |    1 +
 drivers/input/qt1070.c |  296 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/input/qt1070.h |   18 +++
 4 files changed, 323 insertions(+)
 create mode 100644 drivers/input/qt1070.c
 create mode 100644 include/input/qt1070.h

diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 15979a2..846483c 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -30,4 +30,12 @@ config KEYBOARD_IMX_KEYPAD
 	  setup logic must also provide a 'matrix_keymap_data' structure,
 	  defining the used keys.
 
+config KEYBOARD_QT1070
+	tristate "Atmel AT42QT1070 Touch Sensor Chip"
+	depends on I2C
+	select POLLER
+	help
+	  Say Y here if you want to use Atmel AT42QT1070 QTouch
+	  Sensor chip as input device.
+
 endmenu
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 3d105cc..d042980 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
 obj-$(CONFIG_KEYBOARD_IMX_KEYPAD) += imx_keypad.o
+obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o
diff --git a/drivers/input/qt1070.c b/drivers/input/qt1070.c
new file mode 100644
index 0000000..c66189e
--- /dev/null
+++ b/drivers/input/qt1070.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <init.h>
+#include <clock.h>
+#include <poller.h>
+#include <kfifo.h>
+#include <i2c/i2c.h>
+#include <malloc.h>
+#include <readkey.h>
+#include <input/qt1070.h>
+#include <gpio.h>
+
+#define QT1070_CHIP_ID		0x2e
+
+#define QT1070_READ_CHIP_ID	0x00
+#define QT1070_FW_VERSION	0x01
+#define QT1070_DET_STATUS	0x02
+#define QT1070_KEY_STATUS	0x03
+
+/* Calibrate */
+#define QT1070_CALIBRATE_CMD	0x38
+#define QT1070_CAL_TIME		200
+
+/* Reset */
+#define QT1070_RESET		0x39
+#define QT1070_RESET_TIME	255
+
+static int default_code[QT1070_NB_BUTTONS] = {
+	KEY_ENTER, KEY_HOME, KEY_UP, KEY_DOWN,
+	KEY_RIGHT, KEY_LEFT, KEY_CLEAR_SCREEN };
+
+struct qt1070_data {
+	int code[QT1070_NB_BUTTONS];
+
+	int irq_pin;
+
+	u64 start;
+
+	/* optional */
+	int fifo_size;
+
+	struct i2c_client *client;
+	u8 button_state[QT1070_NB_BUTTONS];
+	u8 previous_state;
+
+	struct kfifo *recv_fifo;
+	struct poller_struct poller;
+	struct console_device cdev;
+};
+
+static inline struct qt1070_data *
+poller_to_qt_data(struct poller_struct *poller)
+{
+	return container_of(poller, struct qt1070_data, poller);
+}
+
+static inline struct qt1070_data *
+cdev_to_qt_data(struct console_device *cdev)
+{
+	return container_of(cdev, struct qt1070_data, cdev);
+}
+
+static bool qt1070_read(struct qt1070_data *data, u8 reg, u8 *val)
+{
+	int ret;
+
+	ret = i2c_read_reg(data->client, reg, val, 1);
+
+	if (ret < 0)
+		return ret;
+	if (ret != 1)
+		return -EIO;
+	return 0;
+}
+
+static bool qt1070_write(struct qt1070_data *data, u8 reg, const u8 val)
+{
+	int ret;
+
+	ret = i2c_write_reg(data->client, reg, &val, 1);
+	if (ret < 0)
+		return ret;
+	if (ret != 1)
+		return -EIO;
+	return 0;
+}
+
+static void qt1070_poller(struct poller_struct *poller)
+{
+	struct qt1070_data *data = poller_to_qt_data(poller);
+	int i;
+	u8 buf, bt;
+	u8 mask = 0x1;
+
+	if (gpio_is_valid(data->irq_pin)) {
+		/* active low */
+		if (gpio_get_value(data->irq_pin))
+			return;
+	}
+
+	qt1070_read(data, QT1070_DET_STATUS, &buf);
+
+	if (qt1070_read(data, QT1070_KEY_STATUS, &buf))
+		return;
+
+	if (!buf & !data->previous_state)
+		return;
+
+	for (i = 0; i < QT1070_NB_BUTTONS; i++) {
+		bt = buf & mask;
+
+		if (!bt && data->button_state[i]) {
+			dev_dbg(data->cdev.dev, "release key(%d) as %d\n", i, data->code[i]);
+			kfifo_put(data->recv_fifo, (u_char*)&data->code[i], sizeof(int));
+		} else if (bt) {
+			dev_dbg(data->cdev.dev, "pressed key(%d) as %d\n", i, data->code[i]);
+		}
+
+		data->button_state[i] = bt;
+		mask <<= 1;
+	}
+
+	data->previous_state = buf;
+}
+
+static void qt1070_reset_poller(struct poller_struct *poller)
+{
+	struct qt1070_data *data = poller_to_qt_data(poller);
+	u8 buf;
+
+	if (!is_timeout_non_interruptible(data->start, QT1070_RESET_TIME * MSECOND))
+		return;
+
+	/* clear the status */
+	qt1070_read(data, QT1070_DET_STATUS, &buf);
+
+	poller->func = qt1070_poller;
+}
+
+static void qt1070_calibrate_poller(struct poller_struct *poller)
+{
+	struct qt1070_data *data = poller_to_qt_data(poller);
+	int ret;
+
+	if (!is_timeout_non_interruptible(data->start, QT1070_CAL_TIME * MSECOND))
+		return;
+
+	/* Soft reset */
+	ret = qt1070_write(data, QT1070_RESET, 1);
+	if (ret) {
+		dev_err(data->cdev.dev, "can not reset the chip (%d)\n", ret);
+		poller_unregister(poller);
+		return;
+	}
+	data->start = get_time_ns();
+
+	poller->func = qt1070_reset_poller;
+}
+
+static int qt1070_tstc(struct console_device *cdev)
+{
+	struct qt1070_data *data = cdev_to_qt_data(cdev);
+
+	return (kfifo_len(data->recv_fifo) == 0) ? 0 : 1;
+}
+
+static int qt1070_getc(struct console_device *cdev)
+{
+	int code = 0;
+	struct qt1070_data *data = cdev_to_qt_data(cdev);
+
+	kfifo_get(data->recv_fifo, (u_char*)&code, sizeof(int));
+	return code;
+}
+
+static int qt1070_pdata_init(struct device_d *dev, struct qt1070_data *data)
+{
+	struct qt1070_platform_data *pdata = dev->platform_data;
+	int ret;
+
+	if (!pdata)
+		return 0;
+
+	if (pdata->nb_code)
+		memcpy(data->code, pdata->code, sizeof(int) * pdata->nb_code);
+
+	if (!gpio_is_valid(pdata->irq_pin))
+		return 0;
+
+	ret = gpio_request(pdata->irq_pin, "qt1070");
+	if (ret)
+		return ret;
+
+	ret = gpio_direction_input(pdata->irq_pin);
+	if (ret)
+		goto err;
+
+	data->irq_pin = pdata->irq_pin;
+
+	return 0;
+err:
+	gpio_free(pdata->irq_pin);
+	return ret;
+}
+
+static int qt1070_probe(struct device_d *dev)
+{
+	struct console_device *cdev;
+	struct qt1070_data *data;
+	u8 fw_version, chip_id;
+	int ret;
+	char buf[6];
+
+	data = xzalloc(sizeof(*data));
+	data->client = to_i2c_client(dev);
+	data->irq_pin = -EINVAL;
+
+	ret = qt1070_read(data, QT1070_READ_CHIP_ID, &chip_id);
+	if (ret) {
+		dev_err(dev, "can not read chip id (%d)\n", ret);
+		goto err;
+	}
+
+	if (chip_id != QT1070_CHIP_ID) {
+		dev_err(dev, "unsupported id 0x%x\n", chip_id);
+		ret = -ENXIO;
+		goto err;
+	}
+
+	ret = qt1070_read(data, QT1070_FW_VERSION, &fw_version);
+	if (ret) {
+		dev_err(dev, "can not read firmware version (%d)\n", ret);
+		goto err;
+	}
+
+	sprintf(buf, "0x%x", fw_version);
+	dev_add_param_fixed(dev, "fw_version", buf);
+	sprintf(buf, "0x%x", chip_id);
+	dev_add_param_fixed(dev, "chip_ip", buf);
+
+	ret = qt1070_pdata_init(dev, data);
+	if (ret) {
+		dev_err(dev, "can not get pdata (%d)\n", ret);
+		goto err;
+	}
+
+	/* Calibrate device */
+	ret = qt1070_write(data, QT1070_CALIBRATE_CMD, 1);
+	if (ret) {
+		dev_err(dev, "can not calibrate the chip (%d)\n", ret);
+		goto err;
+	}
+	data->start = get_time_ns();
+
+	memcpy(data->code, default_code, sizeof(int) * ARRAY_SIZE(default_code));
+
+	data->fifo_size = 50;
+	data->recv_fifo = kfifo_alloc(data->fifo_size);
+
+	data->poller.func = qt1070_calibrate_poller;
+
+	cdev = &data->cdev;
+	cdev->dev = dev;
+	cdev->f_caps = CONSOLE_STDIN;
+	cdev->tstc = qt1070_tstc;
+	cdev->getc = qt1070_getc;
+
+	console_register(&data->cdev);
+
+	ret = poller_register(&data->poller);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	free(data);
+	return ret;
+}
+
+static struct driver_d qt1070_driver = {
+	.name	= "qt1070",
+	.probe	= qt1070_probe,
+};
+
+static int qt1070_init(void)
+{
+	i2c_register_driver(&qt1070_driver);
+	return 0;
+}
+device_initcall(qt1070_init);
diff --git a/include/input/qt1070.h b/include/input/qt1070.h
new file mode 100644
index 0000000..014f67b
--- /dev/null
+++ b/include/input/qt1070.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2
+ */
+
+#ifndef __QT1070_H__
+#define __QT1070_H__
+
+#define QT1070_NB_BUTTONS	7
+
+struct qt1070_platform_data {
+	int code[QT1070_NB_BUTTONS];
+	int nb_code;
+	int irq_pin;
+};
+
+#endif /* __QT1070_H__ */
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2012-11-03 11:28 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-01 13:22 [PATCH 1/1] input: add qt1070 touch keyboard support Jean-Christophe PLAGNIOL-VILLARD
2012-11-01 13:52 ` [PATCH 1/1 v2] " Jean-Christophe PLAGNIOL-VILLARD
2012-11-02 20:15   ` Sascha Hauer
2012-11-03  7:32     ` Jean-Christophe PLAGNIOL-VILLARD
2012-11-03 11:26   ` [PATCH 1/1 v3] " Jean-Christophe PLAGNIOL-VILLARD

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox