All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/6] iio: at91: Add touch screen support in at91 adc
@ 2013-08-27 11:28 ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, thomas.petazzoni, mark.rutland, b.brezillon,
	Josh Wu

This patch series introduce multiple compatible string for different ip.
So remove some adc dt parameters as it already included in driver code.

It also touch screen support for at91 adc driver.
To enable touch screen you need add the touch screen related dt properties.

v2 --> v3:
  1. move the dt parameters to driver itself.
  2. trival fix in touch driver.

v1 --> v2:
  1. use multiple compatible string for different ADC IP.
  2. drop the patch that add the adc-clock in dt since we will move to clock
     common framework.
  3. don't expose the driver configuration to dt. Such like sample period,
     pen detect debounce time and etc.
  4. add a new dt parameter: ts-pressure-threshold.

Josh Wu (6):
  iio: at91: fix adc_clk overflow
  iio: at91: introduce the multiple compatible string for different
    IPs.
  iio: at91: Use different prescal, startup mask in MR for different IP
  iio: at91: ADC start-up time calculation changed since at91sam9x5
  iio: at91: move the num_channels from DT to driver itself
  iio: at91: introduce touch screen support in iio adc driver

 .../devicetree/bindings/arm/atmel-adc.txt          |   15 +-
 arch/arm/mach-at91/include/mach/at91_adc.h         |   50 +-
 drivers/iio/adc/at91_adc.c                         |  550 +++++++++++++++++---
 include/linux/platform_data/at91_adc.h             |    4 +
 4 files changed, 530 insertions(+), 89 deletions(-)

-- 
1.7.10


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

* [PATCH v3 0/6] iio: at91: Add touch screen support in at91 adc
@ 2013-08-27 11:28 ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: linux-arm-kernel

This patch series introduce multiple compatible string for different ip.
So remove some adc dt parameters as it already included in driver code.

It also touch screen support for at91 adc driver.
To enable touch screen you need add the touch screen related dt properties.

v2 --> v3:
  1. move the dt parameters to driver itself.
  2. trival fix in touch driver.

v1 --> v2:
  1. use multiple compatible string for different ADC IP.
  2. drop the patch that add the adc-clock in dt since we will move to clock
     common framework.
  3. don't expose the driver configuration to dt. Such like sample period,
     pen detect debounce time and etc.
  4. add a new dt parameter: ts-pressure-threshold.

Josh Wu (6):
  iio: at91: fix adc_clk overflow
  iio: at91: introduce the multiple compatible string for different
    IPs.
  iio: at91: Use different prescal, startup mask in MR for different IP
  iio: at91: ADC start-up time calculation changed since at91sam9x5
  iio: at91: move the num_channels from DT to driver itself
  iio: at91: introduce touch screen support in iio adc driver

 .../devicetree/bindings/arm/atmel-adc.txt          |   15 +-
 arch/arm/mach-at91/include/mach/at91_adc.h         |   50 +-
 drivers/iio/adc/at91_adc.c                         |  550 +++++++++++++++++---
 include/linux/platform_data/at91_adc.h             |    4 +
 4 files changed, 530 insertions(+), 89 deletions(-)

-- 
1.7.10

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

* [PATCH v3 1/6] iio: at91: fix adc_clk overflow
  2013-08-27 11:28 ` Josh Wu
@ 2013-08-27 11:28   ` Josh Wu
  -1 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, thomas.petazzoni, mark.rutland, b.brezillon,
	Josh Wu

The adc_clk variable is currently defined using a 32-bits unsigned integer,
which will overflow under some very valid range of operations.

Such overflow will occur if, for example, the parent clock is set to a
20MHz frequency and the ADC startup time is larger than 215ns.

To fix this, introduce an intermediate variable holding the clock rate
in kHz.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
v1 --> v2:
  refined the commit message.

 drivers/iio/adc/at91_adc.c |   11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index b6db6a0..9cf8ab5 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -582,7 +582,7 @@ static const struct iio_info at91_adc_info = {
 
 static int at91_adc_probe(struct platform_device *pdev)
 {
-	unsigned int prsc, mstrclk, ticks, adc_clk, shtim;
+	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
 	int ret;
 	struct iio_dev *idev;
 	struct at91_adc_state *st;
@@ -680,6 +680,7 @@ static int at91_adc_probe(struct platform_device *pdev)
 	 */
 	mstrclk = clk_get_rate(st->clk);
 	adc_clk = clk_get_rate(st->adc_clk);
+	adc_clk_khz = adc_clk / 1000;
 	prsc = (mstrclk / (2 * adc_clk)) - 1;
 
 	if (!st->startup_time) {
@@ -693,15 +694,15 @@ static int at91_adc_probe(struct platform_device *pdev)
 	 * defined in the electrical characteristics of the board, divided by 8.
 	 * The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock
 	 */
-	ticks = round_up((st->startup_time * adc_clk /
-			  1000000) - 1, 8) / 8;
+	ticks = round_up((st->startup_time * adc_clk_khz /
+			  1000) - 1, 8) / 8;
 	/*
 	 * a minimal Sample and Hold Time is necessary for the ADC to guarantee
 	 * the best converted final value between two channels selection
 	 * The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock
 	 */
-	shtim = round_up((st->sample_hold_time * adc_clk /
-			  1000000) - 1, 1);
+	shtim = round_up((st->sample_hold_time * adc_clk_khz /
+			  1000) - 1, 1);
 
 	reg = AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL;
 	reg |= AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP;
-- 
1.7.10


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

* [PATCH v3 1/6] iio: at91: fix adc_clk overflow
@ 2013-08-27 11:28   ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: linux-arm-kernel

The adc_clk variable is currently defined using a 32-bits unsigned integer,
which will overflow under some very valid range of operations.

Such overflow will occur if, for example, the parent clock is set to a
20MHz frequency and the ADC startup time is larger than 215ns.

To fix this, introduce an intermediate variable holding the clock rate
in kHz.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
v1 --> v2:
  refined the commit message.

 drivers/iio/adc/at91_adc.c |   11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index b6db6a0..9cf8ab5 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -582,7 +582,7 @@ static const struct iio_info at91_adc_info = {
 
 static int at91_adc_probe(struct platform_device *pdev)
 {
-	unsigned int prsc, mstrclk, ticks, adc_clk, shtim;
+	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
 	int ret;
 	struct iio_dev *idev;
 	struct at91_adc_state *st;
@@ -680,6 +680,7 @@ static int at91_adc_probe(struct platform_device *pdev)
 	 */
 	mstrclk = clk_get_rate(st->clk);
 	adc_clk = clk_get_rate(st->adc_clk);
+	adc_clk_khz = adc_clk / 1000;
 	prsc = (mstrclk / (2 * adc_clk)) - 1;
 
 	if (!st->startup_time) {
@@ -693,15 +694,15 @@ static int at91_adc_probe(struct platform_device *pdev)
 	 * defined in the electrical characteristics of the board, divided by 8.
 	 * The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock
 	 */
-	ticks = round_up((st->startup_time * adc_clk /
-			  1000000) - 1, 8) / 8;
+	ticks = round_up((st->startup_time * adc_clk_khz /
+			  1000) - 1, 8) / 8;
 	/*
 	 * a minimal Sample and Hold Time is necessary for the ADC to guarantee
 	 * the best converted final value between two channels selection
 	 * The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock
 	 */
-	shtim = round_up((st->sample_hold_time * adc_clk /
-			  1000000) - 1, 1);
+	shtim = round_up((st->sample_hold_time * adc_clk_khz /
+			  1000) - 1, 1);
 
 	reg = AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL;
 	reg |= AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP;
-- 
1.7.10

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

* [PATCH v3 2/6] iio: at91: introduce the multiple compatible string for different IPs.
  2013-08-27 11:28 ` Josh Wu
  (?)
@ 2013-08-27 11:28     ` Josh Wu
  -1 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: jic23-KWPb1pKIrIJaa/9Udqfwiw
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	plagnioj-sclMFOaUSTBWk0Htik3J/w,
	nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	mark.rutland-5wv7dgnIgG8, b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ,
	Josh Wu, devicetree-u79uwXL29TY76Z2rM5mHXA

As use the multiple compatible string, we can remove hardware register in dt.

CC: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Signed-off-by: Josh Wu <josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
---
 .../devicetree/bindings/arm/atmel-adc.txt          |    7 +-
 arch/arm/mach-at91/include/mach/at91_adc.h         |    9 +++
 drivers/iio/adc/at91_adc.c                         |   79 ++++++++++----------
 3 files changed, 52 insertions(+), 43 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 16769d9..723c205 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -1,18 +1,15 @@
 * AT91's Analog to Digital Converter (ADC)
 
 Required properties:
-  - compatible: Should be "atmel,at91sam9260-adc"
+  - compatible: Should be "atmel,<chip>-adc"
+    <chip> can be "at91sam9260", "at91sam9g45" or "at91sam9x5"
   - reg: Should contain ADC registers location and length
   - interrupts: Should contain the IRQ line for the ADC
-  - atmel,adc-channel-base: Offset of the first channel data register
   - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
     device
-  - atmel,adc-drdy-mask: Mask of the DRDY interruption in the ADC
   - atmel,adc-num-channels: Number of channels available in the ADC
   - atmel,adc-startup-time: Startup Time of the ADC in microseconds as
     defined in the datasheet
-  - atmel,adc-status-register: Offset of the Interrupt Status Register
-  - atmel,adc-trigger-register: Offset of the Trigger Register
   - atmel,adc-vref: Reference voltage in millivolts for the conversions
   - atmel,adc-res: List of resolution in bits supported by the ADC. List size
 		   must be two at least.
diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
index 8e7ed5c..bea1a20 100644
--- a/arch/arm/mach-at91/include/mach/at91_adc.h
+++ b/arch/arm/mach-at91/include/mach/at91_adc.h
@@ -48,6 +48,9 @@
 #define		AT91_ADC_ENDRX		(1 << 18)	/* End of RX Buffer */
 #define		AT91_ADC_RXFUFF		(1 << 19)	/* RX Buffer Full */
 
+#define AT91_ADC_SR_9X5		0x30		/* Status Register for 9x5 */
+#define		AT91_ADC_SR_DRDY_9X5	(1 << 24)	/* Data Ready */
+
 #define AT91_ADC_LCDR		0x20		/* Last Converted Data Register */
 #define		AT91_ADC_LDATA		(0x3ff)
 
@@ -58,4 +61,10 @@
 #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
 #define		AT91_ADC_DATA		(0x3ff)
 
+#define AT91_ADC_CDR0_9X5	(0x50)			/* Channel Data Register 0 for 9X5 */
+
+#define AT91_ADC_TRGR_9260	AT91_ADC_MR
+#define AT91_ADC_TRGR_9G45	0x08
+#define AT91_ADC_TRGR_9X5	0xC0
+
 #endif
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 9cf8ab5..49dd751 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -39,6 +39,10 @@
 #define at91_adc_writel(st, reg, val) \
 	(writel_relaxed(val, st->reg_base + reg))
 
+struct at91_adc_caps {
+	struct at91_adc_reg_desc registers;
+};
+
 struct at91_adc_state {
 	struct clk		*adc_clk;
 	u16			*buffer;
@@ -62,6 +66,7 @@ struct at91_adc_state {
 	u32			res;		/* resolution used for convertions */
 	bool			low_res;	/* the resolution corresponds to the lowest one */
 	wait_queue_head_t	wq_data_avail;
+	struct at91_adc_caps	*caps;
 };
 
 static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
@@ -429,6 +434,8 @@ ret:
 	return ret;
 }
 
+static const struct of_device_id at91_adc_dt_ids[];
+
 static int at91_adc_probe_dt(struct at91_adc_state *st,
 			     struct platform_device *pdev)
 {
@@ -441,6 +448,9 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 	if (!node)
 		return -EINVAL;
 
+	st->caps = (struct at91_adc_caps *)
+		of_match_device(at91_adc_dt_ids, &pdev->dev)->data;
+
 	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
 
 	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
@@ -481,43 +491,7 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 	if (ret)
 		goto error_ret;
 
-	st->registers = devm_kzalloc(&idev->dev,
-				     sizeof(struct at91_adc_reg_desc),
-				     GFP_KERNEL);
-	if (!st->registers) {
-		dev_err(&idev->dev, "Could not allocate register memory.\n");
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-
-	if (of_property_read_u32(node, "atmel,adc-channel-base", &prop)) {
-		dev_err(&idev->dev, "Missing adc-channel-base property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->registers->channel_base = prop;
-
-	if (of_property_read_u32(node, "atmel,adc-drdy-mask", &prop)) {
-		dev_err(&idev->dev, "Missing adc-drdy-mask property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->registers->drdy_mask = prop;
-
-	if (of_property_read_u32(node, "atmel,adc-status-register", &prop)) {
-		dev_err(&idev->dev, "Missing adc-status-register property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->registers->status_register = prop;
-
-	if (of_property_read_u32(node, "atmel,adc-trigger-register", &prop)) {
-		dev_err(&idev->dev, "Missing adc-trigger-register property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->registers->trigger_register = prop;
-
+	st->registers = &st->caps->registers;
 	st->trigger_number = of_get_child_count(node);
 	st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
 					sizeof(struct at91_adc_trigger),
@@ -776,8 +750,37 @@ static int at91_adc_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_OF
+static struct at91_adc_caps at91sam9260_caps = {
+	.registers = {
+		.channel_base = AT91_ADC_CHR(0),
+		.drdy_mask = AT91_ADC_DRDY,
+		.status_register = AT91_ADC_SR,
+		.trigger_register = AT91_ADC_TRGR_9260,
+	},
+};
+
+static struct at91_adc_caps at91sam9g45_caps = {
+	.registers = {
+		.channel_base = AT91_ADC_CHR(0),
+		.drdy_mask = AT91_ADC_DRDY,
+		.status_register = AT91_ADC_SR,
+		.trigger_register = AT91_ADC_TRGR_9G45,
+	},
+};
+
+static struct at91_adc_caps at91sam9x5_caps = {
+	.registers = {
+		.channel_base = AT91_ADC_CDR0_9X5,
+		.drdy_mask = AT91_ADC_SR_DRDY_9X5,
+		.status_register = AT91_ADC_SR_9X5,
+		.trigger_register = AT91_ADC_TRGR_9X5,
+	},
+};
+
 static const struct of_device_id at91_adc_dt_ids[] = {
-	{ .compatible = "atmel,at91sam9260-adc" },
+	{ .compatible = "atmel,at91sam9260-adc", .data = &at91sam9260_caps },
+	{ .compatible = "atmel,at91sam9g45-adc", .data = &at91sam9g45_caps },
+	{ .compatible = "atmel,at91sam9x5-adc", .data = &at91sam9x5_caps },
 	{},
 };
 MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
-- 
1.7.10

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

* [PATCH v3 2/6] iio: at91: introduce the multiple compatible string for different IPs.
@ 2013-08-27 11:28     ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, thomas.petazzoni, mark.rutland, b.brezillon,
	Josh Wu, devicetree

As use the multiple compatible string, we can remove hardware register in dt.

CC: devicetree@vger.kernel.org
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
 .../devicetree/bindings/arm/atmel-adc.txt          |    7 +-
 arch/arm/mach-at91/include/mach/at91_adc.h         |    9 +++
 drivers/iio/adc/at91_adc.c                         |   79 ++++++++++----------
 3 files changed, 52 insertions(+), 43 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 16769d9..723c205 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -1,18 +1,15 @@
 * AT91's Analog to Digital Converter (ADC)
 
 Required properties:
-  - compatible: Should be "atmel,at91sam9260-adc"
+  - compatible: Should be "atmel,<chip>-adc"
+    <chip> can be "at91sam9260", "at91sam9g45" or "at91sam9x5"
   - reg: Should contain ADC registers location and length
   - interrupts: Should contain the IRQ line for the ADC
-  - atmel,adc-channel-base: Offset of the first channel data register
   - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
     device
-  - atmel,adc-drdy-mask: Mask of the DRDY interruption in the ADC
   - atmel,adc-num-channels: Number of channels available in the ADC
   - atmel,adc-startup-time: Startup Time of the ADC in microseconds as
     defined in the datasheet
-  - atmel,adc-status-register: Offset of the Interrupt Status Register
-  - atmel,adc-trigger-register: Offset of the Trigger Register
   - atmel,adc-vref: Reference voltage in millivolts for the conversions
   - atmel,adc-res: List of resolution in bits supported by the ADC. List size
 		   must be two at least.
diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
index 8e7ed5c..bea1a20 100644
--- a/arch/arm/mach-at91/include/mach/at91_adc.h
+++ b/arch/arm/mach-at91/include/mach/at91_adc.h
@@ -48,6 +48,9 @@
 #define		AT91_ADC_ENDRX		(1 << 18)	/* End of RX Buffer */
 #define		AT91_ADC_RXFUFF		(1 << 19)	/* RX Buffer Full */
 
+#define AT91_ADC_SR_9X5		0x30		/* Status Register for 9x5 */
+#define		AT91_ADC_SR_DRDY_9X5	(1 << 24)	/* Data Ready */
+
 #define AT91_ADC_LCDR		0x20		/* Last Converted Data Register */
 #define		AT91_ADC_LDATA		(0x3ff)
 
@@ -58,4 +61,10 @@
 #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
 #define		AT91_ADC_DATA		(0x3ff)
 
+#define AT91_ADC_CDR0_9X5	(0x50)			/* Channel Data Register 0 for 9X5 */
+
+#define AT91_ADC_TRGR_9260	AT91_ADC_MR
+#define AT91_ADC_TRGR_9G45	0x08
+#define AT91_ADC_TRGR_9X5	0xC0
+
 #endif
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 9cf8ab5..49dd751 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -39,6 +39,10 @@
 #define at91_adc_writel(st, reg, val) \
 	(writel_relaxed(val, st->reg_base + reg))
 
+struct at91_adc_caps {
+	struct at91_adc_reg_desc registers;
+};
+
 struct at91_adc_state {
 	struct clk		*adc_clk;
 	u16			*buffer;
@@ -62,6 +66,7 @@ struct at91_adc_state {
 	u32			res;		/* resolution used for convertions */
 	bool			low_res;	/* the resolution corresponds to the lowest one */
 	wait_queue_head_t	wq_data_avail;
+	struct at91_adc_caps	*caps;
 };
 
 static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
@@ -429,6 +434,8 @@ ret:
 	return ret;
 }
 
+static const struct of_device_id at91_adc_dt_ids[];
+
 static int at91_adc_probe_dt(struct at91_adc_state *st,
 			     struct platform_device *pdev)
 {
@@ -441,6 +448,9 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 	if (!node)
 		return -EINVAL;
 
+	st->caps = (struct at91_adc_caps *)
+		of_match_device(at91_adc_dt_ids, &pdev->dev)->data;
+
 	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
 
 	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
@@ -481,43 +491,7 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 	if (ret)
 		goto error_ret;
 
-	st->registers = devm_kzalloc(&idev->dev,
-				     sizeof(struct at91_adc_reg_desc),
-				     GFP_KERNEL);
-	if (!st->registers) {
-		dev_err(&idev->dev, "Could not allocate register memory.\n");
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-
-	if (of_property_read_u32(node, "atmel,adc-channel-base", &prop)) {
-		dev_err(&idev->dev, "Missing adc-channel-base property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->registers->channel_base = prop;
-
-	if (of_property_read_u32(node, "atmel,adc-drdy-mask", &prop)) {
-		dev_err(&idev->dev, "Missing adc-drdy-mask property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->registers->drdy_mask = prop;
-
-	if (of_property_read_u32(node, "atmel,adc-status-register", &prop)) {
-		dev_err(&idev->dev, "Missing adc-status-register property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->registers->status_register = prop;
-
-	if (of_property_read_u32(node, "atmel,adc-trigger-register", &prop)) {
-		dev_err(&idev->dev, "Missing adc-trigger-register property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->registers->trigger_register = prop;
-
+	st->registers = &st->caps->registers;
 	st->trigger_number = of_get_child_count(node);
 	st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
 					sizeof(struct at91_adc_trigger),
@@ -776,8 +750,37 @@ static int at91_adc_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_OF
+static struct at91_adc_caps at91sam9260_caps = {
+	.registers = {
+		.channel_base = AT91_ADC_CHR(0),
+		.drdy_mask = AT91_ADC_DRDY,
+		.status_register = AT91_ADC_SR,
+		.trigger_register = AT91_ADC_TRGR_9260,
+	},
+};
+
+static struct at91_adc_caps at91sam9g45_caps = {
+	.registers = {
+		.channel_base = AT91_ADC_CHR(0),
+		.drdy_mask = AT91_ADC_DRDY,
+		.status_register = AT91_ADC_SR,
+		.trigger_register = AT91_ADC_TRGR_9G45,
+	},
+};
+
+static struct at91_adc_caps at91sam9x5_caps = {
+	.registers = {
+		.channel_base = AT91_ADC_CDR0_9X5,
+		.drdy_mask = AT91_ADC_SR_DRDY_9X5,
+		.status_register = AT91_ADC_SR_9X5,
+		.trigger_register = AT91_ADC_TRGR_9X5,
+	},
+};
+
 static const struct of_device_id at91_adc_dt_ids[] = {
-	{ .compatible = "atmel,at91sam9260-adc" },
+	{ .compatible = "atmel,at91sam9260-adc", .data = &at91sam9260_caps },
+	{ .compatible = "atmel,at91sam9g45-adc", .data = &at91sam9g45_caps },
+	{ .compatible = "atmel,at91sam9x5-adc", .data = &at91sam9x5_caps },
 	{},
 };
 MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
-- 
1.7.10


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

* [PATCH v3 2/6] iio: at91: introduce the multiple compatible string for different IPs.
@ 2013-08-27 11:28     ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: linux-arm-kernel

As use the multiple compatible string, we can remove hardware register in dt.

CC: devicetree at vger.kernel.org
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
 .../devicetree/bindings/arm/atmel-adc.txt          |    7 +-
 arch/arm/mach-at91/include/mach/at91_adc.h         |    9 +++
 drivers/iio/adc/at91_adc.c                         |   79 ++++++++++----------
 3 files changed, 52 insertions(+), 43 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 16769d9..723c205 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -1,18 +1,15 @@
 * AT91's Analog to Digital Converter (ADC)
 
 Required properties:
-  - compatible: Should be "atmel,at91sam9260-adc"
+  - compatible: Should be "atmel,<chip>-adc"
+    <chip> can be "at91sam9260", "at91sam9g45" or "at91sam9x5"
   - reg: Should contain ADC registers location and length
   - interrupts: Should contain the IRQ line for the ADC
-  - atmel,adc-channel-base: Offset of the first channel data register
   - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
     device
-  - atmel,adc-drdy-mask: Mask of the DRDY interruption in the ADC
   - atmel,adc-num-channels: Number of channels available in the ADC
   - atmel,adc-startup-time: Startup Time of the ADC in microseconds as
     defined in the datasheet
-  - atmel,adc-status-register: Offset of the Interrupt Status Register
-  - atmel,adc-trigger-register: Offset of the Trigger Register
   - atmel,adc-vref: Reference voltage in millivolts for the conversions
   - atmel,adc-res: List of resolution in bits supported by the ADC. List size
 		   must be two at least.
diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
index 8e7ed5c..bea1a20 100644
--- a/arch/arm/mach-at91/include/mach/at91_adc.h
+++ b/arch/arm/mach-at91/include/mach/at91_adc.h
@@ -48,6 +48,9 @@
 #define		AT91_ADC_ENDRX		(1 << 18)	/* End of RX Buffer */
 #define		AT91_ADC_RXFUFF		(1 << 19)	/* RX Buffer Full */
 
+#define AT91_ADC_SR_9X5		0x30		/* Status Register for 9x5 */
+#define		AT91_ADC_SR_DRDY_9X5	(1 << 24)	/* Data Ready */
+
 #define AT91_ADC_LCDR		0x20		/* Last Converted Data Register */
 #define		AT91_ADC_LDATA		(0x3ff)
 
@@ -58,4 +61,10 @@
 #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
 #define		AT91_ADC_DATA		(0x3ff)
 
+#define AT91_ADC_CDR0_9X5	(0x50)			/* Channel Data Register 0 for 9X5 */
+
+#define AT91_ADC_TRGR_9260	AT91_ADC_MR
+#define AT91_ADC_TRGR_9G45	0x08
+#define AT91_ADC_TRGR_9X5	0xC0
+
 #endif
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 9cf8ab5..49dd751 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -39,6 +39,10 @@
 #define at91_adc_writel(st, reg, val) \
 	(writel_relaxed(val, st->reg_base + reg))
 
+struct at91_adc_caps {
+	struct at91_adc_reg_desc registers;
+};
+
 struct at91_adc_state {
 	struct clk		*adc_clk;
 	u16			*buffer;
@@ -62,6 +66,7 @@ struct at91_adc_state {
 	u32			res;		/* resolution used for convertions */
 	bool			low_res;	/* the resolution corresponds to the lowest one */
 	wait_queue_head_t	wq_data_avail;
+	struct at91_adc_caps	*caps;
 };
 
 static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
@@ -429,6 +434,8 @@ ret:
 	return ret;
 }
 
+static const struct of_device_id at91_adc_dt_ids[];
+
 static int at91_adc_probe_dt(struct at91_adc_state *st,
 			     struct platform_device *pdev)
 {
@@ -441,6 +448,9 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 	if (!node)
 		return -EINVAL;
 
+	st->caps = (struct at91_adc_caps *)
+		of_match_device(at91_adc_dt_ids, &pdev->dev)->data;
+
 	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
 
 	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
@@ -481,43 +491,7 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 	if (ret)
 		goto error_ret;
 
-	st->registers = devm_kzalloc(&idev->dev,
-				     sizeof(struct at91_adc_reg_desc),
-				     GFP_KERNEL);
-	if (!st->registers) {
-		dev_err(&idev->dev, "Could not allocate register memory.\n");
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-
-	if (of_property_read_u32(node, "atmel,adc-channel-base", &prop)) {
-		dev_err(&idev->dev, "Missing adc-channel-base property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->registers->channel_base = prop;
-
-	if (of_property_read_u32(node, "atmel,adc-drdy-mask", &prop)) {
-		dev_err(&idev->dev, "Missing adc-drdy-mask property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->registers->drdy_mask = prop;
-
-	if (of_property_read_u32(node, "atmel,adc-status-register", &prop)) {
-		dev_err(&idev->dev, "Missing adc-status-register property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->registers->status_register = prop;
-
-	if (of_property_read_u32(node, "atmel,adc-trigger-register", &prop)) {
-		dev_err(&idev->dev, "Missing adc-trigger-register property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->registers->trigger_register = prop;
-
+	st->registers = &st->caps->registers;
 	st->trigger_number = of_get_child_count(node);
 	st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
 					sizeof(struct at91_adc_trigger),
@@ -776,8 +750,37 @@ static int at91_adc_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_OF
+static struct at91_adc_caps at91sam9260_caps = {
+	.registers = {
+		.channel_base = AT91_ADC_CHR(0),
+		.drdy_mask = AT91_ADC_DRDY,
+		.status_register = AT91_ADC_SR,
+		.trigger_register = AT91_ADC_TRGR_9260,
+	},
+};
+
+static struct at91_adc_caps at91sam9g45_caps = {
+	.registers = {
+		.channel_base = AT91_ADC_CHR(0),
+		.drdy_mask = AT91_ADC_DRDY,
+		.status_register = AT91_ADC_SR,
+		.trigger_register = AT91_ADC_TRGR_9G45,
+	},
+};
+
+static struct at91_adc_caps at91sam9x5_caps = {
+	.registers = {
+		.channel_base = AT91_ADC_CDR0_9X5,
+		.drdy_mask = AT91_ADC_SR_DRDY_9X5,
+		.status_register = AT91_ADC_SR_9X5,
+		.trigger_register = AT91_ADC_TRGR_9X5,
+	},
+};
+
 static const struct of_device_id at91_adc_dt_ids[] = {
-	{ .compatible = "atmel,at91sam9260-adc" },
+	{ .compatible = "atmel,at91sam9260-adc", .data = &at91sam9260_caps },
+	{ .compatible = "atmel,at91sam9g45-adc", .data = &at91sam9g45_caps },
+	{ .compatible = "atmel,at91sam9x5-adc", .data = &at91sam9x5_caps },
 	{},
 };
 MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
-- 
1.7.10

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

* [PATCH v3 3/6] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-08-27 11:28 ` Josh Wu
@ 2013-08-27 11:28   ` Josh Wu
  -1 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, thomas.petazzoni, mark.rutland, b.brezillon,
	Josh Wu

For at91 boards, there are different IPs for adc. Different IPs has different
STARTUP & PRESCAL mask in ADC_MR.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
 arch/arm/mach-at91/include/mach/at91_adc.h |    7 +++++--
 drivers/iio/adc/at91_adc.c                 |   11 +++++++++--
 include/linux/platform_data/at91_adc.h     |    4 ++++
 3 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
index bea1a20..048a57f 100644
--- a/arch/arm/mach-at91/include/mach/at91_adc.h
+++ b/arch/arm/mach-at91/include/mach/at91_adc.h
@@ -28,9 +28,12 @@
 #define			AT91_ADC_TRGSEL_EXTERNAL	(6 << 1)
 #define		AT91_ADC_LOWRES		(1 << 4)	/* Low Resolution */
 #define		AT91_ADC_SLEEP		(1 << 5)	/* Sleep Mode */
-#define		AT91_ADC_PRESCAL	(0x3f << 8)	/* Prescalar Rate Selection */
+#define		AT91_ADC_PRESCAL_9260	(0x3f << 8)	/* Prescalar Rate Selection */
+#define		AT91_ADC_PRESCAL_9G45	(0xff << 8)
 #define			AT91_ADC_PRESCAL_(x)	((x) << 8)
-#define		AT91_ADC_STARTUP	(0x1f << 16)	/* Startup Up Time */
+#define		AT91_ADC_STARTUP_9260	(0x1f << 16)	/* Startup Up Time */
+#define		AT91_ADC_STARTUP_9G45	(0x7f << 16)
+#define		AT91_ADC_STARTUP_9X5	(0xf << 16)
 #define			AT91_ADC_STARTUP_(x)	((x) << 16)
 #define		AT91_ADC_SHTIM		(0xf  << 24)	/* Sample & Hold Time */
 #define			AT91_ADC_SHTIM_(x)	((x) << 24)
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 49dd751..bccc407 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -678,8 +678,8 @@ static int at91_adc_probe(struct platform_device *pdev)
 	shtim = round_up((st->sample_hold_time * adc_clk_khz /
 			  1000) - 1, 1);
 
-	reg = AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL;
-	reg |= AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP;
+	reg = AT91_ADC_PRESCAL_(prsc) & st->registers->mr_prescal_mask;
+	reg |= AT91_ADC_STARTUP_(ticks) & st->registers->mr_startup_mask;
 	if (st->low_res)
 		reg |= AT91_ADC_LOWRES;
 	if (st->sleep_mode)
@@ -756,6 +756,8 @@ static struct at91_adc_caps at91sam9260_caps = {
 		.drdy_mask = AT91_ADC_DRDY,
 		.status_register = AT91_ADC_SR,
 		.trigger_register = AT91_ADC_TRGR_9260,
+		.mr_prescal_mask = AT91_ADC_PRESCAL_9260,
+		.mr_startup_mask = AT91_ADC_STARTUP_9260,
 	},
 };
 
@@ -765,6 +767,8 @@ static struct at91_adc_caps at91sam9g45_caps = {
 		.drdy_mask = AT91_ADC_DRDY,
 		.status_register = AT91_ADC_SR,
 		.trigger_register = AT91_ADC_TRGR_9G45,
+		.mr_prescal_mask = AT91_ADC_PRESCAL_9G45,
+		.mr_startup_mask = AT91_ADC_STARTUP_9G45,
 	},
 };
 
@@ -774,6 +778,9 @@ static struct at91_adc_caps at91sam9x5_caps = {
 		.drdy_mask = AT91_ADC_SR_DRDY_9X5,
 		.status_register = AT91_ADC_SR_9X5,
 		.trigger_register = AT91_ADC_TRGR_9X5,
+		/* prescal mask is same as 9G45 */
+		.mr_prescal_mask = AT91_ADC_PRESCAL_9G45,
+		.mr_startup_mask = AT91_ADC_STARTUP_9X5,
 	},
 };
 
diff --git a/include/linux/platform_data/at91_adc.h b/include/linux/platform_data/at91_adc.h
index e15745b..b3ca1e9 100644
--- a/include/linux/platform_data/at91_adc.h
+++ b/include/linux/platform_data/at91_adc.h
@@ -14,12 +14,16 @@
 			(Interruptions registers mostly)
  * @status_register:	Offset of the Interrupt Status Register
  * @trigger_register:	Offset of the Trigger setup register
+ * @mr_prescal_mask:	Mask of the PRESCAL field in the adc MR register
+ * @mr_startup_mask:	Mask of the STARTUP field in the adc MR register
  */
 struct at91_adc_reg_desc {
 	u8	channel_base;
 	u32	drdy_mask;
 	u8	status_register;
 	u8	trigger_register;
+	u32	mr_prescal_mask;
+	u32	mr_startup_mask;
 };
 
 /**
-- 
1.7.10


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

* [PATCH v3 3/6] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-08-27 11:28   ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: linux-arm-kernel

For at91 boards, there are different IPs for adc. Different IPs has different
STARTUP & PRESCAL mask in ADC_MR.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
 arch/arm/mach-at91/include/mach/at91_adc.h |    7 +++++--
 drivers/iio/adc/at91_adc.c                 |   11 +++++++++--
 include/linux/platform_data/at91_adc.h     |    4 ++++
 3 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
index bea1a20..048a57f 100644
--- a/arch/arm/mach-at91/include/mach/at91_adc.h
+++ b/arch/arm/mach-at91/include/mach/at91_adc.h
@@ -28,9 +28,12 @@
 #define			AT91_ADC_TRGSEL_EXTERNAL	(6 << 1)
 #define		AT91_ADC_LOWRES		(1 << 4)	/* Low Resolution */
 #define		AT91_ADC_SLEEP		(1 << 5)	/* Sleep Mode */
-#define		AT91_ADC_PRESCAL	(0x3f << 8)	/* Prescalar Rate Selection */
+#define		AT91_ADC_PRESCAL_9260	(0x3f << 8)	/* Prescalar Rate Selection */
+#define		AT91_ADC_PRESCAL_9G45	(0xff << 8)
 #define			AT91_ADC_PRESCAL_(x)	((x) << 8)
-#define		AT91_ADC_STARTUP	(0x1f << 16)	/* Startup Up Time */
+#define		AT91_ADC_STARTUP_9260	(0x1f << 16)	/* Startup Up Time */
+#define		AT91_ADC_STARTUP_9G45	(0x7f << 16)
+#define		AT91_ADC_STARTUP_9X5	(0xf << 16)
 #define			AT91_ADC_STARTUP_(x)	((x) << 16)
 #define		AT91_ADC_SHTIM		(0xf  << 24)	/* Sample & Hold Time */
 #define			AT91_ADC_SHTIM_(x)	((x) << 24)
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 49dd751..bccc407 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -678,8 +678,8 @@ static int at91_adc_probe(struct platform_device *pdev)
 	shtim = round_up((st->sample_hold_time * adc_clk_khz /
 			  1000) - 1, 1);
 
-	reg = AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL;
-	reg |= AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP;
+	reg = AT91_ADC_PRESCAL_(prsc) & st->registers->mr_prescal_mask;
+	reg |= AT91_ADC_STARTUP_(ticks) & st->registers->mr_startup_mask;
 	if (st->low_res)
 		reg |= AT91_ADC_LOWRES;
 	if (st->sleep_mode)
@@ -756,6 +756,8 @@ static struct at91_adc_caps at91sam9260_caps = {
 		.drdy_mask = AT91_ADC_DRDY,
 		.status_register = AT91_ADC_SR,
 		.trigger_register = AT91_ADC_TRGR_9260,
+		.mr_prescal_mask = AT91_ADC_PRESCAL_9260,
+		.mr_startup_mask = AT91_ADC_STARTUP_9260,
 	},
 };
 
@@ -765,6 +767,8 @@ static struct at91_adc_caps at91sam9g45_caps = {
 		.drdy_mask = AT91_ADC_DRDY,
 		.status_register = AT91_ADC_SR,
 		.trigger_register = AT91_ADC_TRGR_9G45,
+		.mr_prescal_mask = AT91_ADC_PRESCAL_9G45,
+		.mr_startup_mask = AT91_ADC_STARTUP_9G45,
 	},
 };
 
@@ -774,6 +778,9 @@ static struct at91_adc_caps at91sam9x5_caps = {
 		.drdy_mask = AT91_ADC_SR_DRDY_9X5,
 		.status_register = AT91_ADC_SR_9X5,
 		.trigger_register = AT91_ADC_TRGR_9X5,
+		/* prescal mask is same as 9G45 */
+		.mr_prescal_mask = AT91_ADC_PRESCAL_9G45,
+		.mr_startup_mask = AT91_ADC_STARTUP_9X5,
 	},
 };
 
diff --git a/include/linux/platform_data/at91_adc.h b/include/linux/platform_data/at91_adc.h
index e15745b..b3ca1e9 100644
--- a/include/linux/platform_data/at91_adc.h
+++ b/include/linux/platform_data/at91_adc.h
@@ -14,12 +14,16 @@
 			(Interruptions registers mostly)
  * @status_register:	Offset of the Interrupt Status Register
  * @trigger_register:	Offset of the Trigger setup register
+ * @mr_prescal_mask:	Mask of the PRESCAL field in the adc MR register
+ * @mr_startup_mask:	Mask of the STARTUP field in the adc MR register
  */
 struct at91_adc_reg_desc {
 	u8	channel_base;
 	u32	drdy_mask;
 	u8	status_register;
 	u8	trigger_register;
+	u32	mr_prescal_mask;
+	u32	mr_startup_mask;
 };
 
 /**
-- 
1.7.10

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

* [PATCH v3 4/6] iio: at91: ADC start-up time calculation changed since at91sam9x5
  2013-08-27 11:28 ` Josh Wu
@ 2013-08-27 11:28   ` Josh Wu
  -1 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, thomas.petazzoni, mark.rutland, b.brezillon,
	Josh Wu

Since in at91sam9x5, sama5d3x chip. the start up time calucation is changed.
This patch can choose different start up time calculation formula for different
chips.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
v2 --> v3:
 use function pointer for the startup time calculation.

 drivers/iio/adc/at91_adc.c |   53 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 46 insertions(+), 7 deletions(-)

diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index bccc407..f32a69d 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -40,6 +40,9 @@
 	(writel_relaxed(val, st->reg_base + reg))
 
 struct at91_adc_caps {
+	/* startup time calculate function */
+	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
+
 	struct at91_adc_reg_desc registers;
 };
 
@@ -434,6 +437,45 @@ ret:
 	return ret;
 }
 
+static u32 calc_startup_ticks_9260(u8 startup_time, u32 adc_clk_khz)
+{
+	/*
+	 * Number of ticks needed to cover the startup time of the ADC
+	 * as defined in the electrical characteristics of the board,
+	 * divided by 8. The formula thus is :
+	 *   Startup Time = (ticks + 1) * 8 / ADC Clock
+	 */
+	return round_up((startup_time * adc_clk_khz / 1000) - 1, 8) / 8;
+}
+
+static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz)
+{
+	/*
+	 * For sama5d3x and at91sam9x5, the formula changes to:
+	 * Startup Time = <lookup_table_value> / ADC Clock
+	 */
+	const int startup_lookup[] = {
+		0  , 8  , 16 , 24 ,
+		64 , 80 , 96 , 112,
+		512, 576, 640, 704,
+		768, 832, 896, 960
+		};
+	int i, size = ARRAY_SIZE(startup_lookup);
+	unsigned int ticks;
+
+	ticks = startup_time * adc_clk_khz / 1000;
+	for (i = 0; i < size; i++)
+		if (ticks < startup_lookup[i])
+			break;
+
+	ticks = i;
+	if (ticks == size)
+		/* Reach the end of lookup table */
+		ticks = size - 1;
+
+	return ticks;
+}
+
 static const struct of_device_id at91_adc_dt_ids[];
 
 static int at91_adc_probe_dt(struct at91_adc_state *st,
@@ -662,15 +704,9 @@ static int at91_adc_probe(struct platform_device *pdev)
 		ret = -EINVAL;
 		goto error_disable_adc_clk;
 	}
+	ticks = (*st->caps->calc_startup_ticks)(st->startup_time, adc_clk_khz);
 
 	/*
-	 * Number of ticks needed to cover the startup time of the ADC as
-	 * defined in the electrical characteristics of the board, divided by 8.
-	 * The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock
-	 */
-	ticks = round_up((st->startup_time * adc_clk_khz /
-			  1000) - 1, 8) / 8;
-	/*
 	 * a minimal Sample and Hold Time is necessary for the ADC to guarantee
 	 * the best converted final value between two channels selection
 	 * The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock
@@ -751,6 +787,7 @@ static int at91_adc_remove(struct platform_device *pdev)
 
 #ifdef CONFIG_OF
 static struct at91_adc_caps at91sam9260_caps = {
+	.calc_startup_ticks = calc_startup_ticks_9260,
 	.registers = {
 		.channel_base = AT91_ADC_CHR(0),
 		.drdy_mask = AT91_ADC_DRDY,
@@ -762,6 +799,7 @@ static struct at91_adc_caps at91sam9260_caps = {
 };
 
 static struct at91_adc_caps at91sam9g45_caps = {
+	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
 	.registers = {
 		.channel_base = AT91_ADC_CHR(0),
 		.drdy_mask = AT91_ADC_DRDY,
@@ -773,6 +811,7 @@ static struct at91_adc_caps at91sam9g45_caps = {
 };
 
 static struct at91_adc_caps at91sam9x5_caps = {
+	.calc_startup_ticks = calc_startup_ticks_9x5,
 	.registers = {
 		.channel_base = AT91_ADC_CDR0_9X5,
 		.drdy_mask = AT91_ADC_SR_DRDY_9X5,
-- 
1.7.10


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

* [PATCH v3 4/6] iio: at91: ADC start-up time calculation changed since at91sam9x5
@ 2013-08-27 11:28   ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: linux-arm-kernel

Since in at91sam9x5, sama5d3x chip. the start up time calucation is changed.
This patch can choose different start up time calculation formula for different
chips.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
v2 --> v3:
 use function pointer for the startup time calculation.

 drivers/iio/adc/at91_adc.c |   53 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 46 insertions(+), 7 deletions(-)

diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index bccc407..f32a69d 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -40,6 +40,9 @@
 	(writel_relaxed(val, st->reg_base + reg))
 
 struct at91_adc_caps {
+	/* startup time calculate function */
+	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
+
 	struct at91_adc_reg_desc registers;
 };
 
@@ -434,6 +437,45 @@ ret:
 	return ret;
 }
 
+static u32 calc_startup_ticks_9260(u8 startup_time, u32 adc_clk_khz)
+{
+	/*
+	 * Number of ticks needed to cover the startup time of the ADC
+	 * as defined in the electrical characteristics of the board,
+	 * divided by 8. The formula thus is :
+	 *   Startup Time = (ticks + 1) * 8 / ADC Clock
+	 */
+	return round_up((startup_time * adc_clk_khz / 1000) - 1, 8) / 8;
+}
+
+static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz)
+{
+	/*
+	 * For sama5d3x and at91sam9x5, the formula changes to:
+	 * Startup Time = <lookup_table_value> / ADC Clock
+	 */
+	const int startup_lookup[] = {
+		0  , 8  , 16 , 24 ,
+		64 , 80 , 96 , 112,
+		512, 576, 640, 704,
+		768, 832, 896, 960
+		};
+	int i, size = ARRAY_SIZE(startup_lookup);
+	unsigned int ticks;
+
+	ticks = startup_time * adc_clk_khz / 1000;
+	for (i = 0; i < size; i++)
+		if (ticks < startup_lookup[i])
+			break;
+
+	ticks = i;
+	if (ticks == size)
+		/* Reach the end of lookup table */
+		ticks = size - 1;
+
+	return ticks;
+}
+
 static const struct of_device_id at91_adc_dt_ids[];
 
 static int at91_adc_probe_dt(struct at91_adc_state *st,
@@ -662,15 +704,9 @@ static int at91_adc_probe(struct platform_device *pdev)
 		ret = -EINVAL;
 		goto error_disable_adc_clk;
 	}
+	ticks = (*st->caps->calc_startup_ticks)(st->startup_time, adc_clk_khz);
 
 	/*
-	 * Number of ticks needed to cover the startup time of the ADC as
-	 * defined in the electrical characteristics of the board, divided by 8.
-	 * The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock
-	 */
-	ticks = round_up((st->startup_time * adc_clk_khz /
-			  1000) - 1, 8) / 8;
-	/*
 	 * a minimal Sample and Hold Time is necessary for the ADC to guarantee
 	 * the best converted final value between two channels selection
 	 * The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock
@@ -751,6 +787,7 @@ static int at91_adc_remove(struct platform_device *pdev)
 
 #ifdef CONFIG_OF
 static struct at91_adc_caps at91sam9260_caps = {
+	.calc_startup_ticks = calc_startup_ticks_9260,
 	.registers = {
 		.channel_base = AT91_ADC_CHR(0),
 		.drdy_mask = AT91_ADC_DRDY,
@@ -762,6 +799,7 @@ static struct at91_adc_caps at91sam9260_caps = {
 };
 
 static struct at91_adc_caps at91sam9g45_caps = {
+	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
 	.registers = {
 		.channel_base = AT91_ADC_CHR(0),
 		.drdy_mask = AT91_ADC_DRDY,
@@ -773,6 +811,7 @@ static struct at91_adc_caps at91sam9g45_caps = {
 };
 
 static struct at91_adc_caps at91sam9x5_caps = {
+	.calc_startup_ticks = calc_startup_ticks_9x5,
 	.registers = {
 		.channel_base = AT91_ADC_CDR0_9X5,
 		.drdy_mask = AT91_ADC_SR_DRDY_9X5,
-- 
1.7.10

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

* [PATCH v3 5/6] iio: at91: move the num_channels from DT to driver itself
  2013-08-27 11:28 ` Josh Wu
  (?)
@ 2013-08-27 11:28     ` Josh Wu
  -1 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: jic23-KWPb1pKIrIJaa/9Udqfwiw
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	plagnioj-sclMFOaUSTBWk0Htik3J/w,
	nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	mark.rutland-5wv7dgnIgG8, b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ,
	Josh Wu, devicetree-u79uwXL29TY76Z2rM5mHXA

CC: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Signed-off-by: Josh Wu <josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
---
 Documentation/devicetree/bindings/arm/atmel-adc.txt |    1 -
 drivers/iio/adc/at91_adc.c                          |   12 +++++-------
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 723c205..0e65e01 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -7,7 +7,6 @@ Required properties:
   - interrupts: Should contain the IRQ line for the ADC
   - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
     device
-  - atmel,adc-num-channels: Number of channels available in the ADC
   - atmel,adc-startup-time: Startup Time of the ADC in microseconds as
     defined in the datasheet
   - atmel,adc-vref: Reference voltage in millivolts for the conversions
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index f32a69d..bd72b0e 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -43,6 +43,7 @@ struct at91_adc_caps {
 	/* startup time calculate function */
 	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
 
+	u8	num_channels;
 	struct at91_adc_reg_desc registers;
 };
 
@@ -502,13 +503,6 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 	}
 	st->channels_mask = prop;
 
-	if (of_property_read_u32(node, "atmel,adc-num-channels", &prop)) {
-		dev_err(&idev->dev, "Missing adc-num-channels property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->num_channels = prop;
-
 	st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode");
 
 	if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
@@ -534,6 +528,7 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 		goto error_ret;
 
 	st->registers = &st->caps->registers;
+	st->num_channels = &st->caps->num_channels;
 	st->trigger_number = of_get_child_count(node);
 	st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
 					sizeof(struct at91_adc_trigger),
@@ -788,6 +783,7 @@ static int at91_adc_remove(struct platform_device *pdev)
 #ifdef CONFIG_OF
 static struct at91_adc_caps at91sam9260_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9260,
+	.num_channels = 4;
 	.registers = {
 		.channel_base = AT91_ADC_CHR(0),
 		.drdy_mask = AT91_ADC_DRDY,
@@ -800,6 +796,7 @@ static struct at91_adc_caps at91sam9260_caps = {
 
 static struct at91_adc_caps at91sam9g45_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
+	.num_channels = 8;
 	.registers = {
 		.channel_base = AT91_ADC_CHR(0),
 		.drdy_mask = AT91_ADC_DRDY,
@@ -812,6 +809,7 @@ static struct at91_adc_caps at91sam9g45_caps = {
 
 static struct at91_adc_caps at91sam9x5_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9x5,
+	.num_channels = 12;
 	.registers = {
 		.channel_base = AT91_ADC_CDR0_9X5,
 		.drdy_mask = AT91_ADC_SR_DRDY_9X5,
-- 
1.7.10

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

* [PATCH v3 5/6] iio: at91: move the num_channels from DT to driver itself
@ 2013-08-27 11:28     ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, thomas.petazzoni, mark.rutland, b.brezillon,
	Josh Wu, devicetree

CC: devicetree@vger.kernel.org
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
 Documentation/devicetree/bindings/arm/atmel-adc.txt |    1 -
 drivers/iio/adc/at91_adc.c                          |   12 +++++-------
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 723c205..0e65e01 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -7,7 +7,6 @@ Required properties:
   - interrupts: Should contain the IRQ line for the ADC
   - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
     device
-  - atmel,adc-num-channels: Number of channels available in the ADC
   - atmel,adc-startup-time: Startup Time of the ADC in microseconds as
     defined in the datasheet
   - atmel,adc-vref: Reference voltage in millivolts for the conversions
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index f32a69d..bd72b0e 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -43,6 +43,7 @@ struct at91_adc_caps {
 	/* startup time calculate function */
 	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
 
+	u8	num_channels;
 	struct at91_adc_reg_desc registers;
 };
 
@@ -502,13 +503,6 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 	}
 	st->channels_mask = prop;
 
-	if (of_property_read_u32(node, "atmel,adc-num-channels", &prop)) {
-		dev_err(&idev->dev, "Missing adc-num-channels property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->num_channels = prop;
-
 	st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode");
 
 	if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
@@ -534,6 +528,7 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 		goto error_ret;
 
 	st->registers = &st->caps->registers;
+	st->num_channels = &st->caps->num_channels;
 	st->trigger_number = of_get_child_count(node);
 	st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
 					sizeof(struct at91_adc_trigger),
@@ -788,6 +783,7 @@ static int at91_adc_remove(struct platform_device *pdev)
 #ifdef CONFIG_OF
 static struct at91_adc_caps at91sam9260_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9260,
+	.num_channels = 4;
 	.registers = {
 		.channel_base = AT91_ADC_CHR(0),
 		.drdy_mask = AT91_ADC_DRDY,
@@ -800,6 +796,7 @@ static struct at91_adc_caps at91sam9260_caps = {
 
 static struct at91_adc_caps at91sam9g45_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
+	.num_channels = 8;
 	.registers = {
 		.channel_base = AT91_ADC_CHR(0),
 		.drdy_mask = AT91_ADC_DRDY,
@@ -812,6 +809,7 @@ static struct at91_adc_caps at91sam9g45_caps = {
 
 static struct at91_adc_caps at91sam9x5_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9x5,
+	.num_channels = 12;
 	.registers = {
 		.channel_base = AT91_ADC_CDR0_9X5,
 		.drdy_mask = AT91_ADC_SR_DRDY_9X5,
-- 
1.7.10


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

* [PATCH v3 5/6] iio: at91: move the num_channels from DT to driver itself
@ 2013-08-27 11:28     ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: linux-arm-kernel

CC: devicetree at vger.kernel.org
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
 Documentation/devicetree/bindings/arm/atmel-adc.txt |    1 -
 drivers/iio/adc/at91_adc.c                          |   12 +++++-------
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 723c205..0e65e01 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -7,7 +7,6 @@ Required properties:
   - interrupts: Should contain the IRQ line for the ADC
   - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
     device
-  - atmel,adc-num-channels: Number of channels available in the ADC
   - atmel,adc-startup-time: Startup Time of the ADC in microseconds as
     defined in the datasheet
   - atmel,adc-vref: Reference voltage in millivolts for the conversions
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index f32a69d..bd72b0e 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -43,6 +43,7 @@ struct at91_adc_caps {
 	/* startup time calculate function */
 	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
 
+	u8	num_channels;
 	struct at91_adc_reg_desc registers;
 };
 
@@ -502,13 +503,6 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 	}
 	st->channels_mask = prop;
 
-	if (of_property_read_u32(node, "atmel,adc-num-channels", &prop)) {
-		dev_err(&idev->dev, "Missing adc-num-channels property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->num_channels = prop;
-
 	st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode");
 
 	if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
@@ -534,6 +528,7 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 		goto error_ret;
 
 	st->registers = &st->caps->registers;
+	st->num_channels = &st->caps->num_channels;
 	st->trigger_number = of_get_child_count(node);
 	st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
 					sizeof(struct at91_adc_trigger),
@@ -788,6 +783,7 @@ static int at91_adc_remove(struct platform_device *pdev)
 #ifdef CONFIG_OF
 static struct at91_adc_caps at91sam9260_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9260,
+	.num_channels = 4;
 	.registers = {
 		.channel_base = AT91_ADC_CHR(0),
 		.drdy_mask = AT91_ADC_DRDY,
@@ -800,6 +796,7 @@ static struct at91_adc_caps at91sam9260_caps = {
 
 static struct at91_adc_caps at91sam9g45_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
+	.num_channels = 8;
 	.registers = {
 		.channel_base = AT91_ADC_CHR(0),
 		.drdy_mask = AT91_ADC_DRDY,
@@ -812,6 +809,7 @@ static struct at91_adc_caps at91sam9g45_caps = {
 
 static struct at91_adc_caps at91sam9x5_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9x5,
+	.num_channels = 12;
 	.registers = {
 		.channel_base = AT91_ADC_CDR0_9X5,
 		.drdy_mask = AT91_ADC_SR_DRDY_9X5,
-- 
1.7.10

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

* [PATCH v3 6/6] iio: at91: introduce touch screen support in iio adc driver
  2013-08-27 11:28 ` Josh Wu
  (?)
@ 2013-08-27 11:28     ` Josh Wu
  -1 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: jic23-KWPb1pKIrIJaa/9Udqfwiw
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	plagnioj-sclMFOaUSTBWk0Htik3J/w,
	nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	mark.rutland-5wv7dgnIgG8, b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ,
	Josh Wu, Dmitry Torokhov, devicetree-u79uwXL29TY76Z2rM5mHXA

AT91 ADC hardware integrate touch screen support. So this patch add touch
screen support for at91 adc iio driver.
To enable touch screen support in adc, you need to add the dt parameters:
  1. which type of touch are used? (4 or 5 wires), sample period time.
  2. correct pressure detect threshold value.

In the meantime, since touch screen will use a interal period trigger of adc,
so it is conflict to other hardware triggers. Driver will disable the hardware
trigger support if touch screen is enabled.

This driver has been tested in AT91SAM9X5-EK and SAMA5D3x-EK.

Signed-off-by: Josh Wu <josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Cc: Dmitry Torokhov <dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
CC: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
---
v2 --> v3:
  1. fix according to Dmitry's suggestion.

v1 --> v2:
  1. use the multiple compatible string for different IPs.
  2. hide the driver configuration in driver code instead of exposing them in dt.
     Such like sample period, pen detect debounce time and etc.
  3. add a new dt parameter: ts-pressure-threshold. this value is much related
     with different chips and boards.

 .../devicetree/bindings/arm/atmel-adc.txt          |    7 +
 arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
 drivers/iio/adc/at91_adc.c                         |  388 ++++++++++++++++++--
 3 files changed, 405 insertions(+), 24 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 0e65e01..d106146 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -23,6 +23,13 @@ Optional properties:
 		       resolution will be used.
   - atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion
   - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
+  - atmel,adc-ts-wires: Number of touch screen wires. Should be 4 or 5. If this
+                        value is set, then adc driver will enable touch screen
+                        support.
+    NOTE: when adc touch screen enabled, the adc hardware trigger will be
+          disabled. Since touch screen will occupied the trigger register.
+  - atmel,adc-ts-pressure-threshold: a pressure threshold for touchscreen. It
+                                     make touch detect more precision.
  
 Optional trigger Nodes:
   - Required properties:
diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
index 048a57f..c287307 100644
--- a/arch/arm/mach-at91/include/mach/at91_adc.h
+++ b/arch/arm/mach-at91/include/mach/at91_adc.h
@@ -60,14 +60,48 @@
 #define AT91_ADC_IER		0x24		/* Interrupt Enable Register */
 #define AT91_ADC_IDR		0x28		/* Interrupt Disable Register */
 #define AT91_ADC_IMR		0x2C		/* Interrupt Mask Register */
+#define		AT91_ADC_IER_PEN	(1 << 29)
+#define		AT91_ADC_IER_NOPEN	(1 << 30)
+#define		AT91_ADC_IER_XRDY	(1 << 20)
+#define		AT91_ADC_IER_YRDY	(1 << 21)
+#define		AT91_ADC_IER_PRDY	(1 << 22)
+#define		AT91_ADC_ISR_PENS	(1 << 31)
 
 #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
 #define		AT91_ADC_DATA		(0x3ff)
 
 #define AT91_ADC_CDR0_9X5	(0x50)			/* Channel Data Register 0 for 9X5 */
 
+#define AT91_ADC_ACR		0x94	/* Analog Control Register */
+#define		AT91_ADC_ACR_PENDETSENS	(0x3 << 0)	/* pull-up resistor */
+
+#define AT91_ADC_TSMR		0xB0
+#define		AT91_ADC_TSMR_TSMODE	(3 << 0)	/* Touch Screen Mode */
+#define			AT91_ADC_TSMR_TSMODE_NONE		(0 << 0)
+#define			AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS	(1 << 0)
+#define			AT91_ADC_TSMR_TSMODE_4WIRE_PRESS	(2 << 0)
+#define			AT91_ADC_TSMR_TSMODE_5WIRE		(3 << 0)
+#define		AT91_ADC_TSMR_TSAV	(3 << 4)	/* Averages samples */
+#define			AT91_ADC_TSMR_TSAV_(x)		((x) << 4)
+#define		AT91_ADC_TSMR_SCTIM	(0x0f << 16)	/* Switch closure time */
+#define		AT91_ADC_TSMR_PENDBC	(0x0f << 28)	/* Pen Debounce time */
+#define			AT91_ADC_TSMR_PENDBC_(x)	((x) << 28)
+#define		AT91_ADC_TSMR_NOTSDMA	(1 << 22)	/* No Touchscreen DMA */
+#define		AT91_ADC_TSMR_PENDET_DIS	(0 << 24)	/* Pen contact detection disable */
+#define		AT91_ADC_TSMR_PENDET_ENA	(1 << 24)	/* Pen contact detection enable */
+
+#define AT91_ADC_TSXPOSR	0xB4
+#define AT91_ADC_TSYPOSR	0xB8
+#define AT91_ADC_TSPRESSR	0xBC
+
 #define AT91_ADC_TRGR_9260	AT91_ADC_MR
 #define AT91_ADC_TRGR_9G45	0x08
 #define AT91_ADC_TRGR_9X5	0xC0
 
+/* Trigger Register bit field */
+#define		AT91_ADC_TRGR_TRGPER	(0xffff << 16)
+#define			AT91_ADC_TRGR_TRGPER_(x)	((x) << 16)
+#define		AT91_ADC_TRGR_TRGMOD	(0x7 << 0)
+#define			AT91_ADC_TRGR_MOD_PERIOD_TRIG	(5 << 0)
+
 #endif
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index bd72b0e..0e9424c 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -11,6 +11,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
@@ -39,7 +40,23 @@
 #define at91_adc_writel(st, reg, val) \
 	(writel_relaxed(val, st->reg_base + reg))
 
+#define DRIVER_NAME		"at91_adc"
+#define MAX_POS_BITS		12
+
+#define TOUCH_SAMPLE_PERIOD_US		2000	/* 2ms */
+#define TOUCH_PEN_DETECT_DEBOUNCE_US	200
+
 struct at91_adc_caps {
+	bool	has_ts;		/* Support touch screen */
+	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
+	/*
+	 * Numbers of sampling data will be averaged. Can be 0~3.
+	 * Hardware can average (2 ^ ts_filter_average) sample data.
+	 */
+	u8	ts_filter_average;
+	/* Pen Detection input pull-up resistor, can be 0~3 */
+	u8	ts_pen_detect_sensitivity;
+
 	/* startup time calculate function */
 	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
 
@@ -47,6 +64,12 @@ struct at91_adc_caps {
 	struct at91_adc_reg_desc registers;
 };
 
+enum atmel_adc_ts_type {
+	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
+	ATMEL_ADC_TOUCHSCREEN_4WIRE = 4,
+	ATMEL_ADC_TOUCHSCREEN_5WIRE = 5,
+};
+
 struct at91_adc_state {
 	struct clk		*adc_clk;
 	u16			*buffer;
@@ -71,6 +94,26 @@ struct at91_adc_state {
 	bool			low_res;	/* the resolution corresponds to the lowest one */
 	wait_queue_head_t	wq_data_avail;
 	struct at91_adc_caps	*caps;
+
+	/*
+	 * Following ADC channels are shared by touchscreen:
+	 *
+	 * CH0 -- Touch screen XP/UL
+	 * CH1 -- Touch screen XM/UR
+	 * CH2 -- Touch screen YP/LL
+	 * CH3 -- Touch screen YM/Sense
+	 * CH4 -- Touch screen LR(5-wire only)
+	 *
+	 * The bitfields below represents the reserved channel in the
+	 * touchscreen mode.
+	 */
+#define CHAN_MASK_TOUCHSCREEN_4WIRE	(0xf << 0)
+#define CHAN_MASK_TOUCHSCREEN_5WIRE	(0x1f << 0)
+	enum atmel_adc_ts_type	touchscreen_type;
+	struct input_dev	*ts_input;
+
+	u16			ts_sample_period_val;
+	u32			ts_pressure_threshold;
 };
 
 static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
@@ -105,14 +148,10 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
+/* Handler for classic adc channel eoc trigger */
+void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
 {
-	struct iio_dev *idev = private;
 	struct at91_adc_state *st = iio_priv(idev);
-	u32 status = at91_adc_readl(st, st->registers->status_register);
-
-	if (!(status & st->registers->drdy_mask))
-		return IRQ_HANDLED;
 
 	if (iio_buffer_enabled(idev)) {
 		disable_irq_nosync(irq);
@@ -122,6 +161,115 @@ static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
 		st->done = true;
 		wake_up_interruptible(&st->wq_data_avail);
 	}
+}
+
+static int at91_ts_sample(struct at91_adc_state *st)
+{
+	unsigned int xscale, yscale, reg, z1, z2;
+	unsigned int x, y, pres, xpos, ypos;
+	unsigned int rxp = 1;
+	unsigned int factor = 1000;
+	struct iio_dev *idev = iio_priv_to_dev(st);
+
+	unsigned int xyz_mask_bits = st->res;
+	unsigned int xyz_mask = (1 << xyz_mask_bits) - 1;
+
+	/* calculate position */
+	/* x position = (x / xscale) * max, max = 2^MAX_POS_BITS - 1 */
+	reg = at91_adc_readl(st, AT91_ADC_TSXPOSR);
+	xpos = reg & xyz_mask;
+	x = (xpos << MAX_POS_BITS) - xpos;
+	xscale = (reg >> 16) & xyz_mask;
+	if (xscale == 0) {
+		dev_err(&idev->dev, "Error: xscale == 0!\n");
+		return -1;
+	}
+	x /= xscale;
+
+	/* y position = (y / yscale) * max, max = 2^MAX_POS_BITS - 1 */
+	reg = at91_adc_readl(st, AT91_ADC_TSYPOSR);
+	ypos = reg & xyz_mask;
+	y = (ypos << MAX_POS_BITS) - ypos;
+	yscale = (reg >> 16) & xyz_mask;
+	if (yscale == 0) {
+		dev_err(&idev->dev, "Error: yscale == 0!\n");
+		return -1;
+	}
+	y /= yscale;
+
+	/* calculate the pressure */
+	reg = at91_adc_readl(st, AT91_ADC_TSPRESSR);
+	z1 = reg & xyz_mask;
+	z2 = (reg >> 16) & xyz_mask;
+
+	if (z1 != 0)
+		pres = rxp * (x * factor / 1024) * (z2 * factor / z1 - factor)
+			/ factor;
+	else
+		pres = st->ts_pressure_threshold;	/* no pen contacted */
+
+	dev_dbg(&idev->dev, "xpos = %d, xscale = %d, ypos = %d, yscale = %d, z1 = %d, z2 = %d, press = %d\n",
+				xpos, xscale, ypos, yscale, z1, z2, pres);
+
+	if (pres < st->ts_pressure_threshold) {
+		dev_dbg(&idev->dev, "x = %d, y = %d, pressure = %d\n",
+					x, y, pres / factor);
+		input_report_abs(st->ts_input, ABS_X, x);
+		input_report_abs(st->ts_input, ABS_Y, y);
+		input_report_abs(st->ts_input, ABS_PRESSURE, pres);
+		input_report_key(st->ts_input, BTN_TOUCH, 1);
+		input_sync(st->ts_input);
+	} else {
+		dev_dbg(&idev->dev, "pressure too low: not reporting\n");
+	}
+
+	return 0;
+}
+
+static irqreturn_t at91_adc_interrupt(int irq, void *private)
+{
+	struct iio_dev *idev = private;
+	struct at91_adc_state *st = iio_priv(idev);
+	u32 status = at91_adc_readl(st, st->registers->status_register);
+	const uint32_t ts_data_irq_mask =
+		AT91_ADC_IER_XRDY |
+		AT91_ADC_IER_YRDY |
+		AT91_ADC_IER_PRDY;
+
+	if (status & st->registers->drdy_mask)
+		handle_adc_eoc_trigger(irq, idev);
+
+	if (status & AT91_ADC_IER_PEN) {
+		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
+		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_NOPEN |
+			ts_data_irq_mask);
+		/* Set up period trigger for sampling */
+		at91_adc_writel(st, st->registers->trigger_register,
+			AT91_ADC_TRGR_MOD_PERIOD_TRIG |
+			AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val));
+	} else if (status & AT91_ADC_IER_NOPEN) {
+		at91_adc_writel(st, st->registers->trigger_register, 0);
+		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_NOPEN |
+			ts_data_irq_mask);
+		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
+
+		input_report_key(st->ts_input, BTN_TOUCH, 0);
+		input_sync(st->ts_input);
+	} else if ((status & ts_data_irq_mask) == ts_data_irq_mask) {
+		/* Now all touchscreen data is ready */
+
+		if (status & AT91_ADC_ISR_PENS) {
+			/* validate data by pen contact */
+			at91_ts_sample(st);
+		} else {
+			/* triggered by event that is no pen contact, just read
+			 * them to clean the interrupt and discard all.
+			 */
+			at91_adc_readl(st, AT91_ADC_TSXPOSR);
+			at91_adc_readl(st, AT91_ADC_TSYPOSR);
+			at91_adc_readl(st, AT91_ADC_TSPRESSR);
+		}
+	}
 
 	return IRQ_HANDLED;
 }
@@ -131,6 +279,16 @@ static int at91_adc_channel_init(struct iio_dev *idev)
 	struct at91_adc_state *st = iio_priv(idev);
 	struct iio_chan_spec *chan_array, *timestamp;
 	int bit, idx = 0;
+	unsigned long rsvd_mask = 0;
+
+	/* If touchscreen is enable, then reserve the adc channels */
+	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
+		rsvd_mask = CHAN_MASK_TOUCHSCREEN_4WIRE;
+	else if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_5WIRE)
+		rsvd_mask = CHAN_MASK_TOUCHSCREEN_5WIRE;
+
+	/* set up the channel mask to reserve touchscreen channels */
+	st->channels_mask &= ~rsvd_mask;
 
 	idev->num_channels = bitmap_weight(&st->channels_mask,
 					   st->num_channels) + 1;
@@ -479,6 +637,39 @@ static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz)
 
 static const struct of_device_id at91_adc_dt_ids[];
 
+static int at91_adc_probe_dt_ts(struct device_node *node,
+	struct at91_adc_state *st, struct device *dev)
+{
+	int ret;
+	u32 prop;
+
+	ret = of_property_read_u32(node, "atmel,adc-ts-wires", &prop);
+	if (ret) {
+		dev_info(dev, "ADC Touch screen is disabled.\n");
+		return 0;
+	}
+
+	switch (prop) {
+	case 4:
+	case 5:
+		st->touchscreen_type = prop;
+		break;
+	default:
+		dev_err(dev, "Unsupported number of touchscreen wires (%d). Should be 4 or 5.\n", prop);
+		return -EINVAL;
+	}
+
+	prop = 0;
+	of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop);
+	st->ts_pressure_threshold = prop;
+	if (st->ts_pressure_threshold) {
+		return 0;
+	} else {
+		dev_err(dev, "Invalid pressure threshold for the touchscreen\n");
+		return -EINVAL;
+	}
+}
+
 static int at91_adc_probe_dt(struct at91_adc_state *st,
 			     struct platform_device *pdev)
 {
@@ -560,6 +751,12 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 		i++;
 	}
 
+	/* Check if touchscreen is supported. */
+	if (st->caps->has_ts)
+		return at91_adc_probe_dt_ts(node, st, &idev->dev);
+	else
+		dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n");
+
 	return 0;
 
 error_ret:
@@ -591,6 +788,114 @@ static const struct iio_info at91_adc_info = {
 	.read_raw = &at91_adc_read_raw,
 };
 
+/* Touchscreen related functions */
+static int atmel_ts_open(struct input_dev *dev)
+{
+	struct at91_adc_state *st = input_get_drvdata(dev);
+
+	at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
+	return 0;
+}
+
+static void atmel_ts_close(struct input_dev *dev)
+{
+	struct at91_adc_state *st = input_get_drvdata(dev);
+
+	at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
+}
+
+static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
+{
+	u32 reg = 0, pendbc;
+	int i = 0;
+
+	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
+		reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
+	else
+		reg = AT91_ADC_TSMR_TSMODE_5WIRE;
+
+	/* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid
+	 * pen detect noise.
+	 * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock
+	 */
+	pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / 1000, 1);
+
+	while (pendbc >> ++i)
+		;	/* Empty! Find the shift offset */
+	if (abs(pendbc - (1 << i)) < abs(pendbc - (1 << (i - 1))))
+		pendbc = i;
+	else
+		pendbc = i - 1;
+
+	if (st->caps->has_tsmr) {
+		reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average)
+				& AT91_ADC_TSMR_TSAV;
+		reg |= AT91_ADC_TSMR_PENDBC_(pendbc) & AT91_ADC_TSMR_PENDBC;
+		reg |= AT91_ADC_TSMR_NOTSDMA;
+		reg |= AT91_ADC_TSMR_PENDET_ENA;
+		reg |= 0x03 << 8;	/* TSFREQ, need bigger than TSAV */
+
+		at91_adc_writel(st, AT91_ADC_TSMR, reg);
+	} else {
+		/* TODO: for 9g45 which has no TSMR */
+	}
+
+	/* Change adc internal resistor value for better pen detection,
+	 * default value is 100 kOhm.
+	 * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
+	 * option only available on ES2 and higher
+	 */
+	at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity
+			& AT91_ADC_ACR_PENDETSENS);
+
+	/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
+	st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US *
+			adc_clk_khz / 1000) - 1, 1);
+
+	return 0;
+}
+
+static int at91_ts_register(struct at91_adc_state *st,
+		struct platform_device *pdev)
+{
+	struct input_dev *input;
+	struct iio_dev *idev = iio_priv_to_dev(st);
+	int ret;
+
+	input = input_allocate_device();
+	if (!input) {
+		dev_err(&idev->dev, "Failed to allocate TS device!\n");
+		return -ENOMEM;
+	}
+
+	input->name = DRIVER_NAME;
+	input->id.bustype = BUS_HOST;
+	input->dev.parent = &pdev->dev;
+	input->open = atmel_ts_open;
+	input->close = atmel_ts_close;
+
+	__set_bit(EV_ABS, input->evbit);
+	__set_bit(EV_KEY, input->evbit);
+	__set_bit(BTN_TOUCH, input->keybit);
+	input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
+	input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
+	input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0);
+
+	st->ts_input = input;
+	input_set_drvdata(input, st);
+
+	ret = input_register_device(input);
+	if (ret)
+		input_free_device(st->ts_input);
+
+	return ret;
+}
+
+static void at91_ts_unregister(struct at91_adc_state *st)
+{
+	input_unregister_device(st->ts_input);
+}
+
 static int at91_adc_probe(struct platform_device *pdev)
 {
 	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
@@ -647,7 +952,7 @@ static int at91_adc_probe(struct platform_device *pdev)
 	at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
 	at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
 	ret = request_irq(st->irq,
-			  at91_adc_eoc_trigger,
+			  at91_adc_interrupt,
 			  0,
 			  pdev->dev.driver->name,
 			  idev);
@@ -692,6 +997,10 @@ static int at91_adc_probe(struct platform_device *pdev)
 	mstrclk = clk_get_rate(st->clk);
 	adc_clk = clk_get_rate(st->adc_clk);
 	adc_clk_khz = adc_clk / 1000;
+
+	dev_dbg(&pdev->dev, "Master clock is set as: %d Hz, adc_clk should set as: %d Hz\n",
+		mstrclk, adc_clk);
+
 	prsc = (mstrclk / (2 * adc_clk)) - 1;
 
 	if (!st->startup_time) {
@@ -728,30 +1037,52 @@ static int at91_adc_probe(struct platform_device *pdev)
 	init_waitqueue_head(&st->wq_data_avail);
 	mutex_init(&st->lock);
 
-	ret = at91_adc_buffer_init(idev);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
-		goto error_disable_adc_clk;
-	}
+	/*
+	 * Since touch screen will set trigger register as period trigger. So
+	 * when touch screen is enabled, then we have to disable hardware
+	 * trigger for classic adc.
+	 */
+	if (!st->touchscreen_type) {
+		ret = at91_adc_buffer_init(idev);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
+			goto error_disable_adc_clk;
+		}
 
-	ret = at91_adc_trigger_init(idev);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
-		goto error_unregister_buffer;
+		ret = at91_adc_trigger_init(idev);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
+			at91_adc_buffer_remove(idev);
+			goto error_disable_adc_clk;
+		}
+	} else {
+		if (!st->caps->has_tsmr) {
+			dev_err(&pdev->dev, "We don't support non-TSMR adc\n");
+			goto error_disable_adc_clk;
+		}
+
+		ret = at91_ts_register(st, pdev);
+		if (ret)
+			goto error_disable_adc_clk;
+
+		at91_ts_hw_init(st, adc_clk_khz);
 	}
 
 	ret = iio_device_register(idev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Couldn't register the device.\n");
-		goto error_remove_triggers;
+		goto error_iio_device_register;
 	}
 
 	return 0;
 
-error_remove_triggers:
-	at91_adc_trigger_remove(idev);
-error_unregister_buffer:
-	at91_adc_buffer_remove(idev);
+error_iio_device_register:
+	if (!st->touchscreen_type) {
+		at91_adc_trigger_remove(idev);
+		at91_adc_buffer_remove(idev);
+	} else {
+		at91_ts_unregister(st);
+	}
 error_disable_adc_clk:
 	clk_disable_unprepare(st->adc_clk);
 error_disable_clk:
@@ -770,8 +1101,12 @@ static int at91_adc_remove(struct platform_device *pdev)
 	struct at91_adc_state *st = iio_priv(idev);
 
 	iio_device_unregister(idev);
-	at91_adc_trigger_remove(idev);
-	at91_adc_buffer_remove(idev);
+	if (!st->touchscreen_type) {
+		at91_adc_trigger_remove(idev);
+		at91_adc_buffer_remove(idev);
+	} else {
+		at91_ts_unregister(st);
+	}
 	clk_disable_unprepare(st->adc_clk);
 	clk_disable_unprepare(st->clk);
 	free_irq(st->irq, idev);
@@ -795,6 +1130,7 @@ static struct at91_adc_caps at91sam9260_caps = {
 };
 
 static struct at91_adc_caps at91sam9g45_caps = {
+	.has_ts = true,
 	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
 	.num_channels = 8;
 	.registers = {
@@ -808,6 +1144,10 @@ static struct at91_adc_caps at91sam9g45_caps = {
 };
 
 static struct at91_adc_caps at91sam9x5_caps = {
+	.has_ts = true,
+	.has_tsmr = true,
+	.ts_filter_average = 3,
+	.ts_pen_detect_sensitivity = 2,
 	.calc_startup_ticks = calc_startup_ticks_9x5,
 	.num_channels = 12;
 	.registers = {
@@ -834,7 +1174,7 @@ static struct platform_driver at91_adc_driver = {
 	.probe = at91_adc_probe,
 	.remove = at91_adc_remove,
 	.driver = {
-		   .name = "at91_adc",
+		   .name = DRIVER_NAME,
 		   .of_match_table = of_match_ptr(at91_adc_dt_ids),
 	},
 };
-- 
1.7.10

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

* [PATCH v3 6/6] iio: at91: introduce touch screen support in iio adc driver
@ 2013-08-27 11:28     ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, thomas.petazzoni, mark.rutland, b.brezillon,
	Josh Wu, Dmitry Torokhov, devicetree

AT91 ADC hardware integrate touch screen support. So this patch add touch
screen support for at91 adc iio driver.
To enable touch screen support in adc, you need to add the dt parameters:
  1. which type of touch are used? (4 or 5 wires), sample period time.
  2. correct pressure detect threshold value.

In the meantime, since touch screen will use a interal period trigger of adc,
so it is conflict to other hardware triggers. Driver will disable the hardware
trigger support if touch screen is enabled.

This driver has been tested in AT91SAM9X5-EK and SAMA5D3x-EK.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
CC: devicetree@vger.kernel.org
---
v2 --> v3:
  1. fix according to Dmitry's suggestion.

v1 --> v2:
  1. use the multiple compatible string for different IPs.
  2. hide the driver configuration in driver code instead of exposing them in dt.
     Such like sample period, pen detect debounce time and etc.
  3. add a new dt parameter: ts-pressure-threshold. this value is much related
     with different chips and boards.

 .../devicetree/bindings/arm/atmel-adc.txt          |    7 +
 arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
 drivers/iio/adc/at91_adc.c                         |  388 ++++++++++++++++++--
 3 files changed, 405 insertions(+), 24 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 0e65e01..d106146 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -23,6 +23,13 @@ Optional properties:
 		       resolution will be used.
   - atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion
   - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
+  - atmel,adc-ts-wires: Number of touch screen wires. Should be 4 or 5. If this
+                        value is set, then adc driver will enable touch screen
+                        support.
+    NOTE: when adc touch screen enabled, the adc hardware trigger will be
+          disabled. Since touch screen will occupied the trigger register.
+  - atmel,adc-ts-pressure-threshold: a pressure threshold for touchscreen. It
+                                     make touch detect more precision.
  
 Optional trigger Nodes:
   - Required properties:
diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
index 048a57f..c287307 100644
--- a/arch/arm/mach-at91/include/mach/at91_adc.h
+++ b/arch/arm/mach-at91/include/mach/at91_adc.h
@@ -60,14 +60,48 @@
 #define AT91_ADC_IER		0x24		/* Interrupt Enable Register */
 #define AT91_ADC_IDR		0x28		/* Interrupt Disable Register */
 #define AT91_ADC_IMR		0x2C		/* Interrupt Mask Register */
+#define		AT91_ADC_IER_PEN	(1 << 29)
+#define		AT91_ADC_IER_NOPEN	(1 << 30)
+#define		AT91_ADC_IER_XRDY	(1 << 20)
+#define		AT91_ADC_IER_YRDY	(1 << 21)
+#define		AT91_ADC_IER_PRDY	(1 << 22)
+#define		AT91_ADC_ISR_PENS	(1 << 31)
 
 #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
 #define		AT91_ADC_DATA		(0x3ff)
 
 #define AT91_ADC_CDR0_9X5	(0x50)			/* Channel Data Register 0 for 9X5 */
 
+#define AT91_ADC_ACR		0x94	/* Analog Control Register */
+#define		AT91_ADC_ACR_PENDETSENS	(0x3 << 0)	/* pull-up resistor */
+
+#define AT91_ADC_TSMR		0xB0
+#define		AT91_ADC_TSMR_TSMODE	(3 << 0)	/* Touch Screen Mode */
+#define			AT91_ADC_TSMR_TSMODE_NONE		(0 << 0)
+#define			AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS	(1 << 0)
+#define			AT91_ADC_TSMR_TSMODE_4WIRE_PRESS	(2 << 0)
+#define			AT91_ADC_TSMR_TSMODE_5WIRE		(3 << 0)
+#define		AT91_ADC_TSMR_TSAV	(3 << 4)	/* Averages samples */
+#define			AT91_ADC_TSMR_TSAV_(x)		((x) << 4)
+#define		AT91_ADC_TSMR_SCTIM	(0x0f << 16)	/* Switch closure time */
+#define		AT91_ADC_TSMR_PENDBC	(0x0f << 28)	/* Pen Debounce time */
+#define			AT91_ADC_TSMR_PENDBC_(x)	((x) << 28)
+#define		AT91_ADC_TSMR_NOTSDMA	(1 << 22)	/* No Touchscreen DMA */
+#define		AT91_ADC_TSMR_PENDET_DIS	(0 << 24)	/* Pen contact detection disable */
+#define		AT91_ADC_TSMR_PENDET_ENA	(1 << 24)	/* Pen contact detection enable */
+
+#define AT91_ADC_TSXPOSR	0xB4
+#define AT91_ADC_TSYPOSR	0xB8
+#define AT91_ADC_TSPRESSR	0xBC
+
 #define AT91_ADC_TRGR_9260	AT91_ADC_MR
 #define AT91_ADC_TRGR_9G45	0x08
 #define AT91_ADC_TRGR_9X5	0xC0
 
+/* Trigger Register bit field */
+#define		AT91_ADC_TRGR_TRGPER	(0xffff << 16)
+#define			AT91_ADC_TRGR_TRGPER_(x)	((x) << 16)
+#define		AT91_ADC_TRGR_TRGMOD	(0x7 << 0)
+#define			AT91_ADC_TRGR_MOD_PERIOD_TRIG	(5 << 0)
+
 #endif
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index bd72b0e..0e9424c 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -11,6 +11,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
@@ -39,7 +40,23 @@
 #define at91_adc_writel(st, reg, val) \
 	(writel_relaxed(val, st->reg_base + reg))
 
+#define DRIVER_NAME		"at91_adc"
+#define MAX_POS_BITS		12
+
+#define TOUCH_SAMPLE_PERIOD_US		2000	/* 2ms */
+#define TOUCH_PEN_DETECT_DEBOUNCE_US	200
+
 struct at91_adc_caps {
+	bool	has_ts;		/* Support touch screen */
+	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
+	/*
+	 * Numbers of sampling data will be averaged. Can be 0~3.
+	 * Hardware can average (2 ^ ts_filter_average) sample data.
+	 */
+	u8	ts_filter_average;
+	/* Pen Detection input pull-up resistor, can be 0~3 */
+	u8	ts_pen_detect_sensitivity;
+
 	/* startup time calculate function */
 	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
 
@@ -47,6 +64,12 @@ struct at91_adc_caps {
 	struct at91_adc_reg_desc registers;
 };
 
+enum atmel_adc_ts_type {
+	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
+	ATMEL_ADC_TOUCHSCREEN_4WIRE = 4,
+	ATMEL_ADC_TOUCHSCREEN_5WIRE = 5,
+};
+
 struct at91_adc_state {
 	struct clk		*adc_clk;
 	u16			*buffer;
@@ -71,6 +94,26 @@ struct at91_adc_state {
 	bool			low_res;	/* the resolution corresponds to the lowest one */
 	wait_queue_head_t	wq_data_avail;
 	struct at91_adc_caps	*caps;
+
+	/*
+	 * Following ADC channels are shared by touchscreen:
+	 *
+	 * CH0 -- Touch screen XP/UL
+	 * CH1 -- Touch screen XM/UR
+	 * CH2 -- Touch screen YP/LL
+	 * CH3 -- Touch screen YM/Sense
+	 * CH4 -- Touch screen LR(5-wire only)
+	 *
+	 * The bitfields below represents the reserved channel in the
+	 * touchscreen mode.
+	 */
+#define CHAN_MASK_TOUCHSCREEN_4WIRE	(0xf << 0)
+#define CHAN_MASK_TOUCHSCREEN_5WIRE	(0x1f << 0)
+	enum atmel_adc_ts_type	touchscreen_type;
+	struct input_dev	*ts_input;
+
+	u16			ts_sample_period_val;
+	u32			ts_pressure_threshold;
 };
 
 static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
@@ -105,14 +148,10 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
+/* Handler for classic adc channel eoc trigger */
+void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
 {
-	struct iio_dev *idev = private;
 	struct at91_adc_state *st = iio_priv(idev);
-	u32 status = at91_adc_readl(st, st->registers->status_register);
-
-	if (!(status & st->registers->drdy_mask))
-		return IRQ_HANDLED;
 
 	if (iio_buffer_enabled(idev)) {
 		disable_irq_nosync(irq);
@@ -122,6 +161,115 @@ static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
 		st->done = true;
 		wake_up_interruptible(&st->wq_data_avail);
 	}
+}
+
+static int at91_ts_sample(struct at91_adc_state *st)
+{
+	unsigned int xscale, yscale, reg, z1, z2;
+	unsigned int x, y, pres, xpos, ypos;
+	unsigned int rxp = 1;
+	unsigned int factor = 1000;
+	struct iio_dev *idev = iio_priv_to_dev(st);
+
+	unsigned int xyz_mask_bits = st->res;
+	unsigned int xyz_mask = (1 << xyz_mask_bits) - 1;
+
+	/* calculate position */
+	/* x position = (x / xscale) * max, max = 2^MAX_POS_BITS - 1 */
+	reg = at91_adc_readl(st, AT91_ADC_TSXPOSR);
+	xpos = reg & xyz_mask;
+	x = (xpos << MAX_POS_BITS) - xpos;
+	xscale = (reg >> 16) & xyz_mask;
+	if (xscale == 0) {
+		dev_err(&idev->dev, "Error: xscale == 0!\n");
+		return -1;
+	}
+	x /= xscale;
+
+	/* y position = (y / yscale) * max, max = 2^MAX_POS_BITS - 1 */
+	reg = at91_adc_readl(st, AT91_ADC_TSYPOSR);
+	ypos = reg & xyz_mask;
+	y = (ypos << MAX_POS_BITS) - ypos;
+	yscale = (reg >> 16) & xyz_mask;
+	if (yscale == 0) {
+		dev_err(&idev->dev, "Error: yscale == 0!\n");
+		return -1;
+	}
+	y /= yscale;
+
+	/* calculate the pressure */
+	reg = at91_adc_readl(st, AT91_ADC_TSPRESSR);
+	z1 = reg & xyz_mask;
+	z2 = (reg >> 16) & xyz_mask;
+
+	if (z1 != 0)
+		pres = rxp * (x * factor / 1024) * (z2 * factor / z1 - factor)
+			/ factor;
+	else
+		pres = st->ts_pressure_threshold;	/* no pen contacted */
+
+	dev_dbg(&idev->dev, "xpos = %d, xscale = %d, ypos = %d, yscale = %d, z1 = %d, z2 = %d, press = %d\n",
+				xpos, xscale, ypos, yscale, z1, z2, pres);
+
+	if (pres < st->ts_pressure_threshold) {
+		dev_dbg(&idev->dev, "x = %d, y = %d, pressure = %d\n",
+					x, y, pres / factor);
+		input_report_abs(st->ts_input, ABS_X, x);
+		input_report_abs(st->ts_input, ABS_Y, y);
+		input_report_abs(st->ts_input, ABS_PRESSURE, pres);
+		input_report_key(st->ts_input, BTN_TOUCH, 1);
+		input_sync(st->ts_input);
+	} else {
+		dev_dbg(&idev->dev, "pressure too low: not reporting\n");
+	}
+
+	return 0;
+}
+
+static irqreturn_t at91_adc_interrupt(int irq, void *private)
+{
+	struct iio_dev *idev = private;
+	struct at91_adc_state *st = iio_priv(idev);
+	u32 status = at91_adc_readl(st, st->registers->status_register);
+	const uint32_t ts_data_irq_mask =
+		AT91_ADC_IER_XRDY |
+		AT91_ADC_IER_YRDY |
+		AT91_ADC_IER_PRDY;
+
+	if (status & st->registers->drdy_mask)
+		handle_adc_eoc_trigger(irq, idev);
+
+	if (status & AT91_ADC_IER_PEN) {
+		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
+		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_NOPEN |
+			ts_data_irq_mask);
+		/* Set up period trigger for sampling */
+		at91_adc_writel(st, st->registers->trigger_register,
+			AT91_ADC_TRGR_MOD_PERIOD_TRIG |
+			AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val));
+	} else if (status & AT91_ADC_IER_NOPEN) {
+		at91_adc_writel(st, st->registers->trigger_register, 0);
+		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_NOPEN |
+			ts_data_irq_mask);
+		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
+
+		input_report_key(st->ts_input, BTN_TOUCH, 0);
+		input_sync(st->ts_input);
+	} else if ((status & ts_data_irq_mask) == ts_data_irq_mask) {
+		/* Now all touchscreen data is ready */
+
+		if (status & AT91_ADC_ISR_PENS) {
+			/* validate data by pen contact */
+			at91_ts_sample(st);
+		} else {
+			/* triggered by event that is no pen contact, just read
+			 * them to clean the interrupt and discard all.
+			 */
+			at91_adc_readl(st, AT91_ADC_TSXPOSR);
+			at91_adc_readl(st, AT91_ADC_TSYPOSR);
+			at91_adc_readl(st, AT91_ADC_TSPRESSR);
+		}
+	}
 
 	return IRQ_HANDLED;
 }
@@ -131,6 +279,16 @@ static int at91_adc_channel_init(struct iio_dev *idev)
 	struct at91_adc_state *st = iio_priv(idev);
 	struct iio_chan_spec *chan_array, *timestamp;
 	int bit, idx = 0;
+	unsigned long rsvd_mask = 0;
+
+	/* If touchscreen is enable, then reserve the adc channels */
+	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
+		rsvd_mask = CHAN_MASK_TOUCHSCREEN_4WIRE;
+	else if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_5WIRE)
+		rsvd_mask = CHAN_MASK_TOUCHSCREEN_5WIRE;
+
+	/* set up the channel mask to reserve touchscreen channels */
+	st->channels_mask &= ~rsvd_mask;
 
 	idev->num_channels = bitmap_weight(&st->channels_mask,
 					   st->num_channels) + 1;
@@ -479,6 +637,39 @@ static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz)
 
 static const struct of_device_id at91_adc_dt_ids[];
 
+static int at91_adc_probe_dt_ts(struct device_node *node,
+	struct at91_adc_state *st, struct device *dev)
+{
+	int ret;
+	u32 prop;
+
+	ret = of_property_read_u32(node, "atmel,adc-ts-wires", &prop);
+	if (ret) {
+		dev_info(dev, "ADC Touch screen is disabled.\n");
+		return 0;
+	}
+
+	switch (prop) {
+	case 4:
+	case 5:
+		st->touchscreen_type = prop;
+		break;
+	default:
+		dev_err(dev, "Unsupported number of touchscreen wires (%d). Should be 4 or 5.\n", prop);
+		return -EINVAL;
+	}
+
+	prop = 0;
+	of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop);
+	st->ts_pressure_threshold = prop;
+	if (st->ts_pressure_threshold) {
+		return 0;
+	} else {
+		dev_err(dev, "Invalid pressure threshold for the touchscreen\n");
+		return -EINVAL;
+	}
+}
+
 static int at91_adc_probe_dt(struct at91_adc_state *st,
 			     struct platform_device *pdev)
 {
@@ -560,6 +751,12 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 		i++;
 	}
 
+	/* Check if touchscreen is supported. */
+	if (st->caps->has_ts)
+		return at91_adc_probe_dt_ts(node, st, &idev->dev);
+	else
+		dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n");
+
 	return 0;
 
 error_ret:
@@ -591,6 +788,114 @@ static const struct iio_info at91_adc_info = {
 	.read_raw = &at91_adc_read_raw,
 };
 
+/* Touchscreen related functions */
+static int atmel_ts_open(struct input_dev *dev)
+{
+	struct at91_adc_state *st = input_get_drvdata(dev);
+
+	at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
+	return 0;
+}
+
+static void atmel_ts_close(struct input_dev *dev)
+{
+	struct at91_adc_state *st = input_get_drvdata(dev);
+
+	at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
+}
+
+static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
+{
+	u32 reg = 0, pendbc;
+	int i = 0;
+
+	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
+		reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
+	else
+		reg = AT91_ADC_TSMR_TSMODE_5WIRE;
+
+	/* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid
+	 * pen detect noise.
+	 * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock
+	 */
+	pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / 1000, 1);
+
+	while (pendbc >> ++i)
+		;	/* Empty! Find the shift offset */
+	if (abs(pendbc - (1 << i)) < abs(pendbc - (1 << (i - 1))))
+		pendbc = i;
+	else
+		pendbc = i - 1;
+
+	if (st->caps->has_tsmr) {
+		reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average)
+				& AT91_ADC_TSMR_TSAV;
+		reg |= AT91_ADC_TSMR_PENDBC_(pendbc) & AT91_ADC_TSMR_PENDBC;
+		reg |= AT91_ADC_TSMR_NOTSDMA;
+		reg |= AT91_ADC_TSMR_PENDET_ENA;
+		reg |= 0x03 << 8;	/* TSFREQ, need bigger than TSAV */
+
+		at91_adc_writel(st, AT91_ADC_TSMR, reg);
+	} else {
+		/* TODO: for 9g45 which has no TSMR */
+	}
+
+	/* Change adc internal resistor value for better pen detection,
+	 * default value is 100 kOhm.
+	 * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
+	 * option only available on ES2 and higher
+	 */
+	at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity
+			& AT91_ADC_ACR_PENDETSENS);
+
+	/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
+	st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US *
+			adc_clk_khz / 1000) - 1, 1);
+
+	return 0;
+}
+
+static int at91_ts_register(struct at91_adc_state *st,
+		struct platform_device *pdev)
+{
+	struct input_dev *input;
+	struct iio_dev *idev = iio_priv_to_dev(st);
+	int ret;
+
+	input = input_allocate_device();
+	if (!input) {
+		dev_err(&idev->dev, "Failed to allocate TS device!\n");
+		return -ENOMEM;
+	}
+
+	input->name = DRIVER_NAME;
+	input->id.bustype = BUS_HOST;
+	input->dev.parent = &pdev->dev;
+	input->open = atmel_ts_open;
+	input->close = atmel_ts_close;
+
+	__set_bit(EV_ABS, input->evbit);
+	__set_bit(EV_KEY, input->evbit);
+	__set_bit(BTN_TOUCH, input->keybit);
+	input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
+	input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
+	input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0);
+
+	st->ts_input = input;
+	input_set_drvdata(input, st);
+
+	ret = input_register_device(input);
+	if (ret)
+		input_free_device(st->ts_input);
+
+	return ret;
+}
+
+static void at91_ts_unregister(struct at91_adc_state *st)
+{
+	input_unregister_device(st->ts_input);
+}
+
 static int at91_adc_probe(struct platform_device *pdev)
 {
 	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
@@ -647,7 +952,7 @@ static int at91_adc_probe(struct platform_device *pdev)
 	at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
 	at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
 	ret = request_irq(st->irq,
-			  at91_adc_eoc_trigger,
+			  at91_adc_interrupt,
 			  0,
 			  pdev->dev.driver->name,
 			  idev);
@@ -692,6 +997,10 @@ static int at91_adc_probe(struct platform_device *pdev)
 	mstrclk = clk_get_rate(st->clk);
 	adc_clk = clk_get_rate(st->adc_clk);
 	adc_clk_khz = adc_clk / 1000;
+
+	dev_dbg(&pdev->dev, "Master clock is set as: %d Hz, adc_clk should set as: %d Hz\n",
+		mstrclk, adc_clk);
+
 	prsc = (mstrclk / (2 * adc_clk)) - 1;
 
 	if (!st->startup_time) {
@@ -728,30 +1037,52 @@ static int at91_adc_probe(struct platform_device *pdev)
 	init_waitqueue_head(&st->wq_data_avail);
 	mutex_init(&st->lock);
 
-	ret = at91_adc_buffer_init(idev);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
-		goto error_disable_adc_clk;
-	}
+	/*
+	 * Since touch screen will set trigger register as period trigger. So
+	 * when touch screen is enabled, then we have to disable hardware
+	 * trigger for classic adc.
+	 */
+	if (!st->touchscreen_type) {
+		ret = at91_adc_buffer_init(idev);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
+			goto error_disable_adc_clk;
+		}
 
-	ret = at91_adc_trigger_init(idev);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
-		goto error_unregister_buffer;
+		ret = at91_adc_trigger_init(idev);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
+			at91_adc_buffer_remove(idev);
+			goto error_disable_adc_clk;
+		}
+	} else {
+		if (!st->caps->has_tsmr) {
+			dev_err(&pdev->dev, "We don't support non-TSMR adc\n");
+			goto error_disable_adc_clk;
+		}
+
+		ret = at91_ts_register(st, pdev);
+		if (ret)
+			goto error_disable_adc_clk;
+
+		at91_ts_hw_init(st, adc_clk_khz);
 	}
 
 	ret = iio_device_register(idev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Couldn't register the device.\n");
-		goto error_remove_triggers;
+		goto error_iio_device_register;
 	}
 
 	return 0;
 
-error_remove_triggers:
-	at91_adc_trigger_remove(idev);
-error_unregister_buffer:
-	at91_adc_buffer_remove(idev);
+error_iio_device_register:
+	if (!st->touchscreen_type) {
+		at91_adc_trigger_remove(idev);
+		at91_adc_buffer_remove(idev);
+	} else {
+		at91_ts_unregister(st);
+	}
 error_disable_adc_clk:
 	clk_disable_unprepare(st->adc_clk);
 error_disable_clk:
@@ -770,8 +1101,12 @@ static int at91_adc_remove(struct platform_device *pdev)
 	struct at91_adc_state *st = iio_priv(idev);
 
 	iio_device_unregister(idev);
-	at91_adc_trigger_remove(idev);
-	at91_adc_buffer_remove(idev);
+	if (!st->touchscreen_type) {
+		at91_adc_trigger_remove(idev);
+		at91_adc_buffer_remove(idev);
+	} else {
+		at91_ts_unregister(st);
+	}
 	clk_disable_unprepare(st->adc_clk);
 	clk_disable_unprepare(st->clk);
 	free_irq(st->irq, idev);
@@ -795,6 +1130,7 @@ static struct at91_adc_caps at91sam9260_caps = {
 };
 
 static struct at91_adc_caps at91sam9g45_caps = {
+	.has_ts = true,
 	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
 	.num_channels = 8;
 	.registers = {
@@ -808,6 +1144,10 @@ static struct at91_adc_caps at91sam9g45_caps = {
 };
 
 static struct at91_adc_caps at91sam9x5_caps = {
+	.has_ts = true,
+	.has_tsmr = true,
+	.ts_filter_average = 3,
+	.ts_pen_detect_sensitivity = 2,
 	.calc_startup_ticks = calc_startup_ticks_9x5,
 	.num_channels = 12;
 	.registers = {
@@ -834,7 +1174,7 @@ static struct platform_driver at91_adc_driver = {
 	.probe = at91_adc_probe,
 	.remove = at91_adc_remove,
 	.driver = {
-		   .name = "at91_adc",
+		   .name = DRIVER_NAME,
 		   .of_match_table = of_match_ptr(at91_adc_dt_ids),
 	},
 };
-- 
1.7.10


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

* [PATCH v3 6/6] iio: at91: introduce touch screen support in iio adc driver
@ 2013-08-27 11:28     ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-27 11:28 UTC (permalink / raw)
  To: linux-arm-kernel

AT91 ADC hardware integrate touch screen support. So this patch add touch
screen support for at91 adc iio driver.
To enable touch screen support in adc, you need to add the dt parameters:
  1. which type of touch are used? (4 or 5 wires), sample period time.
  2. correct pressure detect threshold value.

In the meantime, since touch screen will use a interal period trigger of adc,
so it is conflict to other hardware triggers. Driver will disable the hardware
trigger support if touch screen is enabled.

This driver has been tested in AT91SAM9X5-EK and SAMA5D3x-EK.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
CC: devicetree at vger.kernel.org
---
v2 --> v3:
  1. fix according to Dmitry's suggestion.

v1 --> v2:
  1. use the multiple compatible string for different IPs.
  2. hide the driver configuration in driver code instead of exposing them in dt.
     Such like sample period, pen detect debounce time and etc.
  3. add a new dt parameter: ts-pressure-threshold. this value is much related
     with different chips and boards.

 .../devicetree/bindings/arm/atmel-adc.txt          |    7 +
 arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
 drivers/iio/adc/at91_adc.c                         |  388 ++++++++++++++++++--
 3 files changed, 405 insertions(+), 24 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 0e65e01..d106146 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -23,6 +23,13 @@ Optional properties:
 		       resolution will be used.
   - atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion
   - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
+  - atmel,adc-ts-wires: Number of touch screen wires. Should be 4 or 5. If this
+                        value is set, then adc driver will enable touch screen
+                        support.
+    NOTE: when adc touch screen enabled, the adc hardware trigger will be
+          disabled. Since touch screen will occupied the trigger register.
+  - atmel,adc-ts-pressure-threshold: a pressure threshold for touchscreen. It
+                                     make touch detect more precision.
  
 Optional trigger Nodes:
   - Required properties:
diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
index 048a57f..c287307 100644
--- a/arch/arm/mach-at91/include/mach/at91_adc.h
+++ b/arch/arm/mach-at91/include/mach/at91_adc.h
@@ -60,14 +60,48 @@
 #define AT91_ADC_IER		0x24		/* Interrupt Enable Register */
 #define AT91_ADC_IDR		0x28		/* Interrupt Disable Register */
 #define AT91_ADC_IMR		0x2C		/* Interrupt Mask Register */
+#define		AT91_ADC_IER_PEN	(1 << 29)
+#define		AT91_ADC_IER_NOPEN	(1 << 30)
+#define		AT91_ADC_IER_XRDY	(1 << 20)
+#define		AT91_ADC_IER_YRDY	(1 << 21)
+#define		AT91_ADC_IER_PRDY	(1 << 22)
+#define		AT91_ADC_ISR_PENS	(1 << 31)
 
 #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
 #define		AT91_ADC_DATA		(0x3ff)
 
 #define AT91_ADC_CDR0_9X5	(0x50)			/* Channel Data Register 0 for 9X5 */
 
+#define AT91_ADC_ACR		0x94	/* Analog Control Register */
+#define		AT91_ADC_ACR_PENDETSENS	(0x3 << 0)	/* pull-up resistor */
+
+#define AT91_ADC_TSMR		0xB0
+#define		AT91_ADC_TSMR_TSMODE	(3 << 0)	/* Touch Screen Mode */
+#define			AT91_ADC_TSMR_TSMODE_NONE		(0 << 0)
+#define			AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS	(1 << 0)
+#define			AT91_ADC_TSMR_TSMODE_4WIRE_PRESS	(2 << 0)
+#define			AT91_ADC_TSMR_TSMODE_5WIRE		(3 << 0)
+#define		AT91_ADC_TSMR_TSAV	(3 << 4)	/* Averages samples */
+#define			AT91_ADC_TSMR_TSAV_(x)		((x) << 4)
+#define		AT91_ADC_TSMR_SCTIM	(0x0f << 16)	/* Switch closure time */
+#define		AT91_ADC_TSMR_PENDBC	(0x0f << 28)	/* Pen Debounce time */
+#define			AT91_ADC_TSMR_PENDBC_(x)	((x) << 28)
+#define		AT91_ADC_TSMR_NOTSDMA	(1 << 22)	/* No Touchscreen DMA */
+#define		AT91_ADC_TSMR_PENDET_DIS	(0 << 24)	/* Pen contact detection disable */
+#define		AT91_ADC_TSMR_PENDET_ENA	(1 << 24)	/* Pen contact detection enable */
+
+#define AT91_ADC_TSXPOSR	0xB4
+#define AT91_ADC_TSYPOSR	0xB8
+#define AT91_ADC_TSPRESSR	0xBC
+
 #define AT91_ADC_TRGR_9260	AT91_ADC_MR
 #define AT91_ADC_TRGR_9G45	0x08
 #define AT91_ADC_TRGR_9X5	0xC0
 
+/* Trigger Register bit field */
+#define		AT91_ADC_TRGR_TRGPER	(0xffff << 16)
+#define			AT91_ADC_TRGR_TRGPER_(x)	((x) << 16)
+#define		AT91_ADC_TRGR_TRGMOD	(0x7 << 0)
+#define			AT91_ADC_TRGR_MOD_PERIOD_TRIG	(5 << 0)
+
 #endif
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index bd72b0e..0e9424c 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -11,6 +11,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
@@ -39,7 +40,23 @@
 #define at91_adc_writel(st, reg, val) \
 	(writel_relaxed(val, st->reg_base + reg))
 
+#define DRIVER_NAME		"at91_adc"
+#define MAX_POS_BITS		12
+
+#define TOUCH_SAMPLE_PERIOD_US		2000	/* 2ms */
+#define TOUCH_PEN_DETECT_DEBOUNCE_US	200
+
 struct at91_adc_caps {
+	bool	has_ts;		/* Support touch screen */
+	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
+	/*
+	 * Numbers of sampling data will be averaged. Can be 0~3.
+	 * Hardware can average (2 ^ ts_filter_average) sample data.
+	 */
+	u8	ts_filter_average;
+	/* Pen Detection input pull-up resistor, can be 0~3 */
+	u8	ts_pen_detect_sensitivity;
+
 	/* startup time calculate function */
 	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
 
@@ -47,6 +64,12 @@ struct at91_adc_caps {
 	struct at91_adc_reg_desc registers;
 };
 
+enum atmel_adc_ts_type {
+	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
+	ATMEL_ADC_TOUCHSCREEN_4WIRE = 4,
+	ATMEL_ADC_TOUCHSCREEN_5WIRE = 5,
+};
+
 struct at91_adc_state {
 	struct clk		*adc_clk;
 	u16			*buffer;
@@ -71,6 +94,26 @@ struct at91_adc_state {
 	bool			low_res;	/* the resolution corresponds to the lowest one */
 	wait_queue_head_t	wq_data_avail;
 	struct at91_adc_caps	*caps;
+
+	/*
+	 * Following ADC channels are shared by touchscreen:
+	 *
+	 * CH0 -- Touch screen XP/UL
+	 * CH1 -- Touch screen XM/UR
+	 * CH2 -- Touch screen YP/LL
+	 * CH3 -- Touch screen YM/Sense
+	 * CH4 -- Touch screen LR(5-wire only)
+	 *
+	 * The bitfields below represents the reserved channel in the
+	 * touchscreen mode.
+	 */
+#define CHAN_MASK_TOUCHSCREEN_4WIRE	(0xf << 0)
+#define CHAN_MASK_TOUCHSCREEN_5WIRE	(0x1f << 0)
+	enum atmel_adc_ts_type	touchscreen_type;
+	struct input_dev	*ts_input;
+
+	u16			ts_sample_period_val;
+	u32			ts_pressure_threshold;
 };
 
 static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
@@ -105,14 +148,10 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
+/* Handler for classic adc channel eoc trigger */
+void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
 {
-	struct iio_dev *idev = private;
 	struct at91_adc_state *st = iio_priv(idev);
-	u32 status = at91_adc_readl(st, st->registers->status_register);
-
-	if (!(status & st->registers->drdy_mask))
-		return IRQ_HANDLED;
 
 	if (iio_buffer_enabled(idev)) {
 		disable_irq_nosync(irq);
@@ -122,6 +161,115 @@ static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
 		st->done = true;
 		wake_up_interruptible(&st->wq_data_avail);
 	}
+}
+
+static int at91_ts_sample(struct at91_adc_state *st)
+{
+	unsigned int xscale, yscale, reg, z1, z2;
+	unsigned int x, y, pres, xpos, ypos;
+	unsigned int rxp = 1;
+	unsigned int factor = 1000;
+	struct iio_dev *idev = iio_priv_to_dev(st);
+
+	unsigned int xyz_mask_bits = st->res;
+	unsigned int xyz_mask = (1 << xyz_mask_bits) - 1;
+
+	/* calculate position */
+	/* x position = (x / xscale) * max, max = 2^MAX_POS_BITS - 1 */
+	reg = at91_adc_readl(st, AT91_ADC_TSXPOSR);
+	xpos = reg & xyz_mask;
+	x = (xpos << MAX_POS_BITS) - xpos;
+	xscale = (reg >> 16) & xyz_mask;
+	if (xscale == 0) {
+		dev_err(&idev->dev, "Error: xscale == 0!\n");
+		return -1;
+	}
+	x /= xscale;
+
+	/* y position = (y / yscale) * max, max = 2^MAX_POS_BITS - 1 */
+	reg = at91_adc_readl(st, AT91_ADC_TSYPOSR);
+	ypos = reg & xyz_mask;
+	y = (ypos << MAX_POS_BITS) - ypos;
+	yscale = (reg >> 16) & xyz_mask;
+	if (yscale == 0) {
+		dev_err(&idev->dev, "Error: yscale == 0!\n");
+		return -1;
+	}
+	y /= yscale;
+
+	/* calculate the pressure */
+	reg = at91_adc_readl(st, AT91_ADC_TSPRESSR);
+	z1 = reg & xyz_mask;
+	z2 = (reg >> 16) & xyz_mask;
+
+	if (z1 != 0)
+		pres = rxp * (x * factor / 1024) * (z2 * factor / z1 - factor)
+			/ factor;
+	else
+		pres = st->ts_pressure_threshold;	/* no pen contacted */
+
+	dev_dbg(&idev->dev, "xpos = %d, xscale = %d, ypos = %d, yscale = %d, z1 = %d, z2 = %d, press = %d\n",
+				xpos, xscale, ypos, yscale, z1, z2, pres);
+
+	if (pres < st->ts_pressure_threshold) {
+		dev_dbg(&idev->dev, "x = %d, y = %d, pressure = %d\n",
+					x, y, pres / factor);
+		input_report_abs(st->ts_input, ABS_X, x);
+		input_report_abs(st->ts_input, ABS_Y, y);
+		input_report_abs(st->ts_input, ABS_PRESSURE, pres);
+		input_report_key(st->ts_input, BTN_TOUCH, 1);
+		input_sync(st->ts_input);
+	} else {
+		dev_dbg(&idev->dev, "pressure too low: not reporting\n");
+	}
+
+	return 0;
+}
+
+static irqreturn_t at91_adc_interrupt(int irq, void *private)
+{
+	struct iio_dev *idev = private;
+	struct at91_adc_state *st = iio_priv(idev);
+	u32 status = at91_adc_readl(st, st->registers->status_register);
+	const uint32_t ts_data_irq_mask =
+		AT91_ADC_IER_XRDY |
+		AT91_ADC_IER_YRDY |
+		AT91_ADC_IER_PRDY;
+
+	if (status & st->registers->drdy_mask)
+		handle_adc_eoc_trigger(irq, idev);
+
+	if (status & AT91_ADC_IER_PEN) {
+		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
+		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_NOPEN |
+			ts_data_irq_mask);
+		/* Set up period trigger for sampling */
+		at91_adc_writel(st, st->registers->trigger_register,
+			AT91_ADC_TRGR_MOD_PERIOD_TRIG |
+			AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val));
+	} else if (status & AT91_ADC_IER_NOPEN) {
+		at91_adc_writel(st, st->registers->trigger_register, 0);
+		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_NOPEN |
+			ts_data_irq_mask);
+		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
+
+		input_report_key(st->ts_input, BTN_TOUCH, 0);
+		input_sync(st->ts_input);
+	} else if ((status & ts_data_irq_mask) == ts_data_irq_mask) {
+		/* Now all touchscreen data is ready */
+
+		if (status & AT91_ADC_ISR_PENS) {
+			/* validate data by pen contact */
+			at91_ts_sample(st);
+		} else {
+			/* triggered by event that is no pen contact, just read
+			 * them to clean the interrupt and discard all.
+			 */
+			at91_adc_readl(st, AT91_ADC_TSXPOSR);
+			at91_adc_readl(st, AT91_ADC_TSYPOSR);
+			at91_adc_readl(st, AT91_ADC_TSPRESSR);
+		}
+	}
 
 	return IRQ_HANDLED;
 }
@@ -131,6 +279,16 @@ static int at91_adc_channel_init(struct iio_dev *idev)
 	struct at91_adc_state *st = iio_priv(idev);
 	struct iio_chan_spec *chan_array, *timestamp;
 	int bit, idx = 0;
+	unsigned long rsvd_mask = 0;
+
+	/* If touchscreen is enable, then reserve the adc channels */
+	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
+		rsvd_mask = CHAN_MASK_TOUCHSCREEN_4WIRE;
+	else if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_5WIRE)
+		rsvd_mask = CHAN_MASK_TOUCHSCREEN_5WIRE;
+
+	/* set up the channel mask to reserve touchscreen channels */
+	st->channels_mask &= ~rsvd_mask;
 
 	idev->num_channels = bitmap_weight(&st->channels_mask,
 					   st->num_channels) + 1;
@@ -479,6 +637,39 @@ static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz)
 
 static const struct of_device_id at91_adc_dt_ids[];
 
+static int at91_adc_probe_dt_ts(struct device_node *node,
+	struct at91_adc_state *st, struct device *dev)
+{
+	int ret;
+	u32 prop;
+
+	ret = of_property_read_u32(node, "atmel,adc-ts-wires", &prop);
+	if (ret) {
+		dev_info(dev, "ADC Touch screen is disabled.\n");
+		return 0;
+	}
+
+	switch (prop) {
+	case 4:
+	case 5:
+		st->touchscreen_type = prop;
+		break;
+	default:
+		dev_err(dev, "Unsupported number of touchscreen wires (%d). Should be 4 or 5.\n", prop);
+		return -EINVAL;
+	}
+
+	prop = 0;
+	of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop);
+	st->ts_pressure_threshold = prop;
+	if (st->ts_pressure_threshold) {
+		return 0;
+	} else {
+		dev_err(dev, "Invalid pressure threshold for the touchscreen\n");
+		return -EINVAL;
+	}
+}
+
 static int at91_adc_probe_dt(struct at91_adc_state *st,
 			     struct platform_device *pdev)
 {
@@ -560,6 +751,12 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 		i++;
 	}
 
+	/* Check if touchscreen is supported. */
+	if (st->caps->has_ts)
+		return at91_adc_probe_dt_ts(node, st, &idev->dev);
+	else
+		dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n");
+
 	return 0;
 
 error_ret:
@@ -591,6 +788,114 @@ static const struct iio_info at91_adc_info = {
 	.read_raw = &at91_adc_read_raw,
 };
 
+/* Touchscreen related functions */
+static int atmel_ts_open(struct input_dev *dev)
+{
+	struct at91_adc_state *st = input_get_drvdata(dev);
+
+	at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
+	return 0;
+}
+
+static void atmel_ts_close(struct input_dev *dev)
+{
+	struct at91_adc_state *st = input_get_drvdata(dev);
+
+	at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
+}
+
+static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
+{
+	u32 reg = 0, pendbc;
+	int i = 0;
+
+	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
+		reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
+	else
+		reg = AT91_ADC_TSMR_TSMODE_5WIRE;
+
+	/* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid
+	 * pen detect noise.
+	 * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock
+	 */
+	pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / 1000, 1);
+
+	while (pendbc >> ++i)
+		;	/* Empty! Find the shift offset */
+	if (abs(pendbc - (1 << i)) < abs(pendbc - (1 << (i - 1))))
+		pendbc = i;
+	else
+		pendbc = i - 1;
+
+	if (st->caps->has_tsmr) {
+		reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average)
+				& AT91_ADC_TSMR_TSAV;
+		reg |= AT91_ADC_TSMR_PENDBC_(pendbc) & AT91_ADC_TSMR_PENDBC;
+		reg |= AT91_ADC_TSMR_NOTSDMA;
+		reg |= AT91_ADC_TSMR_PENDET_ENA;
+		reg |= 0x03 << 8;	/* TSFREQ, need bigger than TSAV */
+
+		at91_adc_writel(st, AT91_ADC_TSMR, reg);
+	} else {
+		/* TODO: for 9g45 which has no TSMR */
+	}
+
+	/* Change adc internal resistor value for better pen detection,
+	 * default value is 100 kOhm.
+	 * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
+	 * option only available on ES2 and higher
+	 */
+	at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity
+			& AT91_ADC_ACR_PENDETSENS);
+
+	/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
+	st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US *
+			adc_clk_khz / 1000) - 1, 1);
+
+	return 0;
+}
+
+static int at91_ts_register(struct at91_adc_state *st,
+		struct platform_device *pdev)
+{
+	struct input_dev *input;
+	struct iio_dev *idev = iio_priv_to_dev(st);
+	int ret;
+
+	input = input_allocate_device();
+	if (!input) {
+		dev_err(&idev->dev, "Failed to allocate TS device!\n");
+		return -ENOMEM;
+	}
+
+	input->name = DRIVER_NAME;
+	input->id.bustype = BUS_HOST;
+	input->dev.parent = &pdev->dev;
+	input->open = atmel_ts_open;
+	input->close = atmel_ts_close;
+
+	__set_bit(EV_ABS, input->evbit);
+	__set_bit(EV_KEY, input->evbit);
+	__set_bit(BTN_TOUCH, input->keybit);
+	input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
+	input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
+	input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0);
+
+	st->ts_input = input;
+	input_set_drvdata(input, st);
+
+	ret = input_register_device(input);
+	if (ret)
+		input_free_device(st->ts_input);
+
+	return ret;
+}
+
+static void at91_ts_unregister(struct at91_adc_state *st)
+{
+	input_unregister_device(st->ts_input);
+}
+
 static int at91_adc_probe(struct platform_device *pdev)
 {
 	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
@@ -647,7 +952,7 @@ static int at91_adc_probe(struct platform_device *pdev)
 	at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
 	at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
 	ret = request_irq(st->irq,
-			  at91_adc_eoc_trigger,
+			  at91_adc_interrupt,
 			  0,
 			  pdev->dev.driver->name,
 			  idev);
@@ -692,6 +997,10 @@ static int at91_adc_probe(struct platform_device *pdev)
 	mstrclk = clk_get_rate(st->clk);
 	adc_clk = clk_get_rate(st->adc_clk);
 	adc_clk_khz = adc_clk / 1000;
+
+	dev_dbg(&pdev->dev, "Master clock is set as: %d Hz, adc_clk should set as: %d Hz\n",
+		mstrclk, adc_clk);
+
 	prsc = (mstrclk / (2 * adc_clk)) - 1;
 
 	if (!st->startup_time) {
@@ -728,30 +1037,52 @@ static int at91_adc_probe(struct platform_device *pdev)
 	init_waitqueue_head(&st->wq_data_avail);
 	mutex_init(&st->lock);
 
-	ret = at91_adc_buffer_init(idev);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
-		goto error_disable_adc_clk;
-	}
+	/*
+	 * Since touch screen will set trigger register as period trigger. So
+	 * when touch screen is enabled, then we have to disable hardware
+	 * trigger for classic adc.
+	 */
+	if (!st->touchscreen_type) {
+		ret = at91_adc_buffer_init(idev);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
+			goto error_disable_adc_clk;
+		}
 
-	ret = at91_adc_trigger_init(idev);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
-		goto error_unregister_buffer;
+		ret = at91_adc_trigger_init(idev);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
+			at91_adc_buffer_remove(idev);
+			goto error_disable_adc_clk;
+		}
+	} else {
+		if (!st->caps->has_tsmr) {
+			dev_err(&pdev->dev, "We don't support non-TSMR adc\n");
+			goto error_disable_adc_clk;
+		}
+
+		ret = at91_ts_register(st, pdev);
+		if (ret)
+			goto error_disable_adc_clk;
+
+		at91_ts_hw_init(st, adc_clk_khz);
 	}
 
 	ret = iio_device_register(idev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Couldn't register the device.\n");
-		goto error_remove_triggers;
+		goto error_iio_device_register;
 	}
 
 	return 0;
 
-error_remove_triggers:
-	at91_adc_trigger_remove(idev);
-error_unregister_buffer:
-	at91_adc_buffer_remove(idev);
+error_iio_device_register:
+	if (!st->touchscreen_type) {
+		at91_adc_trigger_remove(idev);
+		at91_adc_buffer_remove(idev);
+	} else {
+		at91_ts_unregister(st);
+	}
 error_disable_adc_clk:
 	clk_disable_unprepare(st->adc_clk);
 error_disable_clk:
@@ -770,8 +1101,12 @@ static int at91_adc_remove(struct platform_device *pdev)
 	struct at91_adc_state *st = iio_priv(idev);
 
 	iio_device_unregister(idev);
-	at91_adc_trigger_remove(idev);
-	at91_adc_buffer_remove(idev);
+	if (!st->touchscreen_type) {
+		at91_adc_trigger_remove(idev);
+		at91_adc_buffer_remove(idev);
+	} else {
+		at91_ts_unregister(st);
+	}
 	clk_disable_unprepare(st->adc_clk);
 	clk_disable_unprepare(st->clk);
 	free_irq(st->irq, idev);
@@ -795,6 +1130,7 @@ static struct at91_adc_caps at91sam9260_caps = {
 };
 
 static struct at91_adc_caps at91sam9g45_caps = {
+	.has_ts = true,
 	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
 	.num_channels = 8;
 	.registers = {
@@ -808,6 +1144,10 @@ static struct at91_adc_caps at91sam9g45_caps = {
 };
 
 static struct at91_adc_caps at91sam9x5_caps = {
+	.has_ts = true,
+	.has_tsmr = true,
+	.ts_filter_average = 3,
+	.ts_pen_detect_sensitivity = 2,
 	.calc_startup_ticks = calc_startup_ticks_9x5,
 	.num_channels = 12;
 	.registers = {
@@ -834,7 +1174,7 @@ static struct platform_driver at91_adc_driver = {
 	.probe = at91_adc_probe,
 	.remove = at91_adc_remove,
 	.driver = {
-		   .name = "at91_adc",
+		   .name = DRIVER_NAME,
 		   .of_match_table = of_match_ptr(at91_adc_dt_ids),
 	},
 };
-- 
1.7.10

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

* [resend][PATCH v3 5/6] iio: at91: move the num_channels from DT to driver itself
  2013-08-27 11:28     ` Josh Wu
  (?)
@ 2013-08-28  7:42         ` Josh Wu
  -1 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-28  7:42 UTC (permalink / raw)
  To: jic23-KWPb1pKIrIJaa/9Udqfwiw
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	plagnioj-sclMFOaUSTBWk0Htik3J/w,
	nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	mark.rutland-5wv7dgnIgG8, b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Josh Wu

CC: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Signed-off-by: Josh Wu <josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
---
Sorry for not testing the previous email for this patch.
Now I find the compiling error in the patch, so I resend a fix version of this
patch.

In this resended version:
  - fix the compile error the typo.
  - fix the num_channels assignment type error.

 Documentation/devicetree/bindings/arm/atmel-adc.txt |    1 -
 drivers/iio/adc/at91_adc.c                          |   12 +++++-------
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 723c205..0e65e01 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -7,7 +7,6 @@ Required properties:
   - interrupts: Should contain the IRQ line for the ADC
   - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
     device
-  - atmel,adc-num-channels: Number of channels available in the ADC
   - atmel,adc-startup-time: Startup Time of the ADC in microseconds as
     defined in the datasheet
   - atmel,adc-vref: Reference voltage in millivolts for the conversions
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index f32a69d..0f4621a 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -43,6 +43,7 @@ struct at91_adc_caps {
 	/* startup time calculate function */
 	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
 
+	u8	num_channels;
 	struct at91_adc_reg_desc registers;
 };
 
@@ -502,13 +503,6 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 	}
 	st->channels_mask = prop;
 
-	if (of_property_read_u32(node, "atmel,adc-num-channels", &prop)) {
-		dev_err(&idev->dev, "Missing adc-num-channels property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->num_channels = prop;
-
 	st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode");
 
 	if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
@@ -534,6 +528,7 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 		goto error_ret;
 
 	st->registers = &st->caps->registers;
+	st->num_channels = st->caps->num_channels;
 	st->trigger_number = of_get_child_count(node);
 	st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
 					sizeof(struct at91_adc_trigger),
@@ -788,6 +783,7 @@ static int at91_adc_remove(struct platform_device *pdev)
 #ifdef CONFIG_OF
 static struct at91_adc_caps at91sam9260_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9260,
+	.num_channels = 4,
 	.registers = {
 		.channel_base = AT91_ADC_CHR(0),
 		.drdy_mask = AT91_ADC_DRDY,
@@ -800,6 +796,7 @@ static struct at91_adc_caps at91sam9260_caps = {
 
 static struct at91_adc_caps at91sam9g45_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
+	.num_channels = 8,
 	.registers = {
 		.channel_base = AT91_ADC_CHR(0),
 		.drdy_mask = AT91_ADC_DRDY,
@@ -812,6 +809,7 @@ static struct at91_adc_caps at91sam9g45_caps = {
 
 static struct at91_adc_caps at91sam9x5_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9x5,
+	.num_channels = 12,
 	.registers = {
 		.channel_base = AT91_ADC_CDR0_9X5,
 		.drdy_mask = AT91_ADC_SR_DRDY_9X5,
-- 
1.7.10

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

* [resend][PATCH v3 5/6] iio: at91: move the num_channels from DT to driver itself
@ 2013-08-28  7:42         ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-28  7:42 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, thomas.petazzoni, mark.rutland, b.brezillon,
	devicetree, Josh Wu

CC: devicetree@vger.kernel.org
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
Sorry for not testing the previous email for this patch.
Now I find the compiling error in the patch, so I resend a fix version of this
patch.

In this resended version:
  - fix the compile error the typo.
  - fix the num_channels assignment type error.

 Documentation/devicetree/bindings/arm/atmel-adc.txt |    1 -
 drivers/iio/adc/at91_adc.c                          |   12 +++++-------
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 723c205..0e65e01 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -7,7 +7,6 @@ Required properties:
   - interrupts: Should contain the IRQ line for the ADC
   - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
     device
-  - atmel,adc-num-channels: Number of channels available in the ADC
   - atmel,adc-startup-time: Startup Time of the ADC in microseconds as
     defined in the datasheet
   - atmel,adc-vref: Reference voltage in millivolts for the conversions
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index f32a69d..0f4621a 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -43,6 +43,7 @@ struct at91_adc_caps {
 	/* startup time calculate function */
 	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
 
+	u8	num_channels;
 	struct at91_adc_reg_desc registers;
 };
 
@@ -502,13 +503,6 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 	}
 	st->channels_mask = prop;
 
-	if (of_property_read_u32(node, "atmel,adc-num-channels", &prop)) {
-		dev_err(&idev->dev, "Missing adc-num-channels property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->num_channels = prop;
-
 	st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode");
 
 	if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
@@ -534,6 +528,7 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 		goto error_ret;
 
 	st->registers = &st->caps->registers;
+	st->num_channels = st->caps->num_channels;
 	st->trigger_number = of_get_child_count(node);
 	st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
 					sizeof(struct at91_adc_trigger),
@@ -788,6 +783,7 @@ static int at91_adc_remove(struct platform_device *pdev)
 #ifdef CONFIG_OF
 static struct at91_adc_caps at91sam9260_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9260,
+	.num_channels = 4,
 	.registers = {
 		.channel_base = AT91_ADC_CHR(0),
 		.drdy_mask = AT91_ADC_DRDY,
@@ -800,6 +796,7 @@ static struct at91_adc_caps at91sam9260_caps = {
 
 static struct at91_adc_caps at91sam9g45_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
+	.num_channels = 8,
 	.registers = {
 		.channel_base = AT91_ADC_CHR(0),
 		.drdy_mask = AT91_ADC_DRDY,
@@ -812,6 +809,7 @@ static struct at91_adc_caps at91sam9g45_caps = {
 
 static struct at91_adc_caps at91sam9x5_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9x5,
+	.num_channels = 12,
 	.registers = {
 		.channel_base = AT91_ADC_CDR0_9X5,
 		.drdy_mask = AT91_ADC_SR_DRDY_9X5,
-- 
1.7.10

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

* [resend][PATCH v3 5/6] iio: at91: move the num_channels from DT to driver itself
@ 2013-08-28  7:42         ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-28  7:42 UTC (permalink / raw)
  To: linux-arm-kernel

CC: devicetree at vger.kernel.org
Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
Sorry for not testing the previous email for this patch.
Now I find the compiling error in the patch, so I resend a fix version of this
patch.

In this resended version:
  - fix the compile error the typo.
  - fix the num_channels assignment type error.

 Documentation/devicetree/bindings/arm/atmel-adc.txt |    1 -
 drivers/iio/adc/at91_adc.c                          |   12 +++++-------
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 723c205..0e65e01 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -7,7 +7,6 @@ Required properties:
   - interrupts: Should contain the IRQ line for the ADC
   - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
     device
-  - atmel,adc-num-channels: Number of channels available in the ADC
   - atmel,adc-startup-time: Startup Time of the ADC in microseconds as
     defined in the datasheet
   - atmel,adc-vref: Reference voltage in millivolts for the conversions
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index f32a69d..0f4621a 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -43,6 +43,7 @@ struct at91_adc_caps {
 	/* startup time calculate function */
 	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
 
+	u8	num_channels;
 	struct at91_adc_reg_desc registers;
 };
 
@@ -502,13 +503,6 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 	}
 	st->channels_mask = prop;
 
-	if (of_property_read_u32(node, "atmel,adc-num-channels", &prop)) {
-		dev_err(&idev->dev, "Missing adc-num-channels property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->num_channels = prop;
-
 	st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode");
 
 	if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
@@ -534,6 +528,7 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 		goto error_ret;
 
 	st->registers = &st->caps->registers;
+	st->num_channels = st->caps->num_channels;
 	st->trigger_number = of_get_child_count(node);
 	st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
 					sizeof(struct at91_adc_trigger),
@@ -788,6 +783,7 @@ static int at91_adc_remove(struct platform_device *pdev)
 #ifdef CONFIG_OF
 static struct at91_adc_caps at91sam9260_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9260,
+	.num_channels = 4,
 	.registers = {
 		.channel_base = AT91_ADC_CHR(0),
 		.drdy_mask = AT91_ADC_DRDY,
@@ -800,6 +796,7 @@ static struct at91_adc_caps at91sam9260_caps = {
 
 static struct at91_adc_caps at91sam9g45_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
+	.num_channels = 8,
 	.registers = {
 		.channel_base = AT91_ADC_CHR(0),
 		.drdy_mask = AT91_ADC_DRDY,
@@ -812,6 +809,7 @@ static struct at91_adc_caps at91sam9g45_caps = {
 
 static struct at91_adc_caps at91sam9x5_caps = {
 	.calc_startup_ticks = calc_startup_ticks_9x5,
+	.num_channels = 12,
 	.registers = {
 		.channel_base = AT91_ADC_CDR0_9X5,
 		.drdy_mask = AT91_ADC_SR_DRDY_9X5,
-- 
1.7.10

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

* [resend][PATCH v3 6/6] iio: at91: introduce touch screen support in iio adc driver
  2013-08-27 11:28     ` Josh Wu
  (?)
@ 2013-08-28  7:45         ` Josh Wu
  -1 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-28  7:45 UTC (permalink / raw)
  To: jic23-KWPb1pKIrIJaa/9Udqfwiw
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	plagnioj-sclMFOaUSTBWk0Htik3J/w,
	nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	mark.rutland-5wv7dgnIgG8, b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Josh Wu, Dmitry Torokhov

AT91 ADC hardware integrate touch screen support. So this patch add touch
screen support for at91 adc iio driver.
To enable touch screen support in adc, you need to add the dt parameters:
  1. which type of touch are used? (4 or 5 wires), sample period time.
  2. correct pressure detect threshold value.

In the meantime, since touch screen will use a interal period trigger of adc,
so it is conflict to other hardware triggers. Driver will disable the hardware
trigger support if touch screen is enabled.

This driver has been tested in AT91SAM9X5-EK and SAMA5D3x-EK.

Signed-off-by: Josh Wu <josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Cc: Dmitry Torokhov <dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
CC: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
---
resend v3:
  Since [v3 5/6] is resended for compiling error fix. So rebase this patch

v2 --> v3:
  1. fix according to Dmitry's suggestion.

v1 --> v2:
  1. use the multiple compatible string for different IPs.
  2. hide the driver configuration in driver code instead of exposing them in dt.
     Such like sample period, pen detect debounce time and etc.
  3. add a new dt parameter: ts-pressure-threshold. this value is much related
     with different chips and boards.

 .../devicetree/bindings/arm/atmel-adc.txt          |    7 +
 arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
 drivers/iio/adc/at91_adc.c                         |  388 ++++++++++++++++++--
 3 files changed, 405 insertions(+), 24 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 0e65e01..d106146 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -23,6 +23,13 @@ Optional properties:
 		       resolution will be used.
   - atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion
   - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
+  - atmel,adc-ts-wires: Number of touch screen wires. Should be 4 or 5. If this
+                        value is set, then adc driver will enable touch screen
+                        support.
+    NOTE: when adc touch screen enabled, the adc hardware trigger will be
+          disabled. Since touch screen will occupied the trigger register.
+  - atmel,adc-ts-pressure-threshold: a pressure threshold for touchscreen. It
+                                     make touch detect more precision.
  
 Optional trigger Nodes:
   - Required properties:
diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
index 048a57f..c287307 100644
--- a/arch/arm/mach-at91/include/mach/at91_adc.h
+++ b/arch/arm/mach-at91/include/mach/at91_adc.h
@@ -60,14 +60,48 @@
 #define AT91_ADC_IER		0x24		/* Interrupt Enable Register */
 #define AT91_ADC_IDR		0x28		/* Interrupt Disable Register */
 #define AT91_ADC_IMR		0x2C		/* Interrupt Mask Register */
+#define		AT91_ADC_IER_PEN	(1 << 29)
+#define		AT91_ADC_IER_NOPEN	(1 << 30)
+#define		AT91_ADC_IER_XRDY	(1 << 20)
+#define		AT91_ADC_IER_YRDY	(1 << 21)
+#define		AT91_ADC_IER_PRDY	(1 << 22)
+#define		AT91_ADC_ISR_PENS	(1 << 31)
 
 #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
 #define		AT91_ADC_DATA		(0x3ff)
 
 #define AT91_ADC_CDR0_9X5	(0x50)			/* Channel Data Register 0 for 9X5 */
 
+#define AT91_ADC_ACR		0x94	/* Analog Control Register */
+#define		AT91_ADC_ACR_PENDETSENS	(0x3 << 0)	/* pull-up resistor */
+
+#define AT91_ADC_TSMR		0xB0
+#define		AT91_ADC_TSMR_TSMODE	(3 << 0)	/* Touch Screen Mode */
+#define			AT91_ADC_TSMR_TSMODE_NONE		(0 << 0)
+#define			AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS	(1 << 0)
+#define			AT91_ADC_TSMR_TSMODE_4WIRE_PRESS	(2 << 0)
+#define			AT91_ADC_TSMR_TSMODE_5WIRE		(3 << 0)
+#define		AT91_ADC_TSMR_TSAV	(3 << 4)	/* Averages samples */
+#define			AT91_ADC_TSMR_TSAV_(x)		((x) << 4)
+#define		AT91_ADC_TSMR_SCTIM	(0x0f << 16)	/* Switch closure time */
+#define		AT91_ADC_TSMR_PENDBC	(0x0f << 28)	/* Pen Debounce time */
+#define			AT91_ADC_TSMR_PENDBC_(x)	((x) << 28)
+#define		AT91_ADC_TSMR_NOTSDMA	(1 << 22)	/* No Touchscreen DMA */
+#define		AT91_ADC_TSMR_PENDET_DIS	(0 << 24)	/* Pen contact detection disable */
+#define		AT91_ADC_TSMR_PENDET_ENA	(1 << 24)	/* Pen contact detection enable */
+
+#define AT91_ADC_TSXPOSR	0xB4
+#define AT91_ADC_TSYPOSR	0xB8
+#define AT91_ADC_TSPRESSR	0xBC
+
 #define AT91_ADC_TRGR_9260	AT91_ADC_MR
 #define AT91_ADC_TRGR_9G45	0x08
 #define AT91_ADC_TRGR_9X5	0xC0
 
+/* Trigger Register bit field */
+#define		AT91_ADC_TRGR_TRGPER	(0xffff << 16)
+#define			AT91_ADC_TRGR_TRGPER_(x)	((x) << 16)
+#define		AT91_ADC_TRGR_TRGMOD	(0x7 << 0)
+#define			AT91_ADC_TRGR_MOD_PERIOD_TRIG	(5 << 0)
+
 #endif
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 0f4621a..beec9ae 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -11,6 +11,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
@@ -39,7 +40,23 @@
 #define at91_adc_writel(st, reg, val) \
 	(writel_relaxed(val, st->reg_base + reg))
 
+#define DRIVER_NAME		"at91_adc"
+#define MAX_POS_BITS		12
+
+#define TOUCH_SAMPLE_PERIOD_US		2000	/* 2ms */
+#define TOUCH_PEN_DETECT_DEBOUNCE_US	200
+
 struct at91_adc_caps {
+	bool	has_ts;		/* Support touch screen */
+	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
+	/*
+	 * Numbers of sampling data will be averaged. Can be 0~3.
+	 * Hardware can average (2 ^ ts_filter_average) sample data.
+	 */
+	u8	ts_filter_average;
+	/* Pen Detection input pull-up resistor, can be 0~3 */
+	u8	ts_pen_detect_sensitivity;
+
 	/* startup time calculate function */
 	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
 
@@ -47,6 +64,12 @@ struct at91_adc_caps {
 	struct at91_adc_reg_desc registers;
 };
 
+enum atmel_adc_ts_type {
+	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
+	ATMEL_ADC_TOUCHSCREEN_4WIRE = 4,
+	ATMEL_ADC_TOUCHSCREEN_5WIRE = 5,
+};
+
 struct at91_adc_state {
 	struct clk		*adc_clk;
 	u16			*buffer;
@@ -71,6 +94,26 @@ struct at91_adc_state {
 	bool			low_res;	/* the resolution corresponds to the lowest one */
 	wait_queue_head_t	wq_data_avail;
 	struct at91_adc_caps	*caps;
+
+	/*
+	 * Following ADC channels are shared by touchscreen:
+	 *
+	 * CH0 -- Touch screen XP/UL
+	 * CH1 -- Touch screen XM/UR
+	 * CH2 -- Touch screen YP/LL
+	 * CH3 -- Touch screen YM/Sense
+	 * CH4 -- Touch screen LR(5-wire only)
+	 *
+	 * The bitfields below represents the reserved channel in the
+	 * touchscreen mode.
+	 */
+#define CHAN_MASK_TOUCHSCREEN_4WIRE	(0xf << 0)
+#define CHAN_MASK_TOUCHSCREEN_5WIRE	(0x1f << 0)
+	enum atmel_adc_ts_type	touchscreen_type;
+	struct input_dev	*ts_input;
+
+	u16			ts_sample_period_val;
+	u32			ts_pressure_threshold;
 };
 
 static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
@@ -105,14 +148,10 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
+/* Handler for classic adc channel eoc trigger */
+void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
 {
-	struct iio_dev *idev = private;
 	struct at91_adc_state *st = iio_priv(idev);
-	u32 status = at91_adc_readl(st, st->registers->status_register);
-
-	if (!(status & st->registers->drdy_mask))
-		return IRQ_HANDLED;
 
 	if (iio_buffer_enabled(idev)) {
 		disable_irq_nosync(irq);
@@ -122,6 +161,115 @@ static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
 		st->done = true;
 		wake_up_interruptible(&st->wq_data_avail);
 	}
+}
+
+static int at91_ts_sample(struct at91_adc_state *st)
+{
+	unsigned int xscale, yscale, reg, z1, z2;
+	unsigned int x, y, pres, xpos, ypos;
+	unsigned int rxp = 1;
+	unsigned int factor = 1000;
+	struct iio_dev *idev = iio_priv_to_dev(st);
+
+	unsigned int xyz_mask_bits = st->res;
+	unsigned int xyz_mask = (1 << xyz_mask_bits) - 1;
+
+	/* calculate position */
+	/* x position = (x / xscale) * max, max = 2^MAX_POS_BITS - 1 */
+	reg = at91_adc_readl(st, AT91_ADC_TSXPOSR);
+	xpos = reg & xyz_mask;
+	x = (xpos << MAX_POS_BITS) - xpos;
+	xscale = (reg >> 16) & xyz_mask;
+	if (xscale == 0) {
+		dev_err(&idev->dev, "Error: xscale == 0!\n");
+		return -1;
+	}
+	x /= xscale;
+
+	/* y position = (y / yscale) * max, max = 2^MAX_POS_BITS - 1 */
+	reg = at91_adc_readl(st, AT91_ADC_TSYPOSR);
+	ypos = reg & xyz_mask;
+	y = (ypos << MAX_POS_BITS) - ypos;
+	yscale = (reg >> 16) & xyz_mask;
+	if (yscale == 0) {
+		dev_err(&idev->dev, "Error: yscale == 0!\n");
+		return -1;
+	}
+	y /= yscale;
+
+	/* calculate the pressure */
+	reg = at91_adc_readl(st, AT91_ADC_TSPRESSR);
+	z1 = reg & xyz_mask;
+	z2 = (reg >> 16) & xyz_mask;
+
+	if (z1 != 0)
+		pres = rxp * (x * factor / 1024) * (z2 * factor / z1 - factor)
+			/ factor;
+	else
+		pres = st->ts_pressure_threshold;	/* no pen contacted */
+
+	dev_dbg(&idev->dev, "xpos = %d, xscale = %d, ypos = %d, yscale = %d, z1 = %d, z2 = %d, press = %d\n",
+				xpos, xscale, ypos, yscale, z1, z2, pres);
+
+	if (pres < st->ts_pressure_threshold) {
+		dev_dbg(&idev->dev, "x = %d, y = %d, pressure = %d\n",
+					x, y, pres / factor);
+		input_report_abs(st->ts_input, ABS_X, x);
+		input_report_abs(st->ts_input, ABS_Y, y);
+		input_report_abs(st->ts_input, ABS_PRESSURE, pres);
+		input_report_key(st->ts_input, BTN_TOUCH, 1);
+		input_sync(st->ts_input);
+	} else {
+		dev_dbg(&idev->dev, "pressure too low: not reporting\n");
+	}
+
+	return 0;
+}
+
+static irqreturn_t at91_adc_interrupt(int irq, void *private)
+{
+	struct iio_dev *idev = private;
+	struct at91_adc_state *st = iio_priv(idev);
+	u32 status = at91_adc_readl(st, st->registers->status_register);
+	const uint32_t ts_data_irq_mask =
+		AT91_ADC_IER_XRDY |
+		AT91_ADC_IER_YRDY |
+		AT91_ADC_IER_PRDY;
+
+	if (status & st->registers->drdy_mask)
+		handle_adc_eoc_trigger(irq, idev);
+
+	if (status & AT91_ADC_IER_PEN) {
+		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
+		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_NOPEN |
+			ts_data_irq_mask);
+		/* Set up period trigger for sampling */
+		at91_adc_writel(st, st->registers->trigger_register,
+			AT91_ADC_TRGR_MOD_PERIOD_TRIG |
+			AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val));
+	} else if (status & AT91_ADC_IER_NOPEN) {
+		at91_adc_writel(st, st->registers->trigger_register, 0);
+		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_NOPEN |
+			ts_data_irq_mask);
+		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
+
+		input_report_key(st->ts_input, BTN_TOUCH, 0);
+		input_sync(st->ts_input);
+	} else if ((status & ts_data_irq_mask) == ts_data_irq_mask) {
+		/* Now all touchscreen data is ready */
+
+		if (status & AT91_ADC_ISR_PENS) {
+			/* validate data by pen contact */
+			at91_ts_sample(st);
+		} else {
+			/* triggered by event that is no pen contact, just read
+			 * them to clean the interrupt and discard all.
+			 */
+			at91_adc_readl(st, AT91_ADC_TSXPOSR);
+			at91_adc_readl(st, AT91_ADC_TSYPOSR);
+			at91_adc_readl(st, AT91_ADC_TSPRESSR);
+		}
+	}
 
 	return IRQ_HANDLED;
 }
@@ -131,6 +279,16 @@ static int at91_adc_channel_init(struct iio_dev *idev)
 	struct at91_adc_state *st = iio_priv(idev);
 	struct iio_chan_spec *chan_array, *timestamp;
 	int bit, idx = 0;
+	unsigned long rsvd_mask = 0;
+
+	/* If touchscreen is enable, then reserve the adc channels */
+	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
+		rsvd_mask = CHAN_MASK_TOUCHSCREEN_4WIRE;
+	else if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_5WIRE)
+		rsvd_mask = CHAN_MASK_TOUCHSCREEN_5WIRE;
+
+	/* set up the channel mask to reserve touchscreen channels */
+	st->channels_mask &= ~rsvd_mask;
 
 	idev->num_channels = bitmap_weight(&st->channels_mask,
 					   st->num_channels) + 1;
@@ -479,6 +637,39 @@ static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz)
 
 static const struct of_device_id at91_adc_dt_ids[];
 
+static int at91_adc_probe_dt_ts(struct device_node *node,
+	struct at91_adc_state *st, struct device *dev)
+{
+	int ret;
+	u32 prop;
+
+	ret = of_property_read_u32(node, "atmel,adc-ts-wires", &prop);
+	if (ret) {
+		dev_info(dev, "ADC Touch screen is disabled.\n");
+		return 0;
+	}
+
+	switch (prop) {
+	case 4:
+	case 5:
+		st->touchscreen_type = prop;
+		break;
+	default:
+		dev_err(dev, "Unsupported number of touchscreen wires (%d). Should be 4 or 5.\n", prop);
+		return -EINVAL;
+	}
+
+	prop = 0;
+	of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop);
+	st->ts_pressure_threshold = prop;
+	if (st->ts_pressure_threshold) {
+		return 0;
+	} else {
+		dev_err(dev, "Invalid pressure threshold for the touchscreen\n");
+		return -EINVAL;
+	}
+}
+
 static int at91_adc_probe_dt(struct at91_adc_state *st,
 			     struct platform_device *pdev)
 {
@@ -560,6 +751,12 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 		i++;
 	}
 
+	/* Check if touchscreen is supported. */
+	if (st->caps->has_ts)
+		return at91_adc_probe_dt_ts(node, st, &idev->dev);
+	else
+		dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n");
+
 	return 0;
 
 error_ret:
@@ -591,6 +788,114 @@ static const struct iio_info at91_adc_info = {
 	.read_raw = &at91_adc_read_raw,
 };
 
+/* Touchscreen related functions */
+static int atmel_ts_open(struct input_dev *dev)
+{
+	struct at91_adc_state *st = input_get_drvdata(dev);
+
+	at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
+	return 0;
+}
+
+static void atmel_ts_close(struct input_dev *dev)
+{
+	struct at91_adc_state *st = input_get_drvdata(dev);
+
+	at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
+}
+
+static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
+{
+	u32 reg = 0, pendbc;
+	int i = 0;
+
+	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
+		reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
+	else
+		reg = AT91_ADC_TSMR_TSMODE_5WIRE;
+
+	/* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid
+	 * pen detect noise.
+	 * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock
+	 */
+	pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / 1000, 1);
+
+	while (pendbc >> ++i)
+		;	/* Empty! Find the shift offset */
+	if (abs(pendbc - (1 << i)) < abs(pendbc - (1 << (i - 1))))
+		pendbc = i;
+	else
+		pendbc = i - 1;
+
+	if (st->caps->has_tsmr) {
+		reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average)
+				& AT91_ADC_TSMR_TSAV;
+		reg |= AT91_ADC_TSMR_PENDBC_(pendbc) & AT91_ADC_TSMR_PENDBC;
+		reg |= AT91_ADC_TSMR_NOTSDMA;
+		reg |= AT91_ADC_TSMR_PENDET_ENA;
+		reg |= 0x03 << 8;	/* TSFREQ, need bigger than TSAV */
+
+		at91_adc_writel(st, AT91_ADC_TSMR, reg);
+	} else {
+		/* TODO: for 9g45 which has no TSMR */
+	}
+
+	/* Change adc internal resistor value for better pen detection,
+	 * default value is 100 kOhm.
+	 * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
+	 * option only available on ES2 and higher
+	 */
+	at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity
+			& AT91_ADC_ACR_PENDETSENS);
+
+	/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
+	st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US *
+			adc_clk_khz / 1000) - 1, 1);
+
+	return 0;
+}
+
+static int at91_ts_register(struct at91_adc_state *st,
+		struct platform_device *pdev)
+{
+	struct input_dev *input;
+	struct iio_dev *idev = iio_priv_to_dev(st);
+	int ret;
+
+	input = input_allocate_device();
+	if (!input) {
+		dev_err(&idev->dev, "Failed to allocate TS device!\n");
+		return -ENOMEM;
+	}
+
+	input->name = DRIVER_NAME;
+	input->id.bustype = BUS_HOST;
+	input->dev.parent = &pdev->dev;
+	input->open = atmel_ts_open;
+	input->close = atmel_ts_close;
+
+	__set_bit(EV_ABS, input->evbit);
+	__set_bit(EV_KEY, input->evbit);
+	__set_bit(BTN_TOUCH, input->keybit);
+	input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
+	input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
+	input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0);
+
+	st->ts_input = input;
+	input_set_drvdata(input, st);
+
+	ret = input_register_device(input);
+	if (ret)
+		input_free_device(st->ts_input);
+
+	return ret;
+}
+
+static void at91_ts_unregister(struct at91_adc_state *st)
+{
+	input_unregister_device(st->ts_input);
+}
+
 static int at91_adc_probe(struct platform_device *pdev)
 {
 	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
@@ -647,7 +952,7 @@ static int at91_adc_probe(struct platform_device *pdev)
 	at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
 	at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
 	ret = request_irq(st->irq,
-			  at91_adc_eoc_trigger,
+			  at91_adc_interrupt,
 			  0,
 			  pdev->dev.driver->name,
 			  idev);
@@ -692,6 +997,10 @@ static int at91_adc_probe(struct platform_device *pdev)
 	mstrclk = clk_get_rate(st->clk);
 	adc_clk = clk_get_rate(st->adc_clk);
 	adc_clk_khz = adc_clk / 1000;
+
+	dev_dbg(&pdev->dev, "Master clock is set as: %d Hz, adc_clk should set as: %d Hz\n",
+		mstrclk, adc_clk);
+
 	prsc = (mstrclk / (2 * adc_clk)) - 1;
 
 	if (!st->startup_time) {
@@ -728,30 +1037,52 @@ static int at91_adc_probe(struct platform_device *pdev)
 	init_waitqueue_head(&st->wq_data_avail);
 	mutex_init(&st->lock);
 
-	ret = at91_adc_buffer_init(idev);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
-		goto error_disable_adc_clk;
-	}
+	/*
+	 * Since touch screen will set trigger register as period trigger. So
+	 * when touch screen is enabled, then we have to disable hardware
+	 * trigger for classic adc.
+	 */
+	if (!st->touchscreen_type) {
+		ret = at91_adc_buffer_init(idev);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
+			goto error_disable_adc_clk;
+		}
 
-	ret = at91_adc_trigger_init(idev);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
-		goto error_unregister_buffer;
+		ret = at91_adc_trigger_init(idev);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
+			at91_adc_buffer_remove(idev);
+			goto error_disable_adc_clk;
+		}
+	} else {
+		if (!st->caps->has_tsmr) {
+			dev_err(&pdev->dev, "We don't support non-TSMR adc\n");
+			goto error_disable_adc_clk;
+		}
+
+		ret = at91_ts_register(st, pdev);
+		if (ret)
+			goto error_disable_adc_clk;
+
+		at91_ts_hw_init(st, adc_clk_khz);
 	}
 
 	ret = iio_device_register(idev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Couldn't register the device.\n");
-		goto error_remove_triggers;
+		goto error_iio_device_register;
 	}
 
 	return 0;
 
-error_remove_triggers:
-	at91_adc_trigger_remove(idev);
-error_unregister_buffer:
-	at91_adc_buffer_remove(idev);
+error_iio_device_register:
+	if (!st->touchscreen_type) {
+		at91_adc_trigger_remove(idev);
+		at91_adc_buffer_remove(idev);
+	} else {
+		at91_ts_unregister(st);
+	}
 error_disable_adc_clk:
 	clk_disable_unprepare(st->adc_clk);
 error_disable_clk:
@@ -770,8 +1101,12 @@ static int at91_adc_remove(struct platform_device *pdev)
 	struct at91_adc_state *st = iio_priv(idev);
 
 	iio_device_unregister(idev);
-	at91_adc_trigger_remove(idev);
-	at91_adc_buffer_remove(idev);
+	if (!st->touchscreen_type) {
+		at91_adc_trigger_remove(idev);
+		at91_adc_buffer_remove(idev);
+	} else {
+		at91_ts_unregister(st);
+	}
 	clk_disable_unprepare(st->adc_clk);
 	clk_disable_unprepare(st->clk);
 	free_irq(st->irq, idev);
@@ -795,6 +1130,7 @@ static struct at91_adc_caps at91sam9260_caps = {
 };
 
 static struct at91_adc_caps at91sam9g45_caps = {
+	.has_ts = true,
 	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
 	.num_channels = 8,
 	.registers = {
@@ -808,6 +1144,10 @@ static struct at91_adc_caps at91sam9g45_caps = {
 };
 
 static struct at91_adc_caps at91sam9x5_caps = {
+	.has_ts = true,
+	.has_tsmr = true,
+	.ts_filter_average = 3,
+	.ts_pen_detect_sensitivity = 2,
 	.calc_startup_ticks = calc_startup_ticks_9x5,
 	.num_channels = 12,
 	.registers = {
@@ -834,7 +1174,7 @@ static struct platform_driver at91_adc_driver = {
 	.probe = at91_adc_probe,
 	.remove = at91_adc_remove,
 	.driver = {
-		   .name = "at91_adc",
+		   .name = DRIVER_NAME,
 		   .of_match_table = of_match_ptr(at91_adc_dt_ids),
 	},
 };
-- 
1.7.10

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

* [resend][PATCH v3 6/6] iio: at91: introduce touch screen support in iio adc driver
@ 2013-08-28  7:45         ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-28  7:45 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, thomas.petazzoni, mark.rutland, b.brezillon,
	devicetree, Josh Wu, Dmitry Torokhov

AT91 ADC hardware integrate touch screen support. So this patch add touch
screen support for at91 adc iio driver.
To enable touch screen support in adc, you need to add the dt parameters:
  1. which type of touch are used? (4 or 5 wires), sample period time.
  2. correct pressure detect threshold value.

In the meantime, since touch screen will use a interal period trigger of adc,
so it is conflict to other hardware triggers. Driver will disable the hardware
trigger support if touch screen is enabled.

This driver has been tested in AT91SAM9X5-EK and SAMA5D3x-EK.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
CC: devicetree@vger.kernel.org
---
resend v3:
  Since [v3 5/6] is resended for compiling error fix. So rebase this patch

v2 --> v3:
  1. fix according to Dmitry's suggestion.

v1 --> v2:
  1. use the multiple compatible string for different IPs.
  2. hide the driver configuration in driver code instead of exposing them in dt.
     Such like sample period, pen detect debounce time and etc.
  3. add a new dt parameter: ts-pressure-threshold. this value is much related
     with different chips and boards.

 .../devicetree/bindings/arm/atmel-adc.txt          |    7 +
 arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
 drivers/iio/adc/at91_adc.c                         |  388 ++++++++++++++++++--
 3 files changed, 405 insertions(+), 24 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 0e65e01..d106146 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -23,6 +23,13 @@ Optional properties:
 		       resolution will be used.
   - atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion
   - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
+  - atmel,adc-ts-wires: Number of touch screen wires. Should be 4 or 5. If this
+                        value is set, then adc driver will enable touch screen
+                        support.
+    NOTE: when adc touch screen enabled, the adc hardware trigger will be
+          disabled. Since touch screen will occupied the trigger register.
+  - atmel,adc-ts-pressure-threshold: a pressure threshold for touchscreen. It
+                                     make touch detect more precision.
  
 Optional trigger Nodes:
   - Required properties:
diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
index 048a57f..c287307 100644
--- a/arch/arm/mach-at91/include/mach/at91_adc.h
+++ b/arch/arm/mach-at91/include/mach/at91_adc.h
@@ -60,14 +60,48 @@
 #define AT91_ADC_IER		0x24		/* Interrupt Enable Register */
 #define AT91_ADC_IDR		0x28		/* Interrupt Disable Register */
 #define AT91_ADC_IMR		0x2C		/* Interrupt Mask Register */
+#define		AT91_ADC_IER_PEN	(1 << 29)
+#define		AT91_ADC_IER_NOPEN	(1 << 30)
+#define		AT91_ADC_IER_XRDY	(1 << 20)
+#define		AT91_ADC_IER_YRDY	(1 << 21)
+#define		AT91_ADC_IER_PRDY	(1 << 22)
+#define		AT91_ADC_ISR_PENS	(1 << 31)
 
 #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
 #define		AT91_ADC_DATA		(0x3ff)
 
 #define AT91_ADC_CDR0_9X5	(0x50)			/* Channel Data Register 0 for 9X5 */
 
+#define AT91_ADC_ACR		0x94	/* Analog Control Register */
+#define		AT91_ADC_ACR_PENDETSENS	(0x3 << 0)	/* pull-up resistor */
+
+#define AT91_ADC_TSMR		0xB0
+#define		AT91_ADC_TSMR_TSMODE	(3 << 0)	/* Touch Screen Mode */
+#define			AT91_ADC_TSMR_TSMODE_NONE		(0 << 0)
+#define			AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS	(1 << 0)
+#define			AT91_ADC_TSMR_TSMODE_4WIRE_PRESS	(2 << 0)
+#define			AT91_ADC_TSMR_TSMODE_5WIRE		(3 << 0)
+#define		AT91_ADC_TSMR_TSAV	(3 << 4)	/* Averages samples */
+#define			AT91_ADC_TSMR_TSAV_(x)		((x) << 4)
+#define		AT91_ADC_TSMR_SCTIM	(0x0f << 16)	/* Switch closure time */
+#define		AT91_ADC_TSMR_PENDBC	(0x0f << 28)	/* Pen Debounce time */
+#define			AT91_ADC_TSMR_PENDBC_(x)	((x) << 28)
+#define		AT91_ADC_TSMR_NOTSDMA	(1 << 22)	/* No Touchscreen DMA */
+#define		AT91_ADC_TSMR_PENDET_DIS	(0 << 24)	/* Pen contact detection disable */
+#define		AT91_ADC_TSMR_PENDET_ENA	(1 << 24)	/* Pen contact detection enable */
+
+#define AT91_ADC_TSXPOSR	0xB4
+#define AT91_ADC_TSYPOSR	0xB8
+#define AT91_ADC_TSPRESSR	0xBC
+
 #define AT91_ADC_TRGR_9260	AT91_ADC_MR
 #define AT91_ADC_TRGR_9G45	0x08
 #define AT91_ADC_TRGR_9X5	0xC0
 
+/* Trigger Register bit field */
+#define		AT91_ADC_TRGR_TRGPER	(0xffff << 16)
+#define			AT91_ADC_TRGR_TRGPER_(x)	((x) << 16)
+#define		AT91_ADC_TRGR_TRGMOD	(0x7 << 0)
+#define			AT91_ADC_TRGR_MOD_PERIOD_TRIG	(5 << 0)
+
 #endif
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 0f4621a..beec9ae 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -11,6 +11,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
@@ -39,7 +40,23 @@
 #define at91_adc_writel(st, reg, val) \
 	(writel_relaxed(val, st->reg_base + reg))
 
+#define DRIVER_NAME		"at91_adc"
+#define MAX_POS_BITS		12
+
+#define TOUCH_SAMPLE_PERIOD_US		2000	/* 2ms */
+#define TOUCH_PEN_DETECT_DEBOUNCE_US	200
+
 struct at91_adc_caps {
+	bool	has_ts;		/* Support touch screen */
+	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
+	/*
+	 * Numbers of sampling data will be averaged. Can be 0~3.
+	 * Hardware can average (2 ^ ts_filter_average) sample data.
+	 */
+	u8	ts_filter_average;
+	/* Pen Detection input pull-up resistor, can be 0~3 */
+	u8	ts_pen_detect_sensitivity;
+
 	/* startup time calculate function */
 	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
 
@@ -47,6 +64,12 @@ struct at91_adc_caps {
 	struct at91_adc_reg_desc registers;
 };
 
+enum atmel_adc_ts_type {
+	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
+	ATMEL_ADC_TOUCHSCREEN_4WIRE = 4,
+	ATMEL_ADC_TOUCHSCREEN_5WIRE = 5,
+};
+
 struct at91_adc_state {
 	struct clk		*adc_clk;
 	u16			*buffer;
@@ -71,6 +94,26 @@ struct at91_adc_state {
 	bool			low_res;	/* the resolution corresponds to the lowest one */
 	wait_queue_head_t	wq_data_avail;
 	struct at91_adc_caps	*caps;
+
+	/*
+	 * Following ADC channels are shared by touchscreen:
+	 *
+	 * CH0 -- Touch screen XP/UL
+	 * CH1 -- Touch screen XM/UR
+	 * CH2 -- Touch screen YP/LL
+	 * CH3 -- Touch screen YM/Sense
+	 * CH4 -- Touch screen LR(5-wire only)
+	 *
+	 * The bitfields below represents the reserved channel in the
+	 * touchscreen mode.
+	 */
+#define CHAN_MASK_TOUCHSCREEN_4WIRE	(0xf << 0)
+#define CHAN_MASK_TOUCHSCREEN_5WIRE	(0x1f << 0)
+	enum atmel_adc_ts_type	touchscreen_type;
+	struct input_dev	*ts_input;
+
+	u16			ts_sample_period_val;
+	u32			ts_pressure_threshold;
 };
 
 static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
@@ -105,14 +148,10 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
+/* Handler for classic adc channel eoc trigger */
+void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
 {
-	struct iio_dev *idev = private;
 	struct at91_adc_state *st = iio_priv(idev);
-	u32 status = at91_adc_readl(st, st->registers->status_register);
-
-	if (!(status & st->registers->drdy_mask))
-		return IRQ_HANDLED;
 
 	if (iio_buffer_enabled(idev)) {
 		disable_irq_nosync(irq);
@@ -122,6 +161,115 @@ static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
 		st->done = true;
 		wake_up_interruptible(&st->wq_data_avail);
 	}
+}
+
+static int at91_ts_sample(struct at91_adc_state *st)
+{
+	unsigned int xscale, yscale, reg, z1, z2;
+	unsigned int x, y, pres, xpos, ypos;
+	unsigned int rxp = 1;
+	unsigned int factor = 1000;
+	struct iio_dev *idev = iio_priv_to_dev(st);
+
+	unsigned int xyz_mask_bits = st->res;
+	unsigned int xyz_mask = (1 << xyz_mask_bits) - 1;
+
+	/* calculate position */
+	/* x position = (x / xscale) * max, max = 2^MAX_POS_BITS - 1 */
+	reg = at91_adc_readl(st, AT91_ADC_TSXPOSR);
+	xpos = reg & xyz_mask;
+	x = (xpos << MAX_POS_BITS) - xpos;
+	xscale = (reg >> 16) & xyz_mask;
+	if (xscale == 0) {
+		dev_err(&idev->dev, "Error: xscale == 0!\n");
+		return -1;
+	}
+	x /= xscale;
+
+	/* y position = (y / yscale) * max, max = 2^MAX_POS_BITS - 1 */
+	reg = at91_adc_readl(st, AT91_ADC_TSYPOSR);
+	ypos = reg & xyz_mask;
+	y = (ypos << MAX_POS_BITS) - ypos;
+	yscale = (reg >> 16) & xyz_mask;
+	if (yscale == 0) {
+		dev_err(&idev->dev, "Error: yscale == 0!\n");
+		return -1;
+	}
+	y /= yscale;
+
+	/* calculate the pressure */
+	reg = at91_adc_readl(st, AT91_ADC_TSPRESSR);
+	z1 = reg & xyz_mask;
+	z2 = (reg >> 16) & xyz_mask;
+
+	if (z1 != 0)
+		pres = rxp * (x * factor / 1024) * (z2 * factor / z1 - factor)
+			/ factor;
+	else
+		pres = st->ts_pressure_threshold;	/* no pen contacted */
+
+	dev_dbg(&idev->dev, "xpos = %d, xscale = %d, ypos = %d, yscale = %d, z1 = %d, z2 = %d, press = %d\n",
+				xpos, xscale, ypos, yscale, z1, z2, pres);
+
+	if (pres < st->ts_pressure_threshold) {
+		dev_dbg(&idev->dev, "x = %d, y = %d, pressure = %d\n",
+					x, y, pres / factor);
+		input_report_abs(st->ts_input, ABS_X, x);
+		input_report_abs(st->ts_input, ABS_Y, y);
+		input_report_abs(st->ts_input, ABS_PRESSURE, pres);
+		input_report_key(st->ts_input, BTN_TOUCH, 1);
+		input_sync(st->ts_input);
+	} else {
+		dev_dbg(&idev->dev, "pressure too low: not reporting\n");
+	}
+
+	return 0;
+}
+
+static irqreturn_t at91_adc_interrupt(int irq, void *private)
+{
+	struct iio_dev *idev = private;
+	struct at91_adc_state *st = iio_priv(idev);
+	u32 status = at91_adc_readl(st, st->registers->status_register);
+	const uint32_t ts_data_irq_mask =
+		AT91_ADC_IER_XRDY |
+		AT91_ADC_IER_YRDY |
+		AT91_ADC_IER_PRDY;
+
+	if (status & st->registers->drdy_mask)
+		handle_adc_eoc_trigger(irq, idev);
+
+	if (status & AT91_ADC_IER_PEN) {
+		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
+		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_NOPEN |
+			ts_data_irq_mask);
+		/* Set up period trigger for sampling */
+		at91_adc_writel(st, st->registers->trigger_register,
+			AT91_ADC_TRGR_MOD_PERIOD_TRIG |
+			AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val));
+	} else if (status & AT91_ADC_IER_NOPEN) {
+		at91_adc_writel(st, st->registers->trigger_register, 0);
+		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_NOPEN |
+			ts_data_irq_mask);
+		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
+
+		input_report_key(st->ts_input, BTN_TOUCH, 0);
+		input_sync(st->ts_input);
+	} else if ((status & ts_data_irq_mask) == ts_data_irq_mask) {
+		/* Now all touchscreen data is ready */
+
+		if (status & AT91_ADC_ISR_PENS) {
+			/* validate data by pen contact */
+			at91_ts_sample(st);
+		} else {
+			/* triggered by event that is no pen contact, just read
+			 * them to clean the interrupt and discard all.
+			 */
+			at91_adc_readl(st, AT91_ADC_TSXPOSR);
+			at91_adc_readl(st, AT91_ADC_TSYPOSR);
+			at91_adc_readl(st, AT91_ADC_TSPRESSR);
+		}
+	}
 
 	return IRQ_HANDLED;
 }
@@ -131,6 +279,16 @@ static int at91_adc_channel_init(struct iio_dev *idev)
 	struct at91_adc_state *st = iio_priv(idev);
 	struct iio_chan_spec *chan_array, *timestamp;
 	int bit, idx = 0;
+	unsigned long rsvd_mask = 0;
+
+	/* If touchscreen is enable, then reserve the adc channels */
+	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
+		rsvd_mask = CHAN_MASK_TOUCHSCREEN_4WIRE;
+	else if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_5WIRE)
+		rsvd_mask = CHAN_MASK_TOUCHSCREEN_5WIRE;
+
+	/* set up the channel mask to reserve touchscreen channels */
+	st->channels_mask &= ~rsvd_mask;
 
 	idev->num_channels = bitmap_weight(&st->channels_mask,
 					   st->num_channels) + 1;
@@ -479,6 +637,39 @@ static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz)
 
 static const struct of_device_id at91_adc_dt_ids[];
 
+static int at91_adc_probe_dt_ts(struct device_node *node,
+	struct at91_adc_state *st, struct device *dev)
+{
+	int ret;
+	u32 prop;
+
+	ret = of_property_read_u32(node, "atmel,adc-ts-wires", &prop);
+	if (ret) {
+		dev_info(dev, "ADC Touch screen is disabled.\n");
+		return 0;
+	}
+
+	switch (prop) {
+	case 4:
+	case 5:
+		st->touchscreen_type = prop;
+		break;
+	default:
+		dev_err(dev, "Unsupported number of touchscreen wires (%d). Should be 4 or 5.\n", prop);
+		return -EINVAL;
+	}
+
+	prop = 0;
+	of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop);
+	st->ts_pressure_threshold = prop;
+	if (st->ts_pressure_threshold) {
+		return 0;
+	} else {
+		dev_err(dev, "Invalid pressure threshold for the touchscreen\n");
+		return -EINVAL;
+	}
+}
+
 static int at91_adc_probe_dt(struct at91_adc_state *st,
 			     struct platform_device *pdev)
 {
@@ -560,6 +751,12 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 		i++;
 	}
 
+	/* Check if touchscreen is supported. */
+	if (st->caps->has_ts)
+		return at91_adc_probe_dt_ts(node, st, &idev->dev);
+	else
+		dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n");
+
 	return 0;
 
 error_ret:
@@ -591,6 +788,114 @@ static const struct iio_info at91_adc_info = {
 	.read_raw = &at91_adc_read_raw,
 };
 
+/* Touchscreen related functions */
+static int atmel_ts_open(struct input_dev *dev)
+{
+	struct at91_adc_state *st = input_get_drvdata(dev);
+
+	at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
+	return 0;
+}
+
+static void atmel_ts_close(struct input_dev *dev)
+{
+	struct at91_adc_state *st = input_get_drvdata(dev);
+
+	at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
+}
+
+static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
+{
+	u32 reg = 0, pendbc;
+	int i = 0;
+
+	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
+		reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
+	else
+		reg = AT91_ADC_TSMR_TSMODE_5WIRE;
+
+	/* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid
+	 * pen detect noise.
+	 * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock
+	 */
+	pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / 1000, 1);
+
+	while (pendbc >> ++i)
+		;	/* Empty! Find the shift offset */
+	if (abs(pendbc - (1 << i)) < abs(pendbc - (1 << (i - 1))))
+		pendbc = i;
+	else
+		pendbc = i - 1;
+
+	if (st->caps->has_tsmr) {
+		reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average)
+				& AT91_ADC_TSMR_TSAV;
+		reg |= AT91_ADC_TSMR_PENDBC_(pendbc) & AT91_ADC_TSMR_PENDBC;
+		reg |= AT91_ADC_TSMR_NOTSDMA;
+		reg |= AT91_ADC_TSMR_PENDET_ENA;
+		reg |= 0x03 << 8;	/* TSFREQ, need bigger than TSAV */
+
+		at91_adc_writel(st, AT91_ADC_TSMR, reg);
+	} else {
+		/* TODO: for 9g45 which has no TSMR */
+	}
+
+	/* Change adc internal resistor value for better pen detection,
+	 * default value is 100 kOhm.
+	 * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
+	 * option only available on ES2 and higher
+	 */
+	at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity
+			& AT91_ADC_ACR_PENDETSENS);
+
+	/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
+	st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US *
+			adc_clk_khz / 1000) - 1, 1);
+
+	return 0;
+}
+
+static int at91_ts_register(struct at91_adc_state *st,
+		struct platform_device *pdev)
+{
+	struct input_dev *input;
+	struct iio_dev *idev = iio_priv_to_dev(st);
+	int ret;
+
+	input = input_allocate_device();
+	if (!input) {
+		dev_err(&idev->dev, "Failed to allocate TS device!\n");
+		return -ENOMEM;
+	}
+
+	input->name = DRIVER_NAME;
+	input->id.bustype = BUS_HOST;
+	input->dev.parent = &pdev->dev;
+	input->open = atmel_ts_open;
+	input->close = atmel_ts_close;
+
+	__set_bit(EV_ABS, input->evbit);
+	__set_bit(EV_KEY, input->evbit);
+	__set_bit(BTN_TOUCH, input->keybit);
+	input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
+	input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
+	input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0);
+
+	st->ts_input = input;
+	input_set_drvdata(input, st);
+
+	ret = input_register_device(input);
+	if (ret)
+		input_free_device(st->ts_input);
+
+	return ret;
+}
+
+static void at91_ts_unregister(struct at91_adc_state *st)
+{
+	input_unregister_device(st->ts_input);
+}
+
 static int at91_adc_probe(struct platform_device *pdev)
 {
 	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
@@ -647,7 +952,7 @@ static int at91_adc_probe(struct platform_device *pdev)
 	at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
 	at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
 	ret = request_irq(st->irq,
-			  at91_adc_eoc_trigger,
+			  at91_adc_interrupt,
 			  0,
 			  pdev->dev.driver->name,
 			  idev);
@@ -692,6 +997,10 @@ static int at91_adc_probe(struct platform_device *pdev)
 	mstrclk = clk_get_rate(st->clk);
 	adc_clk = clk_get_rate(st->adc_clk);
 	adc_clk_khz = adc_clk / 1000;
+
+	dev_dbg(&pdev->dev, "Master clock is set as: %d Hz, adc_clk should set as: %d Hz\n",
+		mstrclk, adc_clk);
+
 	prsc = (mstrclk / (2 * adc_clk)) - 1;
 
 	if (!st->startup_time) {
@@ -728,30 +1037,52 @@ static int at91_adc_probe(struct platform_device *pdev)
 	init_waitqueue_head(&st->wq_data_avail);
 	mutex_init(&st->lock);
 
-	ret = at91_adc_buffer_init(idev);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
-		goto error_disable_adc_clk;
-	}
+	/*
+	 * Since touch screen will set trigger register as period trigger. So
+	 * when touch screen is enabled, then we have to disable hardware
+	 * trigger for classic adc.
+	 */
+	if (!st->touchscreen_type) {
+		ret = at91_adc_buffer_init(idev);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
+			goto error_disable_adc_clk;
+		}
 
-	ret = at91_adc_trigger_init(idev);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
-		goto error_unregister_buffer;
+		ret = at91_adc_trigger_init(idev);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
+			at91_adc_buffer_remove(idev);
+			goto error_disable_adc_clk;
+		}
+	} else {
+		if (!st->caps->has_tsmr) {
+			dev_err(&pdev->dev, "We don't support non-TSMR adc\n");
+			goto error_disable_adc_clk;
+		}
+
+		ret = at91_ts_register(st, pdev);
+		if (ret)
+			goto error_disable_adc_clk;
+
+		at91_ts_hw_init(st, adc_clk_khz);
 	}
 
 	ret = iio_device_register(idev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Couldn't register the device.\n");
-		goto error_remove_triggers;
+		goto error_iio_device_register;
 	}
 
 	return 0;
 
-error_remove_triggers:
-	at91_adc_trigger_remove(idev);
-error_unregister_buffer:
-	at91_adc_buffer_remove(idev);
+error_iio_device_register:
+	if (!st->touchscreen_type) {
+		at91_adc_trigger_remove(idev);
+		at91_adc_buffer_remove(idev);
+	} else {
+		at91_ts_unregister(st);
+	}
 error_disable_adc_clk:
 	clk_disable_unprepare(st->adc_clk);
 error_disable_clk:
@@ -770,8 +1101,12 @@ static int at91_adc_remove(struct platform_device *pdev)
 	struct at91_adc_state *st = iio_priv(idev);
 
 	iio_device_unregister(idev);
-	at91_adc_trigger_remove(idev);
-	at91_adc_buffer_remove(idev);
+	if (!st->touchscreen_type) {
+		at91_adc_trigger_remove(idev);
+		at91_adc_buffer_remove(idev);
+	} else {
+		at91_ts_unregister(st);
+	}
 	clk_disable_unprepare(st->adc_clk);
 	clk_disable_unprepare(st->clk);
 	free_irq(st->irq, idev);
@@ -795,6 +1130,7 @@ static struct at91_adc_caps at91sam9260_caps = {
 };
 
 static struct at91_adc_caps at91sam9g45_caps = {
+	.has_ts = true,
 	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
 	.num_channels = 8,
 	.registers = {
@@ -808,6 +1144,10 @@ static struct at91_adc_caps at91sam9g45_caps = {
 };
 
 static struct at91_adc_caps at91sam9x5_caps = {
+	.has_ts = true,
+	.has_tsmr = true,
+	.ts_filter_average = 3,
+	.ts_pen_detect_sensitivity = 2,
 	.calc_startup_ticks = calc_startup_ticks_9x5,
 	.num_channels = 12,
 	.registers = {
@@ -834,7 +1174,7 @@ static struct platform_driver at91_adc_driver = {
 	.probe = at91_adc_probe,
 	.remove = at91_adc_remove,
 	.driver = {
-		   .name = "at91_adc",
+		   .name = DRIVER_NAME,
 		   .of_match_table = of_match_ptr(at91_adc_dt_ids),
 	},
 };
-- 
1.7.10

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

* [resend][PATCH v3 6/6] iio: at91: introduce touch screen support in iio adc driver
@ 2013-08-28  7:45         ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-08-28  7:45 UTC (permalink / raw)
  To: linux-arm-kernel

AT91 ADC hardware integrate touch screen support. So this patch add touch
screen support for at91 adc iio driver.
To enable touch screen support in adc, you need to add the dt parameters:
  1. which type of touch are used? (4 or 5 wires), sample period time.
  2. correct pressure detect threshold value.

In the meantime, since touch screen will use a interal period trigger of adc,
so it is conflict to other hardware triggers. Driver will disable the hardware
trigger support if touch screen is enabled.

This driver has been tested in AT91SAM9X5-EK and SAMA5D3x-EK.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
CC: devicetree at vger.kernel.org
---
resend v3:
  Since [v3 5/6] is resended for compiling error fix. So rebase this patch

v2 --> v3:
  1. fix according to Dmitry's suggestion.

v1 --> v2:
  1. use the multiple compatible string for different IPs.
  2. hide the driver configuration in driver code instead of exposing them in dt.
     Such like sample period, pen detect debounce time and etc.
  3. add a new dt parameter: ts-pressure-threshold. this value is much related
     with different chips and boards.

 .../devicetree/bindings/arm/atmel-adc.txt          |    7 +
 arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
 drivers/iio/adc/at91_adc.c                         |  388 ++++++++++++++++++--
 3 files changed, 405 insertions(+), 24 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 0e65e01..d106146 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -23,6 +23,13 @@ Optional properties:
 		       resolution will be used.
   - atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion
   - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
+  - atmel,adc-ts-wires: Number of touch screen wires. Should be 4 or 5. If this
+                        value is set, then adc driver will enable touch screen
+                        support.
+    NOTE: when adc touch screen enabled, the adc hardware trigger will be
+          disabled. Since touch screen will occupied the trigger register.
+  - atmel,adc-ts-pressure-threshold: a pressure threshold for touchscreen. It
+                                     make touch detect more precision.
  
 Optional trigger Nodes:
   - Required properties:
diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
index 048a57f..c287307 100644
--- a/arch/arm/mach-at91/include/mach/at91_adc.h
+++ b/arch/arm/mach-at91/include/mach/at91_adc.h
@@ -60,14 +60,48 @@
 #define AT91_ADC_IER		0x24		/* Interrupt Enable Register */
 #define AT91_ADC_IDR		0x28		/* Interrupt Disable Register */
 #define AT91_ADC_IMR		0x2C		/* Interrupt Mask Register */
+#define		AT91_ADC_IER_PEN	(1 << 29)
+#define		AT91_ADC_IER_NOPEN	(1 << 30)
+#define		AT91_ADC_IER_XRDY	(1 << 20)
+#define		AT91_ADC_IER_YRDY	(1 << 21)
+#define		AT91_ADC_IER_PRDY	(1 << 22)
+#define		AT91_ADC_ISR_PENS	(1 << 31)
 
 #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
 #define		AT91_ADC_DATA		(0x3ff)
 
 #define AT91_ADC_CDR0_9X5	(0x50)			/* Channel Data Register 0 for 9X5 */
 
+#define AT91_ADC_ACR		0x94	/* Analog Control Register */
+#define		AT91_ADC_ACR_PENDETSENS	(0x3 << 0)	/* pull-up resistor */
+
+#define AT91_ADC_TSMR		0xB0
+#define		AT91_ADC_TSMR_TSMODE	(3 << 0)	/* Touch Screen Mode */
+#define			AT91_ADC_TSMR_TSMODE_NONE		(0 << 0)
+#define			AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS	(1 << 0)
+#define			AT91_ADC_TSMR_TSMODE_4WIRE_PRESS	(2 << 0)
+#define			AT91_ADC_TSMR_TSMODE_5WIRE		(3 << 0)
+#define		AT91_ADC_TSMR_TSAV	(3 << 4)	/* Averages samples */
+#define			AT91_ADC_TSMR_TSAV_(x)		((x) << 4)
+#define		AT91_ADC_TSMR_SCTIM	(0x0f << 16)	/* Switch closure time */
+#define		AT91_ADC_TSMR_PENDBC	(0x0f << 28)	/* Pen Debounce time */
+#define			AT91_ADC_TSMR_PENDBC_(x)	((x) << 28)
+#define		AT91_ADC_TSMR_NOTSDMA	(1 << 22)	/* No Touchscreen DMA */
+#define		AT91_ADC_TSMR_PENDET_DIS	(0 << 24)	/* Pen contact detection disable */
+#define		AT91_ADC_TSMR_PENDET_ENA	(1 << 24)	/* Pen contact detection enable */
+
+#define AT91_ADC_TSXPOSR	0xB4
+#define AT91_ADC_TSYPOSR	0xB8
+#define AT91_ADC_TSPRESSR	0xBC
+
 #define AT91_ADC_TRGR_9260	AT91_ADC_MR
 #define AT91_ADC_TRGR_9G45	0x08
 #define AT91_ADC_TRGR_9X5	0xC0
 
+/* Trigger Register bit field */
+#define		AT91_ADC_TRGR_TRGPER	(0xffff << 16)
+#define			AT91_ADC_TRGR_TRGPER_(x)	((x) << 16)
+#define		AT91_ADC_TRGR_TRGMOD	(0x7 << 0)
+#define			AT91_ADC_TRGR_MOD_PERIOD_TRIG	(5 << 0)
+
 #endif
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 0f4621a..beec9ae 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -11,6 +11,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
@@ -39,7 +40,23 @@
 #define at91_adc_writel(st, reg, val) \
 	(writel_relaxed(val, st->reg_base + reg))
 
+#define DRIVER_NAME		"at91_adc"
+#define MAX_POS_BITS		12
+
+#define TOUCH_SAMPLE_PERIOD_US		2000	/* 2ms */
+#define TOUCH_PEN_DETECT_DEBOUNCE_US	200
+
 struct at91_adc_caps {
+	bool	has_ts;		/* Support touch screen */
+	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
+	/*
+	 * Numbers of sampling data will be averaged. Can be 0~3.
+	 * Hardware can average (2 ^ ts_filter_average) sample data.
+	 */
+	u8	ts_filter_average;
+	/* Pen Detection input pull-up resistor, can be 0~3 */
+	u8	ts_pen_detect_sensitivity;
+
 	/* startup time calculate function */
 	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
 
@@ -47,6 +64,12 @@ struct at91_adc_caps {
 	struct at91_adc_reg_desc registers;
 };
 
+enum atmel_adc_ts_type {
+	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
+	ATMEL_ADC_TOUCHSCREEN_4WIRE = 4,
+	ATMEL_ADC_TOUCHSCREEN_5WIRE = 5,
+};
+
 struct at91_adc_state {
 	struct clk		*adc_clk;
 	u16			*buffer;
@@ -71,6 +94,26 @@ struct at91_adc_state {
 	bool			low_res;	/* the resolution corresponds to the lowest one */
 	wait_queue_head_t	wq_data_avail;
 	struct at91_adc_caps	*caps;
+
+	/*
+	 * Following ADC channels are shared by touchscreen:
+	 *
+	 * CH0 -- Touch screen XP/UL
+	 * CH1 -- Touch screen XM/UR
+	 * CH2 -- Touch screen YP/LL
+	 * CH3 -- Touch screen YM/Sense
+	 * CH4 -- Touch screen LR(5-wire only)
+	 *
+	 * The bitfields below represents the reserved channel in the
+	 * touchscreen mode.
+	 */
+#define CHAN_MASK_TOUCHSCREEN_4WIRE	(0xf << 0)
+#define CHAN_MASK_TOUCHSCREEN_5WIRE	(0x1f << 0)
+	enum atmel_adc_ts_type	touchscreen_type;
+	struct input_dev	*ts_input;
+
+	u16			ts_sample_period_val;
+	u32			ts_pressure_threshold;
 };
 
 static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
@@ -105,14 +148,10 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
+/* Handler for classic adc channel eoc trigger */
+void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
 {
-	struct iio_dev *idev = private;
 	struct at91_adc_state *st = iio_priv(idev);
-	u32 status = at91_adc_readl(st, st->registers->status_register);
-
-	if (!(status & st->registers->drdy_mask))
-		return IRQ_HANDLED;
 
 	if (iio_buffer_enabled(idev)) {
 		disable_irq_nosync(irq);
@@ -122,6 +161,115 @@ static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
 		st->done = true;
 		wake_up_interruptible(&st->wq_data_avail);
 	}
+}
+
+static int at91_ts_sample(struct at91_adc_state *st)
+{
+	unsigned int xscale, yscale, reg, z1, z2;
+	unsigned int x, y, pres, xpos, ypos;
+	unsigned int rxp = 1;
+	unsigned int factor = 1000;
+	struct iio_dev *idev = iio_priv_to_dev(st);
+
+	unsigned int xyz_mask_bits = st->res;
+	unsigned int xyz_mask = (1 << xyz_mask_bits) - 1;
+
+	/* calculate position */
+	/* x position = (x / xscale) * max, max = 2^MAX_POS_BITS - 1 */
+	reg = at91_adc_readl(st, AT91_ADC_TSXPOSR);
+	xpos = reg & xyz_mask;
+	x = (xpos << MAX_POS_BITS) - xpos;
+	xscale = (reg >> 16) & xyz_mask;
+	if (xscale == 0) {
+		dev_err(&idev->dev, "Error: xscale == 0!\n");
+		return -1;
+	}
+	x /= xscale;
+
+	/* y position = (y / yscale) * max, max = 2^MAX_POS_BITS - 1 */
+	reg = at91_adc_readl(st, AT91_ADC_TSYPOSR);
+	ypos = reg & xyz_mask;
+	y = (ypos << MAX_POS_BITS) - ypos;
+	yscale = (reg >> 16) & xyz_mask;
+	if (yscale == 0) {
+		dev_err(&idev->dev, "Error: yscale == 0!\n");
+		return -1;
+	}
+	y /= yscale;
+
+	/* calculate the pressure */
+	reg = at91_adc_readl(st, AT91_ADC_TSPRESSR);
+	z1 = reg & xyz_mask;
+	z2 = (reg >> 16) & xyz_mask;
+
+	if (z1 != 0)
+		pres = rxp * (x * factor / 1024) * (z2 * factor / z1 - factor)
+			/ factor;
+	else
+		pres = st->ts_pressure_threshold;	/* no pen contacted */
+
+	dev_dbg(&idev->dev, "xpos = %d, xscale = %d, ypos = %d, yscale = %d, z1 = %d, z2 = %d, press = %d\n",
+				xpos, xscale, ypos, yscale, z1, z2, pres);
+
+	if (pres < st->ts_pressure_threshold) {
+		dev_dbg(&idev->dev, "x = %d, y = %d, pressure = %d\n",
+					x, y, pres / factor);
+		input_report_abs(st->ts_input, ABS_X, x);
+		input_report_abs(st->ts_input, ABS_Y, y);
+		input_report_abs(st->ts_input, ABS_PRESSURE, pres);
+		input_report_key(st->ts_input, BTN_TOUCH, 1);
+		input_sync(st->ts_input);
+	} else {
+		dev_dbg(&idev->dev, "pressure too low: not reporting\n");
+	}
+
+	return 0;
+}
+
+static irqreturn_t at91_adc_interrupt(int irq, void *private)
+{
+	struct iio_dev *idev = private;
+	struct at91_adc_state *st = iio_priv(idev);
+	u32 status = at91_adc_readl(st, st->registers->status_register);
+	const uint32_t ts_data_irq_mask =
+		AT91_ADC_IER_XRDY |
+		AT91_ADC_IER_YRDY |
+		AT91_ADC_IER_PRDY;
+
+	if (status & st->registers->drdy_mask)
+		handle_adc_eoc_trigger(irq, idev);
+
+	if (status & AT91_ADC_IER_PEN) {
+		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
+		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_NOPEN |
+			ts_data_irq_mask);
+		/* Set up period trigger for sampling */
+		at91_adc_writel(st, st->registers->trigger_register,
+			AT91_ADC_TRGR_MOD_PERIOD_TRIG |
+			AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val));
+	} else if (status & AT91_ADC_IER_NOPEN) {
+		at91_adc_writel(st, st->registers->trigger_register, 0);
+		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_NOPEN |
+			ts_data_irq_mask);
+		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
+
+		input_report_key(st->ts_input, BTN_TOUCH, 0);
+		input_sync(st->ts_input);
+	} else if ((status & ts_data_irq_mask) == ts_data_irq_mask) {
+		/* Now all touchscreen data is ready */
+
+		if (status & AT91_ADC_ISR_PENS) {
+			/* validate data by pen contact */
+			at91_ts_sample(st);
+		} else {
+			/* triggered by event that is no pen contact, just read
+			 * them to clean the interrupt and discard all.
+			 */
+			at91_adc_readl(st, AT91_ADC_TSXPOSR);
+			at91_adc_readl(st, AT91_ADC_TSYPOSR);
+			at91_adc_readl(st, AT91_ADC_TSPRESSR);
+		}
+	}
 
 	return IRQ_HANDLED;
 }
@@ -131,6 +279,16 @@ static int at91_adc_channel_init(struct iio_dev *idev)
 	struct at91_adc_state *st = iio_priv(idev);
 	struct iio_chan_spec *chan_array, *timestamp;
 	int bit, idx = 0;
+	unsigned long rsvd_mask = 0;
+
+	/* If touchscreen is enable, then reserve the adc channels */
+	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
+		rsvd_mask = CHAN_MASK_TOUCHSCREEN_4WIRE;
+	else if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_5WIRE)
+		rsvd_mask = CHAN_MASK_TOUCHSCREEN_5WIRE;
+
+	/* set up the channel mask to reserve touchscreen channels */
+	st->channels_mask &= ~rsvd_mask;
 
 	idev->num_channels = bitmap_weight(&st->channels_mask,
 					   st->num_channels) + 1;
@@ -479,6 +637,39 @@ static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz)
 
 static const struct of_device_id at91_adc_dt_ids[];
 
+static int at91_adc_probe_dt_ts(struct device_node *node,
+	struct at91_adc_state *st, struct device *dev)
+{
+	int ret;
+	u32 prop;
+
+	ret = of_property_read_u32(node, "atmel,adc-ts-wires", &prop);
+	if (ret) {
+		dev_info(dev, "ADC Touch screen is disabled.\n");
+		return 0;
+	}
+
+	switch (prop) {
+	case 4:
+	case 5:
+		st->touchscreen_type = prop;
+		break;
+	default:
+		dev_err(dev, "Unsupported number of touchscreen wires (%d). Should be 4 or 5.\n", prop);
+		return -EINVAL;
+	}
+
+	prop = 0;
+	of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop);
+	st->ts_pressure_threshold = prop;
+	if (st->ts_pressure_threshold) {
+		return 0;
+	} else {
+		dev_err(dev, "Invalid pressure threshold for the touchscreen\n");
+		return -EINVAL;
+	}
+}
+
 static int at91_adc_probe_dt(struct at91_adc_state *st,
 			     struct platform_device *pdev)
 {
@@ -560,6 +751,12 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 		i++;
 	}
 
+	/* Check if touchscreen is supported. */
+	if (st->caps->has_ts)
+		return at91_adc_probe_dt_ts(node, st, &idev->dev);
+	else
+		dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n");
+
 	return 0;
 
 error_ret:
@@ -591,6 +788,114 @@ static const struct iio_info at91_adc_info = {
 	.read_raw = &at91_adc_read_raw,
 };
 
+/* Touchscreen related functions */
+static int atmel_ts_open(struct input_dev *dev)
+{
+	struct at91_adc_state *st = input_get_drvdata(dev);
+
+	at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
+	return 0;
+}
+
+static void atmel_ts_close(struct input_dev *dev)
+{
+	struct at91_adc_state *st = input_get_drvdata(dev);
+
+	at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
+}
+
+static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
+{
+	u32 reg = 0, pendbc;
+	int i = 0;
+
+	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
+		reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
+	else
+		reg = AT91_ADC_TSMR_TSMODE_5WIRE;
+
+	/* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid
+	 * pen detect noise.
+	 * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock
+	 */
+	pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / 1000, 1);
+
+	while (pendbc >> ++i)
+		;	/* Empty! Find the shift offset */
+	if (abs(pendbc - (1 << i)) < abs(pendbc - (1 << (i - 1))))
+		pendbc = i;
+	else
+		pendbc = i - 1;
+
+	if (st->caps->has_tsmr) {
+		reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average)
+				& AT91_ADC_TSMR_TSAV;
+		reg |= AT91_ADC_TSMR_PENDBC_(pendbc) & AT91_ADC_TSMR_PENDBC;
+		reg |= AT91_ADC_TSMR_NOTSDMA;
+		reg |= AT91_ADC_TSMR_PENDET_ENA;
+		reg |= 0x03 << 8;	/* TSFREQ, need bigger than TSAV */
+
+		at91_adc_writel(st, AT91_ADC_TSMR, reg);
+	} else {
+		/* TODO: for 9g45 which has no TSMR */
+	}
+
+	/* Change adc internal resistor value for better pen detection,
+	 * default value is 100 kOhm.
+	 * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
+	 * option only available on ES2 and higher
+	 */
+	at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity
+			& AT91_ADC_ACR_PENDETSENS);
+
+	/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
+	st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US *
+			adc_clk_khz / 1000) - 1, 1);
+
+	return 0;
+}
+
+static int at91_ts_register(struct at91_adc_state *st,
+		struct platform_device *pdev)
+{
+	struct input_dev *input;
+	struct iio_dev *idev = iio_priv_to_dev(st);
+	int ret;
+
+	input = input_allocate_device();
+	if (!input) {
+		dev_err(&idev->dev, "Failed to allocate TS device!\n");
+		return -ENOMEM;
+	}
+
+	input->name = DRIVER_NAME;
+	input->id.bustype = BUS_HOST;
+	input->dev.parent = &pdev->dev;
+	input->open = atmel_ts_open;
+	input->close = atmel_ts_close;
+
+	__set_bit(EV_ABS, input->evbit);
+	__set_bit(EV_KEY, input->evbit);
+	__set_bit(BTN_TOUCH, input->keybit);
+	input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
+	input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
+	input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0);
+
+	st->ts_input = input;
+	input_set_drvdata(input, st);
+
+	ret = input_register_device(input);
+	if (ret)
+		input_free_device(st->ts_input);
+
+	return ret;
+}
+
+static void at91_ts_unregister(struct at91_adc_state *st)
+{
+	input_unregister_device(st->ts_input);
+}
+
 static int at91_adc_probe(struct platform_device *pdev)
 {
 	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
@@ -647,7 +952,7 @@ static int at91_adc_probe(struct platform_device *pdev)
 	at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
 	at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
 	ret = request_irq(st->irq,
-			  at91_adc_eoc_trigger,
+			  at91_adc_interrupt,
 			  0,
 			  pdev->dev.driver->name,
 			  idev);
@@ -692,6 +997,10 @@ static int at91_adc_probe(struct platform_device *pdev)
 	mstrclk = clk_get_rate(st->clk);
 	adc_clk = clk_get_rate(st->adc_clk);
 	adc_clk_khz = adc_clk / 1000;
+
+	dev_dbg(&pdev->dev, "Master clock is set as: %d Hz, adc_clk should set as: %d Hz\n",
+		mstrclk, adc_clk);
+
 	prsc = (mstrclk / (2 * adc_clk)) - 1;
 
 	if (!st->startup_time) {
@@ -728,30 +1037,52 @@ static int at91_adc_probe(struct platform_device *pdev)
 	init_waitqueue_head(&st->wq_data_avail);
 	mutex_init(&st->lock);
 
-	ret = at91_adc_buffer_init(idev);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
-		goto error_disable_adc_clk;
-	}
+	/*
+	 * Since touch screen will set trigger register as period trigger. So
+	 * when touch screen is enabled, then we have to disable hardware
+	 * trigger for classic adc.
+	 */
+	if (!st->touchscreen_type) {
+		ret = at91_adc_buffer_init(idev);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
+			goto error_disable_adc_clk;
+		}
 
-	ret = at91_adc_trigger_init(idev);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
-		goto error_unregister_buffer;
+		ret = at91_adc_trigger_init(idev);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
+			at91_adc_buffer_remove(idev);
+			goto error_disable_adc_clk;
+		}
+	} else {
+		if (!st->caps->has_tsmr) {
+			dev_err(&pdev->dev, "We don't support non-TSMR adc\n");
+			goto error_disable_adc_clk;
+		}
+
+		ret = at91_ts_register(st, pdev);
+		if (ret)
+			goto error_disable_adc_clk;
+
+		at91_ts_hw_init(st, adc_clk_khz);
 	}
 
 	ret = iio_device_register(idev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Couldn't register the device.\n");
-		goto error_remove_triggers;
+		goto error_iio_device_register;
 	}
 
 	return 0;
 
-error_remove_triggers:
-	at91_adc_trigger_remove(idev);
-error_unregister_buffer:
-	at91_adc_buffer_remove(idev);
+error_iio_device_register:
+	if (!st->touchscreen_type) {
+		at91_adc_trigger_remove(idev);
+		at91_adc_buffer_remove(idev);
+	} else {
+		at91_ts_unregister(st);
+	}
 error_disable_adc_clk:
 	clk_disable_unprepare(st->adc_clk);
 error_disable_clk:
@@ -770,8 +1101,12 @@ static int at91_adc_remove(struct platform_device *pdev)
 	struct at91_adc_state *st = iio_priv(idev);
 
 	iio_device_unregister(idev);
-	at91_adc_trigger_remove(idev);
-	at91_adc_buffer_remove(idev);
+	if (!st->touchscreen_type) {
+		at91_adc_trigger_remove(idev);
+		at91_adc_buffer_remove(idev);
+	} else {
+		at91_ts_unregister(st);
+	}
 	clk_disable_unprepare(st->adc_clk);
 	clk_disable_unprepare(st->clk);
 	free_irq(st->irq, idev);
@@ -795,6 +1130,7 @@ static struct at91_adc_caps at91sam9260_caps = {
 };
 
 static struct at91_adc_caps at91sam9g45_caps = {
+	.has_ts = true,
 	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
 	.num_channels = 8,
 	.registers = {
@@ -808,6 +1144,10 @@ static struct at91_adc_caps at91sam9g45_caps = {
 };
 
 static struct at91_adc_caps at91sam9x5_caps = {
+	.has_ts = true,
+	.has_tsmr = true,
+	.ts_filter_average = 3,
+	.ts_pen_detect_sensitivity = 2,
 	.calc_startup_ticks = calc_startup_ticks_9x5,
 	.num_channels = 12,
 	.registers = {
@@ -834,7 +1174,7 @@ static struct platform_driver at91_adc_driver = {
 	.probe = at91_adc_probe,
 	.remove = at91_adc_remove,
 	.driver = {
-		   .name = "at91_adc",
+		   .name = DRIVER_NAME,
 		   .of_match_table = of_match_ptr(at91_adc_dt_ids),
 	},
 };
-- 
1.7.10

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

* Re: [PATCH v3 2/6] iio: at91: introduce the multiple compatible string for different IPs.
  2013-08-27 11:28     ` Josh Wu
  (?)
@ 2013-08-28  8:02         ` Maxime Ripard
  -1 siblings, 0 replies; 55+ messages in thread
From: Maxime Ripard @ 2013-08-28  8:02 UTC (permalink / raw)
  To: Josh Wu
  Cc: jic23-KWPb1pKIrIJaa/9Udqfwiw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	plagnioj-sclMFOaUSTBWk0Htik3J/w,
	nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	mark.rutland-5wv7dgnIgG8, b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 546 bytes --]

Hi Josh,

On Tue, Aug 27, 2013 at 07:28:48PM +0800, Josh Wu wrote:
> As use the multiple compatible string, we can remove hardware register in dt.
> 
> CC: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Signed-off-by: Josh Wu <josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>

It's ok for me. You can add my
Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH v3 2/6] iio: at91: introduce the multiple compatible string for different IPs.
@ 2013-08-28  8:02         ` Maxime Ripard
  0 siblings, 0 replies; 55+ messages in thread
From: Maxime Ripard @ 2013-08-28  8:02 UTC (permalink / raw)
  To: Josh Wu
  Cc: jic23, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre,
	thomas.petazzoni, mark.rutland, b.brezillon, devicetree

[-- Attachment #1: Type: text/plain, Size: 461 bytes --]

Hi Josh,

On Tue, Aug 27, 2013 at 07:28:48PM +0800, Josh Wu wrote:
> As use the multiple compatible string, we can remove hardware register in dt.
> 
> CC: devicetree@vger.kernel.org
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

It's ok for me. You can add my
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* [PATCH v3 2/6] iio: at91: introduce the multiple compatible string for different IPs.
@ 2013-08-28  8:02         ` Maxime Ripard
  0 siblings, 0 replies; 55+ messages in thread
From: Maxime Ripard @ 2013-08-28  8:02 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Josh,

On Tue, Aug 27, 2013 at 07:28:48PM +0800, Josh Wu wrote:
> As use the multiple compatible string, we can remove hardware register in dt.
> 
> CC: devicetree at vger.kernel.org
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

It's ok for me. You can add my
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130828/76598e98/attachment.sig>

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

* Re: [resend][PATCH v3 5/6] iio: at91: move the num_channels from DT to driver itself
  2013-08-28  7:42         ` Josh Wu
  (?)
@ 2013-08-28  8:39             ` Maxime Ripard
  -1 siblings, 0 replies; 55+ messages in thread
From: Maxime Ripard @ 2013-08-28  8:39 UTC (permalink / raw)
  To: Josh Wu
  Cc: jic23-KWPb1pKIrIJaa/9Udqfwiw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	plagnioj-sclMFOaUSTBWk0Htik3J/w,
	nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	mark.rutland-5wv7dgnIgG8, b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 429 bytes --]

Hi Josh,

On Wed, Aug 28, 2013 at 03:42:50PM +0800, Josh Wu wrote:
> CC: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Signed-off-by: Josh Wu <josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>

Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [resend][PATCH v3 5/6] iio: at91: move the num_channels from DT to driver itself
@ 2013-08-28  8:39             ` Maxime Ripard
  0 siblings, 0 replies; 55+ messages in thread
From: Maxime Ripard @ 2013-08-28  8:39 UTC (permalink / raw)
  To: Josh Wu
  Cc: jic23, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre,
	thomas.petazzoni, mark.rutland, b.brezillon, devicetree

[-- Attachment #1: Type: text/plain, Size: 344 bytes --]

Hi Josh,

On Wed, Aug 28, 2013 at 03:42:50PM +0800, Josh Wu wrote:
> CC: devicetree@vger.kernel.org
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* [resend][PATCH v3 5/6] iio: at91: move the num_channels from DT to driver itself
@ 2013-08-28  8:39             ` Maxime Ripard
  0 siblings, 0 replies; 55+ messages in thread
From: Maxime Ripard @ 2013-08-28  8:39 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Josh,

On Wed, Aug 28, 2013 at 03:42:50PM +0800, Josh Wu wrote:
> CC: devicetree at vger.kernel.org
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130828/6e3f0f9a/attachment.sig>

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

* Re: [PATCH v3 3/6] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-08-27 11:28   ` Josh Wu
@ 2013-08-28  8:56     ` Maxime Ripard
  -1 siblings, 0 replies; 55+ messages in thread
From: Maxime Ripard @ 2013-08-28  8:56 UTC (permalink / raw)
  To: Josh Wu
  Cc: jic23, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre,
	thomas.petazzoni, mark.rutland, b.brezillon

[-- Attachment #1: Type: text/plain, Size: 443 bytes --]

Hi Josh,


On Tue, Aug 27, 2013 at 07:28:49PM +0800, Josh Wu wrote:
> For at91 boards, there are different IPs for adc. Different IPs has different
> STARTUP & PRESCAL mask in ADC_MR.
> 
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

It looks fine.

Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* [PATCH v3 3/6] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-08-28  8:56     ` Maxime Ripard
  0 siblings, 0 replies; 55+ messages in thread
From: Maxime Ripard @ 2013-08-28  8:56 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Josh,


On Tue, Aug 27, 2013 at 07:28:49PM +0800, Josh Wu wrote:
> For at91 boards, there are different IPs for adc. Different IPs has different
> STARTUP & PRESCAL mask in ADC_MR.
> 
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

It looks fine.

Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130828/182cee81/attachment.sig>

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

* Re: [PATCH v3 4/6] iio: at91: ADC start-up time calculation changed since at91sam9x5
  2013-08-27 11:28   ` Josh Wu
@ 2013-08-28  9:03     ` Maxime Ripard
  -1 siblings, 0 replies; 55+ messages in thread
From: Maxime Ripard @ 2013-08-28  9:03 UTC (permalink / raw)
  To: Josh Wu
  Cc: jic23, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre,
	thomas.petazzoni, mark.rutland, b.brezillon

[-- Attachment #1: Type: text/plain, Size: 501 bytes --]

Hi Josh,

On Tue, Aug 27, 2013 at 07:28:50PM +0800, Josh Wu wrote:
> Since in at91sam9x5, sama5d3x chip. the start up time calucation is changed.
> This patch can choose different start up time calculation formula for different
> chips.
> 
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Thanks for your work,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* [PATCH v3 4/6] iio: at91: ADC start-up time calculation changed since at91sam9x5
@ 2013-08-28  9:03     ` Maxime Ripard
  0 siblings, 0 replies; 55+ messages in thread
From: Maxime Ripard @ 2013-08-28  9:03 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Josh,

On Tue, Aug 27, 2013 at 07:28:50PM +0800, Josh Wu wrote:
> Since in at91sam9x5, sama5d3x chip. the start up time calucation is changed.
> This patch can choose different start up time calculation formula for different
> chips.
> 
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Thanks for your work,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130828/29aaa6f1/attachment.sig>

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

* Re: [PATCH v3 2/6] iio: at91: introduce the multiple compatible string for different IPs.
  2013-08-27 11:28     ` Josh Wu
                       ` (3 preceding siblings ...)
  (?)
@ 2013-08-28 13:25     ` Ludovic Desroches
  -1 siblings, 0 replies; 55+ messages in thread
From: Ludovic Desroches @ 2013-08-28 13:25 UTC (permalink / raw)
  To: Josh Wu
  Cc: thomas.petazzoni, mark.rutland, devicetree, linux-iio,
	nicolas.ferre, b.brezillon, jic23, maxime.ripard, plagnioj,
	linux-arm-kernel

On Tue, Aug 27, 2013 at 07:28:48PM +0800, Josh Wu wrote:
> As use the multiple compatible string, we can remove hardware register in dt.
> 
> CC: devicetree@vger.kernel.org
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>

> ---
>  .../devicetree/bindings/arm/atmel-adc.txt          |    7 +-
>  arch/arm/mach-at91/include/mach/at91_adc.h         |    9 +++
>  drivers/iio/adc/at91_adc.c                         |   79 ++++++++++----------
>  3 files changed, 52 insertions(+), 43 deletions(-)

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

* Re: [PATCH v3 2/6] iio: at91: introduce the multiple compatible string for different IPs.
  2013-08-27 11:28     ` Josh Wu
@ 2013-08-28 13:25       ` Ludovic Desroches
  -1 siblings, 0 replies; 55+ messages in thread
From: Ludovic Desroches @ 2013-08-28 13:25 UTC (permalink / raw)
  To: Josh Wu
  Cc: jic23, thomas.petazzoni, mark.rutland, devicetree, linux-iio,
	nicolas.ferre, b.brezillon, maxime.ripard, plagnioj,
	linux-arm-kernel

On Tue, Aug 27, 2013 at 07:28:48PM +0800, Josh Wu wrote:
> As use the multiple compatible string, we can remove hardware register in dt.
> 
> CC: devicetree@vger.kernel.org
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>

> ---
>  .../devicetree/bindings/arm/atmel-adc.txt          |    7 +-
>  arch/arm/mach-at91/include/mach/at91_adc.h         |    9 +++
>  drivers/iio/adc/at91_adc.c                         |   79 ++++++++++----------
>  3 files changed, 52 insertions(+), 43 deletions(-)

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

* [PATCH v3 2/6] iio: at91: introduce the multiple compatible string for different IPs.
@ 2013-08-28 13:25       ` Ludovic Desroches
  0 siblings, 0 replies; 55+ messages in thread
From: Ludovic Desroches @ 2013-08-28 13:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Aug 27, 2013 at 07:28:48PM +0800, Josh Wu wrote:
> As use the multiple compatible string, we can remove hardware register in dt.
> 
> CC: devicetree at vger.kernel.org
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>

> ---
>  .../devicetree/bindings/arm/atmel-adc.txt          |    7 +-
>  arch/arm/mach-at91/include/mach/at91_adc.h         |    9 +++
>  drivers/iio/adc/at91_adc.c                         |   79 ++++++++++----------
>  3 files changed, 52 insertions(+), 43 deletions(-)

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

* Re: [PATCH v3 5/6] iio: at91: move the num_channels from DT to driver itself
  2013-08-27 11:28     ` Josh Wu
                       ` (2 preceding siblings ...)
  (?)
@ 2013-08-28 13:27     ` Ludovic Desroches
  -1 siblings, 0 replies; 55+ messages in thread
From: Ludovic Desroches @ 2013-08-28 13:27 UTC (permalink / raw)
  To: Josh Wu
  Cc: thomas.petazzoni, mark.rutland, devicetree, linux-iio,
	nicolas.ferre, b.brezillon, jic23, maxime.ripard, plagnioj,
	linux-arm-kernel

On Tue, Aug 27, 2013 at 07:28:51PM +0800, Josh Wu wrote:
> CC: devicetree@vger.kernel.org
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>

> ---
>  Documentation/devicetree/bindings/arm/atmel-adc.txt |    1 -
>  drivers/iio/adc/at91_adc.c                          |   12 +++++-------
>  2 files changed, 5 insertions(+), 8 deletions(-)

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

* Re: [PATCH v3 5/6] iio: at91: move the num_channels from DT to driver itself
  2013-08-27 11:28     ` Josh Wu
@ 2013-08-28 13:27       ` Ludovic Desroches
  -1 siblings, 0 replies; 55+ messages in thread
From: Ludovic Desroches @ 2013-08-28 13:27 UTC (permalink / raw)
  To: Josh Wu
  Cc: jic23, thomas.petazzoni, mark.rutland, devicetree, linux-iio,
	nicolas.ferre, b.brezillon, maxime.ripard, plagnioj,
	linux-arm-kernel

On Tue, Aug 27, 2013 at 07:28:51PM +0800, Josh Wu wrote:
> CC: devicetree@vger.kernel.org
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>

> ---
>  Documentation/devicetree/bindings/arm/atmel-adc.txt |    1 -
>  drivers/iio/adc/at91_adc.c                          |   12 +++++-------
>  2 files changed, 5 insertions(+), 8 deletions(-)

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

* [PATCH v3 5/6] iio: at91: move the num_channels from DT to driver itself
@ 2013-08-28 13:27       ` Ludovic Desroches
  0 siblings, 0 replies; 55+ messages in thread
From: Ludovic Desroches @ 2013-08-28 13:27 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Aug 27, 2013 at 07:28:51PM +0800, Josh Wu wrote:
> CC: devicetree at vger.kernel.org
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>

> ---
>  Documentation/devicetree/bindings/arm/atmel-adc.txt |    1 -
>  drivers/iio/adc/at91_adc.c                          |   12 +++++-------
>  2 files changed, 5 insertions(+), 8 deletions(-)

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

* Re: [PATCH v3 1/6] iio: at91: fix adc_clk overflow
  2013-08-27 11:28   ` Josh Wu
@ 2013-08-29 20:43     ` Jonathan Cameron
  -1 siblings, 0 replies; 55+ messages in thread
From: Jonathan Cameron @ 2013-08-29 20:43 UTC (permalink / raw)
  To: Josh Wu
  Cc: jic23, linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, thomas.petazzoni, mark.rutland, b.brezillon

On 08/27/13 12:28, Josh Wu wrote:
> The adc_clk variable is currently defined using a 32-bits unsigned integer,
> which will overflow under some very valid range of operations.
> 
> Such overflow will occur if, for example, the parent clock is set to a
> 20MHz frequency and the ADC startup time is larger than 215ns.
> 
> To fix this, introduce an intermediate variable holding the clock rate
> in kHz.
> 
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Applied to the fixes-togreg branch of iio.git

Please in future separate out new stuff and fixes into separate series.
I tend to leave large series to review when I have time to do the whole
thing whereas little fixes in theory at least get picked up fast.

Thanks,

Jonathan
> ---
> v1 --> v2:
>   refined the commit message.
> 
>  drivers/iio/adc/at91_adc.c |   11 ++++++-----
>  1 file changed, 6 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index b6db6a0..9cf8ab5 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -582,7 +582,7 @@ static const struct iio_info at91_adc_info = {
>  
>  static int at91_adc_probe(struct platform_device *pdev)
>  {
> -	unsigned int prsc, mstrclk, ticks, adc_clk, shtim;
> +	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
>  	int ret;
>  	struct iio_dev *idev;
>  	struct at91_adc_state *st;
> @@ -680,6 +680,7 @@ static int at91_adc_probe(struct platform_device *pdev)
>  	 */
>  	mstrclk = clk_get_rate(st->clk);
>  	adc_clk = clk_get_rate(st->adc_clk);
> +	adc_clk_khz = adc_clk / 1000;
>  	prsc = (mstrclk / (2 * adc_clk)) - 1;
>  
>  	if (!st->startup_time) {
> @@ -693,15 +694,15 @@ static int at91_adc_probe(struct platform_device *pdev)
>  	 * defined in the electrical characteristics of the board, divided by 8.
>  	 * The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock
>  	 */
> -	ticks = round_up((st->startup_time * adc_clk /
> -			  1000000) - 1, 8) / 8;
> +	ticks = round_up((st->startup_time * adc_clk_khz /
> +			  1000) - 1, 8) / 8;
>  	/*
>  	 * a minimal Sample and Hold Time is necessary for the ADC to guarantee
>  	 * the best converted final value between two channels selection
>  	 * The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock
>  	 */
> -	shtim = round_up((st->sample_hold_time * adc_clk /
> -			  1000000) - 1, 1);
> +	shtim = round_up((st->sample_hold_time * adc_clk_khz /
> +			  1000) - 1, 1);
>  
>  	reg = AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL;
>  	reg |= AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP;
> 

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

* [PATCH v3 1/6] iio: at91: fix adc_clk overflow
@ 2013-08-29 20:43     ` Jonathan Cameron
  0 siblings, 0 replies; 55+ messages in thread
From: Jonathan Cameron @ 2013-08-29 20:43 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/27/13 12:28, Josh Wu wrote:
> The adc_clk variable is currently defined using a 32-bits unsigned integer,
> which will overflow under some very valid range of operations.
> 
> Such overflow will occur if, for example, the parent clock is set to a
> 20MHz frequency and the ADC startup time is larger than 215ns.
> 
> To fix this, introduce an intermediate variable holding the clock rate
> in kHz.
> 
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Applied to the fixes-togreg branch of iio.git

Please in future separate out new stuff and fixes into separate series.
I tend to leave large series to review when I have time to do the whole
thing whereas little fixes in theory at least get picked up fast.

Thanks,

Jonathan
> ---
> v1 --> v2:
>   refined the commit message.
> 
>  drivers/iio/adc/at91_adc.c |   11 ++++++-----
>  1 file changed, 6 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index b6db6a0..9cf8ab5 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -582,7 +582,7 @@ static const struct iio_info at91_adc_info = {
>  
>  static int at91_adc_probe(struct platform_device *pdev)
>  {
> -	unsigned int prsc, mstrclk, ticks, adc_clk, shtim;
> +	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
>  	int ret;
>  	struct iio_dev *idev;
>  	struct at91_adc_state *st;
> @@ -680,6 +680,7 @@ static int at91_adc_probe(struct platform_device *pdev)
>  	 */
>  	mstrclk = clk_get_rate(st->clk);
>  	adc_clk = clk_get_rate(st->adc_clk);
> +	adc_clk_khz = adc_clk / 1000;
>  	prsc = (mstrclk / (2 * adc_clk)) - 1;
>  
>  	if (!st->startup_time) {
> @@ -693,15 +694,15 @@ static int at91_adc_probe(struct platform_device *pdev)
>  	 * defined in the electrical characteristics of the board, divided by 8.
>  	 * The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock
>  	 */
> -	ticks = round_up((st->startup_time * adc_clk /
> -			  1000000) - 1, 8) / 8;
> +	ticks = round_up((st->startup_time * adc_clk_khz /
> +			  1000) - 1, 8) / 8;
>  	/*
>  	 * a minimal Sample and Hold Time is necessary for the ADC to guarantee
>  	 * the best converted final value between two channels selection
>  	 * The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock
>  	 */
> -	shtim = round_up((st->sample_hold_time * adc_clk /
> -			  1000000) - 1, 1);
> +	shtim = round_up((st->sample_hold_time * adc_clk_khz /
> +			  1000) - 1, 1);
>  
>  	reg = AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL;
>  	reg |= AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP;
> 

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

* Re: [PATCH v3 2/6] iio: at91: introduce the multiple compatible string for different IPs.
  2013-08-28  8:02         ` Maxime Ripard
  (?)
@ 2013-08-29 20:47           ` Jonathan Cameron
  -1 siblings, 0 replies; 55+ messages in thread
From: Jonathan Cameron @ 2013-08-29 20:47 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Josh Wu, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	plagnioj-sclMFOaUSTBWk0Htik3J/w,
	nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	mark.rutland-5wv7dgnIgG8, b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On 08/28/13 09:02, Maxime Ripard wrote:
> Hi Josh,
> 
> On Tue, Aug 27, 2013 at 07:28:48PM +0800, Josh Wu wrote:
>> As use the multiple compatible string, we can remove hardware register in dt.
>> 
>> CC: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org Signed-off-by: Josh Wu <josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
> 
> It's ok for me. You can add my Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
I've assumed for such and obviously good change that none of the devicetree
maintainers need to give an ack and applied this to the togreg branch of iio.git

Thanks,

Jonathan
> 
> Thanks! Maxime
> 

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

* Re: [PATCH v3 2/6] iio: at91: introduce the multiple compatible string for different IPs.
@ 2013-08-29 20:47           ` Jonathan Cameron
  0 siblings, 0 replies; 55+ messages in thread
From: Jonathan Cameron @ 2013-08-29 20:47 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Josh Wu, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre,
	thomas.petazzoni, mark.rutland, b.brezillon, devicetree

On 08/28/13 09:02, Maxime Ripard wrote:
> Hi Josh,
> 
> On Tue, Aug 27, 2013 at 07:28:48PM +0800, Josh Wu wrote:
>> As use the multiple compatible string, we can remove hardware register in dt.
>> 
>> CC: devicetree@vger.kernel.org Signed-off-by: Josh Wu <josh.wu@atmel.com>
> 
> It's ok for me. You can add my Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
I've assumed for such and obviously good change that none of the devicetree
maintainers need to give an ack and applied this to the togreg branch of iio.git

Thanks,

Jonathan
> 
> Thanks! Maxime
> 

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

* [PATCH v3 2/6] iio: at91: introduce the multiple compatible string for different IPs.
@ 2013-08-29 20:47           ` Jonathan Cameron
  0 siblings, 0 replies; 55+ messages in thread
From: Jonathan Cameron @ 2013-08-29 20:47 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/28/13 09:02, Maxime Ripard wrote:
> Hi Josh,
> 
> On Tue, Aug 27, 2013 at 07:28:48PM +0800, Josh Wu wrote:
>> As use the multiple compatible string, we can remove hardware register in dt.
>> 
>> CC: devicetree at vger.kernel.org Signed-off-by: Josh Wu <josh.wu@atmel.com>
> 
> It's ok for me. You can add my Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
I've assumed for such and obviously good change that none of the devicetree
maintainers need to give an ack and applied this to the togreg branch of iio.git

Thanks,

Jonathan
> 
> Thanks! Maxime
> 

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

* Re: [PATCH v3 3/6] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-08-28  8:56     ` Maxime Ripard
@ 2013-08-29 20:50       ` Jonathan Cameron
  -1 siblings, 0 replies; 55+ messages in thread
From: Jonathan Cameron @ 2013-08-29 20:50 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Josh Wu, jic23, linux-arm-kernel, linux-iio, plagnioj,
	nicolas.ferre, thomas.petazzoni, mark.rutland, b.brezillon

On 08/28/13 09:56, Maxime Ripard wrote:
> Hi Josh,
> 
> 
> On Tue, Aug 27, 2013 at 07:28:49PM +0800, Josh Wu wrote:
>> For at91 boards, there are different IPs for adc. Different IPs has different
>> STARTUP & PRESCAL mask in ADC_MR.
>>
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> 
> It looks fine.
> 
> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> 
> Maxime
> 
Note there was some fuzz with this one (because of taking the fix
via the other branch I would guess).  Hence please sanity check
it is fine when you have a minute.

Applied to the togreg branch of iio.git

Thanks,

Jonathan

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

* [PATCH v3 3/6] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-08-29 20:50       ` Jonathan Cameron
  0 siblings, 0 replies; 55+ messages in thread
From: Jonathan Cameron @ 2013-08-29 20:50 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/28/13 09:56, Maxime Ripard wrote:
> Hi Josh,
> 
> 
> On Tue, Aug 27, 2013 at 07:28:49PM +0800, Josh Wu wrote:
>> For at91 boards, there are different IPs for adc. Different IPs has different
>> STARTUP & PRESCAL mask in ADC_MR.
>>
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> 
> It looks fine.
> 
> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> 
> Maxime
> 
Note there was some fuzz with this one (because of taking the fix
via the other branch I would guess).  Hence please sanity check
it is fine when you have a minute.

Applied to the togreg branch of iio.git

Thanks,

Jonathan

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

* Re: [PATCH v3 4/6] iio: at91: ADC start-up time calculation changed since at91sam9x5
  2013-08-28  9:03     ` Maxime Ripard
@ 2013-08-29 21:00       ` Jonathan Cameron
  -1 siblings, 0 replies; 55+ messages in thread
From: Jonathan Cameron @ 2013-08-29 21:00 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Josh Wu, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre,
	thomas.petazzoni, mark.rutland, b.brezillon

On 08/28/13 10:03, Maxime Ripard wrote:
> Hi Josh,
> 
> On Tue, Aug 27, 2013 at 07:28:50PM +0800, Josh Wu wrote:
>> Since in at91sam9x5, sama5d3x chip. the start up time calucation is changed. This patch can choose different
>> start up time calculation formula for different chips.
>> 
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> 
> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> 
Unfortunately this one has a dependency on the fix patch which is going in through
my fixes branch so will have to wait until that hits my upstream.

I'd like 5 and 6 to sit a while longer anyway (and 6 needs Dmitry's sign off before
I take that.)

Thanks for these,

Jonathan

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

* [PATCH v3 4/6] iio: at91: ADC start-up time calculation changed since at91sam9x5
@ 2013-08-29 21:00       ` Jonathan Cameron
  0 siblings, 0 replies; 55+ messages in thread
From: Jonathan Cameron @ 2013-08-29 21:00 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/28/13 10:03, Maxime Ripard wrote:
> Hi Josh,
> 
> On Tue, Aug 27, 2013 at 07:28:50PM +0800, Josh Wu wrote:
>> Since in at91sam9x5, sama5d3x chip. the start up time calucation is changed. This patch can choose different
>> start up time calculation formula for different chips.
>> 
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> 
> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> 
Unfortunately this one has a dependency on the fix patch which is going in through
my fixes branch so will have to wait until that hits my upstream.

I'd like 5 and 6 to sit a while longer anyway (and 6 needs Dmitry's sign off before
I take that.)

Thanks for these,

Jonathan

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

* Re: [resend][PATCH v3 6/6] iio: at91: introduce touch screen support in iio adc driver
  2013-08-28  7:45         ` Josh Wu
  (?)
@ 2013-09-13  9:32             ` Josh Wu
  -1 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-09-13  9:32 UTC (permalink / raw)
  To: Josh Wu, Dmitry Torokhov
  Cc: jic23-KWPb1pKIrIJaa/9Udqfwiw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	plagnioj-sclMFOaUSTBWk0Htik3J/w,
	nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	mark.rutland-5wv7dgnIgG8, b.brezillon-ZNYIgs0QAGpBDgjK7y7TUQ,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Dear Dmitry Torokhov

Could you have any comments for this patch?

Best Regards,
Josh Wu

On 8/28/2013 3:45 PM, Josh Wu wrote:
> AT91 ADC hardware integrate touch screen support. So this patch add touch
> screen support for at91 adc iio driver.
> To enable touch screen support in adc, you need to add the dt parameters:
>    1. which type of touch are used? (4 or 5 wires), sample period time.
>    2. correct pressure detect threshold value.
>
> In the meantime, since touch screen will use a interal period trigger of adc,
> so it is conflict to other hardware triggers. Driver will disable the hardware
> trigger support if touch screen is enabled.
>
> This driver has been tested in AT91SAM9X5-EK and SAMA5D3x-EK.
>
> Signed-off-by: Josh Wu <josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
> Cc: Dmitry Torokhov <dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> CC: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> ---
> resend v3:
>    Since [v3 5/6] is resended for compiling error fix. So rebase this patch
>
> v2 --> v3:
>    1. fix according to Dmitry's suggestion.
>
> v1 --> v2:
>    1. use the multiple compatible string for different IPs.
>    2. hide the driver configuration in driver code instead of exposing them in dt.
>       Such like sample period, pen detect debounce time and etc.
>    3. add a new dt parameter: ts-pressure-threshold. this value is much related
>       with different chips and boards.
>
>   .../devicetree/bindings/arm/atmel-adc.txt          |    7 +
>   arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>   drivers/iio/adc/at91_adc.c                         |  388 ++++++++++++++++++--
>   3 files changed, 405 insertions(+), 24 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> index 0e65e01..d106146 100644
> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> @@ -23,6 +23,13 @@ Optional properties:
>   		       resolution will be used.
>     - atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion
>     - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
> +  - atmel,adc-ts-wires: Number of touch screen wires. Should be 4 or 5. If this
> +                        value is set, then adc driver will enable touch screen
> +                        support.
> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> +          disabled. Since touch screen will occupied the trigger register.
> +  - atmel,adc-ts-pressure-threshold: a pressure threshold for touchscreen. It
> +                                     make touch detect more precision.
>    
>   Optional trigger Nodes:
>     - Required properties:
> diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
> index 048a57f..c287307 100644
> --- a/arch/arm/mach-at91/include/mach/at91_adc.h
> +++ b/arch/arm/mach-at91/include/mach/at91_adc.h
> @@ -60,14 +60,48 @@
>   #define AT91_ADC_IER		0x24		/* Interrupt Enable Register */
>   #define AT91_ADC_IDR		0x28		/* Interrupt Disable Register */
>   #define AT91_ADC_IMR		0x2C		/* Interrupt Mask Register */
> +#define		AT91_ADC_IER_PEN	(1 << 29)
> +#define		AT91_ADC_IER_NOPEN	(1 << 30)
> +#define		AT91_ADC_IER_XRDY	(1 << 20)
> +#define		AT91_ADC_IER_YRDY	(1 << 21)
> +#define		AT91_ADC_IER_PRDY	(1 << 22)
> +#define		AT91_ADC_ISR_PENS	(1 << 31)
>   
>   #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
>   #define		AT91_ADC_DATA		(0x3ff)
>   
>   #define AT91_ADC_CDR0_9X5	(0x50)			/* Channel Data Register 0 for 9X5 */
>   
> +#define AT91_ADC_ACR		0x94	/* Analog Control Register */
> +#define		AT91_ADC_ACR_PENDETSENS	(0x3 << 0)	/* pull-up resistor */
> +
> +#define AT91_ADC_TSMR		0xB0
> +#define		AT91_ADC_TSMR_TSMODE	(3 << 0)	/* Touch Screen Mode */
> +#define			AT91_ADC_TSMR_TSMODE_NONE		(0 << 0)
> +#define			AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS	(1 << 0)
> +#define			AT91_ADC_TSMR_TSMODE_4WIRE_PRESS	(2 << 0)
> +#define			AT91_ADC_TSMR_TSMODE_5WIRE		(3 << 0)
> +#define		AT91_ADC_TSMR_TSAV	(3 << 4)	/* Averages samples */
> +#define			AT91_ADC_TSMR_TSAV_(x)		((x) << 4)
> +#define		AT91_ADC_TSMR_SCTIM	(0x0f << 16)	/* Switch closure time */
> +#define		AT91_ADC_TSMR_PENDBC	(0x0f << 28)	/* Pen Debounce time */
> +#define			AT91_ADC_TSMR_PENDBC_(x)	((x) << 28)
> +#define		AT91_ADC_TSMR_NOTSDMA	(1 << 22)	/* No Touchscreen DMA */
> +#define		AT91_ADC_TSMR_PENDET_DIS	(0 << 24)	/* Pen contact detection disable */
> +#define		AT91_ADC_TSMR_PENDET_ENA	(1 << 24)	/* Pen contact detection enable */
> +
> +#define AT91_ADC_TSXPOSR	0xB4
> +#define AT91_ADC_TSYPOSR	0xB8
> +#define AT91_ADC_TSPRESSR	0xBC
> +
>   #define AT91_ADC_TRGR_9260	AT91_ADC_MR
>   #define AT91_ADC_TRGR_9G45	0x08
>   #define AT91_ADC_TRGR_9X5	0xC0
>   
> +/* Trigger Register bit field */
> +#define		AT91_ADC_TRGR_TRGPER	(0xffff << 16)
> +#define			AT91_ADC_TRGR_TRGPER_(x)	((x) << 16)
> +#define		AT91_ADC_TRGR_TRGMOD	(0x7 << 0)
> +#define			AT91_ADC_TRGR_MOD_PERIOD_TRIG	(5 << 0)
> +
>   #endif
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index 0f4621a..beec9ae 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -11,6 +11,7 @@
>   #include <linux/clk.h>
>   #include <linux/err.h>
>   #include <linux/io.h>
> +#include <linux/input.h>
>   #include <linux/interrupt.h>
>   #include <linux/jiffies.h>
>   #include <linux/kernel.h>
> @@ -39,7 +40,23 @@
>   #define at91_adc_writel(st, reg, val) \
>   	(writel_relaxed(val, st->reg_base + reg))
>   
> +#define DRIVER_NAME		"at91_adc"
> +#define MAX_POS_BITS		12
> +
> +#define TOUCH_SAMPLE_PERIOD_US		2000	/* 2ms */
> +#define TOUCH_PEN_DETECT_DEBOUNCE_US	200
> +
>   struct at91_adc_caps {
> +	bool	has_ts;		/* Support touch screen */
> +	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
> +	/*
> +	 * Numbers of sampling data will be averaged. Can be 0~3.
> +	 * Hardware can average (2 ^ ts_filter_average) sample data.
> +	 */
> +	u8	ts_filter_average;
> +	/* Pen Detection input pull-up resistor, can be 0~3 */
> +	u8	ts_pen_detect_sensitivity;
> +
>   	/* startup time calculate function */
>   	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
>   
> @@ -47,6 +64,12 @@ struct at91_adc_caps {
>   	struct at91_adc_reg_desc registers;
>   };
>   
> +enum atmel_adc_ts_type {
> +	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
> +	ATMEL_ADC_TOUCHSCREEN_4WIRE = 4,
> +	ATMEL_ADC_TOUCHSCREEN_5WIRE = 5,
> +};
> +
>   struct at91_adc_state {
>   	struct clk		*adc_clk;
>   	u16			*buffer;
> @@ -71,6 +94,26 @@ struct at91_adc_state {
>   	bool			low_res;	/* the resolution corresponds to the lowest one */
>   	wait_queue_head_t	wq_data_avail;
>   	struct at91_adc_caps	*caps;
> +
> +	/*
> +	 * Following ADC channels are shared by touchscreen:
> +	 *
> +	 * CH0 -- Touch screen XP/UL
> +	 * CH1 -- Touch screen XM/UR
> +	 * CH2 -- Touch screen YP/LL
> +	 * CH3 -- Touch screen YM/Sense
> +	 * CH4 -- Touch screen LR(5-wire only)
> +	 *
> +	 * The bitfields below represents the reserved channel in the
> +	 * touchscreen mode.
> +	 */
> +#define CHAN_MASK_TOUCHSCREEN_4WIRE	(0xf << 0)
> +#define CHAN_MASK_TOUCHSCREEN_5WIRE	(0x1f << 0)
> +	enum atmel_adc_ts_type	touchscreen_type;
> +	struct input_dev	*ts_input;
> +
> +	u16			ts_sample_period_val;
> +	u32			ts_pressure_threshold;
>   };
>   
>   static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
> @@ -105,14 +148,10 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
>   	return IRQ_HANDLED;
>   }
>   
> -static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
> +/* Handler for classic adc channel eoc trigger */
> +void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
>   {
> -	struct iio_dev *idev = private;
>   	struct at91_adc_state *st = iio_priv(idev);
> -	u32 status = at91_adc_readl(st, st->registers->status_register);
> -
> -	if (!(status & st->registers->drdy_mask))
> -		return IRQ_HANDLED;
>   
>   	if (iio_buffer_enabled(idev)) {
>   		disable_irq_nosync(irq);
> @@ -122,6 +161,115 @@ static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
>   		st->done = true;
>   		wake_up_interruptible(&st->wq_data_avail);
>   	}
> +}
> +
> +static int at91_ts_sample(struct at91_adc_state *st)
> +{
> +	unsigned int xscale, yscale, reg, z1, z2;
> +	unsigned int x, y, pres, xpos, ypos;
> +	unsigned int rxp = 1;
> +	unsigned int factor = 1000;
> +	struct iio_dev *idev = iio_priv_to_dev(st);
> +
> +	unsigned int xyz_mask_bits = st->res;
> +	unsigned int xyz_mask = (1 << xyz_mask_bits) - 1;
> +
> +	/* calculate position */
> +	/* x position = (x / xscale) * max, max = 2^MAX_POS_BITS - 1 */
> +	reg = at91_adc_readl(st, AT91_ADC_TSXPOSR);
> +	xpos = reg & xyz_mask;
> +	x = (xpos << MAX_POS_BITS) - xpos;
> +	xscale = (reg >> 16) & xyz_mask;
> +	if (xscale == 0) {
> +		dev_err(&idev->dev, "Error: xscale == 0!\n");
> +		return -1;
> +	}
> +	x /= xscale;
> +
> +	/* y position = (y / yscale) * max, max = 2^MAX_POS_BITS - 1 */
> +	reg = at91_adc_readl(st, AT91_ADC_TSYPOSR);
> +	ypos = reg & xyz_mask;
> +	y = (ypos << MAX_POS_BITS) - ypos;
> +	yscale = (reg >> 16) & xyz_mask;
> +	if (yscale == 0) {
> +		dev_err(&idev->dev, "Error: yscale == 0!\n");
> +		return -1;
> +	}
> +	y /= yscale;
> +
> +	/* calculate the pressure */
> +	reg = at91_adc_readl(st, AT91_ADC_TSPRESSR);
> +	z1 = reg & xyz_mask;
> +	z2 = (reg >> 16) & xyz_mask;
> +
> +	if (z1 != 0)
> +		pres = rxp * (x * factor / 1024) * (z2 * factor / z1 - factor)
> +			/ factor;
> +	else
> +		pres = st->ts_pressure_threshold;	/* no pen contacted */
> +
> +	dev_dbg(&idev->dev, "xpos = %d, xscale = %d, ypos = %d, yscale = %d, z1 = %d, z2 = %d, press = %d\n",
> +				xpos, xscale, ypos, yscale, z1, z2, pres);
> +
> +	if (pres < st->ts_pressure_threshold) {
> +		dev_dbg(&idev->dev, "x = %d, y = %d, pressure = %d\n",
> +					x, y, pres / factor);
> +		input_report_abs(st->ts_input, ABS_X, x);
> +		input_report_abs(st->ts_input, ABS_Y, y);
> +		input_report_abs(st->ts_input, ABS_PRESSURE, pres);
> +		input_report_key(st->ts_input, BTN_TOUCH, 1);
> +		input_sync(st->ts_input);
> +	} else {
> +		dev_dbg(&idev->dev, "pressure too low: not reporting\n");
> +	}
> +
> +	return 0;
> +}
> +
> +static irqreturn_t at91_adc_interrupt(int irq, void *private)
> +{
> +	struct iio_dev *idev = private;
> +	struct at91_adc_state *st = iio_priv(idev);
> +	u32 status = at91_adc_readl(st, st->registers->status_register);
> +	const uint32_t ts_data_irq_mask =
> +		AT91_ADC_IER_XRDY |
> +		AT91_ADC_IER_YRDY |
> +		AT91_ADC_IER_PRDY;
> +
> +	if (status & st->registers->drdy_mask)
> +		handle_adc_eoc_trigger(irq, idev);
> +
> +	if (status & AT91_ADC_IER_PEN) {
> +		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
> +		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_NOPEN |
> +			ts_data_irq_mask);
> +		/* Set up period trigger for sampling */
> +		at91_adc_writel(st, st->registers->trigger_register,
> +			AT91_ADC_TRGR_MOD_PERIOD_TRIG |
> +			AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val));
> +	} else if (status & AT91_ADC_IER_NOPEN) {
> +		at91_adc_writel(st, st->registers->trigger_register, 0);
> +		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_NOPEN |
> +			ts_data_irq_mask);
> +		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
> +
> +		input_report_key(st->ts_input, BTN_TOUCH, 0);
> +		input_sync(st->ts_input);
> +	} else if ((status & ts_data_irq_mask) == ts_data_irq_mask) {
> +		/* Now all touchscreen data is ready */
> +
> +		if (status & AT91_ADC_ISR_PENS) {
> +			/* validate data by pen contact */
> +			at91_ts_sample(st);
> +		} else {
> +			/* triggered by event that is no pen contact, just read
> +			 * them to clean the interrupt and discard all.
> +			 */
> +			at91_adc_readl(st, AT91_ADC_TSXPOSR);
> +			at91_adc_readl(st, AT91_ADC_TSYPOSR);
> +			at91_adc_readl(st, AT91_ADC_TSPRESSR);
> +		}
> +	}
>   
>   	return IRQ_HANDLED;
>   }
> @@ -131,6 +279,16 @@ static int at91_adc_channel_init(struct iio_dev *idev)
>   	struct at91_adc_state *st = iio_priv(idev);
>   	struct iio_chan_spec *chan_array, *timestamp;
>   	int bit, idx = 0;
> +	unsigned long rsvd_mask = 0;
> +
> +	/* If touchscreen is enable, then reserve the adc channels */
> +	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
> +		rsvd_mask = CHAN_MASK_TOUCHSCREEN_4WIRE;
> +	else if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_5WIRE)
> +		rsvd_mask = CHAN_MASK_TOUCHSCREEN_5WIRE;
> +
> +	/* set up the channel mask to reserve touchscreen channels */
> +	st->channels_mask &= ~rsvd_mask;
>   
>   	idev->num_channels = bitmap_weight(&st->channels_mask,
>   					   st->num_channels) + 1;
> @@ -479,6 +637,39 @@ static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz)
>   
>   static const struct of_device_id at91_adc_dt_ids[];
>   
> +static int at91_adc_probe_dt_ts(struct device_node *node,
> +	struct at91_adc_state *st, struct device *dev)
> +{
> +	int ret;
> +	u32 prop;
> +
> +	ret = of_property_read_u32(node, "atmel,adc-ts-wires", &prop);
> +	if (ret) {
> +		dev_info(dev, "ADC Touch screen is disabled.\n");
> +		return 0;
> +	}
> +
> +	switch (prop) {
> +	case 4:
> +	case 5:
> +		st->touchscreen_type = prop;
> +		break;
> +	default:
> +		dev_err(dev, "Unsupported number of touchscreen wires (%d). Should be 4 or 5.\n", prop);
> +		return -EINVAL;
> +	}
> +
> +	prop = 0;
> +	of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop);
> +	st->ts_pressure_threshold = prop;
> +	if (st->ts_pressure_threshold) {
> +		return 0;
> +	} else {
> +		dev_err(dev, "Invalid pressure threshold for the touchscreen\n");
> +		return -EINVAL;
> +	}
> +}
> +
>   static int at91_adc_probe_dt(struct at91_adc_state *st,
>   			     struct platform_device *pdev)
>   {
> @@ -560,6 +751,12 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>   		i++;
>   	}
>   
> +	/* Check if touchscreen is supported. */
> +	if (st->caps->has_ts)
> +		return at91_adc_probe_dt_ts(node, st, &idev->dev);
> +	else
> +		dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n");
> +
>   	return 0;
>   
>   error_ret:
> @@ -591,6 +788,114 @@ static const struct iio_info at91_adc_info = {
>   	.read_raw = &at91_adc_read_raw,
>   };
>   
> +/* Touchscreen related functions */
> +static int atmel_ts_open(struct input_dev *dev)
> +{
> +	struct at91_adc_state *st = input_get_drvdata(dev);
> +
> +	at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
> +	return 0;
> +}
> +
> +static void atmel_ts_close(struct input_dev *dev)
> +{
> +	struct at91_adc_state *st = input_get_drvdata(dev);
> +
> +	at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
> +}
> +
> +static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
> +{
> +	u32 reg = 0, pendbc;
> +	int i = 0;
> +
> +	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
> +		reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
> +	else
> +		reg = AT91_ADC_TSMR_TSMODE_5WIRE;
> +
> +	/* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid
> +	 * pen detect noise.
> +	 * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock
> +	 */
> +	pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / 1000, 1);
> +
> +	while (pendbc >> ++i)
> +		;	/* Empty! Find the shift offset */
> +	if (abs(pendbc - (1 << i)) < abs(pendbc - (1 << (i - 1))))
> +		pendbc = i;
> +	else
> +		pendbc = i - 1;
> +
> +	if (st->caps->has_tsmr) {
> +		reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average)
> +				& AT91_ADC_TSMR_TSAV;
> +		reg |= AT91_ADC_TSMR_PENDBC_(pendbc) & AT91_ADC_TSMR_PENDBC;
> +		reg |= AT91_ADC_TSMR_NOTSDMA;
> +		reg |= AT91_ADC_TSMR_PENDET_ENA;
> +		reg |= 0x03 << 8;	/* TSFREQ, need bigger than TSAV */
> +
> +		at91_adc_writel(st, AT91_ADC_TSMR, reg);
> +	} else {
> +		/* TODO: for 9g45 which has no TSMR */
> +	}
> +
> +	/* Change adc internal resistor value for better pen detection,
> +	 * default value is 100 kOhm.
> +	 * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
> +	 * option only available on ES2 and higher
> +	 */
> +	at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity
> +			& AT91_ADC_ACR_PENDETSENS);
> +
> +	/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
> +	st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US *
> +			adc_clk_khz / 1000) - 1, 1);
> +
> +	return 0;
> +}
> +
> +static int at91_ts_register(struct at91_adc_state *st,
> +		struct platform_device *pdev)
> +{
> +	struct input_dev *input;
> +	struct iio_dev *idev = iio_priv_to_dev(st);
> +	int ret;
> +
> +	input = input_allocate_device();
> +	if (!input) {
> +		dev_err(&idev->dev, "Failed to allocate TS device!\n");
> +		return -ENOMEM;
> +	}
> +
> +	input->name = DRIVER_NAME;
> +	input->id.bustype = BUS_HOST;
> +	input->dev.parent = &pdev->dev;
> +	input->open = atmel_ts_open;
> +	input->close = atmel_ts_close;
> +
> +	__set_bit(EV_ABS, input->evbit);
> +	__set_bit(EV_KEY, input->evbit);
> +	__set_bit(BTN_TOUCH, input->keybit);
> +	input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
> +	input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
> +	input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0);
> +
> +	st->ts_input = input;
> +	input_set_drvdata(input, st);
> +
> +	ret = input_register_device(input);
> +	if (ret)
> +		input_free_device(st->ts_input);
> +
> +	return ret;
> +}
> +
> +static void at91_ts_unregister(struct at91_adc_state *st)
> +{
> +	input_unregister_device(st->ts_input);
> +}
> +
>   static int at91_adc_probe(struct platform_device *pdev)
>   {
>   	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
> @@ -647,7 +952,7 @@ static int at91_adc_probe(struct platform_device *pdev)
>   	at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
>   	at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
>   	ret = request_irq(st->irq,
> -			  at91_adc_eoc_trigger,
> +			  at91_adc_interrupt,
>   			  0,
>   			  pdev->dev.driver->name,
>   			  idev);
> @@ -692,6 +997,10 @@ static int at91_adc_probe(struct platform_device *pdev)
>   	mstrclk = clk_get_rate(st->clk);
>   	adc_clk = clk_get_rate(st->adc_clk);
>   	adc_clk_khz = adc_clk / 1000;
> +
> +	dev_dbg(&pdev->dev, "Master clock is set as: %d Hz, adc_clk should set as: %d Hz\n",
> +		mstrclk, adc_clk);
> +
>   	prsc = (mstrclk / (2 * adc_clk)) - 1;
>   
>   	if (!st->startup_time) {
> @@ -728,30 +1037,52 @@ static int at91_adc_probe(struct platform_device *pdev)
>   	init_waitqueue_head(&st->wq_data_avail);
>   	mutex_init(&st->lock);
>   
> -	ret = at91_adc_buffer_init(idev);
> -	if (ret < 0) {
> -		dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
> -		goto error_disable_adc_clk;
> -	}
> +	/*
> +	 * Since touch screen will set trigger register as period trigger. So
> +	 * when touch screen is enabled, then we have to disable hardware
> +	 * trigger for classic adc.
> +	 */
> +	if (!st->touchscreen_type) {
> +		ret = at91_adc_buffer_init(idev);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
> +			goto error_disable_adc_clk;
> +		}
>   
> -	ret = at91_adc_trigger_init(idev);
> -	if (ret < 0) {
> -		dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
> -		goto error_unregister_buffer;
> +		ret = at91_adc_trigger_init(idev);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
> +			at91_adc_buffer_remove(idev);
> +			goto error_disable_adc_clk;
> +		}
> +	} else {
> +		if (!st->caps->has_tsmr) {
> +			dev_err(&pdev->dev, "We don't support non-TSMR adc\n");
> +			goto error_disable_adc_clk;
> +		}
> +
> +		ret = at91_ts_register(st, pdev);
> +		if (ret)
> +			goto error_disable_adc_clk;
> +
> +		at91_ts_hw_init(st, adc_clk_khz);
>   	}
>   
>   	ret = iio_device_register(idev);
>   	if (ret < 0) {
>   		dev_err(&pdev->dev, "Couldn't register the device.\n");
> -		goto error_remove_triggers;
> +		goto error_iio_device_register;
>   	}
>   
>   	return 0;
>   
> -error_remove_triggers:
> -	at91_adc_trigger_remove(idev);
> -error_unregister_buffer:
> -	at91_adc_buffer_remove(idev);
> +error_iio_device_register:
> +	if (!st->touchscreen_type) {
> +		at91_adc_trigger_remove(idev);
> +		at91_adc_buffer_remove(idev);
> +	} else {
> +		at91_ts_unregister(st);
> +	}
>   error_disable_adc_clk:
>   	clk_disable_unprepare(st->adc_clk);
>   error_disable_clk:
> @@ -770,8 +1101,12 @@ static int at91_adc_remove(struct platform_device *pdev)
>   	struct at91_adc_state *st = iio_priv(idev);
>   
>   	iio_device_unregister(idev);
> -	at91_adc_trigger_remove(idev);
> -	at91_adc_buffer_remove(idev);
> +	if (!st->touchscreen_type) {
> +		at91_adc_trigger_remove(idev);
> +		at91_adc_buffer_remove(idev);
> +	} else {
> +		at91_ts_unregister(st);
> +	}
>   	clk_disable_unprepare(st->adc_clk);
>   	clk_disable_unprepare(st->clk);
>   	free_irq(st->irq, idev);
> @@ -795,6 +1130,7 @@ static struct at91_adc_caps at91sam9260_caps = {
>   };
>   
>   static struct at91_adc_caps at91sam9g45_caps = {
> +	.has_ts = true,
>   	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
>   	.num_channels = 8,
>   	.registers = {
> @@ -808,6 +1144,10 @@ static struct at91_adc_caps at91sam9g45_caps = {
>   };
>   
>   static struct at91_adc_caps at91sam9x5_caps = {
> +	.has_ts = true,
> +	.has_tsmr = true,
> +	.ts_filter_average = 3,
> +	.ts_pen_detect_sensitivity = 2,
>   	.calc_startup_ticks = calc_startup_ticks_9x5,
>   	.num_channels = 12,
>   	.registers = {
> @@ -834,7 +1174,7 @@ static struct platform_driver at91_adc_driver = {
>   	.probe = at91_adc_probe,
>   	.remove = at91_adc_remove,
>   	.driver = {
> -		   .name = "at91_adc",
> +		   .name = DRIVER_NAME,
>   		   .of_match_table = of_match_ptr(at91_adc_dt_ids),
>   	},
>   };

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

* Re: [resend][PATCH v3 6/6] iio: at91: introduce touch screen support in iio adc driver
@ 2013-09-13  9:32             ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-09-13  9:32 UTC (permalink / raw)
  To: Josh Wu, Dmitry Torokhov
  Cc: jic23, linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, thomas.petazzoni, mark.rutland, b.brezillon,
	devicetree

Dear Dmitry Torokhov

Could you have any comments for this patch?

Best Regards,
Josh Wu

On 8/28/2013 3:45 PM, Josh Wu wrote:
> AT91 ADC hardware integrate touch screen support. So this patch add touch
> screen support for at91 adc iio driver.
> To enable touch screen support in adc, you need to add the dt parameters:
>    1. which type of touch are used? (4 or 5 wires), sample period time.
>    2. correct pressure detect threshold value.
>
> In the meantime, since touch screen will use a interal period trigger of adc,
> so it is conflict to other hardware triggers. Driver will disable the hardware
> trigger support if touch screen is enabled.
>
> This driver has been tested in AT91SAM9X5-EK and SAMA5D3x-EK.
>
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> CC: devicetree@vger.kernel.org
> ---
> resend v3:
>    Since [v3 5/6] is resended for compiling error fix. So rebase this patch
>
> v2 --> v3:
>    1. fix according to Dmitry's suggestion.
>
> v1 --> v2:
>    1. use the multiple compatible string for different IPs.
>    2. hide the driver configuration in driver code instead of exposing them in dt.
>       Such like sample period, pen detect debounce time and etc.
>    3. add a new dt parameter: ts-pressure-threshold. this value is much related
>       with different chips and boards.
>
>   .../devicetree/bindings/arm/atmel-adc.txt          |    7 +
>   arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>   drivers/iio/adc/at91_adc.c                         |  388 ++++++++++++++++++--
>   3 files changed, 405 insertions(+), 24 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> index 0e65e01..d106146 100644
> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> @@ -23,6 +23,13 @@ Optional properties:
>   		       resolution will be used.
>     - atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion
>     - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
> +  - atmel,adc-ts-wires: Number of touch screen wires. Should be 4 or 5. If this
> +                        value is set, then adc driver will enable touch screen
> +                        support.
> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> +          disabled. Since touch screen will occupied the trigger register.
> +  - atmel,adc-ts-pressure-threshold: a pressure threshold for touchscreen. It
> +                                     make touch detect more precision.
>    
>   Optional trigger Nodes:
>     - Required properties:
> diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
> index 048a57f..c287307 100644
> --- a/arch/arm/mach-at91/include/mach/at91_adc.h
> +++ b/arch/arm/mach-at91/include/mach/at91_adc.h
> @@ -60,14 +60,48 @@
>   #define AT91_ADC_IER		0x24		/* Interrupt Enable Register */
>   #define AT91_ADC_IDR		0x28		/* Interrupt Disable Register */
>   #define AT91_ADC_IMR		0x2C		/* Interrupt Mask Register */
> +#define		AT91_ADC_IER_PEN	(1 << 29)
> +#define		AT91_ADC_IER_NOPEN	(1 << 30)
> +#define		AT91_ADC_IER_XRDY	(1 << 20)
> +#define		AT91_ADC_IER_YRDY	(1 << 21)
> +#define		AT91_ADC_IER_PRDY	(1 << 22)
> +#define		AT91_ADC_ISR_PENS	(1 << 31)
>   
>   #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
>   #define		AT91_ADC_DATA		(0x3ff)
>   
>   #define AT91_ADC_CDR0_9X5	(0x50)			/* Channel Data Register 0 for 9X5 */
>   
> +#define AT91_ADC_ACR		0x94	/* Analog Control Register */
> +#define		AT91_ADC_ACR_PENDETSENS	(0x3 << 0)	/* pull-up resistor */
> +
> +#define AT91_ADC_TSMR		0xB0
> +#define		AT91_ADC_TSMR_TSMODE	(3 << 0)	/* Touch Screen Mode */
> +#define			AT91_ADC_TSMR_TSMODE_NONE		(0 << 0)
> +#define			AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS	(1 << 0)
> +#define			AT91_ADC_TSMR_TSMODE_4WIRE_PRESS	(2 << 0)
> +#define			AT91_ADC_TSMR_TSMODE_5WIRE		(3 << 0)
> +#define		AT91_ADC_TSMR_TSAV	(3 << 4)	/* Averages samples */
> +#define			AT91_ADC_TSMR_TSAV_(x)		((x) << 4)
> +#define		AT91_ADC_TSMR_SCTIM	(0x0f << 16)	/* Switch closure time */
> +#define		AT91_ADC_TSMR_PENDBC	(0x0f << 28)	/* Pen Debounce time */
> +#define			AT91_ADC_TSMR_PENDBC_(x)	((x) << 28)
> +#define		AT91_ADC_TSMR_NOTSDMA	(1 << 22)	/* No Touchscreen DMA */
> +#define		AT91_ADC_TSMR_PENDET_DIS	(0 << 24)	/* Pen contact detection disable */
> +#define		AT91_ADC_TSMR_PENDET_ENA	(1 << 24)	/* Pen contact detection enable */
> +
> +#define AT91_ADC_TSXPOSR	0xB4
> +#define AT91_ADC_TSYPOSR	0xB8
> +#define AT91_ADC_TSPRESSR	0xBC
> +
>   #define AT91_ADC_TRGR_9260	AT91_ADC_MR
>   #define AT91_ADC_TRGR_9G45	0x08
>   #define AT91_ADC_TRGR_9X5	0xC0
>   
> +/* Trigger Register bit field */
> +#define		AT91_ADC_TRGR_TRGPER	(0xffff << 16)
> +#define			AT91_ADC_TRGR_TRGPER_(x)	((x) << 16)
> +#define		AT91_ADC_TRGR_TRGMOD	(0x7 << 0)
> +#define			AT91_ADC_TRGR_MOD_PERIOD_TRIG	(5 << 0)
> +
>   #endif
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index 0f4621a..beec9ae 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -11,6 +11,7 @@
>   #include <linux/clk.h>
>   #include <linux/err.h>
>   #include <linux/io.h>
> +#include <linux/input.h>
>   #include <linux/interrupt.h>
>   #include <linux/jiffies.h>
>   #include <linux/kernel.h>
> @@ -39,7 +40,23 @@
>   #define at91_adc_writel(st, reg, val) \
>   	(writel_relaxed(val, st->reg_base + reg))
>   
> +#define DRIVER_NAME		"at91_adc"
> +#define MAX_POS_BITS		12
> +
> +#define TOUCH_SAMPLE_PERIOD_US		2000	/* 2ms */
> +#define TOUCH_PEN_DETECT_DEBOUNCE_US	200
> +
>   struct at91_adc_caps {
> +	bool	has_ts;		/* Support touch screen */
> +	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
> +	/*
> +	 * Numbers of sampling data will be averaged. Can be 0~3.
> +	 * Hardware can average (2 ^ ts_filter_average) sample data.
> +	 */
> +	u8	ts_filter_average;
> +	/* Pen Detection input pull-up resistor, can be 0~3 */
> +	u8	ts_pen_detect_sensitivity;
> +
>   	/* startup time calculate function */
>   	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
>   
> @@ -47,6 +64,12 @@ struct at91_adc_caps {
>   	struct at91_adc_reg_desc registers;
>   };
>   
> +enum atmel_adc_ts_type {
> +	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
> +	ATMEL_ADC_TOUCHSCREEN_4WIRE = 4,
> +	ATMEL_ADC_TOUCHSCREEN_5WIRE = 5,
> +};
> +
>   struct at91_adc_state {
>   	struct clk		*adc_clk;
>   	u16			*buffer;
> @@ -71,6 +94,26 @@ struct at91_adc_state {
>   	bool			low_res;	/* the resolution corresponds to the lowest one */
>   	wait_queue_head_t	wq_data_avail;
>   	struct at91_adc_caps	*caps;
> +
> +	/*
> +	 * Following ADC channels are shared by touchscreen:
> +	 *
> +	 * CH0 -- Touch screen XP/UL
> +	 * CH1 -- Touch screen XM/UR
> +	 * CH2 -- Touch screen YP/LL
> +	 * CH3 -- Touch screen YM/Sense
> +	 * CH4 -- Touch screen LR(5-wire only)
> +	 *
> +	 * The bitfields below represents the reserved channel in the
> +	 * touchscreen mode.
> +	 */
> +#define CHAN_MASK_TOUCHSCREEN_4WIRE	(0xf << 0)
> +#define CHAN_MASK_TOUCHSCREEN_5WIRE	(0x1f << 0)
> +	enum atmel_adc_ts_type	touchscreen_type;
> +	struct input_dev	*ts_input;
> +
> +	u16			ts_sample_period_val;
> +	u32			ts_pressure_threshold;
>   };
>   
>   static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
> @@ -105,14 +148,10 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
>   	return IRQ_HANDLED;
>   }
>   
> -static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
> +/* Handler for classic adc channel eoc trigger */
> +void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
>   {
> -	struct iio_dev *idev = private;
>   	struct at91_adc_state *st = iio_priv(idev);
> -	u32 status = at91_adc_readl(st, st->registers->status_register);
> -
> -	if (!(status & st->registers->drdy_mask))
> -		return IRQ_HANDLED;
>   
>   	if (iio_buffer_enabled(idev)) {
>   		disable_irq_nosync(irq);
> @@ -122,6 +161,115 @@ static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
>   		st->done = true;
>   		wake_up_interruptible(&st->wq_data_avail);
>   	}
> +}
> +
> +static int at91_ts_sample(struct at91_adc_state *st)
> +{
> +	unsigned int xscale, yscale, reg, z1, z2;
> +	unsigned int x, y, pres, xpos, ypos;
> +	unsigned int rxp = 1;
> +	unsigned int factor = 1000;
> +	struct iio_dev *idev = iio_priv_to_dev(st);
> +
> +	unsigned int xyz_mask_bits = st->res;
> +	unsigned int xyz_mask = (1 << xyz_mask_bits) - 1;
> +
> +	/* calculate position */
> +	/* x position = (x / xscale) * max, max = 2^MAX_POS_BITS - 1 */
> +	reg = at91_adc_readl(st, AT91_ADC_TSXPOSR);
> +	xpos = reg & xyz_mask;
> +	x = (xpos << MAX_POS_BITS) - xpos;
> +	xscale = (reg >> 16) & xyz_mask;
> +	if (xscale == 0) {
> +		dev_err(&idev->dev, "Error: xscale == 0!\n");
> +		return -1;
> +	}
> +	x /= xscale;
> +
> +	/* y position = (y / yscale) * max, max = 2^MAX_POS_BITS - 1 */
> +	reg = at91_adc_readl(st, AT91_ADC_TSYPOSR);
> +	ypos = reg & xyz_mask;
> +	y = (ypos << MAX_POS_BITS) - ypos;
> +	yscale = (reg >> 16) & xyz_mask;
> +	if (yscale == 0) {
> +		dev_err(&idev->dev, "Error: yscale == 0!\n");
> +		return -1;
> +	}
> +	y /= yscale;
> +
> +	/* calculate the pressure */
> +	reg = at91_adc_readl(st, AT91_ADC_TSPRESSR);
> +	z1 = reg & xyz_mask;
> +	z2 = (reg >> 16) & xyz_mask;
> +
> +	if (z1 != 0)
> +		pres = rxp * (x * factor / 1024) * (z2 * factor / z1 - factor)
> +			/ factor;
> +	else
> +		pres = st->ts_pressure_threshold;	/* no pen contacted */
> +
> +	dev_dbg(&idev->dev, "xpos = %d, xscale = %d, ypos = %d, yscale = %d, z1 = %d, z2 = %d, press = %d\n",
> +				xpos, xscale, ypos, yscale, z1, z2, pres);
> +
> +	if (pres < st->ts_pressure_threshold) {
> +		dev_dbg(&idev->dev, "x = %d, y = %d, pressure = %d\n",
> +					x, y, pres / factor);
> +		input_report_abs(st->ts_input, ABS_X, x);
> +		input_report_abs(st->ts_input, ABS_Y, y);
> +		input_report_abs(st->ts_input, ABS_PRESSURE, pres);
> +		input_report_key(st->ts_input, BTN_TOUCH, 1);
> +		input_sync(st->ts_input);
> +	} else {
> +		dev_dbg(&idev->dev, "pressure too low: not reporting\n");
> +	}
> +
> +	return 0;
> +}
> +
> +static irqreturn_t at91_adc_interrupt(int irq, void *private)
> +{
> +	struct iio_dev *idev = private;
> +	struct at91_adc_state *st = iio_priv(idev);
> +	u32 status = at91_adc_readl(st, st->registers->status_register);
> +	const uint32_t ts_data_irq_mask =
> +		AT91_ADC_IER_XRDY |
> +		AT91_ADC_IER_YRDY |
> +		AT91_ADC_IER_PRDY;
> +
> +	if (status & st->registers->drdy_mask)
> +		handle_adc_eoc_trigger(irq, idev);
> +
> +	if (status & AT91_ADC_IER_PEN) {
> +		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
> +		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_NOPEN |
> +			ts_data_irq_mask);
> +		/* Set up period trigger for sampling */
> +		at91_adc_writel(st, st->registers->trigger_register,
> +			AT91_ADC_TRGR_MOD_PERIOD_TRIG |
> +			AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val));
> +	} else if (status & AT91_ADC_IER_NOPEN) {
> +		at91_adc_writel(st, st->registers->trigger_register, 0);
> +		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_NOPEN |
> +			ts_data_irq_mask);
> +		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
> +
> +		input_report_key(st->ts_input, BTN_TOUCH, 0);
> +		input_sync(st->ts_input);
> +	} else if ((status & ts_data_irq_mask) == ts_data_irq_mask) {
> +		/* Now all touchscreen data is ready */
> +
> +		if (status & AT91_ADC_ISR_PENS) {
> +			/* validate data by pen contact */
> +			at91_ts_sample(st);
> +		} else {
> +			/* triggered by event that is no pen contact, just read
> +			 * them to clean the interrupt and discard all.
> +			 */
> +			at91_adc_readl(st, AT91_ADC_TSXPOSR);
> +			at91_adc_readl(st, AT91_ADC_TSYPOSR);
> +			at91_adc_readl(st, AT91_ADC_TSPRESSR);
> +		}
> +	}
>   
>   	return IRQ_HANDLED;
>   }
> @@ -131,6 +279,16 @@ static int at91_adc_channel_init(struct iio_dev *idev)
>   	struct at91_adc_state *st = iio_priv(idev);
>   	struct iio_chan_spec *chan_array, *timestamp;
>   	int bit, idx = 0;
> +	unsigned long rsvd_mask = 0;
> +
> +	/* If touchscreen is enable, then reserve the adc channels */
> +	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
> +		rsvd_mask = CHAN_MASK_TOUCHSCREEN_4WIRE;
> +	else if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_5WIRE)
> +		rsvd_mask = CHAN_MASK_TOUCHSCREEN_5WIRE;
> +
> +	/* set up the channel mask to reserve touchscreen channels */
> +	st->channels_mask &= ~rsvd_mask;
>   
>   	idev->num_channels = bitmap_weight(&st->channels_mask,
>   					   st->num_channels) + 1;
> @@ -479,6 +637,39 @@ static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz)
>   
>   static const struct of_device_id at91_adc_dt_ids[];
>   
> +static int at91_adc_probe_dt_ts(struct device_node *node,
> +	struct at91_adc_state *st, struct device *dev)
> +{
> +	int ret;
> +	u32 prop;
> +
> +	ret = of_property_read_u32(node, "atmel,adc-ts-wires", &prop);
> +	if (ret) {
> +		dev_info(dev, "ADC Touch screen is disabled.\n");
> +		return 0;
> +	}
> +
> +	switch (prop) {
> +	case 4:
> +	case 5:
> +		st->touchscreen_type = prop;
> +		break;
> +	default:
> +		dev_err(dev, "Unsupported number of touchscreen wires (%d). Should be 4 or 5.\n", prop);
> +		return -EINVAL;
> +	}
> +
> +	prop = 0;
> +	of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop);
> +	st->ts_pressure_threshold = prop;
> +	if (st->ts_pressure_threshold) {
> +		return 0;
> +	} else {
> +		dev_err(dev, "Invalid pressure threshold for the touchscreen\n");
> +		return -EINVAL;
> +	}
> +}
> +
>   static int at91_adc_probe_dt(struct at91_adc_state *st,
>   			     struct platform_device *pdev)
>   {
> @@ -560,6 +751,12 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>   		i++;
>   	}
>   
> +	/* Check if touchscreen is supported. */
> +	if (st->caps->has_ts)
> +		return at91_adc_probe_dt_ts(node, st, &idev->dev);
> +	else
> +		dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n");
> +
>   	return 0;
>   
>   error_ret:
> @@ -591,6 +788,114 @@ static const struct iio_info at91_adc_info = {
>   	.read_raw = &at91_adc_read_raw,
>   };
>   
> +/* Touchscreen related functions */
> +static int atmel_ts_open(struct input_dev *dev)
> +{
> +	struct at91_adc_state *st = input_get_drvdata(dev);
> +
> +	at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
> +	return 0;
> +}
> +
> +static void atmel_ts_close(struct input_dev *dev)
> +{
> +	struct at91_adc_state *st = input_get_drvdata(dev);
> +
> +	at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
> +}
> +
> +static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
> +{
> +	u32 reg = 0, pendbc;
> +	int i = 0;
> +
> +	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
> +		reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
> +	else
> +		reg = AT91_ADC_TSMR_TSMODE_5WIRE;
> +
> +	/* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid
> +	 * pen detect noise.
> +	 * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock
> +	 */
> +	pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / 1000, 1);
> +
> +	while (pendbc >> ++i)
> +		;	/* Empty! Find the shift offset */
> +	if (abs(pendbc - (1 << i)) < abs(pendbc - (1 << (i - 1))))
> +		pendbc = i;
> +	else
> +		pendbc = i - 1;
> +
> +	if (st->caps->has_tsmr) {
> +		reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average)
> +				& AT91_ADC_TSMR_TSAV;
> +		reg |= AT91_ADC_TSMR_PENDBC_(pendbc) & AT91_ADC_TSMR_PENDBC;
> +		reg |= AT91_ADC_TSMR_NOTSDMA;
> +		reg |= AT91_ADC_TSMR_PENDET_ENA;
> +		reg |= 0x03 << 8;	/* TSFREQ, need bigger than TSAV */
> +
> +		at91_adc_writel(st, AT91_ADC_TSMR, reg);
> +	} else {
> +		/* TODO: for 9g45 which has no TSMR */
> +	}
> +
> +	/* Change adc internal resistor value for better pen detection,
> +	 * default value is 100 kOhm.
> +	 * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
> +	 * option only available on ES2 and higher
> +	 */
> +	at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity
> +			& AT91_ADC_ACR_PENDETSENS);
> +
> +	/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
> +	st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US *
> +			adc_clk_khz / 1000) - 1, 1);
> +
> +	return 0;
> +}
> +
> +static int at91_ts_register(struct at91_adc_state *st,
> +		struct platform_device *pdev)
> +{
> +	struct input_dev *input;
> +	struct iio_dev *idev = iio_priv_to_dev(st);
> +	int ret;
> +
> +	input = input_allocate_device();
> +	if (!input) {
> +		dev_err(&idev->dev, "Failed to allocate TS device!\n");
> +		return -ENOMEM;
> +	}
> +
> +	input->name = DRIVER_NAME;
> +	input->id.bustype = BUS_HOST;
> +	input->dev.parent = &pdev->dev;
> +	input->open = atmel_ts_open;
> +	input->close = atmel_ts_close;
> +
> +	__set_bit(EV_ABS, input->evbit);
> +	__set_bit(EV_KEY, input->evbit);
> +	__set_bit(BTN_TOUCH, input->keybit);
> +	input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
> +	input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
> +	input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0);
> +
> +	st->ts_input = input;
> +	input_set_drvdata(input, st);
> +
> +	ret = input_register_device(input);
> +	if (ret)
> +		input_free_device(st->ts_input);
> +
> +	return ret;
> +}
> +
> +static void at91_ts_unregister(struct at91_adc_state *st)
> +{
> +	input_unregister_device(st->ts_input);
> +}
> +
>   static int at91_adc_probe(struct platform_device *pdev)
>   {
>   	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
> @@ -647,7 +952,7 @@ static int at91_adc_probe(struct platform_device *pdev)
>   	at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
>   	at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
>   	ret = request_irq(st->irq,
> -			  at91_adc_eoc_trigger,
> +			  at91_adc_interrupt,
>   			  0,
>   			  pdev->dev.driver->name,
>   			  idev);
> @@ -692,6 +997,10 @@ static int at91_adc_probe(struct platform_device *pdev)
>   	mstrclk = clk_get_rate(st->clk);
>   	adc_clk = clk_get_rate(st->adc_clk);
>   	adc_clk_khz = adc_clk / 1000;
> +
> +	dev_dbg(&pdev->dev, "Master clock is set as: %d Hz, adc_clk should set as: %d Hz\n",
> +		mstrclk, adc_clk);
> +
>   	prsc = (mstrclk / (2 * adc_clk)) - 1;
>   
>   	if (!st->startup_time) {
> @@ -728,30 +1037,52 @@ static int at91_adc_probe(struct platform_device *pdev)
>   	init_waitqueue_head(&st->wq_data_avail);
>   	mutex_init(&st->lock);
>   
> -	ret = at91_adc_buffer_init(idev);
> -	if (ret < 0) {
> -		dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
> -		goto error_disable_adc_clk;
> -	}
> +	/*
> +	 * Since touch screen will set trigger register as period trigger. So
> +	 * when touch screen is enabled, then we have to disable hardware
> +	 * trigger for classic adc.
> +	 */
> +	if (!st->touchscreen_type) {
> +		ret = at91_adc_buffer_init(idev);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
> +			goto error_disable_adc_clk;
> +		}
>   
> -	ret = at91_adc_trigger_init(idev);
> -	if (ret < 0) {
> -		dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
> -		goto error_unregister_buffer;
> +		ret = at91_adc_trigger_init(idev);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
> +			at91_adc_buffer_remove(idev);
> +			goto error_disable_adc_clk;
> +		}
> +	} else {
> +		if (!st->caps->has_tsmr) {
> +			dev_err(&pdev->dev, "We don't support non-TSMR adc\n");
> +			goto error_disable_adc_clk;
> +		}
> +
> +		ret = at91_ts_register(st, pdev);
> +		if (ret)
> +			goto error_disable_adc_clk;
> +
> +		at91_ts_hw_init(st, adc_clk_khz);
>   	}
>   
>   	ret = iio_device_register(idev);
>   	if (ret < 0) {
>   		dev_err(&pdev->dev, "Couldn't register the device.\n");
> -		goto error_remove_triggers;
> +		goto error_iio_device_register;
>   	}
>   
>   	return 0;
>   
> -error_remove_triggers:
> -	at91_adc_trigger_remove(idev);
> -error_unregister_buffer:
> -	at91_adc_buffer_remove(idev);
> +error_iio_device_register:
> +	if (!st->touchscreen_type) {
> +		at91_adc_trigger_remove(idev);
> +		at91_adc_buffer_remove(idev);
> +	} else {
> +		at91_ts_unregister(st);
> +	}
>   error_disable_adc_clk:
>   	clk_disable_unprepare(st->adc_clk);
>   error_disable_clk:
> @@ -770,8 +1101,12 @@ static int at91_adc_remove(struct platform_device *pdev)
>   	struct at91_adc_state *st = iio_priv(idev);
>   
>   	iio_device_unregister(idev);
> -	at91_adc_trigger_remove(idev);
> -	at91_adc_buffer_remove(idev);
> +	if (!st->touchscreen_type) {
> +		at91_adc_trigger_remove(idev);
> +		at91_adc_buffer_remove(idev);
> +	} else {
> +		at91_ts_unregister(st);
> +	}
>   	clk_disable_unprepare(st->adc_clk);
>   	clk_disable_unprepare(st->clk);
>   	free_irq(st->irq, idev);
> @@ -795,6 +1130,7 @@ static struct at91_adc_caps at91sam9260_caps = {
>   };
>   
>   static struct at91_adc_caps at91sam9g45_caps = {
> +	.has_ts = true,
>   	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
>   	.num_channels = 8,
>   	.registers = {
> @@ -808,6 +1144,10 @@ static struct at91_adc_caps at91sam9g45_caps = {
>   };
>   
>   static struct at91_adc_caps at91sam9x5_caps = {
> +	.has_ts = true,
> +	.has_tsmr = true,
> +	.ts_filter_average = 3,
> +	.ts_pen_detect_sensitivity = 2,
>   	.calc_startup_ticks = calc_startup_ticks_9x5,
>   	.num_channels = 12,
>   	.registers = {
> @@ -834,7 +1174,7 @@ static struct platform_driver at91_adc_driver = {
>   	.probe = at91_adc_probe,
>   	.remove = at91_adc_remove,
>   	.driver = {
> -		   .name = "at91_adc",
> +		   .name = DRIVER_NAME,
>   		   .of_match_table = of_match_ptr(at91_adc_dt_ids),
>   	},
>   };

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

* [resend][PATCH v3 6/6] iio: at91: introduce touch screen support in iio adc driver
@ 2013-09-13  9:32             ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-09-13  9:32 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Dmitry Torokhov

Could you have any comments for this patch?

Best Regards,
Josh Wu

On 8/28/2013 3:45 PM, Josh Wu wrote:
> AT91 ADC hardware integrate touch screen support. So this patch add touch
> screen support for at91 adc iio driver.
> To enable touch screen support in adc, you need to add the dt parameters:
>    1. which type of touch are used? (4 or 5 wires), sample period time.
>    2. correct pressure detect threshold value.
>
> In the meantime, since touch screen will use a interal period trigger of adc,
> so it is conflict to other hardware triggers. Driver will disable the hardware
> trigger support if touch screen is enabled.
>
> This driver has been tested in AT91SAM9X5-EK and SAMA5D3x-EK.
>
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> CC: devicetree at vger.kernel.org
> ---
> resend v3:
>    Since [v3 5/6] is resended for compiling error fix. So rebase this patch
>
> v2 --> v3:
>    1. fix according to Dmitry's suggestion.
>
> v1 --> v2:
>    1. use the multiple compatible string for different IPs.
>    2. hide the driver configuration in driver code instead of exposing them in dt.
>       Such like sample period, pen detect debounce time and etc.
>    3. add a new dt parameter: ts-pressure-threshold. this value is much related
>       with different chips and boards.
>
>   .../devicetree/bindings/arm/atmel-adc.txt          |    7 +
>   arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>   drivers/iio/adc/at91_adc.c                         |  388 ++++++++++++++++++--
>   3 files changed, 405 insertions(+), 24 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> index 0e65e01..d106146 100644
> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> @@ -23,6 +23,13 @@ Optional properties:
>   		       resolution will be used.
>     - atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion
>     - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
> +  - atmel,adc-ts-wires: Number of touch screen wires. Should be 4 or 5. If this
> +                        value is set, then adc driver will enable touch screen
> +                        support.
> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> +          disabled. Since touch screen will occupied the trigger register.
> +  - atmel,adc-ts-pressure-threshold: a pressure threshold for touchscreen. It
> +                                     make touch detect more precision.
>    
>   Optional trigger Nodes:
>     - Required properties:
> diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
> index 048a57f..c287307 100644
> --- a/arch/arm/mach-at91/include/mach/at91_adc.h
> +++ b/arch/arm/mach-at91/include/mach/at91_adc.h
> @@ -60,14 +60,48 @@
>   #define AT91_ADC_IER		0x24		/* Interrupt Enable Register */
>   #define AT91_ADC_IDR		0x28		/* Interrupt Disable Register */
>   #define AT91_ADC_IMR		0x2C		/* Interrupt Mask Register */
> +#define		AT91_ADC_IER_PEN	(1 << 29)
> +#define		AT91_ADC_IER_NOPEN	(1 << 30)
> +#define		AT91_ADC_IER_XRDY	(1 << 20)
> +#define		AT91_ADC_IER_YRDY	(1 << 21)
> +#define		AT91_ADC_IER_PRDY	(1 << 22)
> +#define		AT91_ADC_ISR_PENS	(1 << 31)
>   
>   #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
>   #define		AT91_ADC_DATA		(0x3ff)
>   
>   #define AT91_ADC_CDR0_9X5	(0x50)			/* Channel Data Register 0 for 9X5 */
>   
> +#define AT91_ADC_ACR		0x94	/* Analog Control Register */
> +#define		AT91_ADC_ACR_PENDETSENS	(0x3 << 0)	/* pull-up resistor */
> +
> +#define AT91_ADC_TSMR		0xB0
> +#define		AT91_ADC_TSMR_TSMODE	(3 << 0)	/* Touch Screen Mode */
> +#define			AT91_ADC_TSMR_TSMODE_NONE		(0 << 0)
> +#define			AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS	(1 << 0)
> +#define			AT91_ADC_TSMR_TSMODE_4WIRE_PRESS	(2 << 0)
> +#define			AT91_ADC_TSMR_TSMODE_5WIRE		(3 << 0)
> +#define		AT91_ADC_TSMR_TSAV	(3 << 4)	/* Averages samples */
> +#define			AT91_ADC_TSMR_TSAV_(x)		((x) << 4)
> +#define		AT91_ADC_TSMR_SCTIM	(0x0f << 16)	/* Switch closure time */
> +#define		AT91_ADC_TSMR_PENDBC	(0x0f << 28)	/* Pen Debounce time */
> +#define			AT91_ADC_TSMR_PENDBC_(x)	((x) << 28)
> +#define		AT91_ADC_TSMR_NOTSDMA	(1 << 22)	/* No Touchscreen DMA */
> +#define		AT91_ADC_TSMR_PENDET_DIS	(0 << 24)	/* Pen contact detection disable */
> +#define		AT91_ADC_TSMR_PENDET_ENA	(1 << 24)	/* Pen contact detection enable */
> +
> +#define AT91_ADC_TSXPOSR	0xB4
> +#define AT91_ADC_TSYPOSR	0xB8
> +#define AT91_ADC_TSPRESSR	0xBC
> +
>   #define AT91_ADC_TRGR_9260	AT91_ADC_MR
>   #define AT91_ADC_TRGR_9G45	0x08
>   #define AT91_ADC_TRGR_9X5	0xC0
>   
> +/* Trigger Register bit field */
> +#define		AT91_ADC_TRGR_TRGPER	(0xffff << 16)
> +#define			AT91_ADC_TRGR_TRGPER_(x)	((x) << 16)
> +#define		AT91_ADC_TRGR_TRGMOD	(0x7 << 0)
> +#define			AT91_ADC_TRGR_MOD_PERIOD_TRIG	(5 << 0)
> +
>   #endif
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index 0f4621a..beec9ae 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -11,6 +11,7 @@
>   #include <linux/clk.h>
>   #include <linux/err.h>
>   #include <linux/io.h>
> +#include <linux/input.h>
>   #include <linux/interrupt.h>
>   #include <linux/jiffies.h>
>   #include <linux/kernel.h>
> @@ -39,7 +40,23 @@
>   #define at91_adc_writel(st, reg, val) \
>   	(writel_relaxed(val, st->reg_base + reg))
>   
> +#define DRIVER_NAME		"at91_adc"
> +#define MAX_POS_BITS		12
> +
> +#define TOUCH_SAMPLE_PERIOD_US		2000	/* 2ms */
> +#define TOUCH_PEN_DETECT_DEBOUNCE_US	200
> +
>   struct at91_adc_caps {
> +	bool	has_ts;		/* Support touch screen */
> +	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
> +	/*
> +	 * Numbers of sampling data will be averaged. Can be 0~3.
> +	 * Hardware can average (2 ^ ts_filter_average) sample data.
> +	 */
> +	u8	ts_filter_average;
> +	/* Pen Detection input pull-up resistor, can be 0~3 */
> +	u8	ts_pen_detect_sensitivity;
> +
>   	/* startup time calculate function */
>   	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
>   
> @@ -47,6 +64,12 @@ struct at91_adc_caps {
>   	struct at91_adc_reg_desc registers;
>   };
>   
> +enum atmel_adc_ts_type {
> +	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
> +	ATMEL_ADC_TOUCHSCREEN_4WIRE = 4,
> +	ATMEL_ADC_TOUCHSCREEN_5WIRE = 5,
> +};
> +
>   struct at91_adc_state {
>   	struct clk		*adc_clk;
>   	u16			*buffer;
> @@ -71,6 +94,26 @@ struct at91_adc_state {
>   	bool			low_res;	/* the resolution corresponds to the lowest one */
>   	wait_queue_head_t	wq_data_avail;
>   	struct at91_adc_caps	*caps;
> +
> +	/*
> +	 * Following ADC channels are shared by touchscreen:
> +	 *
> +	 * CH0 -- Touch screen XP/UL
> +	 * CH1 -- Touch screen XM/UR
> +	 * CH2 -- Touch screen YP/LL
> +	 * CH3 -- Touch screen YM/Sense
> +	 * CH4 -- Touch screen LR(5-wire only)
> +	 *
> +	 * The bitfields below represents the reserved channel in the
> +	 * touchscreen mode.
> +	 */
> +#define CHAN_MASK_TOUCHSCREEN_4WIRE	(0xf << 0)
> +#define CHAN_MASK_TOUCHSCREEN_5WIRE	(0x1f << 0)
> +	enum atmel_adc_ts_type	touchscreen_type;
> +	struct input_dev	*ts_input;
> +
> +	u16			ts_sample_period_val;
> +	u32			ts_pressure_threshold;
>   };
>   
>   static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
> @@ -105,14 +148,10 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
>   	return IRQ_HANDLED;
>   }
>   
> -static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
> +/* Handler for classic adc channel eoc trigger */
> +void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
>   {
> -	struct iio_dev *idev = private;
>   	struct at91_adc_state *st = iio_priv(idev);
> -	u32 status = at91_adc_readl(st, st->registers->status_register);
> -
> -	if (!(status & st->registers->drdy_mask))
> -		return IRQ_HANDLED;
>   
>   	if (iio_buffer_enabled(idev)) {
>   		disable_irq_nosync(irq);
> @@ -122,6 +161,115 @@ static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
>   		st->done = true;
>   		wake_up_interruptible(&st->wq_data_avail);
>   	}
> +}
> +
> +static int at91_ts_sample(struct at91_adc_state *st)
> +{
> +	unsigned int xscale, yscale, reg, z1, z2;
> +	unsigned int x, y, pres, xpos, ypos;
> +	unsigned int rxp = 1;
> +	unsigned int factor = 1000;
> +	struct iio_dev *idev = iio_priv_to_dev(st);
> +
> +	unsigned int xyz_mask_bits = st->res;
> +	unsigned int xyz_mask = (1 << xyz_mask_bits) - 1;
> +
> +	/* calculate position */
> +	/* x position = (x / xscale) * max, max = 2^MAX_POS_BITS - 1 */
> +	reg = at91_adc_readl(st, AT91_ADC_TSXPOSR);
> +	xpos = reg & xyz_mask;
> +	x = (xpos << MAX_POS_BITS) - xpos;
> +	xscale = (reg >> 16) & xyz_mask;
> +	if (xscale == 0) {
> +		dev_err(&idev->dev, "Error: xscale == 0!\n");
> +		return -1;
> +	}
> +	x /= xscale;
> +
> +	/* y position = (y / yscale) * max, max = 2^MAX_POS_BITS - 1 */
> +	reg = at91_adc_readl(st, AT91_ADC_TSYPOSR);
> +	ypos = reg & xyz_mask;
> +	y = (ypos << MAX_POS_BITS) - ypos;
> +	yscale = (reg >> 16) & xyz_mask;
> +	if (yscale == 0) {
> +		dev_err(&idev->dev, "Error: yscale == 0!\n");
> +		return -1;
> +	}
> +	y /= yscale;
> +
> +	/* calculate the pressure */
> +	reg = at91_adc_readl(st, AT91_ADC_TSPRESSR);
> +	z1 = reg & xyz_mask;
> +	z2 = (reg >> 16) & xyz_mask;
> +
> +	if (z1 != 0)
> +		pres = rxp * (x * factor / 1024) * (z2 * factor / z1 - factor)
> +			/ factor;
> +	else
> +		pres = st->ts_pressure_threshold;	/* no pen contacted */
> +
> +	dev_dbg(&idev->dev, "xpos = %d, xscale = %d, ypos = %d, yscale = %d, z1 = %d, z2 = %d, press = %d\n",
> +				xpos, xscale, ypos, yscale, z1, z2, pres);
> +
> +	if (pres < st->ts_pressure_threshold) {
> +		dev_dbg(&idev->dev, "x = %d, y = %d, pressure = %d\n",
> +					x, y, pres / factor);
> +		input_report_abs(st->ts_input, ABS_X, x);
> +		input_report_abs(st->ts_input, ABS_Y, y);
> +		input_report_abs(st->ts_input, ABS_PRESSURE, pres);
> +		input_report_key(st->ts_input, BTN_TOUCH, 1);
> +		input_sync(st->ts_input);
> +	} else {
> +		dev_dbg(&idev->dev, "pressure too low: not reporting\n");
> +	}
> +
> +	return 0;
> +}
> +
> +static irqreturn_t at91_adc_interrupt(int irq, void *private)
> +{
> +	struct iio_dev *idev = private;
> +	struct at91_adc_state *st = iio_priv(idev);
> +	u32 status = at91_adc_readl(st, st->registers->status_register);
> +	const uint32_t ts_data_irq_mask =
> +		AT91_ADC_IER_XRDY |
> +		AT91_ADC_IER_YRDY |
> +		AT91_ADC_IER_PRDY;
> +
> +	if (status & st->registers->drdy_mask)
> +		handle_adc_eoc_trigger(irq, idev);
> +
> +	if (status & AT91_ADC_IER_PEN) {
> +		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
> +		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_NOPEN |
> +			ts_data_irq_mask);
> +		/* Set up period trigger for sampling */
> +		at91_adc_writel(st, st->registers->trigger_register,
> +			AT91_ADC_TRGR_MOD_PERIOD_TRIG |
> +			AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val));
> +	} else if (status & AT91_ADC_IER_NOPEN) {
> +		at91_adc_writel(st, st->registers->trigger_register, 0);
> +		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_NOPEN |
> +			ts_data_irq_mask);
> +		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
> +
> +		input_report_key(st->ts_input, BTN_TOUCH, 0);
> +		input_sync(st->ts_input);
> +	} else if ((status & ts_data_irq_mask) == ts_data_irq_mask) {
> +		/* Now all touchscreen data is ready */
> +
> +		if (status & AT91_ADC_ISR_PENS) {
> +			/* validate data by pen contact */
> +			at91_ts_sample(st);
> +		} else {
> +			/* triggered by event that is no pen contact, just read
> +			 * them to clean the interrupt and discard all.
> +			 */
> +			at91_adc_readl(st, AT91_ADC_TSXPOSR);
> +			at91_adc_readl(st, AT91_ADC_TSYPOSR);
> +			at91_adc_readl(st, AT91_ADC_TSPRESSR);
> +		}
> +	}
>   
>   	return IRQ_HANDLED;
>   }
> @@ -131,6 +279,16 @@ static int at91_adc_channel_init(struct iio_dev *idev)
>   	struct at91_adc_state *st = iio_priv(idev);
>   	struct iio_chan_spec *chan_array, *timestamp;
>   	int bit, idx = 0;
> +	unsigned long rsvd_mask = 0;
> +
> +	/* If touchscreen is enable, then reserve the adc channels */
> +	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
> +		rsvd_mask = CHAN_MASK_TOUCHSCREEN_4WIRE;
> +	else if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_5WIRE)
> +		rsvd_mask = CHAN_MASK_TOUCHSCREEN_5WIRE;
> +
> +	/* set up the channel mask to reserve touchscreen channels */
> +	st->channels_mask &= ~rsvd_mask;
>   
>   	idev->num_channels = bitmap_weight(&st->channels_mask,
>   					   st->num_channels) + 1;
> @@ -479,6 +637,39 @@ static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz)
>   
>   static const struct of_device_id at91_adc_dt_ids[];
>   
> +static int at91_adc_probe_dt_ts(struct device_node *node,
> +	struct at91_adc_state *st, struct device *dev)
> +{
> +	int ret;
> +	u32 prop;
> +
> +	ret = of_property_read_u32(node, "atmel,adc-ts-wires", &prop);
> +	if (ret) {
> +		dev_info(dev, "ADC Touch screen is disabled.\n");
> +		return 0;
> +	}
> +
> +	switch (prop) {
> +	case 4:
> +	case 5:
> +		st->touchscreen_type = prop;
> +		break;
> +	default:
> +		dev_err(dev, "Unsupported number of touchscreen wires (%d). Should be 4 or 5.\n", prop);
> +		return -EINVAL;
> +	}
> +
> +	prop = 0;
> +	of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop);
> +	st->ts_pressure_threshold = prop;
> +	if (st->ts_pressure_threshold) {
> +		return 0;
> +	} else {
> +		dev_err(dev, "Invalid pressure threshold for the touchscreen\n");
> +		return -EINVAL;
> +	}
> +}
> +
>   static int at91_adc_probe_dt(struct at91_adc_state *st,
>   			     struct platform_device *pdev)
>   {
> @@ -560,6 +751,12 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>   		i++;
>   	}
>   
> +	/* Check if touchscreen is supported. */
> +	if (st->caps->has_ts)
> +		return at91_adc_probe_dt_ts(node, st, &idev->dev);
> +	else
> +		dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n");
> +
>   	return 0;
>   
>   error_ret:
> @@ -591,6 +788,114 @@ static const struct iio_info at91_adc_info = {
>   	.read_raw = &at91_adc_read_raw,
>   };
>   
> +/* Touchscreen related functions */
> +static int atmel_ts_open(struct input_dev *dev)
> +{
> +	struct at91_adc_state *st = input_get_drvdata(dev);
> +
> +	at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
> +	return 0;
> +}
> +
> +static void atmel_ts_close(struct input_dev *dev)
> +{
> +	struct at91_adc_state *st = input_get_drvdata(dev);
> +
> +	at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
> +}
> +
> +static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
> +{
> +	u32 reg = 0, pendbc;
> +	int i = 0;
> +
> +	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
> +		reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
> +	else
> +		reg = AT91_ADC_TSMR_TSMODE_5WIRE;
> +
> +	/* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid
> +	 * pen detect noise.
> +	 * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock
> +	 */
> +	pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / 1000, 1);
> +
> +	while (pendbc >> ++i)
> +		;	/* Empty! Find the shift offset */
> +	if (abs(pendbc - (1 << i)) < abs(pendbc - (1 << (i - 1))))
> +		pendbc = i;
> +	else
> +		pendbc = i - 1;
> +
> +	if (st->caps->has_tsmr) {
> +		reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average)
> +				& AT91_ADC_TSMR_TSAV;
> +		reg |= AT91_ADC_TSMR_PENDBC_(pendbc) & AT91_ADC_TSMR_PENDBC;
> +		reg |= AT91_ADC_TSMR_NOTSDMA;
> +		reg |= AT91_ADC_TSMR_PENDET_ENA;
> +		reg |= 0x03 << 8;	/* TSFREQ, need bigger than TSAV */
> +
> +		at91_adc_writel(st, AT91_ADC_TSMR, reg);
> +	} else {
> +		/* TODO: for 9g45 which has no TSMR */
> +	}
> +
> +	/* Change adc internal resistor value for better pen detection,
> +	 * default value is 100 kOhm.
> +	 * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
> +	 * option only available on ES2 and higher
> +	 */
> +	at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity
> +			& AT91_ADC_ACR_PENDETSENS);
> +
> +	/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
> +	st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US *
> +			adc_clk_khz / 1000) - 1, 1);
> +
> +	return 0;
> +}
> +
> +static int at91_ts_register(struct at91_adc_state *st,
> +		struct platform_device *pdev)
> +{
> +	struct input_dev *input;
> +	struct iio_dev *idev = iio_priv_to_dev(st);
> +	int ret;
> +
> +	input = input_allocate_device();
> +	if (!input) {
> +		dev_err(&idev->dev, "Failed to allocate TS device!\n");
> +		return -ENOMEM;
> +	}
> +
> +	input->name = DRIVER_NAME;
> +	input->id.bustype = BUS_HOST;
> +	input->dev.parent = &pdev->dev;
> +	input->open = atmel_ts_open;
> +	input->close = atmel_ts_close;
> +
> +	__set_bit(EV_ABS, input->evbit);
> +	__set_bit(EV_KEY, input->evbit);
> +	__set_bit(BTN_TOUCH, input->keybit);
> +	input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
> +	input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
> +	input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0);
> +
> +	st->ts_input = input;
> +	input_set_drvdata(input, st);
> +
> +	ret = input_register_device(input);
> +	if (ret)
> +		input_free_device(st->ts_input);
> +
> +	return ret;
> +}
> +
> +static void at91_ts_unregister(struct at91_adc_state *st)
> +{
> +	input_unregister_device(st->ts_input);
> +}
> +
>   static int at91_adc_probe(struct platform_device *pdev)
>   {
>   	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
> @@ -647,7 +952,7 @@ static int at91_adc_probe(struct platform_device *pdev)
>   	at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
>   	at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
>   	ret = request_irq(st->irq,
> -			  at91_adc_eoc_trigger,
> +			  at91_adc_interrupt,
>   			  0,
>   			  pdev->dev.driver->name,
>   			  idev);
> @@ -692,6 +997,10 @@ static int at91_adc_probe(struct platform_device *pdev)
>   	mstrclk = clk_get_rate(st->clk);
>   	adc_clk = clk_get_rate(st->adc_clk);
>   	adc_clk_khz = adc_clk / 1000;
> +
> +	dev_dbg(&pdev->dev, "Master clock is set as: %d Hz, adc_clk should set as: %d Hz\n",
> +		mstrclk, adc_clk);
> +
>   	prsc = (mstrclk / (2 * adc_clk)) - 1;
>   
>   	if (!st->startup_time) {
> @@ -728,30 +1037,52 @@ static int at91_adc_probe(struct platform_device *pdev)
>   	init_waitqueue_head(&st->wq_data_avail);
>   	mutex_init(&st->lock);
>   
> -	ret = at91_adc_buffer_init(idev);
> -	if (ret < 0) {
> -		dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
> -		goto error_disable_adc_clk;
> -	}
> +	/*
> +	 * Since touch screen will set trigger register as period trigger. So
> +	 * when touch screen is enabled, then we have to disable hardware
> +	 * trigger for classic adc.
> +	 */
> +	if (!st->touchscreen_type) {
> +		ret = at91_adc_buffer_init(idev);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
> +			goto error_disable_adc_clk;
> +		}
>   
> -	ret = at91_adc_trigger_init(idev);
> -	if (ret < 0) {
> -		dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
> -		goto error_unregister_buffer;
> +		ret = at91_adc_trigger_init(idev);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
> +			at91_adc_buffer_remove(idev);
> +			goto error_disable_adc_clk;
> +		}
> +	} else {
> +		if (!st->caps->has_tsmr) {
> +			dev_err(&pdev->dev, "We don't support non-TSMR adc\n");
> +			goto error_disable_adc_clk;
> +		}
> +
> +		ret = at91_ts_register(st, pdev);
> +		if (ret)
> +			goto error_disable_adc_clk;
> +
> +		at91_ts_hw_init(st, adc_clk_khz);
>   	}
>   
>   	ret = iio_device_register(idev);
>   	if (ret < 0) {
>   		dev_err(&pdev->dev, "Couldn't register the device.\n");
> -		goto error_remove_triggers;
> +		goto error_iio_device_register;
>   	}
>   
>   	return 0;
>   
> -error_remove_triggers:
> -	at91_adc_trigger_remove(idev);
> -error_unregister_buffer:
> -	at91_adc_buffer_remove(idev);
> +error_iio_device_register:
> +	if (!st->touchscreen_type) {
> +		at91_adc_trigger_remove(idev);
> +		at91_adc_buffer_remove(idev);
> +	} else {
> +		at91_ts_unregister(st);
> +	}
>   error_disable_adc_clk:
>   	clk_disable_unprepare(st->adc_clk);
>   error_disable_clk:
> @@ -770,8 +1101,12 @@ static int at91_adc_remove(struct platform_device *pdev)
>   	struct at91_adc_state *st = iio_priv(idev);
>   
>   	iio_device_unregister(idev);
> -	at91_adc_trigger_remove(idev);
> -	at91_adc_buffer_remove(idev);
> +	if (!st->touchscreen_type) {
> +		at91_adc_trigger_remove(idev);
> +		at91_adc_buffer_remove(idev);
> +	} else {
> +		at91_ts_unregister(st);
> +	}
>   	clk_disable_unprepare(st->adc_clk);
>   	clk_disable_unprepare(st->clk);
>   	free_irq(st->irq, idev);
> @@ -795,6 +1130,7 @@ static struct at91_adc_caps at91sam9260_caps = {
>   };
>   
>   static struct at91_adc_caps at91sam9g45_caps = {
> +	.has_ts = true,
>   	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */
>   	.num_channels = 8,
>   	.registers = {
> @@ -808,6 +1144,10 @@ static struct at91_adc_caps at91sam9g45_caps = {
>   };
>   
>   static struct at91_adc_caps at91sam9x5_caps = {
> +	.has_ts = true,
> +	.has_tsmr = true,
> +	.ts_filter_average = 3,
> +	.ts_pen_detect_sensitivity = 2,
>   	.calc_startup_ticks = calc_startup_ticks_9x5,
>   	.num_channels = 12,
>   	.registers = {
> @@ -834,7 +1174,7 @@ static struct platform_driver at91_adc_driver = {
>   	.probe = at91_adc_probe,
>   	.remove = at91_adc_remove,
>   	.driver = {
> -		   .name = "at91_adc",
> +		   .name = DRIVER_NAME,
>   		   .of_match_table = of_match_ptr(at91_adc_dt_ids),
>   	},
>   };

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

* Re: [PATCH v3 4/6] iio: at91: ADC start-up time calculation changed since at91sam9x5
  2013-08-29 21:00       ` Jonathan Cameron
@ 2013-10-01  9:32         ` Jonathan Cameron
  -1 siblings, 0 replies; 55+ messages in thread
From: Jonathan Cameron @ 2013-10-01  9:32 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Josh Wu, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre,
	thomas.petazzoni, mark.rutland, b.brezillon

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 08/29/13 22:00, Jonathan Cameron wrote:
> On 08/28/13 10:03, Maxime Ripard wrote:
>> Hi Josh,
>> 
>> On Tue, Aug 27, 2013 at 07:28:50PM +0800, Josh Wu wrote:
>>> Since in at91sam9x5, sama5d3x chip. the start up time calucation is changed. This patch can choose different 
>>> start up time calculation formula for different chips.
>>> 
>>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>> 
>> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>> 
> Unfortunately this one has a dependency on the fix patch which is going in through my fixes branch so will have to
> wait until that hits my upstream.
> 
> I'd like 5 and 6 to sit a while longer anyway (and 6 needs Dmitry's sign off before I take that.)
> 
Hi All,

This patch no longer applies unfortunately. Josh, could you bring
it up to date and repost the last 3 patches of this series?
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.21 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQIcBAEBAgAGBQJSSpbIAAoJEFSFNJnE9BaIi48QALwC0aVUQNU94RpUBRBqFVkF
H8AB2pLBLYV4JlLD1kg9/ksltZh9+xegd/mM/C/lqZoHaokbSSF0bcAPSV2E3lXN
MJ3sRx0ubmGAMNWOYI22pqD1BQwEWMdjmS/BaZ2FxkOdJyIV/jkR8NpA3BrvL7e2
iOv9k7nBkOI1B//0K/xr4B0MWotnbmq45KeHTR1VnItqGWHDG7gyB+sbnymyf53M
XY99HUpkLggBJrbp05PYmp9RTvyV7NYlMvgMtwUWcM6VaA0YrSRR349P+UsIcmwV
60yXRDRZCM5Vu3HDAVnbGDtumGjSFYsXXVkJQoN8izCBn0ZsbdSzc4bJyGzn90WK
vpt5rpd4k+ne/TTuJSiIiz8g/7aZvlWWSQ17j2Qb+IOfh2yROHuA+yyikfFV8N4e
8jkd5HSMMRoL1Bv1vsf8eOJVlIMTOkG/2Wa7rXJOiWwzmc09Fxp13SoOIOxEMqJY
lCj8In1fYLryMBCjxR2C/ysnullAbTwBv9HtudPm3Lu80eR8GL7lB4VrrhJyHILP
ROvJE4ETYpYQTxQZMJKgVAQBFUAhBmckdc1A/SXMcDJgZKraP9aFvJPYbFR4OlFz
UfjWWS6TzHFgFe2r804DzT+A7fpdZNFrbxyM40ttg7kJ81DgT9aQncEM96dEmiWh
nXz0iA/maOXKkqJluLWl
=HbYR
-----END PGP SIGNATURE-----

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

* [PATCH v3 4/6] iio: at91: ADC start-up time calculation changed since at91sam9x5
@ 2013-10-01  9:32         ` Jonathan Cameron
  0 siblings, 0 replies; 55+ messages in thread
From: Jonathan Cameron @ 2013-10-01  9:32 UTC (permalink / raw)
  To: linux-arm-kernel

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 08/29/13 22:00, Jonathan Cameron wrote:
> On 08/28/13 10:03, Maxime Ripard wrote:
>> Hi Josh,
>> 
>> On Tue, Aug 27, 2013 at 07:28:50PM +0800, Josh Wu wrote:
>>> Since in at91sam9x5, sama5d3x chip. the start up time calucation is changed. This patch can choose different 
>>> start up time calculation formula for different chips.
>>> 
>>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>> 
>> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>> 
> Unfortunately this one has a dependency on the fix patch which is going in through my fixes branch so will have to
> wait until that hits my upstream.
> 
> I'd like 5 and 6 to sit a while longer anyway (and 6 needs Dmitry's sign off before I take that.)
> 
Hi All,

This patch no longer applies unfortunately. Josh, could you bring
it up to date and repost the last 3 patches of this series?
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.21 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQIcBAEBAgAGBQJSSpbIAAoJEFSFNJnE9BaIi48QALwC0aVUQNU94RpUBRBqFVkF
H8AB2pLBLYV4JlLD1kg9/ksltZh9+xegd/mM/C/lqZoHaokbSSF0bcAPSV2E3lXN
MJ3sRx0ubmGAMNWOYI22pqD1BQwEWMdjmS/BaZ2FxkOdJyIV/jkR8NpA3BrvL7e2
iOv9k7nBkOI1B//0K/xr4B0MWotnbmq45KeHTR1VnItqGWHDG7gyB+sbnymyf53M
XY99HUpkLggBJrbp05PYmp9RTvyV7NYlMvgMtwUWcM6VaA0YrSRR349P+UsIcmwV
60yXRDRZCM5Vu3HDAVnbGDtumGjSFYsXXVkJQoN8izCBn0ZsbdSzc4bJyGzn90WK
vpt5rpd4k+ne/TTuJSiIiz8g/7aZvlWWSQ17j2Qb+IOfh2yROHuA+yyikfFV8N4e
8jkd5HSMMRoL1Bv1vsf8eOJVlIMTOkG/2Wa7rXJOiWwzmc09Fxp13SoOIOxEMqJY
lCj8In1fYLryMBCjxR2C/ysnullAbTwBv9HtudPm3Lu80eR8GL7lB4VrrhJyHILP
ROvJE4ETYpYQTxQZMJKgVAQBFUAhBmckdc1A/SXMcDJgZKraP9aFvJPYbFR4OlFz
UfjWWS6TzHFgFe2r804DzT+A7fpdZNFrbxyM40ttg7kJ81DgT9aQncEM96dEmiWh
nXz0iA/maOXKkqJluLWl
=HbYR
-----END PGP SIGNATURE-----

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

* Re: [PATCH v3 4/6] iio: at91: ADC start-up time calculation changed since at91sam9x5
  2013-10-01  9:32         ` Jonathan Cameron
@ 2013-10-08  3:44           ` Josh Wu
  -1 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-10-08  3:44 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Maxime Ripard, linux-arm-kernel, linux-iio, plagnioj,
	nicolas.ferre, thomas.petazzoni, mark.rutland, b.brezillon

Hi, Jonathan

On 10/1/2013 5:32 PM, Jonathan Cameron wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 08/29/13 22:00, Jonathan Cameron wrote:
>> On 08/28/13 10:03, Maxime Ripard wrote:
>>> Hi Josh,
>>>
>>> On Tue, Aug 27, 2013 at 07:28:50PM +0800, Josh Wu wrote:
>>>> Since in at91sam9x5, sama5d3x chip. the start up time calucation is changed. This patch can choose different
>>>> start up time calculation formula for different chips.
>>>>
>>>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>>> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>>>
>> Unfortunately this one has a dependency on the fix patch which is going in through my fixes branch so will have to
>> wait until that hits my upstream.
>>
>> I'd like 5 and 6 to sit a while longer anyway (and 6 needs Dmitry's sign off before I take that.)
>>
> Hi All,
>
> This patch no longer applies unfortunately. Josh, could you bring
> it up to date and repost the last 3 patches of this series?

Sorry for the later reply since I just come back from the holiday.
I will send the last 3 patches of this series (include this one) base on 
the mainline Linux. Thanks.

Best Regards,
Josh Wu

> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v2.0.21 (GNU/Linux)
> Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/
>
> iQIcBAEBAgAGBQJSSpbIAAoJEFSFNJnE9BaIi48QALwC0aVUQNU94RpUBRBqFVkF
> H8AB2pLBLYV4JlLD1kg9/ksltZh9+xegd/mM/C/lqZoHaokbSSF0bcAPSV2E3lXN
> MJ3sRx0ubmGAMNWOYI22pqD1BQwEWMdjmS/BaZ2FxkOdJyIV/jkR8NpA3BrvL7e2
> iOv9k7nBkOI1B//0K/xr4B0MWotnbmq45KeHTR1VnItqGWHDG7gyB+sbnymyf53M
> XY99HUpkLggBJrbp05PYmp9RTvyV7NYlMvgMtwUWcM6VaA0YrSRR349P+UsIcmwV
> 60yXRDRZCM5Vu3HDAVnbGDtumGjSFYsXXVkJQoN8izCBn0ZsbdSzc4bJyGzn90WK
> vpt5rpd4k+ne/TTuJSiIiz8g/7aZvlWWSQ17j2Qb+IOfh2yROHuA+yyikfFV8N4e
> 8jkd5HSMMRoL1Bv1vsf8eOJVlIMTOkG/2Wa7rXJOiWwzmc09Fxp13SoOIOxEMqJY
> lCj8In1fYLryMBCjxR2C/ysnullAbTwBv9HtudPm3Lu80eR8GL7lB4VrrhJyHILP
> ROvJE4ETYpYQTxQZMJKgVAQBFUAhBmckdc1A/SXMcDJgZKraP9aFvJPYbFR4OlFz
> UfjWWS6TzHFgFe2r804DzT+A7fpdZNFrbxyM40ttg7kJ81DgT9aQncEM96dEmiWh
> nXz0iA/maOXKkqJluLWl
> =HbYR
> -----END PGP SIGNATURE-----


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

* [PATCH v3 4/6] iio: at91: ADC start-up time calculation changed since at91sam9x5
@ 2013-10-08  3:44           ` Josh Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Josh Wu @ 2013-10-08  3:44 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, Jonathan

On 10/1/2013 5:32 PM, Jonathan Cameron wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 08/29/13 22:00, Jonathan Cameron wrote:
>> On 08/28/13 10:03, Maxime Ripard wrote:
>>> Hi Josh,
>>>
>>> On Tue, Aug 27, 2013 at 07:28:50PM +0800, Josh Wu wrote:
>>>> Since in at91sam9x5, sama5d3x chip. the start up time calucation is changed. This patch can choose different
>>>> start up time calculation formula for different chips.
>>>>
>>>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>>> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>>>
>> Unfortunately this one has a dependency on the fix patch which is going in through my fixes branch so will have to
>> wait until that hits my upstream.
>>
>> I'd like 5 and 6 to sit a while longer anyway (and 6 needs Dmitry's sign off before I take that.)
>>
> Hi All,
>
> This patch no longer applies unfortunately. Josh, could you bring
> it up to date and repost the last 3 patches of this series?

Sorry for the later reply since I just come back from the holiday.
I will send the last 3 patches of this series (include this one) base on 
the mainline Linux. Thanks.

Best Regards,
Josh Wu

> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v2.0.21 (GNU/Linux)
> Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/
>
> iQIcBAEBAgAGBQJSSpbIAAoJEFSFNJnE9BaIi48QALwC0aVUQNU94RpUBRBqFVkF
> H8AB2pLBLYV4JlLD1kg9/ksltZh9+xegd/mM/C/lqZoHaokbSSF0bcAPSV2E3lXN
> MJ3sRx0ubmGAMNWOYI22pqD1BQwEWMdjmS/BaZ2FxkOdJyIV/jkR8NpA3BrvL7e2
> iOv9k7nBkOI1B//0K/xr4B0MWotnbmq45KeHTR1VnItqGWHDG7gyB+sbnymyf53M
> XY99HUpkLggBJrbp05PYmp9RTvyV7NYlMvgMtwUWcM6VaA0YrSRR349P+UsIcmwV
> 60yXRDRZCM5Vu3HDAVnbGDtumGjSFYsXXVkJQoN8izCBn0ZsbdSzc4bJyGzn90WK
> vpt5rpd4k+ne/TTuJSiIiz8g/7aZvlWWSQ17j2Qb+IOfh2yROHuA+yyikfFV8N4e
> 8jkd5HSMMRoL1Bv1vsf8eOJVlIMTOkG/2Wa7rXJOiWwzmc09Fxp13SoOIOxEMqJY
> lCj8In1fYLryMBCjxR2C/ysnullAbTwBv9HtudPm3Lu80eR8GL7lB4VrrhJyHILP
> ROvJE4ETYpYQTxQZMJKgVAQBFUAhBmckdc1A/SXMcDJgZKraP9aFvJPYbFR4OlFz
> UfjWWS6TzHFgFe2r804DzT+A7fpdZNFrbxyM40ttg7kJ81DgT9aQncEM96dEmiWh
> nXz0iA/maOXKkqJluLWl
> =HbYR
> -----END PGP SIGNATURE-----

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

end of thread, other threads:[~2013-10-08  3:45 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-08-27 11:28 [PATCH v3 0/6] iio: at91: Add touch screen support in at91 adc Josh Wu
2013-08-27 11:28 ` Josh Wu
2013-08-27 11:28 ` [PATCH v3 1/6] iio: at91: fix adc_clk overflow Josh Wu
2013-08-27 11:28   ` Josh Wu
2013-08-29 20:43   ` Jonathan Cameron
2013-08-29 20:43     ` Jonathan Cameron
     [not found] ` <1377602932-1899-1-git-send-email-josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2013-08-27 11:28   ` [PATCH v3 2/6] iio: at91: introduce the multiple compatible string for different IPs Josh Wu
2013-08-27 11:28     ` Josh Wu
2013-08-27 11:28     ` Josh Wu
     [not found]     ` <1377602932-1899-3-git-send-email-josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2013-08-28  8:02       ` Maxime Ripard
2013-08-28  8:02         ` Maxime Ripard
2013-08-28  8:02         ` Maxime Ripard
2013-08-29 20:47         ` Jonathan Cameron
2013-08-29 20:47           ` Jonathan Cameron
2013-08-29 20:47           ` Jonathan Cameron
2013-08-28 13:25     ` Ludovic Desroches
2013-08-28 13:25       ` Ludovic Desroches
2013-08-28 13:25     ` Ludovic Desroches
2013-08-27 11:28   ` [PATCH v3 5/6] iio: at91: move the num_channels from DT to driver itself Josh Wu
2013-08-27 11:28     ` Josh Wu
2013-08-27 11:28     ` Josh Wu
     [not found]     ` <1377602932-1899-6-git-send-email-josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2013-08-28  7:42       ` [resend][PATCH " Josh Wu
2013-08-28  7:42         ` Josh Wu
2013-08-28  7:42         ` Josh Wu
     [not found]         ` <1377675770-30813-1-git-send-email-josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2013-08-28  8:39           ` Maxime Ripard
2013-08-28  8:39             ` Maxime Ripard
2013-08-28  8:39             ` Maxime Ripard
2013-08-28 13:27     ` [PATCH " Ludovic Desroches
2013-08-28 13:27     ` Ludovic Desroches
2013-08-28 13:27       ` Ludovic Desroches
2013-08-27 11:28   ` [PATCH v3 6/6] iio: at91: introduce touch screen support in iio adc driver Josh Wu
2013-08-27 11:28     ` Josh Wu
2013-08-27 11:28     ` Josh Wu
     [not found]     ` <1377602932-1899-7-git-send-email-josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2013-08-28  7:45       ` [resend][PATCH " Josh Wu
2013-08-28  7:45         ` Josh Wu
2013-08-28  7:45         ` Josh Wu
     [not found]         ` <1377675913-30861-1-git-send-email-josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2013-09-13  9:32           ` Josh Wu
2013-09-13  9:32             ` Josh Wu
2013-09-13  9:32             ` Josh Wu
2013-08-27 11:28 ` [PATCH v3 3/6] iio: at91: Use different prescal, startup mask in MR for different IP Josh Wu
2013-08-27 11:28   ` Josh Wu
2013-08-28  8:56   ` Maxime Ripard
2013-08-28  8:56     ` Maxime Ripard
2013-08-29 20:50     ` Jonathan Cameron
2013-08-29 20:50       ` Jonathan Cameron
2013-08-27 11:28 ` [PATCH v3 4/6] iio: at91: ADC start-up time calculation changed since at91sam9x5 Josh Wu
2013-08-27 11:28   ` Josh Wu
2013-08-28  9:03   ` Maxime Ripard
2013-08-28  9:03     ` Maxime Ripard
2013-08-29 21:00     ` Jonathan Cameron
2013-08-29 21:00       ` Jonathan Cameron
2013-10-01  9:32       ` Jonathan Cameron
2013-10-01  9:32         ` Jonathan Cameron
2013-10-08  3:44         ` Josh Wu
2013-10-08  3:44           ` Josh Wu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.