Credit where credit is due:

Thank you, very much, to Tomasz Figa for his work on FriendlyARM '1-wire'.

Thank you to Juergen Borleis for his work supporting the Mini 2440.

With a measure of certainty, I'm reasonably confident that I've done something incorrectly. Hence, it would be nice if someone could test these patches.

Theory:

It seems (from reading the mailing list) that others would like to have this FriendlyARM 1-wire support for both the Mini 2440 and Mini 6410.

Hopefully, it doesn't offend any one that I renamed T. Figa's files (which were applied to the 6410 project). It seemed like they would be useful to both the 2440 and 6410 (and probably other) boards; hence, I created these patches to be (hopefully) useful to both.

Practice:

I added the following:

  # FA 1-wire Support
  fa_1wire_fa_1wire.diff
  fa_1wire_fa_1wire_ts.diff
  fa_1wire_mach-mini2440.c.diff

to:

  configs/platform-friendlyarm-mini2440/patches/linux-3.14/series

near the bottom of the file, and (of course) updated:

  set-marker.diff

accordingly, and added the patch files to the same directory as 'series'. I've used the patches on 3.14.16 and 3.14.19. I am planning to revert the kernel changes and test them on 3.14.2 over the weekend. Thus far, the patches apply cleanly. Next step:

  ./p clean kernel
  ./p go

Just wanted to be certain that the kernel unpack and rebuild works and there is nothing bad happens during patching.

Moving forward.

Add the following:

  SUBSYSTEMS=="input", KERNEL=="event[0-9]*", KERNELS=="input[0-9]*",
    ATTRS{name}=="S3C24XX TouchScreen", SYMLINK+="input/touchscreen"

  SUBSYSTEMS=="input", KERNEL=="event[0-9]*", KERNELS=="input[0-9]*",
    ATTRS{name}=="FA Touchscreen", SYMLINK+="input/fa_1wire"

to:

  /lib/udev/rules.d/10-mini2440.rules

on the target.

Also on the target, in:

  /etc/profile.environment

change:

  MINI2440_TOUCHEVENT=/dev/input/touchscreen

to:

  MINI2440_TOUCHEVENT=/dev/input/touchscreen
  MINI2440_1WIRE=/dev/input/fa_1wire

and change:

  # Qt relevant settings
  export QWS_MOUSE_PROTO=Tslib:${MINI2440_TOUCHEVENT}

to:

  # Qt relevant settings
  export QWS_MOUSE_PROTO="Tslib:${MINI2440_TOUCHEVENT}
    Tslib:${MINI2440_1WIRE}"

nb: the quotes and the space are important (you know what to do)

Oh, yes, I also modified the bootargs variable from:

  bootargs=console=ttySAC0,115200 mini2440=1tb

to:

  bootargs=console=ttySAC0,115200 mini2440=1tbo

With this configuration, I was able to use an A70 (7") display in the 'analog' and 'digital' modes:

  *) analog R6, R7, R8, R9 installed; R11, R20, R21, R22 removed
  *) 1-wire R11, R20, R21, R22 installed; R6, R7, R8, R9 removed

It was a nice test; however, on a 'production' unit 't' and 'o' should, most likely, be mutually exclusive. Although it didn't seem to hurt to have both drivers.

I have to say; in an electrically noisy environment, the 1-wire display appeared to be more 'stable'; meaning the mouse pointer appeared less 'jittery' as compared to the analog touchscreen driver. It would be interesting to see if anyone else makes such an observation.

Let's see ... what else did I do? .... probably something foolish, and I'm certain someone will point it out ... no doubt about that.

Oh yes, I've tested this, of course, with a mini2440, and the following displays:

  /* mini2440 + 7" TFT + touchscreen (Innolux AT070TN83: N43/LCD70) */
  /* LCD-W35i 3.5" display (Sharp LQ035Q1DG06: W35i )*/

I have an H43 (currently installed on a Mini6410) which I'll be able to
test next week.

At this point it seems customary to request a review, and test victims.
Please test the patches if you are able to do so.

GB
diff -X exclude -Naur linux-3.14.orig/drivers/mfd/fa_1wire.c linux-3.14/drivers/mfd/fa_1wire.c
--- linux-3.14.orig/drivers/mfd/fa_1wire.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-3.14/drivers/mfd/fa_1wire.c	2014-10-03 12:13:25.853791973 -0700
@@ -0,0 +1,330 @@
+/*
+ * fa_1wire.c
+ *
+ * LCD-CPU one wire communication for FriendlyARM boards
+ *
+ * Copyright 2011 Tomasz Figa <tomasz.figa at gmail.com>
+ * Modified 2014 G. Brubaker
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/hrtimer.h>
+#include <linux/completion.h>
+#include <linux/gpio.h>
+
+#include <linux/fa_1wire.h>
+#include <linux/mfd/fa_1wire.h>
+
+#define FA_BUS_CLOCK	(9600)
+#define FA_1WIRE_DELAY	((NSEC_PER_SEC / FA_BUS_CLOCK) - 500)
+
+/*
+ * Driver data
+ */
+
+enum fa_1wire_state {
+	FA_1WIRE_IDLE = 0,
+	FA_1WIRE_RESET,
+	FA_1WIRE_TX,
+	FA_1WIRE_WAIT1,
+	FA_1WIRE_WAIT2,
+	FA_1WIRE_RX,
+	FA_1WIRE_STOP,
+};
+
+struct fa_1wire {
+	struct mutex			lock;
+	struct completion		completion;
+	struct hrtimer			timer;
+	enum fa_1wire_state	state;
+	struct device			*dev;
+
+	u16		tx_data;
+	u32		rx_data;
+	int		error;
+	ktime_t		next_event;
+	int		bits_left;
+
+	struct fa_1wire_platform_data	*pdata;
+};
+
+/*
+ * CRC 8
+ */
+
+static const unsigned char crc8_tab[] = {
+	0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15,
+	0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
+	0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
+	0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,
+	0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5,
+	0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
+	0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85,
+	0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,
+	0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
+	0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,
+	0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2,
+	0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
+	0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32,
+	0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,
+	0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
+	0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
+	0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c,
+	0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
+	0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec,
+	0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,
+	0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
+	0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,
+	0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c,
+	0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
+	0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b,
+	0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63,
+	0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
+	0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,
+	0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb,
+	0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
+	0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb,
+	0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3,
+};
+
+/*
+ * 1-wire I/O
+ */
+
+int fa_1wire_transfer(struct fa_1wire *bus,
+						u8 tx_data, u32 *rx_data)
+{
+	int ret;
+	u32 rx;
+	u8 crc;
+	int retry = 0;
+
+	/* Calculate CRC8 checksum */
+	crc = crc8_tab[0xac ^ tx_data];
+
+restart:
+	/* Lock the bus */
+	mutex_lock(&bus->lock);
+
+	/* Prepare the transfer */
+	bus->error = 0;
+	bus->tx_data = (tx_data << 8) | crc;
+
+	/* Put the bus into the reset state */
+	gpio_direction_output(bus->pdata->gpio_pin, 0);
+	bus->state = FA_1WIRE_RESET;
+
+	/* Schedule the timer */
+	bus->next_event = ktime_add_ns(ktime_get(), FA_1WIRE_DELAY);
+	hrtimer_start(&bus->timer, bus->next_event, HRTIMER_MODE_ABS);
+
+	/* Wait for the transfer to finish */
+	ret = wait_for_completion_interruptible(&bus->completion);
+	if (!ret)
+		ret = bus->error;
+	rx = bus->rx_data;
+
+	/* Unlock the bus */
+	mutex_unlock(&bus->lock);
+
+	/* Check CRC8 checksum of received data */
+	if (!ret && rx_data) {
+		*rx_data = rx >> 8;
+		crc = crc8_tab[0xac ^ ((rx >> 24) & 0xff)];
+		crc = crc8_tab[crc ^ ((rx >> 16) & 0xff)];
+		crc = crc8_tab[crc ^ ((rx >> 8) & 0xff)];
+		if (crc != (rx & 0xff))
+			ret = -EBADMSG;
+	}
+
+	if (ret && ++retry <= 10)
+		goto restart;
+
+	return ret;
+}
+EXPORT_SYMBOL(fa_1wire_transfer);
+
+static enum hrtimer_restart fa_1wire_timer(struct hrtimer *timer)
+{
+	struct fa_1wire *bus = container_of(timer,
+						struct fa_1wire, timer);
+	struct fa_1wire_platform_data *pdata = bus->pdata;
+	int ret;
+
+	switch(bus->state) {
+	case FA_1WIRE_RESET:
+		/* Start transfer */
+		bus->bits_left = 16;
+		bus->state = FA_1WIRE_TX;
+		break;
+
+	case FA_1WIRE_TX:
+		/* Send a bit */
+		gpio_set_value(pdata->gpio_pin, bus->tx_data & 0x8000);
+		bus->tx_data <<= 1;
+		if (--bus->bits_left == 0)
+			bus->state = FA_1WIRE_WAIT1;
+		break;
+
+	case FA_1WIRE_WAIT1:
+		/* Wait state */
+		gpio_direction_input(pdata->gpio_pin);
+		bus->state = FA_1WIRE_WAIT2;
+		break;
+
+	case FA_1WIRE_WAIT2:
+		/* Wait state */
+		bus->bits_left = 32;
+		bus->state = FA_1WIRE_RX;
+		break;
+
+	case FA_1WIRE_RX:
+		/* Receive a bit */
+		bus->rx_data <<= 1;
+		bus->rx_data |= gpio_get_value(pdata->gpio_pin);
+		if (--bus->bits_left == 0) {
+			bus->bits_left = 2;
+			bus->state = FA_1WIRE_STOP;
+			gpio_direction_output(pdata->gpio_pin, 1);
+		}
+		break;
+
+	case FA_1WIRE_STOP:
+		/* Stop condition */
+		if (--bus->bits_left == 0) {
+			bus->state = FA_1WIRE_IDLE;
+			complete(&bus->completion);
+			return HRTIMER_NORESTART;
+		}
+		break;
+
+	default:
+		BUG();
+	}
+
+	ret = hrtimer_forward(&bus->timer, bus->next_event,
+					ktime_set(0, FA_1WIRE_DELAY));
+	if (ret > 1) {
+		bus->error = -ETIMEDOUT;
+		complete(&bus->completion);
+		return HRTIMER_NORESTART;
+	}
+
+	bus->next_event = hrtimer_get_expires(&bus->timer);
+
+	return HRTIMER_RESTART;
+}
+
+/*
+ * Platform bus
+ */
+
+static struct mfd_cell fa_1wire_cells[] = {
+	{
+		.name = "fa-1wire-backlight",
+	},
+	{
+		.name = "fa-1wire-touchscreen",
+	},
+};
+
+static int fa_1wire_probe(struct platform_device *pdev)
+{
+	struct fa_1wire_platform_data *pdata = pdev->dev.platform_data;
+	struct fa_1wire *data;
+	int ret;
+
+	if (!pdata || !pdata->set_pullup || !gpio_is_valid(pdata->gpio_pin)) {
+		dev_err(&pdev->dev, "Invalid platform data.\n");
+		return -EINVAL;
+	}
+
+	ret = gpio_request(pdata->gpio_pin, "FA 1-wire");
+	if (ret) {
+		dev_err(&pdev->dev, "Could not request 1-wire GPIO.\n");
+		return ret;
+	}
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		dev_err(&pdev->dev, "Could not allocate driver data.\n");
+		gpio_free(pdata->gpio_pin);
+		return -ENOMEM;
+	}
+
+	data->pdata = pdata;
+	data->dev = &pdev->dev;
+	hrtimer_init(&data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+	mutex_init(&data->lock);
+	init_completion(&data->completion);
+	data->timer.function = fa_1wire_timer;
+	platform_set_drvdata(pdev, data);
+
+	gpio_direction_output(pdata->gpio_pin, 1);
+	pdata->set_pullup(1);
+
+	ret =  mfd_add_devices(&pdev->dev, -1, fa_1wire_cells,
+			ARRAY_SIZE(fa_1wire_cells), NULL, 0, NULL);
+
+	dev_info(&pdev->dev, "FA 1-wire host initialized.\n");
+
+	return ret;
+}
+
+
+static int fa_1wire_remove(struct platform_device *pdev)
+{
+	struct fa_1wire *data = platform_get_drvdata(pdev);
+
+	hrtimer_cancel(&data->timer);
+
+	mfd_remove_devices(&pdev->dev);
+
+	gpio_set_value(data->pdata->gpio_pin, 1);
+	data->pdata->set_pullup(0);
+	gpio_set_value(data->pdata->gpio_pin, 0);
+
+	gpio_free(data->pdata->gpio_pin);
+	kfree(data);
+
+	return 0;
+}
+
+static struct platform_driver fa_1wire_driver = {
+	.driver = {
+		.name	= "fa-1wire",
+		.owner = THIS_MODULE,
+	},
+	.probe	= fa_1wire_probe,
+	.remove	= fa_1wire_remove,
+};
+
+/*
+ * Module init
+ */
+
+static int fa_1wire_init(void)
+{
+	return platform_driver_register(&fa_1wire_driver);
+}
+module_init(fa_1wire_init);
+
+static void fa_1wire_exit(void)
+{
+	platform_driver_unregister(&fa_1wire_driver);
+}
+module_exit(fa_1wire_exit);
+
+MODULE_AUTHOR("Tomasz Figa <tomasz.figa at gmail.com>");
+MODULE_DESCRIPTION("FA virtual 1-wire bus");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:fa-1wire");
diff -X exclude -Naur linux-3.14.orig/drivers/mfd/Kconfig linux-3.14/drivers/mfd/Kconfig
--- linux-3.14.orig/drivers/mfd/Kconfig	2014-03-30 20:40:15.000000000 -0700
+++ linux-3.14/drivers/mfd/Kconfig	2014-10-03 12:13:25.853791973 -0700
@@ -163,6 +163,14 @@
 	  Additional drivers must be enabled in order to use the functionality
 	  of the device.
 
+config FA_1WIRE
+	tristate "Support for FriendlyARM proprietary 1-wire bus virtual host"
+	select MFD_CORE
+	---help---
+	  This is the core driver for the virtual, proprietary 1-wire bus
+	  bitbanged host using a GPIO pin. It is currently used to communicate
+	  with touchscreen and backlights controllers.
+
 config MFD_MC13XXX
 	tristate
 	depends on (SPI_MASTER || I2C)
diff -X exclude -Naur linux-3.14.orig/drivers/mfd/Makefile linux-3.14/drivers/mfd/Makefile
--- linux-3.14.orig/drivers/mfd/Makefile	2014-03-30 20:40:15.000000000 -0700
+++ linux-3.14/drivers/mfd/Makefile	2014-10-03 12:13:25.854791973 -0700
@@ -132,6 +132,7 @@
 obj-$(CONFIG_MFD_DB8500_PRCMU)	+= db8500-prcmu.o
 # ab8500-core need to come after db8500-prcmu (which provides the channel)
 obj-$(CONFIG_AB8500_CORE)	+= ab8500-core.o ab8500-sysctrl.o
+obj-$(CONFIG_FA_1WIRE)    += fa_1wire.o
 obj-$(CONFIG_MFD_TIMBERDALE)    += timberdale.o
 obj-$(CONFIG_PMIC_ADP5520)	+= adp5520.o
 obj-$(CONFIG_MFD_KEMPLD)	+= kempld-core.o
diff -X exclude -Naur linux-3.14.orig/include/linux/fa_1wire.h linux-3.14/include/linux/fa_1wire.h
--- linux-3.14.orig/include/linux/fa_1wire.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-3.14/include/linux/fa_1wire.h	2014-10-03 12:13:25.854791973 -0700
@@ -0,0 +1,32 @@
+/*
+ * include/linux/fa_1wire.h
+ *
+ * Definition of platform data structure for FriendlyARM 1-wire bus driver.
+ *
+ * Copyright 2011 Tomasz Figa <tomasz.figa at gmail.com>
+ * Modified 2014 G. Brubaker
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef FA_1WIRE_H
+#define FA_1WIRE_H
+
+struct fa_1wire_platform_data {
+	int	gpio_pin;
+	void 	(*set_pullup)(int state);
+};
+
+#endif	/* FA_1WIRE_H */
diff -X exclude -Naur linux-3.14.orig/include/linux/mfd/fa_1wire.h linux-3.14/include/linux/mfd/fa_1wire.h
--- linux-3.14.orig/include/linux/mfd/fa_1wire.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-3.14/include/linux/mfd/fa_1wire.h	2014-10-03 12:13:25.854791973 -0700
@@ -0,0 +1,35 @@
+/*
+ * include/linux/mfd/fa_1wire.h
+ *
+ * Some definitions for drivers of devices running on the 1-wire bus
+ * of the FriendlyARM boards.
+ *
+ * Copyright 2011 Tomasz Figa <tomasz.figa at gmail.com>
+ * Modified 2014 G. Brubaker
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef MFD_FA_1WIRE_H
+#define MFD_FA_1WIRE_H
+
+#include <linux/mfd/core.h>
+
+struct fa_1wire;
+
+extern int fa_1wire_transfer(struct fa_1wire *bus,
+						u8 tx_data, u32 *rx_data);
+
+#endif	/* MFD_FA_1WIRE_H */
diff -X exclude -Naur linux-3.14.orig/drivers/input/touchscreen/fa_1wire_ts.c linux-3.14/drivers/input/touchscreen/fa_1wire_ts.c
--- linux-3.14.orig/drivers/input/touchscreen/fa_1wire_ts.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-3.14/drivers/input/touchscreen/fa_1wire_ts.c	2014-10-03 12:13:25.856791973 -0700
@@ -0,0 +1,245 @@
+/*
+ * 1-wire touchscreen driver for FriendlyARM Boards.
+ *
+ * Copyright (C) 2011 Tomasz Figa <tomasz.figa at gmail.com>
+ * Modified 2014 G. Brubaker
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/fa_1wire.h>
+
+#define FA_1WIRE_TS_DELAY	(HZ / 50)
+#define FA_1WIRE_TS_REQ		(0x40)
+
+struct fa_1wire_ts {
+	struct delayed_work	work;
+	struct workqueue_struct	*workqueue;
+	struct fa_1wire	*bus;
+	struct input_dev	*input_dev;
+	struct device		*dev;
+
+	/* Signed fixed point 16:16 offset */
+	s16 base_x;
+	s16 base_y;
+
+	/* Signed fixed point 16:16 scale */
+	s32 scale_x;
+	s32 scale_y;
+
+	/* Screen parameters */
+	u16 width;
+	u16 height;
+
+	u16 x;
+	u16 y;
+	bool down;
+};
+
+static void fa_1wire_ts_report(struct fa_1wire_ts *ts, u32 data)
+{
+	u16 x, y;
+	bool down;
+
+	y  = (data & 0xf00000) >> 12;
+	y |= (data & 0x00ff00) >> 8;
+
+	x  = (data & 0x0f0000) >> 8;
+	x |= (data & 0x0000ff) >> 0;
+
+	down = (x != 0xfff) || (y != 0xfff);
+
+	if (x != ts->x || y != ts->y || down != ts->down) {
+		ts->x = x;
+		ts->y = y;
+		ts->down = down;
+
+		x = ((x + ts->base_x) * ts->scale_x) >> 16;
+		y = ((y + ts->base_y) * ts->scale_y) >> 16;
+
+		if (x >= ts->width)
+			x = ts->width - 1;
+
+		if (y >= ts->height)
+			y = ts->height - 1;
+
+		input_report_key(ts->input_dev, BTN_TOUCH, down);
+		input_report_abs(ts->input_dev, ABS_X, x);
+		input_report_abs(ts->input_dev, ABS_Y, y);
+		input_sync(ts->input_dev);
+	}
+}
+
+static void fa_1wire_ts_workfunc(struct work_struct *work)
+{
+	struct delayed_work *delayed_work = to_delayed_work(work);
+	struct fa_1wire_ts *ts =
+		container_of(delayed_work, struct fa_1wire_ts, work);
+	u32 rx_data;
+	u8 tx_data = FA_1WIRE_TS_REQ;
+	int ret;
+
+	ret = fa_1wire_transfer(ts->bus, tx_data, &rx_data);
+	if (!ret)
+		fa_1wire_ts_report(ts, rx_data);
+
+	schedule_delayed_work(delayed_work, FA_1WIRE_TS_DELAY);
+}
+
+static ssize_t calibration_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct fa_1wire_ts *ts = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u %d %d %u %d %d\n",
+					ts->width, ts->base_x, ts->scale_x,
+					ts->height, ts->base_y, ts->scale_y);
+}
+
+static ssize_t calibration_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct fa_1wire_ts *ts = dev_get_drvdata(dev);
+	int ret;
+	s32 base_x, base_y, scale_x, scale_y;
+	u32 width, height;
+
+	ret = sscanf(buf, "%u %d %d %u %d %d",
+			&width, &base_x, &scale_x, &height, &base_y, &scale_y);
+
+	if (ret != 6)
+		return -EINVAL;
+
+	cancel_delayed_work_sync(&ts->work);
+
+	ts->base_x = base_x;
+	ts->base_y = base_y;
+	ts->scale_x = scale_x;
+	ts->scale_y = scale_y;
+	ts->width = width;
+	ts->height = height;
+
+	input_set_abs_params(ts->input_dev, ABS_X, 0, width - 1, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_Y, 0, height - 1, 0, 0);
+
+	schedule_delayed_work(&ts->work, FA_1WIRE_TS_DELAY);
+
+	return size;
+}
+
+static DEVICE_ATTR(calibration, S_IRUGO | S_IWUSR,
+					calibration_show, calibration_store);
+
+static struct attribute *fa_ts_attrs[] = {
+	&dev_attr_calibration.attr,
+	NULL
+};
+
+static const struct attribute_group fa_ts_attr_group = {
+	.attrs = fa_ts_attrs,
+};
+
+static int fa_1wire_ts_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct fa_1wire_ts *ts;
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (!ts)
+		return -ENOMEM;
+
+	ts->bus = dev_get_drvdata(pdev->dev.parent);
+	ts->dev = &pdev->dev;
+	ts->workqueue = create_singlethread_workqueue("fa_1wire_ts");
+	if (!ts->workqueue) {
+		ret = -ENOMEM;
+		goto err_workqueue;
+	}
+	INIT_DELAYED_WORK(&ts->work, fa_1wire_ts_workfunc);
+
+	ts->input_dev = input_allocate_device();
+	if (!ts->input_dev) {
+		ret = -ENOMEM;
+		goto err_input_alloc;
+	}
+
+	ts->input_dev->name = "FA Touchscreen";
+	ts->input_dev->dev.parent = &pdev->dev;
+	ts->input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	/* Set calibration data for 1:1 operation */
+	ts->base_x = 0;
+	ts->base_y = 0;
+	ts->scale_x = 1 << 16;
+	ts->scale_y = 1 << 16;
+	ts->width = 0x1000;
+	ts->height = 0x1000;
+
+	/* Configure absolute value ranges appropriately */
+	input_set_abs_params(ts->input_dev, ABS_X, 0, 0xfff, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_Y, 0, 0xfff, 0, 0);
+
+	platform_set_drvdata(pdev, ts);
+
+	ret = input_register_device(ts->input_dev);
+	if (ret)
+		goto err_input_register;
+
+	schedule_delayed_work(&ts->work, FA_1WIRE_TS_DELAY);
+
+	if(sysfs_create_group(&pdev->dev.kobj, &fa_ts_attr_group))
+		dev_warn(&pdev->dev, "Failed to create sysfs group.\n");
+
+	return 0;
+
+err_input_register:
+	input_free_device(ts->input_dev);
+err_input_alloc:
+	destroy_workqueue(ts->workqueue);
+err_workqueue:
+	kfree(ts);
+	return ret;
+}
+
+static int fa_1wire_ts_remove(struct platform_device *pdev)
+{
+	struct fa_1wire_ts *ts = platform_get_drvdata(pdev);
+
+	sysfs_remove_group(&pdev->dev.kobj, &fa_ts_attr_group);
+
+	destroy_workqueue(ts->workqueue);
+
+	input_get_device(ts->input_dev);
+	input_unregister_device(ts->input_dev);
+	input_free_device(ts->input_dev);
+
+	kfree(ts);
+
+	return 0;
+}
+
+static struct platform_driver fa_1wire_ts_driver = {
+	.probe = fa_1wire_ts_probe,
+	.remove = fa_1wire_ts_remove,
+	.driver = {
+		.name = "fa-1wire-touchscreen",
+	},
+};
+module_platform_driver(fa_1wire_ts_driver);
+
+MODULE_AUTHOR("Tomasz Figa <tomasz.figa at gmail.com>");
+MODULE_DESCRIPTION("FA 1-wire Touchscreen");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:fa-1wire-touchscreen");
diff -X exclude -Naur linux-3.14.orig/drivers/input/touchscreen/Kconfig linux-3.14/drivers/input/touchscreen/Kconfig
--- linux-3.14.orig/drivers/input/touchscreen/Kconfig	2014-03-30 20:40:15.000000000 -0700
+++ linux-3.14/drivers/input/touchscreen/Kconfig	2014-10-03 12:13:25.857791973 -0700
@@ -265,6 +265,13 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called egalax_ts.
 
+config TOUCHSCREEN_FA_1WIRE
+	tristate "FA 1-wire Touchscreen"
+	depends on FA_1WIRE
+	help
+	  Say Y here if you have a FriendlyARM board equipped with
+	  a FriendlyARM 1-wire touchscreen module.
+
 config TOUCHSCREEN_FUJITSU
 	tristate "Fujitsu serial touchscreen"
 	select SERIO
diff -X exclude -Naur linux-3.14.orig/drivers/input/touchscreen/Makefile linux-3.14/drivers/input/touchscreen/Makefile
--- linux-3.14.orig/drivers/input/touchscreen/Makefile	2014-03-30 20:40:15.000000000 -0700
+++ linux-3.14/drivers/input/touchscreen/Makefile	2014-10-03 12:13:25.857791973 -0700
@@ -32,6 +32,7 @@
 obj-$(CONFIG_TOUCHSCREEN_EETI)		+= eeti_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ELO)		+= elo.o
 obj-$(CONFIG_TOUCHSCREEN_EGALAX)	+= egalax_ts.o
+obj-$(CONFIG_TOUCHSCREEN_FA_1WIRE)	+= fa_1wire_ts.o
 obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ILI210X)	+= ili210x.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
diff -X exclude -Naur linux-3.14.orig/arch/arm/mach-s3c24xx/mach-mini2440.c linux-3.14/arch/arm/mach-s3c24xx/mach-mini2440.c
--- linux-3.14.orig/arch/arm/mach-s3c24xx/mach-mini2440.c	2014-10-03 11:38:10.409812148 -0700
+++ linux-3.14/arch/arm/mach-s3c24xx/mach-mini2440.c	2014-10-03 12:13:25.859791973 -0700
@@ -29,6 +29,7 @@
 #include <linux/gpio_keys.h>
 #include <linux/i2c.h>
 #include <linux/mmc/host.h>
+#include <linux/fa_1wire.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -612,6 +613,27 @@
 	},
 };
 
+static void fa_1wire_pullup(int enable)
+{
+	if (enable)
+		s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_UP);
+	else
+		s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_NONE);
+}
+
+static struct fa_1wire_platform_data fa_1wire_pdata = {
+    .gpio_pin = S3C2410_GPB(1),
+    .set_pullup = fa_1wire_pullup,
+};
+
+static struct platform_device fa_1wire_device = {
+    .name = "fa-1wire",
+    .id = -1,
+    .dev = {
+        .platform_data = &fa_1wire_pdata,
+    },
+};
+
 static struct platform_device *mini2440_devices[] __initdata = {
 	&s3c_device_ohci,
 	&s3c_device_wdt,
@@ -664,6 +686,7 @@
 #define FEATURE_BACKLIGHT (1 << 1)
 #define FEATURE_TOUCH (1 << 2)
 #define FEATURE_CAMERA (1 << 3)
+#define FEATURE_1WIRE (1 << 4)
 
 struct mini2440_features_t {
 	int count;
@@ -709,7 +732,7 @@
 					"backlight already set\n", f);
 			else {
 				features->optional[features->count++] =
-						&mini2440_led_backlight;
+					&mini2440_led_backlight;
 			}
 			features->done |= FEATURE_BACKLIGHT;
 			break;
@@ -719,7 +742,7 @@
 					"touchscreen already set\n", f);
 			else
 				features->optional[features->count++] =
-						&s3c_device_ts;
+					&s3c_device_ts;
 			features->done |= FEATURE_TOUCH;
 			break;
 		case 'c':
@@ -731,6 +754,15 @@
 					&s3c_device_camif;
 			features->done |= FEATURE_CAMERA;
 			break;
+		case 'o':
+			if (features->done & FEATURE_1WIRE)
+				pr_info("MINI2440: '%c' ignored, "
+					"one-wire already registered\n", f);
+			else
+				features->optional[features->count++] =
+					&fa_1wire_device;
+			features->done |= FEATURE_1WIRE;
+			break;
 		}
 	}
 }

Reply via email to