All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] iio: at91: Add touch screen support in at91 adc
@ 2013-07-14  8:04 ` Josh Wu
  0 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-14  8:04 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, Josh Wu

This patch series will add touch screen support for at91 adc driver.
To enable touch screen you need add the touch screen related dt properties.

Josh Wu (5):
  iio: at91: use adc_clk_khz to make the calculation not easy to large
    than u32.
  iio: at91: Use different prescal, startup mask in MR for different IP
  iio: at91: ADC start-up time calculation changed since at91sam9x5
  iio: at91: add an optional dt property for for adc clock hz.
  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         |   43 +-
 drivers/iio/adc/at91_adc.c                         |  492 ++++++++++++++++++--
 3 files changed, 511 insertions(+), 39 deletions(-)

-- 
1.7.10

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

* [PATCH 0/5] iio: at91: Add touch screen support in at91 adc
@ 2013-07-14  8:04 ` Josh Wu
  0 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-14  8:04 UTC (permalink / raw)
  To: linux-arm-kernel

This patch series will add touch screen support for at91 adc driver.
To enable touch screen you need add the touch screen related dt properties.

Josh Wu (5):
  iio: at91: use adc_clk_khz to make the calculation not easy to large
    than u32.
  iio: at91: Use different prescal, startup mask in MR for different IP
  iio: at91: ADC start-up time calculation changed since at91sam9x5
  iio: at91: add an optional dt property for for adc clock hz.
  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         |   43 +-
 drivers/iio/adc/at91_adc.c                         |  492 ++++++++++++++++++--
 3 files changed, 511 insertions(+), 39 deletions(-)

-- 
1.7.10

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

* [PATCH 1/5] iio: at91: use adc_clk_khz to make the calculation not easy to large than u32.
  2013-07-14  8:04 ` Josh Wu
@ 2013-07-14  8:04   ` Josh Wu
  -1 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-14  8:04 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, Josh Wu

for example, if adc_clk is 20Mhz and start-up time set as larger than 215us.
then the calculation "st->startup_time * adc_clk_khz" will out of u32.

In this patch, it will use khz unit for adc_clk, that avoids above problem.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
 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 e5b88d5..18bd54f 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] 85+ messages in thread

* [PATCH 1/5] iio: at91: use adc_clk_khz to make the calculation not easy to large than u32.
@ 2013-07-14  8:04   ` Josh Wu
  0 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-14  8:04 UTC (permalink / raw)
  To: linux-arm-kernel

for example, if adc_clk is 20Mhz and start-up time set as larger than 215us.
then the calculation "st->startup_time * adc_clk_khz" will out of u32.

In this patch, it will use khz unit for adc_clk, that avoids above problem.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
 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 e5b88d5..18bd54f 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] 85+ messages in thread

* [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-07-14  8:04 ` Josh Wu
@ 2013-07-14  8:04   ` Josh Wu
  -1 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-14  8:04 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, Josh Wu

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

This patch can change the masks according to the different IP version.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
 arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
 drivers/iio/adc/at91_adc.c                 |   48 ++++++++++++++++++++++++++--
 2 files changed, 53 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 8e7ed5c..ab273ee 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	(0xff << 8)	/* Prescalar Rate Selection */
+#define		AT91_ADC_PRESCAL_9260	(0x3f << 8)
 #define			AT91_ADC_PRESCAL_(x)	((x) << 8)
-#define		AT91_ADC_STARTUP	(0x1f << 16)	/* Startup Up Time */
+#define		AT91_ADC_STARTUP	(0xf << 16)	/* Startup Up Time */
+#define		AT91_ADC_STARTUP_9260	(0x1f << 16)
+#define		AT91_ADC_STARTUP_9G45	(0x7f << 16)
 #define			AT91_ADC_STARTUP_(x)	((x) << 16)
 #define		AT91_ADC_SHTIM		(0xf  << 24)	/* Sample & Hold Time */
 #define			AT91_ADC_SHTIM_(x)	((x) << 24)
@@ -58,4 +61,6 @@
 #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
 #define		AT91_ADC_DATA		(0x3ff)
 
+#define AT91_ADC_VERSION	0xFC
+
 #endif
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 18bd54f..14e99ba 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -39,6 +39,12 @@
 #define at91_adc_writel(st, reg, val) \
 	(writel_relaxed(val, st->reg_base + reg))
 
+struct at91_adc_caps {
+	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
+	u32	mr_prescal_mask;
+	u32	mr_startup_mask;
+};
+
 struct at91_adc_state {
 	struct clk		*adc_clk;
 	u16			*buffer;
@@ -62,6 +68,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)
@@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
 	.read_raw = &at91_adc_read_raw,
 };
 
+/*
+ * Since atmel adc support different ip for touchscreen mode. Through the
+ * IP check, we will know the touchscreen capbilities.
+ */
+static void atmel_adc_get_cap(struct at91_adc_state *st)
+{
+	unsigned int version;
+	struct iio_dev *idev = iio_priv_to_dev(st);
+
+	version = at91_adc_readl(st, AT91_ADC_VERSION);
+	dev_dbg(&idev->dev, "version: 0x%x\n", version);
+
+	st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
+	st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
+
+	/* keep only major version number */
+	switch (version & 0xf00) {
+	case 0x500:	/* SAMA5D3 */
+	case 0x400:	/* AT91SAM9X5/9N12 */
+		st->caps.has_tsmr = 1;
+		st->caps.mr_startup_mask = AT91_ADC_STARTUP;
+	case 0x200:	/* AT91SAM9M10/9G45 */
+		st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
+
+		if ((version & 0xf00) == 0x200)
+			st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
+	case 0x100:	/* AT91SAM9260/9G20 */
+		break;
+	default:
+		dev_warn(&idev->dev,
+				"Unmanaged adc version, use minimal capabilities\n");
+		break;
+	};
+}
+
 static int at91_adc_probe(struct platform_device *pdev)
 {
 	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
@@ -645,6 +687,8 @@ static int at91_adc_probe(struct platform_device *pdev)
 		goto error_free_device;
 	}
 
+	atmel_adc_get_cap(st);
+
 	st->clk = devm_clk_get(&pdev->dev, "adc_clk");
 	if (IS_ERR(st->clk)) {
 		dev_err(&pdev->dev, "Failed to get the clock.\n");
@@ -704,8 +748,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->caps.mr_prescal_mask;
+	reg |= AT91_ADC_STARTUP_(ticks) & st->caps.mr_startup_mask;
 	if (st->low_res)
 		reg |= AT91_ADC_LOWRES;
 	if (st->sleep_mode)
-- 
1.7.10

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

* [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-14  8:04   ` Josh Wu
  0 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-14  8:04 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.

This patch can change the masks according to the different IP version.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
 arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
 drivers/iio/adc/at91_adc.c                 |   48 ++++++++++++++++++++++++++--
 2 files changed, 53 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 8e7ed5c..ab273ee 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	(0xff << 8)	/* Prescalar Rate Selection */
+#define		AT91_ADC_PRESCAL_9260	(0x3f << 8)
 #define			AT91_ADC_PRESCAL_(x)	((x) << 8)
-#define		AT91_ADC_STARTUP	(0x1f << 16)	/* Startup Up Time */
+#define		AT91_ADC_STARTUP	(0xf << 16)	/* Startup Up Time */
+#define		AT91_ADC_STARTUP_9260	(0x1f << 16)
+#define		AT91_ADC_STARTUP_9G45	(0x7f << 16)
 #define			AT91_ADC_STARTUP_(x)	((x) << 16)
 #define		AT91_ADC_SHTIM		(0xf  << 24)	/* Sample & Hold Time */
 #define			AT91_ADC_SHTIM_(x)	((x) << 24)
@@ -58,4 +61,6 @@
 #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
 #define		AT91_ADC_DATA		(0x3ff)
 
+#define AT91_ADC_VERSION	0xFC
+
 #endif
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 18bd54f..14e99ba 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -39,6 +39,12 @@
 #define at91_adc_writel(st, reg, val) \
 	(writel_relaxed(val, st->reg_base + reg))
 
+struct at91_adc_caps {
+	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
+	u32	mr_prescal_mask;
+	u32	mr_startup_mask;
+};
+
 struct at91_adc_state {
 	struct clk		*adc_clk;
 	u16			*buffer;
@@ -62,6 +68,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)
@@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
 	.read_raw = &at91_adc_read_raw,
 };
 
+/*
+ * Since atmel adc support different ip for touchscreen mode. Through the
+ * IP check, we will know the touchscreen capbilities.
+ */
+static void atmel_adc_get_cap(struct at91_adc_state *st)
+{
+	unsigned int version;
+	struct iio_dev *idev = iio_priv_to_dev(st);
+
+	version = at91_adc_readl(st, AT91_ADC_VERSION);
+	dev_dbg(&idev->dev, "version: 0x%x\n", version);
+
+	st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
+	st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
+
+	/* keep only major version number */
+	switch (version & 0xf00) {
+	case 0x500:	/* SAMA5D3 */
+	case 0x400:	/* AT91SAM9X5/9N12 */
+		st->caps.has_tsmr = 1;
+		st->caps.mr_startup_mask = AT91_ADC_STARTUP;
+	case 0x200:	/* AT91SAM9M10/9G45 */
+		st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
+
+		if ((version & 0xf00) == 0x200)
+			st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
+	case 0x100:	/* AT91SAM9260/9G20 */
+		break;
+	default:
+		dev_warn(&idev->dev,
+				"Unmanaged adc version, use minimal capabilities\n");
+		break;
+	};
+}
+
 static int at91_adc_probe(struct platform_device *pdev)
 {
 	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
@@ -645,6 +687,8 @@ static int at91_adc_probe(struct platform_device *pdev)
 		goto error_free_device;
 	}
 
+	atmel_adc_get_cap(st);
+
 	st->clk = devm_clk_get(&pdev->dev, "adc_clk");
 	if (IS_ERR(st->clk)) {
 		dev_err(&pdev->dev, "Failed to get the clock.\n");
@@ -704,8 +748,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->caps.mr_prescal_mask;
+	reg |= AT91_ADC_STARTUP_(ticks) & st->caps.mr_startup_mask;
 	if (st->low_res)
 		reg |= AT91_ADC_LOWRES;
 	if (st->sleep_mode)
-- 
1.7.10

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

* [PATCH 3/5] iio: at91: ADC start-up time calculation changed since at91sam9x5
  2013-07-14  8:04 ` Josh Wu
@ 2013-07-14  8:04   ` Josh Wu
  -1 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-14  8:04 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, Josh Wu

Since in at91sam9x5, sama5d3x chip. the start up time calucation is changed.
And these two chips also have TSMR, so we check whether ADC has TSMR, then
choose different start up time calculation formula.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
 drivers/iio/adc/at91_adc.c |   40 +++++++++++++++++++++++++++++++++-------
 1 file changed, 33 insertions(+), 7 deletions(-)

diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 14e99ba..e93a075 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -733,13 +733,39 @@ static int at91_adc_probe(struct platform_device *pdev)
 		goto error_disable_adc_clk;
 	}
 
-	/*
-	 * 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;
+	if (!st->caps.has_tsmr) {
+		/*
+		 * 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;
+	} else {
+		/*
+		 * 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);
+		ticks = st->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;
+	}
+
 	/*
 	 * a minimal Sample and Hold Time is necessary for the ADC to guarantee
 	 * the best converted final value between two channels selection
-- 
1.7.10

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

* [PATCH 3/5] iio: at91: ADC start-up time calculation changed since at91sam9x5
@ 2013-07-14  8:04   ` Josh Wu
  0 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-14  8:04 UTC (permalink / raw)
  To: linux-arm-kernel

Since in at91sam9x5, sama5d3x chip. the start up time calucation is changed.
And these two chips also have TSMR, so we check whether ADC has TSMR, then
choose different start up time calculation formula.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
---
 drivers/iio/adc/at91_adc.c |   40 +++++++++++++++++++++++++++++++++-------
 1 file changed, 33 insertions(+), 7 deletions(-)

diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 14e99ba..e93a075 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -733,13 +733,39 @@ static int at91_adc_probe(struct platform_device *pdev)
 		goto error_disable_adc_clk;
 	}
 
-	/*
-	 * 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;
+	if (!st->caps.has_tsmr) {
+		/*
+		 * 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;
+	} else {
+		/*
+		 * 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);
+		ticks = st->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;
+	}
+
 	/*
 	 * a minimal Sample and Hold Time is necessary for the ADC to guarantee
 	 * the best converted final value between two channels selection
-- 
1.7.10

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

* [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz.
  2013-07-14  8:04 ` Josh Wu
@ 2013-07-14  8:04   ` Josh Wu
  -1 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-14  8:04 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, Josh Wu

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

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 16769d9..0db2945 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -27,6 +27,8 @@ 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-clock-rate: ADC clock rate. If not specified, use the default
+			  adc_op_clk.
  
 Optional trigger Nodes:
   - Required properties:
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index e93a075..8f1386f 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -47,6 +47,7 @@ struct at91_adc_caps {
 
 struct at91_adc_state {
 	struct clk		*adc_clk;
+	u32			adc_clk_rate;
 	u16			*buffer;
 	unsigned long		channels_mask;
 	struct clk		*clk;
@@ -448,6 +449,10 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 	if (!node)
 		return -EINVAL;
 
+	prop = 0;
+	of_property_read_u32(node, "atmel,adc-clock-rate", &prop);
+	st->adc_clk_rate = prop;
+
 	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
 
 	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
@@ -723,7 +728,8 @@ static int at91_adc_probe(struct platform_device *pdev)
 	 * specified by the electrical characteristics of the board.
 	 */
 	mstrclk = clk_get_rate(st->clk);
-	adc_clk = clk_get_rate(st->adc_clk);
+	adc_clk = st->adc_clk_rate ?
+		st->adc_clk_rate : clk_get_rate(st->adc_clk);
 	adc_clk_khz = adc_clk / 1000;
 	prsc = (mstrclk / (2 * adc_clk)) - 1;
 
-- 
1.7.10

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

* [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz.
@ 2013-07-14  8:04   ` Josh Wu
  0 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-14  8:04 UTC (permalink / raw)
  To: linux-arm-kernel

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

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 16769d9..0db2945 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -27,6 +27,8 @@ 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-clock-rate: ADC clock rate. If not specified, use the default
+			  adc_op_clk.
  
 Optional trigger Nodes:
   - Required properties:
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index e93a075..8f1386f 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -47,6 +47,7 @@ struct at91_adc_caps {
 
 struct at91_adc_state {
 	struct clk		*adc_clk;
+	u32			adc_clk_rate;
 	u16			*buffer;
 	unsigned long		channels_mask;
 	struct clk		*clk;
@@ -448,6 +449,10 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 	if (!node)
 		return -EINVAL;
 
+	prop = 0;
+	of_property_read_u32(node, "atmel,adc-clock-rate", &prop);
+	st->adc_clk_rate = prop;
+
 	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
 
 	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
@@ -723,7 +728,8 @@ static int at91_adc_probe(struct platform_device *pdev)
 	 * specified by the electrical characteristics of the board.
 	 */
 	mstrclk = clk_get_rate(st->clk);
-	adc_clk = clk_get_rate(st->adc_clk);
+	adc_clk = st->adc_clk_rate ?
+		st->adc_clk_rate : clk_get_rate(st->adc_clk);
 	adc_clk_khz = adc_clk / 1000;
 	prsc = (mstrclk / (2 * adc_clk)) - 1;
 
-- 
1.7.10

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

* [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
  2013-07-14  8:04 ` Josh Wu
@ 2013-07-14  8:04   ` Josh Wu
  -1 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-14  8:04 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, 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:
  which type of touch are used? (4 or 5 wires), sample period time,
  pen detect debounce time, average samples and pen detect resistor.

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>
---
 .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
 arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
 drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
 3 files changed, 412 insertions(+), 24 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 0db2945..925d656 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -29,6 +29,19 @@ Optional properties:
   - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
   - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
 			  adc_op_clk.
+  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
+				 4 and 5 wires touch screen.
+    NOTE: when adc touch screen enabled, the adc hardware trigger will be
+          disabled. Since touch screen will occupied the trigger register.
+  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
+				  detect.
+  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
+				     touch screen
+  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
+    0 means no average. 1 means average two samples. 2 means average four
+    samples. 3 means average eight samples.
+  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
+    It can be 0, 1, 2, 3.
  
 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 ab273ee..6d6cc14 100644
--- a/arch/arm/mach-at91/include/mach/at91_adc.h
+++ b/arch/arm/mach-at91/include/mach/at91_adc.h
@@ -57,10 +57,44 @@
 #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_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_VERSION	0xFC
 
+/* 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 8f1386f..ffc0e42 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,12 +40,24 @@
 #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 ZTHRESHOLD		9000
+
 struct at91_adc_caps {
+	bool	has_12bits_xy;	/* true means use 12 bits. Otherwise 10 bits */
 	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
 	u32	mr_prescal_mask;
 	u32	mr_startup_mask;
 };
 
+enum atmel_adc_ts_type {
+	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
+	ATMEL_ADC_TOUCHSCREEN_4WIRE,
+	ATMEL_ADC_TOUCHSCREEN_5WIRE,
+};
+
 struct at91_adc_state {
 	struct clk		*adc_clk;
 	u32			adc_clk_rate;
@@ -70,6 +83,29 @@ 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;
+
+	u8			ts_filter_average;
+	u16			ts_pen_detect_debounce;
+	u8			ts_pen_detect_sensitivity;
+	u16			ts_sample_period_time;
+	u16			ts_sample_period_val;
 };
 
 static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
@@ -104,14 +140,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);
@@ -121,6 +153,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->caps.has_12bits_xy ? 12 : 10;
+	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)
+		x /= xscale;
+	else
+		dev_err(&idev->dev, "xscale == 0!!!\n");
+
+	/* 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)
+		y /= yscale;
+	else
+		dev_err(&idev->dev, "yscale == 0!!!\n");
+
+	/* 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 = ZTHRESHOLD;	/* 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 < ZTHRESHOLD) {
+		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;
 }
@@ -130,6 +271,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;
@@ -561,6 +712,57 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 		i++;
 	}
 
+	/* Check if touchscreen is enabled in DT. */
+	ret = of_property_read_u32(node, "atmel,adc-touchscreen-wires", &prop);
+	if (ret)
+		dev_info(&idev->dev, "Touchscreen not enabled.\n");
+	else if (prop == 4)
+		st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_4WIRE;
+	else if (prop == 5)
+		st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_5WIRE;
+	else
+		dev_warn(&idev->dev, "Unsupported number of touchscreen wires (%d)\n",
+				prop);
+
+	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_NONE)
+		return 0;
+
+	/* Touch screen is enabled, so check touch screen dt parameters */
+	if (of_property_read_u32(node, "atmel,adc-ts-filter-average", &prop)) {
+		dev_err(&idev->dev, "Missing atmel,adc-ts-filtering-average property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->ts_filter_average = prop;
+	if (st->ts_filter_average > 3) {
+		dev_err(&idev->dev, "Invalid atmel,adc-ts-filtering-average property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+
+	prop = 0;
+	of_property_read_u32(node, "atmel,adc-ts-pendet-debounce", &prop);
+	st->ts_pen_detect_debounce = prop;
+
+	/* default sample period is 2ms. The real touch sample period should be
+	 * this period * TSFREQ.
+	 */
+	prop = 2000;
+	of_property_read_u32(node, "atmel,adc-ts-sample-period-time", &prop);
+	st->ts_sample_period_time = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-ts-pendet-sensitivity", &prop)) {
+		dev_err(&idev->dev, "Missing atmel,adc-ts-pendet-sensitivity property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->ts_pen_detect_sensitivity = prop;
+	if (st->ts_pen_detect_sensitivity > 3) {
+		dev_err(&idev->dev, "Invalid atmel,adc-ts-pendet-sensitivity property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+
 	return 0;
 
 error_ret:
@@ -592,6 +794,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(st->ts_pen_detect_debounce * 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->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->ts_pen_detect_sensitivity
+			& AT91_ADC_ACR_PENDETSENS);
+
+	/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
+	st->ts_sample_period_val = round_up((st->ts_sample_period_time *
+			adc_clk_khz / 1000) - 1, 1);
+
+	return 0;
+}
+
+static int at91_ts_register(struct at91_adc_state *st)
+{
+	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 = idev->dev.parent;
+	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);
+	input_free_device(st->ts_input);
+}
+
 /*
  * Since atmel adc support different ip for touchscreen mode. Through the
  * IP check, we will know the touchscreen capbilities.
@@ -610,6 +920,7 @@ static void atmel_adc_get_cap(struct at91_adc_state *st)
 	/* keep only major version number */
 	switch (version & 0xf00) {
 	case 0x500:	/* SAMA5D3 */
+		st->caps.has_12bits_xy = 1;
 	case 0x400:	/* AT91SAM9X5/9N12 */
 		st->caps.has_tsmr = 1;
 		st->caps.mr_startup_mask = AT91_ADC_STARTUP;
@@ -683,7 +994,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);
@@ -731,6 +1042,10 @@ static int at91_adc_probe(struct platform_device *pdev)
 	adc_clk = st->adc_clk_rate ?
 		st->adc_clk_rate : 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) {
@@ -799,30 +1114,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);
+		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:
@@ -841,8 +1178,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);
@@ -861,7 +1202,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] 85+ messages in thread

* [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
@ 2013-07-14  8:04   ` Josh Wu
  0 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-14  8:04 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:
  which type of touch are used? (4 or 5 wires), sample period time,
  pen detect debounce time, average samples and pen detect resistor.

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>
---
 .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
 arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
 drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
 3 files changed, 412 insertions(+), 24 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 0db2945..925d656 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -29,6 +29,19 @@ Optional properties:
   - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
   - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
 			  adc_op_clk.
+  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
+				 4 and 5 wires touch screen.
+    NOTE: when adc touch screen enabled, the adc hardware trigger will be
+          disabled. Since touch screen will occupied the trigger register.
+  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
+				  detect.
+  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
+				     touch screen
+  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
+    0 means no average. 1 means average two samples. 2 means average four
+    samples. 3 means average eight samples.
+  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
+    It can be 0, 1, 2, 3.
  
 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 ab273ee..6d6cc14 100644
--- a/arch/arm/mach-at91/include/mach/at91_adc.h
+++ b/arch/arm/mach-at91/include/mach/at91_adc.h
@@ -57,10 +57,44 @@
 #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_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_VERSION	0xFC
 
+/* 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 8f1386f..ffc0e42 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,12 +40,24 @@
 #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 ZTHRESHOLD		9000
+
 struct at91_adc_caps {
+	bool	has_12bits_xy;	/* true means use 12 bits. Otherwise 10 bits */
 	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
 	u32	mr_prescal_mask;
 	u32	mr_startup_mask;
 };
 
+enum atmel_adc_ts_type {
+	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
+	ATMEL_ADC_TOUCHSCREEN_4WIRE,
+	ATMEL_ADC_TOUCHSCREEN_5WIRE,
+};
+
 struct at91_adc_state {
 	struct clk		*adc_clk;
 	u32			adc_clk_rate;
@@ -70,6 +83,29 @@ 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;
+
+	u8			ts_filter_average;
+	u16			ts_pen_detect_debounce;
+	u8			ts_pen_detect_sensitivity;
+	u16			ts_sample_period_time;
+	u16			ts_sample_period_val;
 };
 
 static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
@@ -104,14 +140,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);
@@ -121,6 +153,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->caps.has_12bits_xy ? 12 : 10;
+	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)
+		x /= xscale;
+	else
+		dev_err(&idev->dev, "xscale == 0!!!\n");
+
+	/* 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)
+		y /= yscale;
+	else
+		dev_err(&idev->dev, "yscale == 0!!!\n");
+
+	/* 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 = ZTHRESHOLD;	/* 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 < ZTHRESHOLD) {
+		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;
 }
@@ -130,6 +271,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;
@@ -561,6 +712,57 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 		i++;
 	}
 
+	/* Check if touchscreen is enabled in DT. */
+	ret = of_property_read_u32(node, "atmel,adc-touchscreen-wires", &prop);
+	if (ret)
+		dev_info(&idev->dev, "Touchscreen not enabled.\n");
+	else if (prop == 4)
+		st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_4WIRE;
+	else if (prop == 5)
+		st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_5WIRE;
+	else
+		dev_warn(&idev->dev, "Unsupported number of touchscreen wires (%d)\n",
+				prop);
+
+	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_NONE)
+		return 0;
+
+	/* Touch screen is enabled, so check touch screen dt parameters */
+	if (of_property_read_u32(node, "atmel,adc-ts-filter-average", &prop)) {
+		dev_err(&idev->dev, "Missing atmel,adc-ts-filtering-average property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->ts_filter_average = prop;
+	if (st->ts_filter_average > 3) {
+		dev_err(&idev->dev, "Invalid atmel,adc-ts-filtering-average property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+
+	prop = 0;
+	of_property_read_u32(node, "atmel,adc-ts-pendet-debounce", &prop);
+	st->ts_pen_detect_debounce = prop;
+
+	/* default sample period is 2ms. The real touch sample period should be
+	 * this period * TSFREQ.
+	 */
+	prop = 2000;
+	of_property_read_u32(node, "atmel,adc-ts-sample-period-time", &prop);
+	st->ts_sample_period_time = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-ts-pendet-sensitivity", &prop)) {
+		dev_err(&idev->dev, "Missing atmel,adc-ts-pendet-sensitivity property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->ts_pen_detect_sensitivity = prop;
+	if (st->ts_pen_detect_sensitivity > 3) {
+		dev_err(&idev->dev, "Invalid atmel,adc-ts-pendet-sensitivity property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+
 	return 0;
 
 error_ret:
@@ -592,6 +794,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(st->ts_pen_detect_debounce * 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->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->ts_pen_detect_sensitivity
+			& AT91_ADC_ACR_PENDETSENS);
+
+	/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
+	st->ts_sample_period_val = round_up((st->ts_sample_period_time *
+			adc_clk_khz / 1000) - 1, 1);
+
+	return 0;
+}
+
+static int at91_ts_register(struct at91_adc_state *st)
+{
+	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 = idev->dev.parent;
+	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);
+	input_free_device(st->ts_input);
+}
+
 /*
  * Since atmel adc support different ip for touchscreen mode. Through the
  * IP check, we will know the touchscreen capbilities.
@@ -610,6 +920,7 @@ static void atmel_adc_get_cap(struct at91_adc_state *st)
 	/* keep only major version number */
 	switch (version & 0xf00) {
 	case 0x500:	/* SAMA5D3 */
+		st->caps.has_12bits_xy = 1;
 	case 0x400:	/* AT91SAM9X5/9N12 */
 		st->caps.has_tsmr = 1;
 		st->caps.mr_startup_mask = AT91_ADC_STARTUP;
@@ -683,7 +994,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);
@@ -731,6 +1042,10 @@ static int at91_adc_probe(struct platform_device *pdev)
 	adc_clk = st->adc_clk_rate ?
 		st->adc_clk_rate : 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) {
@@ -799,30 +1114,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);
+		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:
@@ -841,8 +1178,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);
@@ -861,7 +1202,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] 85+ messages in thread

* Re: [PATCH 1/5] iio: at91: use adc_clk_khz to make the calculation not easy to large than u32.
  2013-07-14  8:04   ` Josh Wu
@ 2013-07-15 12:52     ` Maxime Ripard
  -1 siblings, 0 replies; 85+ messages in thread
From: Maxime Ripard @ 2013-07-15 12:52 UTC (permalink / raw)
  To: Josh Wu; +Cc: jic23, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre

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

Hi Josh,

On Sun, Jul 14, 2013 at 04:04:25PM +0800, Josh Wu wrote:
> for example, if adc_clk is 20Mhz and start-up time set as larger than 215us.
> then the calculation "st->startup_time * adc_clk_khz" will out of u32.
> 
> In this patch, it will use khz unit for adc_clk, that avoids above problem.
> 
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

Maybe we can have a slightly better commit log here, like:

------8<-----------
iio: at91: Fix adc_clk overflow

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.

--------8<---------------

Or something like that.

For the patch itself, I'm happy about it. You can add my Acked-by.

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] 85+ messages in thread

* [PATCH 1/5] iio: at91: use adc_clk_khz to make the calculation not easy to large than u32.
@ 2013-07-15 12:52     ` Maxime Ripard
  0 siblings, 0 replies; 85+ messages in thread
From: Maxime Ripard @ 2013-07-15 12:52 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Josh,

On Sun, Jul 14, 2013 at 04:04:25PM +0800, Josh Wu wrote:
> for example, if adc_clk is 20Mhz and start-up time set as larger than 215us.
> then the calculation "st->startup_time * adc_clk_khz" will out of u32.
> 
> In this patch, it will use khz unit for adc_clk, that avoids above problem.
> 
> Signed-off-by: Josh Wu <josh.wu@atmel.com>

Maybe we can have a slightly better commit log here, like:

------8<-----------
iio: at91: Fix adc_clk overflow

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.

--------8<---------------

Or something like that.

For the patch itself, I'm happy about it. You can add my Acked-by.

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/20130715/b37339f0/attachment.sig>

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-07-14  8:04   ` Josh Wu
@ 2013-07-15 12:58     ` Maxime Ripard
  -1 siblings, 0 replies; 85+ messages in thread
From: Maxime Ripard @ 2013-07-15 12:58 UTC (permalink / raw)
  To: Josh Wu; +Cc: jic23, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre

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

Hi Josh,

On Sun, Jul 14, 2013 at 04:04:26PM +0800, Josh Wu wrote:
> For at91 boards, there are different IPs for adc. Different IPs has different
> STARTUP & PRESCAL mask in ADC_MR.
> 
> This patch can change the masks according to the different IP version.
> 
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> ---
>  arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
>  drivers/iio/adc/at91_adc.c                 |   48 ++++++++++++++++++++++++++--
>  2 files changed, 53 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 8e7ed5c..ab273ee 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	(0xff << 8)	/* Prescalar Rate Selection */
> +#define		AT91_ADC_PRESCAL_9260	(0x3f << 8)
>  #define			AT91_ADC_PRESCAL_(x)	((x) << 8)
> -#define		AT91_ADC_STARTUP	(0x1f << 16)	/* Startup Up Time */
> +#define		AT91_ADC_STARTUP	(0xf << 16)	/* Startup Up Time */
> +#define		AT91_ADC_STARTUP_9260	(0x1f << 16)
> +#define		AT91_ADC_STARTUP_9G45	(0x7f << 16)
>  #define			AT91_ADC_STARTUP_(x)	((x) << 16)
>  #define		AT91_ADC_SHTIM		(0xf  << 24)	/* Sample & Hold Time */
>  #define			AT91_ADC_SHTIM_(x)	((x) << 24)
> @@ -58,4 +61,6 @@
>  #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
>  #define		AT91_ADC_DATA		(0x3ff)
>  
> +#define AT91_ADC_VERSION	0xFC
> +
>  #endif
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index 18bd54f..14e99ba 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -39,6 +39,12 @@
>  #define at91_adc_writel(st, reg, val) \
>  	(writel_relaxed(val, st->reg_base + reg))
>  
> +struct at91_adc_caps {
> +	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
> +	u32	mr_prescal_mask;
> +	u32	mr_startup_mask;
> +};
> +
>  struct at91_adc_state {
>  	struct clk		*adc_clk;
>  	u16			*buffer;
> @@ -62,6 +68,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)
> @@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
>  	.read_raw = &at91_adc_read_raw,
>  };
>  
> +/*
> + * Since atmel adc support different ip for touchscreen mode. Through the
> + * IP check, we will know the touchscreen capbilities.
> + */
> +static void atmel_adc_get_cap(struct at91_adc_state *st)
> +{
> +	unsigned int version;
> +	struct iio_dev *idev = iio_priv_to_dev(st);
> +
> +	version = at91_adc_readl(st, AT91_ADC_VERSION);
> +	dev_dbg(&idev->dev, "version: 0x%x\n", version);
> +
> +	st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
> +	st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
> +
> +	/* keep only major version number */
> +	switch (version & 0xf00) {
> +	case 0x500:	/* SAMA5D3 */
> +	case 0x400:	/* AT91SAM9X5/9N12 */
> +		st->caps.has_tsmr = 1;
> +		st->caps.mr_startup_mask = AT91_ADC_STARTUP;
> +	case 0x200:	/* AT91SAM9M10/9G45 */
> +		st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
> +
> +		if ((version & 0xf00) == 0x200)
> +			st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
> +	case 0x100:	/* AT91SAM9260/9G20 */
> +		break;
> +	default:
> +		dev_warn(&idev->dev,
> +				"Unmanaged adc version, use minimal capabilities\n");
> +		break;
> +	};
> +}

Why don't you use different compatible names and derive your
capabilities from which compatible is declared.

It seems safer.

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] 85+ messages in thread

* [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-15 12:58     ` Maxime Ripard
  0 siblings, 0 replies; 85+ messages in thread
From: Maxime Ripard @ 2013-07-15 12:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Josh,

On Sun, Jul 14, 2013 at 04:04:26PM +0800, Josh Wu wrote:
> For at91 boards, there are different IPs for adc. Different IPs has different
> STARTUP & PRESCAL mask in ADC_MR.
> 
> This patch can change the masks according to the different IP version.
> 
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> ---
>  arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
>  drivers/iio/adc/at91_adc.c                 |   48 ++++++++++++++++++++++++++--
>  2 files changed, 53 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 8e7ed5c..ab273ee 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	(0xff << 8)	/* Prescalar Rate Selection */
> +#define		AT91_ADC_PRESCAL_9260	(0x3f << 8)
>  #define			AT91_ADC_PRESCAL_(x)	((x) << 8)
> -#define		AT91_ADC_STARTUP	(0x1f << 16)	/* Startup Up Time */
> +#define		AT91_ADC_STARTUP	(0xf << 16)	/* Startup Up Time */
> +#define		AT91_ADC_STARTUP_9260	(0x1f << 16)
> +#define		AT91_ADC_STARTUP_9G45	(0x7f << 16)
>  #define			AT91_ADC_STARTUP_(x)	((x) << 16)
>  #define		AT91_ADC_SHTIM		(0xf  << 24)	/* Sample & Hold Time */
>  #define			AT91_ADC_SHTIM_(x)	((x) << 24)
> @@ -58,4 +61,6 @@
>  #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
>  #define		AT91_ADC_DATA		(0x3ff)
>  
> +#define AT91_ADC_VERSION	0xFC
> +
>  #endif
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index 18bd54f..14e99ba 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -39,6 +39,12 @@
>  #define at91_adc_writel(st, reg, val) \
>  	(writel_relaxed(val, st->reg_base + reg))
>  
> +struct at91_adc_caps {
> +	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
> +	u32	mr_prescal_mask;
> +	u32	mr_startup_mask;
> +};
> +
>  struct at91_adc_state {
>  	struct clk		*adc_clk;
>  	u16			*buffer;
> @@ -62,6 +68,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)
> @@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
>  	.read_raw = &at91_adc_read_raw,
>  };
>  
> +/*
> + * Since atmel adc support different ip for touchscreen mode. Through the
> + * IP check, we will know the touchscreen capbilities.
> + */
> +static void atmel_adc_get_cap(struct at91_adc_state *st)
> +{
> +	unsigned int version;
> +	struct iio_dev *idev = iio_priv_to_dev(st);
> +
> +	version = at91_adc_readl(st, AT91_ADC_VERSION);
> +	dev_dbg(&idev->dev, "version: 0x%x\n", version);
> +
> +	st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
> +	st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
> +
> +	/* keep only major version number */
> +	switch (version & 0xf00) {
> +	case 0x500:	/* SAMA5D3 */
> +	case 0x400:	/* AT91SAM9X5/9N12 */
> +		st->caps.has_tsmr = 1;
> +		st->caps.mr_startup_mask = AT91_ADC_STARTUP;
> +	case 0x200:	/* AT91SAM9M10/9G45 */
> +		st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
> +
> +		if ((version & 0xf00) == 0x200)
> +			st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
> +	case 0x100:	/* AT91SAM9260/9G20 */
> +		break;
> +	default:
> +		dev_warn(&idev->dev,
> +				"Unmanaged adc version, use minimal capabilities\n");
> +		break;
> +	};
> +}

Why don't you use different compatible names and derive your
capabilities from which compatible is declared.

It seems safer.

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/20130715/896a845b/attachment.sig>

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

* Re: [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz.
  2013-07-14  8:04   ` Josh Wu
@ 2013-07-15 13:06     ` Maxime Ripard
  -1 siblings, 0 replies; 85+ messages in thread
From: Maxime Ripard @ 2013-07-15 13:06 UTC (permalink / raw)
  To: Josh Wu; +Cc: jic23, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre

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

Hi Josh,

On Sun, Jul 14, 2013 at 04:04:28PM +0800, Josh Wu wrote:
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> ---
>  Documentation/devicetree/bindings/arm/atmel-adc.txt |    2 ++
>  drivers/iio/adc/at91_adc.c                          |    8 +++++++-
>  2 files changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> index 16769d9..0db2945 100644
> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> @@ -27,6 +27,8 @@ 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-clock-rate: ADC clock rate. If not specified, use the default
> +			  adc_op_clk.
>   
>  Optional trigger Nodes:
>    - Required properties:
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index e93a075..8f1386f 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -47,6 +47,7 @@ struct at91_adc_caps {
>  
>  struct at91_adc_state {
>  	struct clk		*adc_clk;
> +	u32			adc_clk_rate;
>  	u16			*buffer;
>  	unsigned long		channels_mask;
>  	struct clk		*clk;
> @@ -448,6 +449,10 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>  	if (!node)
>  		return -EINVAL;
>  
> +	prop = 0;
> +	of_property_read_u32(node, "atmel,adc-clock-rate", &prop);
> +	st->adc_clk_rate = prop;
> +
>  	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
>  
>  	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
> @@ -723,7 +728,8 @@ static int at91_adc_probe(struct platform_device *pdev)
>  	 * specified by the electrical characteristics of the board.
>  	 */
>  	mstrclk = clk_get_rate(st->clk);
> -	adc_clk = clk_get_rate(st->adc_clk);
> +	adc_clk = st->adc_clk_rate ?
> +		st->adc_clk_rate : clk_get_rate(st->adc_clk);

Why is that needed? Isn't it completely redundant with the clocks
property?

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] 85+ messages in thread

* [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz.
@ 2013-07-15 13:06     ` Maxime Ripard
  0 siblings, 0 replies; 85+ messages in thread
From: Maxime Ripard @ 2013-07-15 13:06 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Josh,

On Sun, Jul 14, 2013 at 04:04:28PM +0800, Josh Wu wrote:
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> ---
>  Documentation/devicetree/bindings/arm/atmel-adc.txt |    2 ++
>  drivers/iio/adc/at91_adc.c                          |    8 +++++++-
>  2 files changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> index 16769d9..0db2945 100644
> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> @@ -27,6 +27,8 @@ 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-clock-rate: ADC clock rate. If not specified, use the default
> +			  adc_op_clk.
>   
>  Optional trigger Nodes:
>    - Required properties:
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index e93a075..8f1386f 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -47,6 +47,7 @@ struct at91_adc_caps {
>  
>  struct at91_adc_state {
>  	struct clk		*adc_clk;
> +	u32			adc_clk_rate;
>  	u16			*buffer;
>  	unsigned long		channels_mask;
>  	struct clk		*clk;
> @@ -448,6 +449,10 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>  	if (!node)
>  		return -EINVAL;
>  
> +	prop = 0;
> +	of_property_read_u32(node, "atmel,adc-clock-rate", &prop);
> +	st->adc_clk_rate = prop;
> +
>  	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
>  
>  	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
> @@ -723,7 +728,8 @@ static int at91_adc_probe(struct platform_device *pdev)
>  	 * specified by the electrical characteristics of the board.
>  	 */
>  	mstrclk = clk_get_rate(st->clk);
> -	adc_clk = clk_get_rate(st->adc_clk);
> +	adc_clk = st->adc_clk_rate ?
> +		st->adc_clk_rate : clk_get_rate(st->adc_clk);

Why is that needed? Isn't it completely redundant with the clocks
property?

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/20130715/bc33e590/attachment-0001.sig>

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

* Re: [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
  2013-07-14  8:04   ` Josh Wu
@ 2013-07-15 13:15     ` Maxime Ripard
  -1 siblings, 0 replies; 85+ messages in thread
From: Maxime Ripard @ 2013-07-15 13:15 UTC (permalink / raw)
  To: Josh Wu
  Cc: jic23, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre,
	Dmitry Torokhov

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

Hi Josh,

On Sun, Jul 14, 2013 at 04:04:29PM +0800, 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:
>   which type of touch are used? (4 or 5 wires), sample period time,
>   pen detect debounce time, average samples and pen detect resistor.
> 
> 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>
> ---
>  .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
>  arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>  drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
>  3 files changed, 412 insertions(+), 24 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> index 0db2945..925d656 100644
> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> @@ -29,6 +29,19 @@ Optional properties:
>    - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
>    - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
>  			  adc_op_clk.
> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
> +				 4 and 5 wires touch screen.
> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> +          disabled. Since touch screen will occupied the trigger register.
> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
> +				  detect.
> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
> +				     touch screen
> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
> +    0 means no average. 1 means average two samples. 2 means average four
> +    samples. 3 means average eight samples.
> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
> +    It can be 0, 1, 2, 3.

Could you expand a bit on what are these properties for? Are they
board-specific? IP-specific?

[...]

> +#define DRIVER_NAME		"at91_adc"

This looks like this part doesn't belong to another cleanup patch.

> +#define MAX_POS_BITS		12
> +
> +#define ZTHRESHOLD		9000
> +
>  struct at91_adc_caps {
> +	bool	has_12bits_xy;	/* true means use 12 bits. Otherwise 10 bits */

Isn't that redundant with the low_res boolean?

>  	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
>  	u32	mr_prescal_mask;
>  	u32	mr_startup_mask;
>  };
>  
> +enum atmel_adc_ts_type {
> +	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
> +	ATMEL_ADC_TOUCHSCREEN_4WIRE,
> +	ATMEL_ADC_TOUCHSCREEN_5WIRE,
> +};
> +
>  struct at91_adc_state {
>  	struct clk		*adc_clk;
>  	u32			adc_clk_rate;
> @@ -70,6 +83,29 @@ 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;
> +
> +	u8			ts_filter_average;
> +	u16			ts_pen_detect_debounce;
> +	u8			ts_pen_detect_sensitivity;
> +	u16			ts_sample_period_time;
> +	u16			ts_sample_period_val;
>  };
>  
>  static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
> @@ -104,14 +140,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;

Why are you changing the prototype and remove most of the useful part
out of the handler?

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] 85+ messages in thread

* [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
@ 2013-07-15 13:15     ` Maxime Ripard
  0 siblings, 0 replies; 85+ messages in thread
From: Maxime Ripard @ 2013-07-15 13:15 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Josh,

On Sun, Jul 14, 2013 at 04:04:29PM +0800, 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:
>   which type of touch are used? (4 or 5 wires), sample period time,
>   pen detect debounce time, average samples and pen detect resistor.
> 
> 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>
> ---
>  .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
>  arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>  drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
>  3 files changed, 412 insertions(+), 24 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> index 0db2945..925d656 100644
> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> @@ -29,6 +29,19 @@ Optional properties:
>    - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
>    - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
>  			  adc_op_clk.
> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
> +				 4 and 5 wires touch screen.
> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> +          disabled. Since touch screen will occupied the trigger register.
> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
> +				  detect.
> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
> +				     touch screen
> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
> +    0 means no average. 1 means average two samples. 2 means average four
> +    samples. 3 means average eight samples.
> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
> +    It can be 0, 1, 2, 3.

Could you expand a bit on what are these properties for? Are they
board-specific? IP-specific?

[...]

> +#define DRIVER_NAME		"at91_adc"

This looks like this part doesn't belong to another cleanup patch.

> +#define MAX_POS_BITS		12
> +
> +#define ZTHRESHOLD		9000
> +
>  struct at91_adc_caps {
> +	bool	has_12bits_xy;	/* true means use 12 bits. Otherwise 10 bits */

Isn't that redundant with the low_res boolean?

>  	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
>  	u32	mr_prescal_mask;
>  	u32	mr_startup_mask;
>  };
>  
> +enum atmel_adc_ts_type {
> +	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
> +	ATMEL_ADC_TOUCHSCREEN_4WIRE,
> +	ATMEL_ADC_TOUCHSCREEN_5WIRE,
> +};
> +
>  struct at91_adc_state {
>  	struct clk		*adc_clk;
>  	u32			adc_clk_rate;
> @@ -70,6 +83,29 @@ 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;
> +
> +	u8			ts_filter_average;
> +	u16			ts_pen_detect_debounce;
> +	u8			ts_pen_detect_sensitivity;
> +	u16			ts_sample_period_time;
> +	u16			ts_sample_period_val;
>  };
>  
>  static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
> @@ -104,14 +140,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;

Why are you changing the prototype and remove most of the useful part
out of the handler?

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/20130715/14495b41/attachment.sig>

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

* Re: [PATCH 1/5] iio: at91: use adc_clk_khz to make the calculation not easy to large than u32.
  2013-07-15 12:52     ` Maxime Ripard
@ 2013-07-16  7:54       ` Josh Wu
  -1 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-16  7:54 UTC (permalink / raw)
  To: Maxime Ripard; +Cc: jic23, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre

Hi, Maxime

On 7/15/2013 8:52 PM, Maxime Ripard wrote:
> Hi Josh,
>
> On Sun, Jul 14, 2013 at 04:04:25PM +0800, Josh Wu wrote:
>> for example, if adc_clk is 20Mhz and start-up time set as larger than 215us.
>> then the calculation "st->startup_time * adc_clk_khz" will out of u32.
>>
>> In this patch, it will use khz unit for adc_clk, that avoids above problem.
>>
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> Maybe we can have a slightly better commit log here, like:
>
> ------8<-----------
> iio: at91: Fix adc_clk overflow
>
> 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.
>
> --------8<---------------
>
> Or something like that.
>
> For the patch itself, I'm happy about it. You can add my Acked-by.

Thank you. Your commit log is better. I will fix the commit log base on 
your commit in next version.

>
> Thanks!
> Maxime
>

Best Regards,
Josh Wu

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

* [PATCH 1/5] iio: at91: use adc_clk_khz to make the calculation not easy to large than u32.
@ 2013-07-16  7:54       ` Josh Wu
  0 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-16  7:54 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, Maxime

On 7/15/2013 8:52 PM, Maxime Ripard wrote:
> Hi Josh,
>
> On Sun, Jul 14, 2013 at 04:04:25PM +0800, Josh Wu wrote:
>> for example, if adc_clk is 20Mhz and start-up time set as larger than 215us.
>> then the calculation "st->startup_time * adc_clk_khz" will out of u32.
>>
>> In this patch, it will use khz unit for adc_clk, that avoids above problem.
>>
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> Maybe we can have a slightly better commit log here, like:
>
> ------8<-----------
> iio: at91: Fix adc_clk overflow
>
> 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.
>
> --------8<---------------
>
> Or something like that.
>
> For the patch itself, I'm happy about it. You can add my Acked-by.

Thank you. Your commit log is better. I will fix the commit log base on 
your commit in next version.

>
> Thanks!
> Maxime
>

Best Regards,
Josh Wu

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

* Re: [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz.
  2013-07-15 13:06     ` Maxime Ripard
@ 2013-07-16  7:55       ` Josh Wu
  -1 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-16  7:55 UTC (permalink / raw)
  To: Maxime Ripard; +Cc: jic23, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre

Hi, Maxime

On 7/15/2013 9:06 PM, Maxime Ripard wrote:
> Hi Josh,
>
> On Sun, Jul 14, 2013 at 04:04:28PM +0800, Josh Wu wrote:
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>> ---
>>   Documentation/devicetree/bindings/arm/atmel-adc.txt |    2 ++
>>   drivers/iio/adc/at91_adc.c                          |    8 +++++++-
>>   2 files changed, 9 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> index 16769d9..0db2945 100644
>> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> @@ -27,6 +27,8 @@ 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-clock-rate: ADC clock rate. If not specified, use the default
>> +			  adc_op_clk.
>>    
>>   Optional trigger Nodes:
>>     - Required properties:
>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>> index e93a075..8f1386f 100644
>> --- a/drivers/iio/adc/at91_adc.c
>> +++ b/drivers/iio/adc/at91_adc.c
>> @@ -47,6 +47,7 @@ struct at91_adc_caps {
>>   
>>   struct at91_adc_state {
>>   	struct clk		*adc_clk;
>> +	u32			adc_clk_rate;
>>   	u16			*buffer;
>>   	unsigned long		channels_mask;
>>   	struct clk		*clk;
>> @@ -448,6 +449,10 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>>   	if (!node)
>>   		return -EINVAL;
>>   
>> +	prop = 0;
>> +	of_property_read_u32(node, "atmel,adc-clock-rate", &prop);
>> +	st->adc_clk_rate = prop;
>> +
>>   	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
>>   
>>   	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
>> @@ -723,7 +728,8 @@ static int at91_adc_probe(struct platform_device *pdev)
>>   	 * specified by the electrical characteristics of the board.
>>   	 */
>>   	mstrclk = clk_get_rate(st->clk);
>> -	adc_clk = clk_get_rate(st->adc_clk);
>> +	adc_clk = st->adc_clk_rate ?
>> +		st->adc_clk_rate : clk_get_rate(st->adc_clk);
> Why is that needed? Isn't it completely redundant with the clocks
> property?

As st->adc_clk rate is specified in arch/arm/mach-at91/sama5d3.c (take 
sama5d3 for example), changing the clock rate should recompile the 
kernel binary.
Use dt parameter will let us easily specify the clock rate instead of 
recompile the code.

And yes, it is redundant that we can define the adc_op_clk rate in two 
places (clock property in .c and adc-clock-rate in dts). But this can be 
compatible with the non-dt platform.

After a further thinking of this, maybe remove the adc_op_clk is better 
since it is a fake clock, and only used to specify the clock rate.
To specify the clock rate use a dt property or platform data parameter 
is better.

>
> Maxime
>
>

Best Regards,
Josh Wu

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

* [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz.
@ 2013-07-16  7:55       ` Josh Wu
  0 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-16  7:55 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, Maxime

On 7/15/2013 9:06 PM, Maxime Ripard wrote:
> Hi Josh,
>
> On Sun, Jul 14, 2013 at 04:04:28PM +0800, Josh Wu wrote:
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>> ---
>>   Documentation/devicetree/bindings/arm/atmel-adc.txt |    2 ++
>>   drivers/iio/adc/at91_adc.c                          |    8 +++++++-
>>   2 files changed, 9 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> index 16769d9..0db2945 100644
>> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> @@ -27,6 +27,8 @@ 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-clock-rate: ADC clock rate. If not specified, use the default
>> +			  adc_op_clk.
>>    
>>   Optional trigger Nodes:
>>     - Required properties:
>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>> index e93a075..8f1386f 100644
>> --- a/drivers/iio/adc/at91_adc.c
>> +++ b/drivers/iio/adc/at91_adc.c
>> @@ -47,6 +47,7 @@ struct at91_adc_caps {
>>   
>>   struct at91_adc_state {
>>   	struct clk		*adc_clk;
>> +	u32			adc_clk_rate;
>>   	u16			*buffer;
>>   	unsigned long		channels_mask;
>>   	struct clk		*clk;
>> @@ -448,6 +449,10 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>>   	if (!node)
>>   		return -EINVAL;
>>   
>> +	prop = 0;
>> +	of_property_read_u32(node, "atmel,adc-clock-rate", &prop);
>> +	st->adc_clk_rate = prop;
>> +
>>   	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
>>   
>>   	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
>> @@ -723,7 +728,8 @@ static int at91_adc_probe(struct platform_device *pdev)
>>   	 * specified by the electrical characteristics of the board.
>>   	 */
>>   	mstrclk = clk_get_rate(st->clk);
>> -	adc_clk = clk_get_rate(st->adc_clk);
>> +	adc_clk = st->adc_clk_rate ?
>> +		st->adc_clk_rate : clk_get_rate(st->adc_clk);
> Why is that needed? Isn't it completely redundant with the clocks
> property?

As st->adc_clk rate is specified in arch/arm/mach-at91/sama5d3.c (take 
sama5d3 for example), changing the clock rate should recompile the 
kernel binary.
Use dt parameter will let us easily specify the clock rate instead of 
recompile the code.

And yes, it is redundant that we can define the adc_op_clk rate in two 
places (clock property in .c and adc-clock-rate in dts). But this can be 
compatible with the non-dt platform.

After a further thinking of this, maybe remove the adc_op_clk is better 
since it is a fake clock, and only used to specify the clock rate.
To specify the clock rate use a dt property or platform data parameter 
is better.

>
> Maxime
>
>

Best Regards,
Josh Wu

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-07-15 12:58     ` Maxime Ripard
@ 2013-07-16  8:35       ` Josh Wu
  -1 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-16  8:35 UTC (permalink / raw)
  To: Maxime Ripard; +Cc: jic23, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre

Hi, Maxime

On 7/15/2013 8:58 PM, Maxime Ripard wrote:
> Hi Josh,
>
> On Sun, Jul 14, 2013 at 04:04:26PM +0800, Josh Wu wrote:
>> For at91 boards, there are different IPs for adc. Different IPs has different
>> STARTUP & PRESCAL mask in ADC_MR.
>>
>> This patch can change the masks according to the different IP version.
>>
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>> ---
>>   arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
>>   drivers/iio/adc/at91_adc.c                 |   48 ++++++++++++++++++++++++++--
>>   2 files changed, 53 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 8e7ed5c..ab273ee 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	(0xff << 8)	/* Prescalar Rate Selection */
>> +#define		AT91_ADC_PRESCAL_9260	(0x3f << 8)
>>   #define			AT91_ADC_PRESCAL_(x)	((x) << 8)
>> -#define		AT91_ADC_STARTUP	(0x1f << 16)	/* Startup Up Time */
>> +#define		AT91_ADC_STARTUP	(0xf << 16)	/* Startup Up Time */
>> +#define		AT91_ADC_STARTUP_9260	(0x1f << 16)
>> +#define		AT91_ADC_STARTUP_9G45	(0x7f << 16)
>>   #define			AT91_ADC_STARTUP_(x)	((x) << 16)
>>   #define		AT91_ADC_SHTIM		(0xf  << 24)	/* Sample & Hold Time */
>>   #define			AT91_ADC_SHTIM_(x)	((x) << 24)
>> @@ -58,4 +61,6 @@
>>   #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
>>   #define		AT91_ADC_DATA		(0x3ff)
>>   
>> +#define AT91_ADC_VERSION	0xFC
>> +
>>   #endif
>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>> index 18bd54f..14e99ba 100644
>> --- a/drivers/iio/adc/at91_adc.c
>> +++ b/drivers/iio/adc/at91_adc.c
>> @@ -39,6 +39,12 @@
>>   #define at91_adc_writel(st, reg, val) \
>>   	(writel_relaxed(val, st->reg_base + reg))
>>   
>> +struct at91_adc_caps {
>> +	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
>> +	u32	mr_prescal_mask;
>> +	u32	mr_startup_mask;
>> +};
>> +
>>   struct at91_adc_state {
>>   	struct clk		*adc_clk;
>>   	u16			*buffer;
>> @@ -62,6 +68,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)
>> @@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
>>   	.read_raw = &at91_adc_read_raw,
>>   };
>>   
>> +/*
>> + * Since atmel adc support different ip for touchscreen mode. Through the
>> + * IP check, we will know the touchscreen capbilities.
>> + */
>> +static void atmel_adc_get_cap(struct at91_adc_state *st)
>> +{
>> +	unsigned int version;
>> +	struct iio_dev *idev = iio_priv_to_dev(st);
>> +
>> +	version = at91_adc_readl(st, AT91_ADC_VERSION);
>> +	dev_dbg(&idev->dev, "version: 0x%x\n", version);
>> +
>> +	st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
>> +	st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
>> +
>> +	/* keep only major version number */
>> +	switch (version & 0xf00) {
>> +	case 0x500:	/* SAMA5D3 */
>> +	case 0x400:	/* AT91SAM9X5/9N12 */
>> +		st->caps.has_tsmr = 1;
>> +		st->caps.mr_startup_mask = AT91_ADC_STARTUP;
>> +	case 0x200:	/* AT91SAM9M10/9G45 */
>> +		st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
>> +
>> +		if ((version & 0xf00) == 0x200)
>> +			st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
>> +	case 0x100:	/* AT91SAM9260/9G20 */
>> +		break;
>> +	default:
>> +		dev_warn(&idev->dev,
>> +				"Unmanaged adc version, use minimal capabilities\n");
>> +		break;
>> +	};
>> +}
> Why don't you use different compatible names and derive your
> capabilities from which compatible is declared.
>
> It seems safer.

Ok, that make sense. I will use compatible names for the capabilities in 
next version. Thanks.

>
> Maxime
>

Best Regards,
Josh Wu

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

* [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-16  8:35       ` Josh Wu
  0 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-16  8:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, Maxime

On 7/15/2013 8:58 PM, Maxime Ripard wrote:
> Hi Josh,
>
> On Sun, Jul 14, 2013 at 04:04:26PM +0800, Josh Wu wrote:
>> For at91 boards, there are different IPs for adc. Different IPs has different
>> STARTUP & PRESCAL mask in ADC_MR.
>>
>> This patch can change the masks according to the different IP version.
>>
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>> ---
>>   arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
>>   drivers/iio/adc/at91_adc.c                 |   48 ++++++++++++++++++++++++++--
>>   2 files changed, 53 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 8e7ed5c..ab273ee 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	(0xff << 8)	/* Prescalar Rate Selection */
>> +#define		AT91_ADC_PRESCAL_9260	(0x3f << 8)
>>   #define			AT91_ADC_PRESCAL_(x)	((x) << 8)
>> -#define		AT91_ADC_STARTUP	(0x1f << 16)	/* Startup Up Time */
>> +#define		AT91_ADC_STARTUP	(0xf << 16)	/* Startup Up Time */
>> +#define		AT91_ADC_STARTUP_9260	(0x1f << 16)
>> +#define		AT91_ADC_STARTUP_9G45	(0x7f << 16)
>>   #define			AT91_ADC_STARTUP_(x)	((x) << 16)
>>   #define		AT91_ADC_SHTIM		(0xf  << 24)	/* Sample & Hold Time */
>>   #define			AT91_ADC_SHTIM_(x)	((x) << 24)
>> @@ -58,4 +61,6 @@
>>   #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
>>   #define		AT91_ADC_DATA		(0x3ff)
>>   
>> +#define AT91_ADC_VERSION	0xFC
>> +
>>   #endif
>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>> index 18bd54f..14e99ba 100644
>> --- a/drivers/iio/adc/at91_adc.c
>> +++ b/drivers/iio/adc/at91_adc.c
>> @@ -39,6 +39,12 @@
>>   #define at91_adc_writel(st, reg, val) \
>>   	(writel_relaxed(val, st->reg_base + reg))
>>   
>> +struct at91_adc_caps {
>> +	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
>> +	u32	mr_prescal_mask;
>> +	u32	mr_startup_mask;
>> +};
>> +
>>   struct at91_adc_state {
>>   	struct clk		*adc_clk;
>>   	u16			*buffer;
>> @@ -62,6 +68,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)
>> @@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
>>   	.read_raw = &at91_adc_read_raw,
>>   };
>>   
>> +/*
>> + * Since atmel adc support different ip for touchscreen mode. Through the
>> + * IP check, we will know the touchscreen capbilities.
>> + */
>> +static void atmel_adc_get_cap(struct at91_adc_state *st)
>> +{
>> +	unsigned int version;
>> +	struct iio_dev *idev = iio_priv_to_dev(st);
>> +
>> +	version = at91_adc_readl(st, AT91_ADC_VERSION);
>> +	dev_dbg(&idev->dev, "version: 0x%x\n", version);
>> +
>> +	st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
>> +	st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
>> +
>> +	/* keep only major version number */
>> +	switch (version & 0xf00) {
>> +	case 0x500:	/* SAMA5D3 */
>> +	case 0x400:	/* AT91SAM9X5/9N12 */
>> +		st->caps.has_tsmr = 1;
>> +		st->caps.mr_startup_mask = AT91_ADC_STARTUP;
>> +	case 0x200:	/* AT91SAM9M10/9G45 */
>> +		st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
>> +
>> +		if ((version & 0xf00) == 0x200)
>> +			st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
>> +	case 0x100:	/* AT91SAM9260/9G20 */
>> +		break;
>> +	default:
>> +		dev_warn(&idev->dev,
>> +				"Unmanaged adc version, use minimal capabilities\n");
>> +		break;
>> +	};
>> +}
> Why don't you use different compatible names and derive your
> capabilities from which compatible is declared.
>
> It seems safer.

Ok, that make sense. I will use compatible names for the capabilities in 
next version. Thanks.

>
> Maxime
>

Best Regards,
Josh Wu

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-07-16  8:35       ` Josh Wu
@ 2013-07-16  8:46         ` Nicolas Ferre
  -1 siblings, 0 replies; 85+ messages in thread
From: Nicolas Ferre @ 2013-07-16  8:46 UTC (permalink / raw)
  To: Josh Wu, Maxime Ripard, plagnioj; +Cc: jic23, linux-arm-kernel, linux-iio

On 16/07/2013 10:35, Josh Wu :
> Hi, Maxime
>
> On 7/15/2013 8:58 PM, Maxime Ripard wrote:
>> Hi Josh,
>>
>> On Sun, Jul 14, 2013 at 04:04:26PM +0800, Josh Wu wrote:
>>> For at91 boards, there are different IPs for adc. Different IPs has
>>> different
>>> STARTUP & PRESCAL mask in ADC_MR.
>>>
>>> This patch can change the masks according to the different IP version.
>>>
>>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>>> ---
>>>   arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
>>>   drivers/iio/adc/at91_adc.c                 |   48
>>> ++++++++++++++++++++++++++--
>>>   2 files changed, 53 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 8e7ed5c..ab273ee 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    (0xff << 8)    /* Prescalar Rate
>>> Selection */
>>> +#define        AT91_ADC_PRESCAL_9260    (0x3f << 8)
>>>   #define            AT91_ADC_PRESCAL_(x)    ((x) << 8)
>>> -#define        AT91_ADC_STARTUP    (0x1f << 16)    /* Startup Up
>>> Time */
>>> +#define        AT91_ADC_STARTUP    (0xf << 16)    /* Startup Up Time */
>>> +#define        AT91_ADC_STARTUP_9260    (0x1f << 16)
>>> +#define        AT91_ADC_STARTUP_9G45    (0x7f << 16)
>>>   #define            AT91_ADC_STARTUP_(x)    ((x) << 16)
>>>   #define        AT91_ADC_SHTIM        (0xf  << 24)    /* Sample &
>>> Hold Time */
>>>   #define            AT91_ADC_SHTIM_(x)    ((x) << 24)
>>> @@ -58,4 +61,6 @@
>>>   #define AT91_ADC_CHR(n)        (0x30 + ((n) * 4))    /* Channel
>>> Data Register N */
>>>   #define        AT91_ADC_DATA        (0x3ff)
>>> +#define AT91_ADC_VERSION    0xFC
>>> +
>>>   #endif
>>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>>> index 18bd54f..14e99ba 100644
>>> --- a/drivers/iio/adc/at91_adc.c
>>> +++ b/drivers/iio/adc/at91_adc.c
>>> @@ -39,6 +39,12 @@
>>>   #define at91_adc_writel(st, reg, val) \
>>>       (writel_relaxed(val, st->reg_base + reg))
>>> +struct at91_adc_caps {
>>> +    bool    has_tsmr;    /* only at91sam9x5, sama5d3 have TSMR reg */
>>> +    u32    mr_prescal_mask;
>>> +    u32    mr_startup_mask;
>>> +};
>>> +
>>>   struct at91_adc_state {
>>>       struct clk        *adc_clk;
>>>       u16            *buffer;
>>> @@ -62,6 +68,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)
>>> @@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
>>>       .read_raw = &at91_adc_read_raw,
>>>   };
>>> +/*
>>> + * Since atmel adc support different ip for touchscreen mode.
>>> Through the
>>> + * IP check, we will know the touchscreen capbilities.
>>> + */
>>> +static void atmel_adc_get_cap(struct at91_adc_state *st)
>>> +{
>>> +    unsigned int version;
>>> +    struct iio_dev *idev = iio_priv_to_dev(st);
>>> +
>>> +    version = at91_adc_readl(st, AT91_ADC_VERSION);
>>> +    dev_dbg(&idev->dev, "version: 0x%x\n", version);
>>> +
>>> +    st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
>>> +    st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
>>> +
>>> +    /* keep only major version number */
>>> +    switch (version & 0xf00) {
>>> +    case 0x500:    /* SAMA5D3 */
>>> +    case 0x400:    /* AT91SAM9X5/9N12 */
>>> +        st->caps.has_tsmr = 1;
>>> +        st->caps.mr_startup_mask = AT91_ADC_STARTUP;
>>> +    case 0x200:    /* AT91SAM9M10/9G45 */
>>> +        st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
>>> +
>>> +        if ((version & 0xf00) == 0x200)
>>> +            st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
>>> +    case 0x100:    /* AT91SAM9260/9G20 */
>>> +        break;
>>> +    default:
>>> +        dev_warn(&idev->dev,
>>> +                "Unmanaged adc version, use minimal capabilities\n");
>>> +        break;
>>> +    };
>>> +}
>> Why don't you use different compatible names and derive your
>> capabilities from which compatible is declared.
>>
>> It seems safer.

I see it as handier in the sense that a different IP version can be 
compatible with an older IP version: so we do not need to modify the 
driver just to use another SoC.

On your side Maxime, what makes you say that it is "safer"?

> Ok, that make sense. I will use compatible names for the capabilities in
> next version. Thanks.

Hold on a little bit Josh, I know that Jean-Christophe is not in favor 
of the use of multiple compatible strings. So, as the code is already 
there, let's wait and see if we find another argument...

Bye,
-- 
Nicolas Ferre

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

* [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-16  8:46         ` Nicolas Ferre
  0 siblings, 0 replies; 85+ messages in thread
From: Nicolas Ferre @ 2013-07-16  8:46 UTC (permalink / raw)
  To: linux-arm-kernel

On 16/07/2013 10:35, Josh Wu :
> Hi, Maxime
>
> On 7/15/2013 8:58 PM, Maxime Ripard wrote:
>> Hi Josh,
>>
>> On Sun, Jul 14, 2013 at 04:04:26PM +0800, Josh Wu wrote:
>>> For at91 boards, there are different IPs for adc. Different IPs has
>>> different
>>> STARTUP & PRESCAL mask in ADC_MR.
>>>
>>> This patch can change the masks according to the different IP version.
>>>
>>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>>> ---
>>>   arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
>>>   drivers/iio/adc/at91_adc.c                 |   48
>>> ++++++++++++++++++++++++++--
>>>   2 files changed, 53 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 8e7ed5c..ab273ee 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    (0xff << 8)    /* Prescalar Rate
>>> Selection */
>>> +#define        AT91_ADC_PRESCAL_9260    (0x3f << 8)
>>>   #define            AT91_ADC_PRESCAL_(x)    ((x) << 8)
>>> -#define        AT91_ADC_STARTUP    (0x1f << 16)    /* Startup Up
>>> Time */
>>> +#define        AT91_ADC_STARTUP    (0xf << 16)    /* Startup Up Time */
>>> +#define        AT91_ADC_STARTUP_9260    (0x1f << 16)
>>> +#define        AT91_ADC_STARTUP_9G45    (0x7f << 16)
>>>   #define            AT91_ADC_STARTUP_(x)    ((x) << 16)
>>>   #define        AT91_ADC_SHTIM        (0xf  << 24)    /* Sample &
>>> Hold Time */
>>>   #define            AT91_ADC_SHTIM_(x)    ((x) << 24)
>>> @@ -58,4 +61,6 @@
>>>   #define AT91_ADC_CHR(n)        (0x30 + ((n) * 4))    /* Channel
>>> Data Register N */
>>>   #define        AT91_ADC_DATA        (0x3ff)
>>> +#define AT91_ADC_VERSION    0xFC
>>> +
>>>   #endif
>>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>>> index 18bd54f..14e99ba 100644
>>> --- a/drivers/iio/adc/at91_adc.c
>>> +++ b/drivers/iio/adc/at91_adc.c
>>> @@ -39,6 +39,12 @@
>>>   #define at91_adc_writel(st, reg, val) \
>>>       (writel_relaxed(val, st->reg_base + reg))
>>> +struct at91_adc_caps {
>>> +    bool    has_tsmr;    /* only at91sam9x5, sama5d3 have TSMR reg */
>>> +    u32    mr_prescal_mask;
>>> +    u32    mr_startup_mask;
>>> +};
>>> +
>>>   struct at91_adc_state {
>>>       struct clk        *adc_clk;
>>>       u16            *buffer;
>>> @@ -62,6 +68,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)
>>> @@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
>>>       .read_raw = &at91_adc_read_raw,
>>>   };
>>> +/*
>>> + * Since atmel adc support different ip for touchscreen mode.
>>> Through the
>>> + * IP check, we will know the touchscreen capbilities.
>>> + */
>>> +static void atmel_adc_get_cap(struct at91_adc_state *st)
>>> +{
>>> +    unsigned int version;
>>> +    struct iio_dev *idev = iio_priv_to_dev(st);
>>> +
>>> +    version = at91_adc_readl(st, AT91_ADC_VERSION);
>>> +    dev_dbg(&idev->dev, "version: 0x%x\n", version);
>>> +
>>> +    st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
>>> +    st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
>>> +
>>> +    /* keep only major version number */
>>> +    switch (version & 0xf00) {
>>> +    case 0x500:    /* SAMA5D3 */
>>> +    case 0x400:    /* AT91SAM9X5/9N12 */
>>> +        st->caps.has_tsmr = 1;
>>> +        st->caps.mr_startup_mask = AT91_ADC_STARTUP;
>>> +    case 0x200:    /* AT91SAM9M10/9G45 */
>>> +        st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
>>> +
>>> +        if ((version & 0xf00) == 0x200)
>>> +            st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
>>> +    case 0x100:    /* AT91SAM9260/9G20 */
>>> +        break;
>>> +    default:
>>> +        dev_warn(&idev->dev,
>>> +                "Unmanaged adc version, use minimal capabilities\n");
>>> +        break;
>>> +    };
>>> +}
>> Why don't you use different compatible names and derive your
>> capabilities from which compatible is declared.
>>
>> It seems safer.

I see it as handier in the sense that a different IP version can be 
compatible with an older IP version: so we do not need to modify the 
driver just to use another SoC.

On your side Maxime, what makes you say that it is "safer"?

> Ok, that make sense. I will use compatible names for the capabilities in
> next version. Thanks.

Hold on a little bit Josh, I know that Jean-Christophe is not in favor 
of the use of multiple compatible strings. So, as the code is already 
there, let's wait and see if we find another argument...

Bye,
-- 
Nicolas Ferre

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

* Re: [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
  2013-07-15 13:15     ` Maxime Ripard
@ 2013-07-16  9:09       ` Josh Wu
  -1 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-16  9:09 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: jic23, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre,
	Dmitry Torokhov

Hi, Maxime

On 7/15/2013 9:15 PM, Maxime Ripard wrote:
> Hi Josh,
>
> On Sun, Jul 14, 2013 at 04:04:29PM +0800, 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:
>>    which type of touch are used? (4 or 5 wires), sample period time,
>>    pen detect debounce time, average samples and pen detect resistor.
>>
>> 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>
>> ---
>>   .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
>>   arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>>   drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
>>   3 files changed, 412 insertions(+), 24 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> index 0db2945..925d656 100644
>> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> @@ -29,6 +29,19 @@ Optional properties:
>>     - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
>>     - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
>>   			  adc_op_clk.
>> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
>> +				 4 and 5 wires touch screen.
>> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
>> +          disabled. Since touch screen will occupied the trigger register.
>> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
>> +				  detect.
>> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
>> +				     touch screen
>> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
>> +    0 means no average. 1 means average two samples. 2 means average four
>> +    samples. 3 means average eight samples.
>> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
>> +    It can be 0, 1, 2, 3.
> Could you expand a bit on what are these properties for? Are they
> board-specific? IP-specific?

+  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
+                 4 and 5 wires touch screen.
+    NOTE: when adc touch screen enabled, the adc hardware trigger will be
+          disabled. Since touch screen will occupied the trigger register.

It is board specific. Currently in AT91SAM9M10G45EK, AT91SAM9X5-EK, 
SAMA5D3x-EK all use 4 wire touch.
Now the driver not support 5 wire yet.

+  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for 
touch pen
+                  detect.

de-glitch time for pen detect. Board specific.

+  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
+                     touch screen

The period to sample a touch data after pen is touched. Board specific.

+  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
+    0 means no average. 1 means average two samples. 2 means average four
+    samples. 3 means average eight samples.
+  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
+    It can be 0, 1, 2, 3.

Above two properties only supported in SAM9X5, SAMA5D3 IP.

>
> [...]
>
>> +#define DRIVER_NAME		"at91_adc"
> This looks like this part doesn't belong to another cleanup patch.

it is part of this patch. As it's a little cleanup, I integrate it as 
add touch feature.

>
>> +#define MAX_POS_BITS		12
>> +
>> +#define ZTHRESHOLD		9000
>> +
>>   struct at91_adc_caps {
>> +	bool	has_12bits_xy;	/* true means use 12 bits. Otherwise 10 bits */
> Isn't that redundant with the low_res boolean?

yes, right. I will remove it.

>
>>   	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
>>   	u32	mr_prescal_mask;
>>   	u32	mr_startup_mask;
>>   };
>>   
>> +enum atmel_adc_ts_type {
>> +	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
>> +	ATMEL_ADC_TOUCHSCREEN_4WIRE,
>> +	ATMEL_ADC_TOUCHSCREEN_5WIRE,
>> +};
>> +
>>   struct at91_adc_state {
>>   	struct clk		*adc_clk;
>>   	u32			adc_clk_rate;
>> @@ -70,6 +83,29 @@ 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;
>> +
>> +	u8			ts_filter_average;
>> +	u16			ts_pen_detect_debounce;
>> +	u8			ts_pen_detect_sensitivity;
>> +	u16			ts_sample_period_time;
>> +	u16			ts_sample_period_val;
>>   };
>>   
>>   static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
>> @@ -104,14 +140,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;
> Why are you changing the prototype and remove most of the useful part
> out of the handler?

I change the protype because I make it as a sub interrupt handler.
Since I just add a new interrupt handler which will check the interrupt 
type, if DRDY interrupt is coming, it will call your original handler.
Otherwise use touch screen interrupt handler code.

Following is the new interrupt handler code in this patch:

+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);

                              ^
                              |
here we call original trigger handler.

+
+	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) {

Those code will handle for the Touch screen interrupt.

>
> Maxime
>

Thanks.
Best Regards,
Josh Wu

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

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

Hi, Maxime

On 7/15/2013 9:15 PM, Maxime Ripard wrote:
> Hi Josh,
>
> On Sun, Jul 14, 2013 at 04:04:29PM +0800, 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:
>>    which type of touch are used? (4 or 5 wires), sample period time,
>>    pen detect debounce time, average samples and pen detect resistor.
>>
>> 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>
>> ---
>>   .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
>>   arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>>   drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
>>   3 files changed, 412 insertions(+), 24 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> index 0db2945..925d656 100644
>> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> @@ -29,6 +29,19 @@ Optional properties:
>>     - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
>>     - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
>>   			  adc_op_clk.
>> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
>> +				 4 and 5 wires touch screen.
>> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
>> +          disabled. Since touch screen will occupied the trigger register.
>> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
>> +				  detect.
>> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
>> +				     touch screen
>> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
>> +    0 means no average. 1 means average two samples. 2 means average four
>> +    samples. 3 means average eight samples.
>> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
>> +    It can be 0, 1, 2, 3.
> Could you expand a bit on what are these properties for? Are they
> board-specific? IP-specific?

+  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
+                 4 and 5 wires touch screen.
+    NOTE: when adc touch screen enabled, the adc hardware trigger will be
+          disabled. Since touch screen will occupied the trigger register.

It is board specific. Currently in AT91SAM9M10G45EK, AT91SAM9X5-EK, 
SAMA5D3x-EK all use 4 wire touch.
Now the driver not support 5 wire yet.

+  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for 
touch pen
+                  detect.

de-glitch time for pen detect. Board specific.

+  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
+                     touch screen

The period to sample a touch data after pen is touched. Board specific.

+  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
+    0 means no average. 1 means average two samples. 2 means average four
+    samples. 3 means average eight samples.
+  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
+    It can be 0, 1, 2, 3.

Above two properties only supported in SAM9X5, SAMA5D3 IP.

>
> [...]
>
>> +#define DRIVER_NAME		"at91_adc"
> This looks like this part doesn't belong to another cleanup patch.

it is part of this patch. As it's a little cleanup, I integrate it as 
add touch feature.

>
>> +#define MAX_POS_BITS		12
>> +
>> +#define ZTHRESHOLD		9000
>> +
>>   struct at91_adc_caps {
>> +	bool	has_12bits_xy;	/* true means use 12 bits. Otherwise 10 bits */
> Isn't that redundant with the low_res boolean?

yes, right. I will remove it.

>
>>   	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
>>   	u32	mr_prescal_mask;
>>   	u32	mr_startup_mask;
>>   };
>>   
>> +enum atmel_adc_ts_type {
>> +	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
>> +	ATMEL_ADC_TOUCHSCREEN_4WIRE,
>> +	ATMEL_ADC_TOUCHSCREEN_5WIRE,
>> +};
>> +
>>   struct at91_adc_state {
>>   	struct clk		*adc_clk;
>>   	u32			adc_clk_rate;
>> @@ -70,6 +83,29 @@ 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;
>> +
>> +	u8			ts_filter_average;
>> +	u16			ts_pen_detect_debounce;
>> +	u8			ts_pen_detect_sensitivity;
>> +	u16			ts_sample_period_time;
>> +	u16			ts_sample_period_val;
>>   };
>>   
>>   static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
>> @@ -104,14 +140,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;
> Why are you changing the prototype and remove most of the useful part
> out of the handler?

I change the protype because I make it as a sub interrupt handler.
Since I just add a new interrupt handler which will check the interrupt 
type, if DRDY interrupt is coming, it will call your original handler.
Otherwise use touch screen interrupt handler code.

Following is the new interrupt handler code in this patch:

+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);

                              ^
                              |
here we call original trigger handler.

+
+	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) {

Those code will handle for the Touch screen interrupt.

>
> Maxime
>

Thanks.
Best Regards,
Josh Wu

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

* Re: [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz.
  2013-07-16  7:55       ` Josh Wu
@ 2013-07-16 10:30         ` Maxime Ripard
  -1 siblings, 0 replies; 85+ messages in thread
From: Maxime Ripard @ 2013-07-16 10:30 UTC (permalink / raw)
  To: Josh Wu; +Cc: jic23, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre

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

On Tue, Jul 16, 2013 at 03:55:28PM +0800, Josh Wu wrote:
> >On Sun, Jul 14, 2013 at 04:04:28PM +0800, Josh Wu wrote:
> >>diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> >>index e93a075..8f1386f 100644
> >>--- a/drivers/iio/adc/at91_adc.c
> >>+++ b/drivers/iio/adc/at91_adc.c
> >>@@ -47,6 +47,7 @@ struct at91_adc_caps {
> >>  struct at91_adc_state {
> >>  	struct clk		*adc_clk;
> >>+	u32			adc_clk_rate;
> >>  	u16			*buffer;
> >>  	unsigned long		channels_mask;
> >>  	struct clk		*clk;
> >>@@ -448,6 +449,10 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
> >>  	if (!node)
> >>  		return -EINVAL;
> >>+	prop = 0;
> >>+	of_property_read_u32(node, "atmel,adc-clock-rate", &prop);
> >>+	st->adc_clk_rate = prop;
> >>+
> >>  	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
> >>  	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
> >>@@ -723,7 +728,8 @@ static int at91_adc_probe(struct platform_device *pdev)
> >>  	 * specified by the electrical characteristics of the board.
> >>  	 */
> >>  	mstrclk = clk_get_rate(st->clk);
> >>-	adc_clk = clk_get_rate(st->adc_clk);
> >>+	adc_clk = st->adc_clk_rate ?
> >>+		st->adc_clk_rate : clk_get_rate(st->adc_clk);
> >Why is that needed? Isn't it completely redundant with the clocks
> >property?
> 
> As st->adc_clk rate is specified in arch/arm/mach-at91/sama5d3.c
> (take sama5d3 for example), changing the clock rate should recompile
> the kernel binary.
> Use dt parameter will let us easily specify the clock rate instead
> of recompile the code.
>
> And yes, it is redundant that we can define the adc_op_clk rate in
> two places (clock property in .c and adc-clock-rate in dts). But
> this can be compatible with the non-dt platform.

Yet, it's not, while, like you pointed at, the common clock framework
actually *is* usable for both DT and non-DT platforms at no cost.

The fact that AT91 isn't using the DT to retrieve its clock tree yet is
another story (but I believe that it's a work in progress).

> After a further thinking of this, maybe remove the adc_op_clk is
> better since it is a fake clock, and only used to specify the clock
> rate.
> To specify the clock rate use a dt property or platform data
> parameter is better.

No, to specify *any* clock, the common clock framework is the better
solution.

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] 85+ messages in thread

* [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz.
@ 2013-07-16 10:30         ` Maxime Ripard
  0 siblings, 0 replies; 85+ messages in thread
From: Maxime Ripard @ 2013-07-16 10:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 16, 2013 at 03:55:28PM +0800, Josh Wu wrote:
> >On Sun, Jul 14, 2013 at 04:04:28PM +0800, Josh Wu wrote:
> >>diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> >>index e93a075..8f1386f 100644
> >>--- a/drivers/iio/adc/at91_adc.c
> >>+++ b/drivers/iio/adc/at91_adc.c
> >>@@ -47,6 +47,7 @@ struct at91_adc_caps {
> >>  struct at91_adc_state {
> >>  	struct clk		*adc_clk;
> >>+	u32			adc_clk_rate;
> >>  	u16			*buffer;
> >>  	unsigned long		channels_mask;
> >>  	struct clk		*clk;
> >>@@ -448,6 +449,10 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
> >>  	if (!node)
> >>  		return -EINVAL;
> >>+	prop = 0;
> >>+	of_property_read_u32(node, "atmel,adc-clock-rate", &prop);
> >>+	st->adc_clk_rate = prop;
> >>+
> >>  	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
> >>  	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
> >>@@ -723,7 +728,8 @@ static int at91_adc_probe(struct platform_device *pdev)
> >>  	 * specified by the electrical characteristics of the board.
> >>  	 */
> >>  	mstrclk = clk_get_rate(st->clk);
> >>-	adc_clk = clk_get_rate(st->adc_clk);
> >>+	adc_clk = st->adc_clk_rate ?
> >>+		st->adc_clk_rate : clk_get_rate(st->adc_clk);
> >Why is that needed? Isn't it completely redundant with the clocks
> >property?
> 
> As st->adc_clk rate is specified in arch/arm/mach-at91/sama5d3.c
> (take sama5d3 for example), changing the clock rate should recompile
> the kernel binary.
> Use dt parameter will let us easily specify the clock rate instead
> of recompile the code.
>
> And yes, it is redundant that we can define the adc_op_clk rate in
> two places (clock property in .c and adc-clock-rate in dts). But
> this can be compatible with the non-dt platform.

Yet, it's not, while, like you pointed at, the common clock framework
actually *is* usable for both DT and non-DT platforms at no cost.

The fact that AT91 isn't using the DT to retrieve its clock tree yet is
another story (but I believe that it's a work in progress).

> After a further thinking of this, maybe remove the adc_op_clk is
> better since it is a fake clock, and only used to specify the clock
> rate.
> To specify the clock rate use a dt property or platform data
> parameter is better.

No, to specify *any* clock, the common clock framework is the better
solution.

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/20130716/4fd79342/attachment-0001.sig>

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

* Re: [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz.
  2013-07-16 10:30         ` Maxime Ripard
@ 2013-07-16 11:16           ` Lars-Peter Clausen
  -1 siblings, 0 replies; 85+ messages in thread
From: Lars-Peter Clausen @ 2013-07-16 11:16 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Josh Wu, jic23, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre

On 07/16/2013 12:30 PM, Maxime Ripard wrote:
[...]
>> After a further thinking of this, maybe remove the adc_op_clk is
>> better since it is a fake clock, and only used to specify the clock
>> rate.
>> To specify the clock rate use a dt property or platform data
>> parameter is better.
> 
> No, to specify *any* clock, the common clock framework is the better
> solution.

Yep, this patch is not the right approach. It's trying to work around the
limitations of the platforms clock API implementation. Please fix the at91
clock implementation instead (e.g. by switching to the common clock framework).

- Lars


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

* [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz.
@ 2013-07-16 11:16           ` Lars-Peter Clausen
  0 siblings, 0 replies; 85+ messages in thread
From: Lars-Peter Clausen @ 2013-07-16 11:16 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/16/2013 12:30 PM, Maxime Ripard wrote:
[...]
>> After a further thinking of this, maybe remove the adc_op_clk is
>> better since it is a fake clock, and only used to specify the clock
>> rate.
>> To specify the clock rate use a dt property or platform data
>> parameter is better.
> 
> No, to specify *any* clock, the common clock framework is the better
> solution.

Yep, this patch is not the right approach. It's trying to work around the
limitations of the platforms clock API implementation. Please fix the at91
clock implementation instead (e.g. by switching to the common clock framework).

- Lars

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-07-16  8:46         ` Nicolas Ferre
@ 2013-07-16 11:20           ` Maxime Ripard
  -1 siblings, 0 replies; 85+ messages in thread
From: Maxime Ripard @ 2013-07-16 11:20 UTC (permalink / raw)
  To: Nicolas Ferre; +Cc: Josh Wu, plagnioj, jic23, linux-arm-kernel, linux-iio

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

On Tue, Jul 16, 2013 at 10:46:28AM +0200, Nicolas Ferre wrote:
> >>capabilities from which compatible is declared.
> >>
> >>It seems safer.
> 
> I see it as handier in the sense that a different IP version can be
> compatible with an older IP version: so we do not need to modify the
> driver just to use another SoC.
> 
> On your side Maxime, what makes you say that it is "safer"?

Well, the register holding the IP version seem to be not programmed in
some cases (or, at least, the driver handles this case).

So, what would happen if one SoC was in such case? You wouldn't be able
to use the ADC/touchscreen, even though the IP in itself might very well
work, which doesn't sound very nice, while the DT will always be there,
and will always have a compatible property.

> >Ok, that make sense. I will use compatible names for the capabilities in
> >next version. Thanks.
> 
> Hold on a little bit Josh, I know that Jean-Christophe is not in
> favor of the use of multiple compatible strings. So, as the code is
> already there, let's wait and see if we find another argument...

And you know my feeling about this for quite some time already ;)

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] 85+ messages in thread

* [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-16 11:20           ` Maxime Ripard
  0 siblings, 0 replies; 85+ messages in thread
From: Maxime Ripard @ 2013-07-16 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 16, 2013 at 10:46:28AM +0200, Nicolas Ferre wrote:
> >>capabilities from which compatible is declared.
> >>
> >>It seems safer.
> 
> I see it as handier in the sense that a different IP version can be
> compatible with an older IP version: so we do not need to modify the
> driver just to use another SoC.
> 
> On your side Maxime, what makes you say that it is "safer"?

Well, the register holding the IP version seem to be not programmed in
some cases (or, at least, the driver handles this case).

So, what would happen if one SoC was in such case? You wouldn't be able
to use the ADC/touchscreen, even though the IP in itself might very well
work, which doesn't sound very nice, while the DT will always be there,
and will always have a compatible property.

> >Ok, that make sense. I will use compatible names for the capabilities in
> >next version. Thanks.
> 
> Hold on a little bit Josh, I know that Jean-Christophe is not in
> favor of the use of multiple compatible strings. So, as the code is
> already there, let's wait and see if we find another argument...

And you know my feeling about this for quite some time already ;)

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/20130716/17f0b0cb/attachment-0001.sig>

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-07-16  8:46         ` Nicolas Ferre
  (?)
@ 2013-07-16 11:30             ` Thomas Petazzoni
  -1 siblings, 0 replies; 85+ messages in thread
From: Thomas Petazzoni @ 2013-07-16 11:30 UTC (permalink / raw)
  To: Nicolas Ferre
  Cc: Josh Wu, Maxime Ripard, plagnioj-sclMFOaUSTBWk0Htik3J/w,
	linux-iio-u79uwXL29TY76Z2rM5mHXA, jic23-KWPb1pKIrIJaa/9Udqfwiw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

Dear Nicolas Ferre,

On Tue, 16 Jul 2013 10:46:28 +0200, Nicolas Ferre wrote:

> > Ok, that make sense. I will use compatible names for the capabilities in
> > next version. Thanks.
> 
> Hold on a little bit Josh, I know that Jean-Christophe is not in favor 
> of the use of multiple compatible strings. So, as the code is already 
> there, let's wait and see if we find another argument...

I've asked exactly this question last week at Linaro Connect during the
ARM SoC consolidation panel/discussion, where Grant Likely, Arnd
Bergmann, Olof and others were answering Device Tree related questions.

My question, which precisely had the at91-adc DT binding in mind was
precisely whether we should use different compatible properties to
identify different revisions of an IP block and let the driver handle
those differences, or whether the DT binding should provide sufficient
properties (register offsets, bit numbers, etc.) to make the driver
independent of the IP revisions. And clearly, the answer was that
different compatible properties should be used to identify the
different versions of the IP block, and the driver should abstract out
the differences. I.e, was has been done for at91-adc is completely the
opposite of the best practices for Device Tree on ARM.

See
http://www.youtube.com/watch?v=zF_AXLgkFy4&feature=player_detailpage#t=1581s
where I ask exactly this question, and get answers from Olof Johansson
and Grant Likely. They clearly say that the solution of having separate
compatible properties and a driver that handles the differences is the
way to go. So the way at91-adc (and possibly other at91 drivers) is
using the Device Tree is wrong, there should have been multiple
compatible properties. It's a shame because this is something we did say
when we submitted at91-adc and during the reviews, but the maintainer
wasn't listening to our comments...

Best regards,

Thomas
-- 
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-16 11:30             ` Thomas Petazzoni
  0 siblings, 0 replies; 85+ messages in thread
From: Thomas Petazzoni @ 2013-07-16 11:30 UTC (permalink / raw)
  To: Nicolas Ferre
  Cc: Josh Wu, Maxime Ripard, plagnioj, linux-iio, jic23,
	linux-arm-kernel, devicetree-discuss

Dear Nicolas Ferre,

On Tue, 16 Jul 2013 10:46:28 +0200, Nicolas Ferre wrote:

> > Ok, that make sense. I will use compatible names for the capabilities in
> > next version. Thanks.
> 
> Hold on a little bit Josh, I know that Jean-Christophe is not in favor 
> of the use of multiple compatible strings. So, as the code is already 
> there, let's wait and see if we find another argument...

I've asked exactly this question last week at Linaro Connect during the
ARM SoC consolidation panel/discussion, where Grant Likely, Arnd
Bergmann, Olof and others were answering Device Tree related questions.

My question, which precisely had the at91-adc DT binding in mind was
precisely whether we should use different compatible properties to
identify different revisions of an IP block and let the driver handle
those differences, or whether the DT binding should provide sufficient
properties (register offsets, bit numbers, etc.) to make the driver
independent of the IP revisions. And clearly, the answer was that
different compatible properties should be used to identify the
different versions of the IP block, and the driver should abstract out
the differences. I.e, was has been done for at91-adc is completely the
opposite of the best practices for Device Tree on ARM.

See
http://www.youtube.com/watch?v=zF_AXLgkFy4&feature=player_detailpage#t=1581s
where I ask exactly this question, and get answers from Olof Johansson
and Grant Likely. They clearly say that the solution of having separate
compatible properties and a driver that handles the differences is the
way to go. So the way at91-adc (and possibly other at91 drivers) is
using the Device Tree is wrong, there should have been multiple
compatible properties. It's a shame because this is something we did say
when we submitted at91-adc and during the reviews, but the maintainer
wasn't listening to our comments...

Best regards,

Thomas
-- 
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-16 11:30             ` Thomas Petazzoni
  0 siblings, 0 replies; 85+ messages in thread
From: Thomas Petazzoni @ 2013-07-16 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Nicolas Ferre,

On Tue, 16 Jul 2013 10:46:28 +0200, Nicolas Ferre wrote:

> > Ok, that make sense. I will use compatible names for the capabilities in
> > next version. Thanks.
> 
> Hold on a little bit Josh, I know that Jean-Christophe is not in favor 
> of the use of multiple compatible strings. So, as the code is already 
> there, let's wait and see if we find another argument...

I've asked exactly this question last week at Linaro Connect during the
ARM SoC consolidation panel/discussion, where Grant Likely, Arnd
Bergmann, Olof and others were answering Device Tree related questions.

My question, which precisely had the at91-adc DT binding in mind was
precisely whether we should use different compatible properties to
identify different revisions of an IP block and let the driver handle
those differences, or whether the DT binding should provide sufficient
properties (register offsets, bit numbers, etc.) to make the driver
independent of the IP revisions. And clearly, the answer was that
different compatible properties should be used to identify the
different versions of the IP block, and the driver should abstract out
the differences. I.e, was has been done for at91-adc is completely the
opposite of the best practices for Device Tree on ARM.

See
http://www.youtube.com/watch?v=zF_AXLgkFy4&feature=player_detailpage#t=1581s
where I ask exactly this question, and get answers from Olof Johansson
and Grant Likely. They clearly say that the solution of having separate
compatible properties and a driver that handles the differences is the
way to go. So the way at91-adc (and possibly other at91 drivers) is
using the Device Tree is wrong, there should have been multiple
compatible properties. It's a shame because this is something we did say
when we submitted at91-adc and during the reviews, but the maintainer
wasn't listening to our comments...

Best regards,

Thomas
-- 
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* Re: [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
  2013-07-16  9:09       ` Josh Wu
@ 2013-07-16 11:43         ` Maxime Ripard
  -1 siblings, 0 replies; 85+ messages in thread
From: Maxime Ripard @ 2013-07-16 11:43 UTC (permalink / raw)
  To: Josh Wu
  Cc: jic23, linux-arm-kernel, linux-iio, plagnioj, nicolas.ferre,
	Dmitry Torokhov

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

Hi Josh,

On Tue, Jul 16, 2013 at 05:09:32PM +0800, Josh Wu wrote:
> On 7/15/2013 9:15 PM, Maxime Ripard wrote:
> >Hi Josh,
> >
> >On Sun, Jul 14, 2013 at 04:04:29PM +0800, 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:
> >>   which type of touch are used? (4 or 5 wires), sample period time,
> >>   pen detect debounce time, average samples and pen detect resistor.
> >>
> >>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>
> >>---
> >>  .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
> >>  arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
> >>  drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
> >>  3 files changed, 412 insertions(+), 24 deletions(-)
> >>
> >>diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >>index 0db2945..925d656 100644
> >>--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >>+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >>@@ -29,6 +29,19 @@ Optional properties:
> >>    - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
> >>    - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
> >>  			  adc_op_clk.
> >>+  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
> >>+				 4 and 5 wires touch screen.
> >>+    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> >>+          disabled. Since touch screen will occupied the trigger register.
> >>+  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
> >>+				  detect.
> >>+  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
> >>+				     touch screen
> >>+  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
> >>+    0 means no average. 1 means average two samples. 2 means average four
> >>+    samples. 3 means average eight samples.
> >>+  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
> >>+    It can be 0, 1, 2, 3.
> >Could you expand a bit on what are these properties for? Are they
> >board-specific? IP-specific?
> 
> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
> +                 4 and 5 wires touch screen.
> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> +          disabled. Since touch screen will occupied the trigger register.
> 
> It is board specific. Currently in AT91SAM9M10G45EK, AT91SAM9X5-EK,
> SAMA5D3x-EK all use 4 wire touch.
> Now the driver not support 5 wire yet.

I see, maybe you should add this in the documentation then

> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for
> touch pen
> +                  detect.
> 
> de-glitch time for pen detect. Board specific.
> 
> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
> +                     touch screen
> 
> The period to sample a touch data after pen is touched. Board specific.
> 
> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
> +    0 means no average. 1 means average two samples. 2 means average four
> +    samples. 3 means average eight samples.
> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
> +    It can be 0, 1, 2, 3.
> 
> Above two properties only supported in SAM9X5, SAMA5D3 IP.

Ok, that should go to the documentation as well. What do the values of
atmel,adc-ts-pendet-sensitivity correspond to?

> >>@@ -104,14 +140,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;
> >Why are you changing the prototype and remove most of the useful part
> >out of the handler?
> 
> I change the protype because I make it as a sub interrupt handler.
> Since I just add a new interrupt handler which will check the
> interrupt type, if DRDY interrupt is coming, it will call your
> original handler.
> Otherwise use touch screen interrupt handler code.
> 
> Following is the new interrupt handler code in this patch:
> 
> +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);
> 
>                              ^
>                              |
> here we call original trigger handler.
> 
> +
> +	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) {
> 
> Those code will handle for the Touch screen interrupt.

Ah, right.

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] 85+ messages in thread

* [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
@ 2013-07-16 11:43         ` Maxime Ripard
  0 siblings, 0 replies; 85+ messages in thread
From: Maxime Ripard @ 2013-07-16 11:43 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Josh,

On Tue, Jul 16, 2013 at 05:09:32PM +0800, Josh Wu wrote:
> On 7/15/2013 9:15 PM, Maxime Ripard wrote:
> >Hi Josh,
> >
> >On Sun, Jul 14, 2013 at 04:04:29PM +0800, 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:
> >>   which type of touch are used? (4 or 5 wires), sample period time,
> >>   pen detect debounce time, average samples and pen detect resistor.
> >>
> >>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>
> >>---
> >>  .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
> >>  arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
> >>  drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
> >>  3 files changed, 412 insertions(+), 24 deletions(-)
> >>
> >>diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >>index 0db2945..925d656 100644
> >>--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >>+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >>@@ -29,6 +29,19 @@ Optional properties:
> >>    - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
> >>    - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
> >>  			  adc_op_clk.
> >>+  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
> >>+				 4 and 5 wires touch screen.
> >>+    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> >>+          disabled. Since touch screen will occupied the trigger register.
> >>+  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
> >>+				  detect.
> >>+  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
> >>+				     touch screen
> >>+  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
> >>+    0 means no average. 1 means average two samples. 2 means average four
> >>+    samples. 3 means average eight samples.
> >>+  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
> >>+    It can be 0, 1, 2, 3.
> >Could you expand a bit on what are these properties for? Are they
> >board-specific? IP-specific?
> 
> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
> +                 4 and 5 wires touch screen.
> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> +          disabled. Since touch screen will occupied the trigger register.
> 
> It is board specific. Currently in AT91SAM9M10G45EK, AT91SAM9X5-EK,
> SAMA5D3x-EK all use 4 wire touch.
> Now the driver not support 5 wire yet.

I see, maybe you should add this in the documentation then

> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for
> touch pen
> +                  detect.
> 
> de-glitch time for pen detect. Board specific.
> 
> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
> +                     touch screen
> 
> The period to sample a touch data after pen is touched. Board specific.
> 
> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
> +    0 means no average. 1 means average two samples. 2 means average four
> +    samples. 3 means average eight samples.
> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
> +    It can be 0, 1, 2, 3.
> 
> Above two properties only supported in SAM9X5, SAMA5D3 IP.

Ok, that should go to the documentation as well. What do the values of
atmel,adc-ts-pendet-sensitivity correspond to?

> >>@@ -104,14 +140,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;
> >Why are you changing the prototype and remove most of the useful part
> >out of the handler?
> 
> I change the protype because I make it as a sub interrupt handler.
> Since I just add a new interrupt handler which will check the
> interrupt type, if DRDY interrupt is coming, it will call your
> original handler.
> Otherwise use touch screen interrupt handler code.
> 
> Following is the new interrupt handler code in this patch:
> 
> +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);
> 
>                              ^
>                              |
> here we call original trigger handler.
> 
> +
> +	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) {
> 
> Those code will handle for the Touch screen interrupt.

Ah, right.

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/20130716/ccb648f8/attachment.sig>

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-07-16 11:30             ` Thomas Petazzoni
  (?)
@ 2013-07-16 19:03               ` Jonathan Cameron
  -1 siblings, 0 replies; 85+ messages in thread
From: Jonathan Cameron @ 2013-07-16 19:03 UTC (permalink / raw)
  To: Thomas Petazzoni
  Cc: Nicolas Ferre, Josh Wu, Maxime Ripard,
	plagnioj-sclMFOaUSTBWk0Htik3J/w,
	linux-iio-u79uwXL29TY76Z2rM5mHXA, jic23-KWPb1pKIrIJaa/9Udqfwiw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

On 07/16/2013 12:30 PM, Thomas Petazzoni wrote:
> Dear Nicolas Ferre,
> 
> On Tue, 16 Jul 2013 10:46:28 +0200, Nicolas Ferre wrote:
> 
>>> Ok, that make sense. I will use compatible names for the capabilities in
>>> next version. Thanks.
>>
>> Hold on a little bit Josh, I know that Jean-Christophe is not in favor 
>> of the use of multiple compatible strings. So, as the code is already 
>> there, let's wait and see if we find another argument...
> 
> I've asked exactly this question last week at Linaro Connect during the
> ARM SoC consolidation panel/discussion, where Grant Likely, Arnd
> Bergmann, Olof and others were answering Device Tree related questions.
> 
> My question, which precisely had the at91-adc DT binding in mind was
> precisely whether we should use different compatible properties to
> identify different revisions of an IP block and let the driver handle
> those differences, or whether the DT binding should provide sufficient
> properties (register offsets, bit numbers, etc.) to make the driver
> independent of the IP revisions. And clearly, the answer was that
> different compatible properties should be used to identify the
> different versions of the IP block, and the driver should abstract out
> the differences. I.e, was has been done for at91-adc is completely the
> opposite of the best practices for Device Tree on ARM.
> 
> See
> http://www.youtube.com/watch?v=zF_AXLgkFy4&feature=player_detailpage#t=1581s
> where I ask exactly this question, and get answers from Olof Johansson
> and Grant Likely. They clearly say that the solution of having separate
> compatible properties and a driver that handles the differences is the
> way to go. So the way at91-adc (and possibly other at91 drivers) is
> using the Device Tree is wrong, there should have been multiple
> compatible properties. It's a shame because this is something we did say
> when we submitted at91-adc and during the reviews, but the maintainer
> wasn't listening to our comments...
> 

Thanks for getting some clarity on this Thomas.  So I'll ask the somewhat obvious
question - how do we unwind from where we are to where we want to be wrt to the
bindings?

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-16 19:03               ` Jonathan Cameron
  0 siblings, 0 replies; 85+ messages in thread
From: Jonathan Cameron @ 2013-07-16 19:03 UTC (permalink / raw)
  To: Thomas Petazzoni
  Cc: Nicolas Ferre, Josh Wu, Maxime Ripard, plagnioj, linux-iio,
	jic23, linux-arm-kernel, devicetree-discuss

On 07/16/2013 12:30 PM, Thomas Petazzoni wrote:
> Dear Nicolas Ferre,
> 
> On Tue, 16 Jul 2013 10:46:28 +0200, Nicolas Ferre wrote:
> 
>>> Ok, that make sense. I will use compatible names for the capabilities in
>>> next version. Thanks.
>>
>> Hold on a little bit Josh, I know that Jean-Christophe is not in favor 
>> of the use of multiple compatible strings. So, as the code is already 
>> there, let's wait and see if we find another argument...
> 
> I've asked exactly this question last week at Linaro Connect during the
> ARM SoC consolidation panel/discussion, where Grant Likely, Arnd
> Bergmann, Olof and others were answering Device Tree related questions.
> 
> My question, which precisely had the at91-adc DT binding in mind was
> precisely whether we should use different compatible properties to
> identify different revisions of an IP block and let the driver handle
> those differences, or whether the DT binding should provide sufficient
> properties (register offsets, bit numbers, etc.) to make the driver
> independent of the IP revisions. And clearly, the answer was that
> different compatible properties should be used to identify the
> different versions of the IP block, and the driver should abstract out
> the differences. I.e, was has been done for at91-adc is completely the
> opposite of the best practices for Device Tree on ARM.
> 
> See
> http://www.youtube.com/watch?v=zF_AXLgkFy4&feature=player_detailpage#t=1581s
> where I ask exactly this question, and get answers from Olof Johansson
> and Grant Likely. They clearly say that the solution of having separate
> compatible properties and a driver that handles the differences is the
> way to go. So the way at91-adc (and possibly other at91 drivers) is
> using the Device Tree is wrong, there should have been multiple
> compatible properties. It's a shame because this is something we did say
> when we submitted at91-adc and during the reviews, but the maintainer
> wasn't listening to our comments...
> 

Thanks for getting some clarity on this Thomas.  So I'll ask the somewhat obvious
question - how do we unwind from where we are to where we want to be wrt to the
bindings?




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

* [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-16 19:03               ` Jonathan Cameron
  0 siblings, 0 replies; 85+ messages in thread
From: Jonathan Cameron @ 2013-07-16 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/16/2013 12:30 PM, Thomas Petazzoni wrote:
> Dear Nicolas Ferre,
> 
> On Tue, 16 Jul 2013 10:46:28 +0200, Nicolas Ferre wrote:
> 
>>> Ok, that make sense. I will use compatible names for the capabilities in
>>> next version. Thanks.
>>
>> Hold on a little bit Josh, I know that Jean-Christophe is not in favor 
>> of the use of multiple compatible strings. So, as the code is already 
>> there, let's wait and see if we find another argument...
> 
> I've asked exactly this question last week at Linaro Connect during the
> ARM SoC consolidation panel/discussion, where Grant Likely, Arnd
> Bergmann, Olof and others were answering Device Tree related questions.
> 
> My question, which precisely had the at91-adc DT binding in mind was
> precisely whether we should use different compatible properties to
> identify different revisions of an IP block and let the driver handle
> those differences, or whether the DT binding should provide sufficient
> properties (register offsets, bit numbers, etc.) to make the driver
> independent of the IP revisions. And clearly, the answer was that
> different compatible properties should be used to identify the
> different versions of the IP block, and the driver should abstract out
> the differences. I.e, was has been done for at91-adc is completely the
> opposite of the best practices for Device Tree on ARM.
> 
> See
> http://www.youtube.com/watch?v=zF_AXLgkFy4&feature=player_detailpage#t=1581s
> where I ask exactly this question, and get answers from Olof Johansson
> and Grant Likely. They clearly say that the solution of having separate
> compatible properties and a driver that handles the differences is the
> way to go. So the way at91-adc (and possibly other at91 drivers) is
> using the Device Tree is wrong, there should have been multiple
> compatible properties. It's a shame because this is something we did say
> when we submitted at91-adc and during the reviews, but the maintainer
> wasn't listening to our comments...
> 

Thanks for getting some clarity on this Thomas.  So I'll ask the somewhat obvious
question - how do we unwind from where we are to where we want to be wrt to the
bindings?

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-07-16 19:03               ` Jonathan Cameron
  (?)
@ 2013-07-16 19:17                   ` Thomas Petazzoni
  -1 siblings, 0 replies; 85+ messages in thread
From: Thomas Petazzoni @ 2013-07-16 19:17 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Nicolas Ferre, Josh Wu, Maxime Ripard,
	plagnioj-sclMFOaUSTBWk0Htik3J/w,
	linux-iio-u79uwXL29TY76Z2rM5mHXA, jic23-KWPb1pKIrIJaa/9Udqfwiw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

Dear Jonathan Cameron,

On Tue, 16 Jul 2013 20:03:38 +0100, Jonathan Cameron wrote:

> On 07/16/2013 12:30 PM, Thomas Petazzoni wrote:
> > I've asked exactly this question last week at Linaro Connect during the
> > ARM SoC consolidation panel/discussion, where Grant Likely, Arnd
> > Bergmann, Olof and others were answering Device Tree related questions.
> > 
> > My question, which precisely had the at91-adc DT binding in mind was
> > precisely whether we should use different compatible properties to
> > identify different revisions of an IP block and let the driver handle
> > those differences, or whether the DT binding should provide sufficient
> > properties (register offsets, bit numbers, etc.) to make the driver
> > independent of the IP revisions. And clearly, the answer was that
> > different compatible properties should be used to identify the
> > different versions of the IP block, and the driver should abstract out
> > the differences. I.e, was has been done for at91-adc is completely the
> > opposite of the best practices for Device Tree on ARM.
> > 
> > See
> > http://www.youtube.com/watch?v=zF_AXLgkFy4&feature=player_detailpage#t=1581s
> > where I ask exactly this question, and get answers from Olof Johansson
> > and Grant Likely. They clearly say that the solution of having separate
> > compatible properties and a driver that handles the differences is the
> > way to go. So the way at91-adc (and possibly other at91 drivers) is
> > using the Device Tree is wrong, there should have been multiple
> > compatible properties. It's a shame because this is something we did say
> > when we submitted at91-adc and during the reviews, but the maintainer
> > wasn't listening to our comments...
> > 
> 
> Thanks for getting some clarity on this Thomas.  So I'll ask the somewhat obvious
> question - how do we unwind from where we are to where we want to be wrt to the
> bindings?

During Linaro Connect last week, there was some discussion about
marking DT bindings as unstable for a little while, once they get
reviewed by a group of DT "experts" that mark them as stable. Until
they are stable, the kernel does not offer any ABI guarantees, and we
are free to change the DT bindings as needed.

Now, since this unstable/stable thing is not in place at the moment,
deciding whether to break or not existing bindings is something to be
decided by the maintainer of this platform, judging what is the best
option depending on whether there are already many users of the DT for
this platform or not, for example.

Best regards,

Thomas
-- 
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-16 19:17                   ` Thomas Petazzoni
  0 siblings, 0 replies; 85+ messages in thread
From: Thomas Petazzoni @ 2013-07-16 19:17 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Nicolas Ferre, Josh Wu, Maxime Ripard, plagnioj, linux-iio,
	jic23, linux-arm-kernel, devicetree-discuss

Dear Jonathan Cameron,

On Tue, 16 Jul 2013 20:03:38 +0100, Jonathan Cameron wrote:

> On 07/16/2013 12:30 PM, Thomas Petazzoni wrote:
> > I've asked exactly this question last week at Linaro Connect during the
> > ARM SoC consolidation panel/discussion, where Grant Likely, Arnd
> > Bergmann, Olof and others were answering Device Tree related questions.
> > 
> > My question, which precisely had the at91-adc DT binding in mind was
> > precisely whether we should use different compatible properties to
> > identify different revisions of an IP block and let the driver handle
> > those differences, or whether the DT binding should provide sufficient
> > properties (register offsets, bit numbers, etc.) to make the driver
> > independent of the IP revisions. And clearly, the answer was that
> > different compatible properties should be used to identify the
> > different versions of the IP block, and the driver should abstract out
> > the differences. I.e, was has been done for at91-adc is completely the
> > opposite of the best practices for Device Tree on ARM.
> > 
> > See
> > http://www.youtube.com/watch?v=zF_AXLgkFy4&feature=player_detailpage#t=1581s
> > where I ask exactly this question, and get answers from Olof Johansson
> > and Grant Likely. They clearly say that the solution of having separate
> > compatible properties and a driver that handles the differences is the
> > way to go. So the way at91-adc (and possibly other at91 drivers) is
> > using the Device Tree is wrong, there should have been multiple
> > compatible properties. It's a shame because this is something we did say
> > when we submitted at91-adc and during the reviews, but the maintainer
> > wasn't listening to our comments...
> > 
> 
> Thanks for getting some clarity on this Thomas.  So I'll ask the somewhat obvious
> question - how do we unwind from where we are to where we want to be wrt to the
> bindings?

During Linaro Connect last week, there was some discussion about
marking DT bindings as unstable for a little while, once they get
reviewed by a group of DT "experts" that mark them as stable. Until
they are stable, the kernel does not offer any ABI guarantees, and we
are free to change the DT bindings as needed.

Now, since this unstable/stable thing is not in place at the moment,
deciding whether to break or not existing bindings is something to be
decided by the maintainer of this platform, judging what is the best
option depending on whether there are already many users of the DT for
this platform or not, for example.

Best regards,

Thomas
-- 
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-16 19:17                   ` Thomas Petazzoni
  0 siblings, 0 replies; 85+ messages in thread
From: Thomas Petazzoni @ 2013-07-16 19:17 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Jonathan Cameron,

On Tue, 16 Jul 2013 20:03:38 +0100, Jonathan Cameron wrote:

> On 07/16/2013 12:30 PM, Thomas Petazzoni wrote:
> > I've asked exactly this question last week at Linaro Connect during the
> > ARM SoC consolidation panel/discussion, where Grant Likely, Arnd
> > Bergmann, Olof and others were answering Device Tree related questions.
> > 
> > My question, which precisely had the at91-adc DT binding in mind was
> > precisely whether we should use different compatible properties to
> > identify different revisions of an IP block and let the driver handle
> > those differences, or whether the DT binding should provide sufficient
> > properties (register offsets, bit numbers, etc.) to make the driver
> > independent of the IP revisions. And clearly, the answer was that
> > different compatible properties should be used to identify the
> > different versions of the IP block, and the driver should abstract out
> > the differences. I.e, was has been done for at91-adc is completely the
> > opposite of the best practices for Device Tree on ARM.
> > 
> > See
> > http://www.youtube.com/watch?v=zF_AXLgkFy4&feature=player_detailpage#t=1581s
> > where I ask exactly this question, and get answers from Olof Johansson
> > and Grant Likely. They clearly say that the solution of having separate
> > compatible properties and a driver that handles the differences is the
> > way to go. So the way at91-adc (and possibly other at91 drivers) is
> > using the Device Tree is wrong, there should have been multiple
> > compatible properties. It's a shame because this is something we did say
> > when we submitted at91-adc and during the reviews, but the maintainer
> > wasn't listening to our comments...
> > 
> 
> Thanks for getting some clarity on this Thomas.  So I'll ask the somewhat obvious
> question - how do we unwind from where we are to where we want to be wrt to the
> bindings?

During Linaro Connect last week, there was some discussion about
marking DT bindings as unstable for a little while, once they get
reviewed by a group of DT "experts" that mark them as stable. Until
they are stable, the kernel does not offer any ABI guarantees, and we
are free to change the DT bindings as needed.

Now, since this unstable/stable thing is not in place at the moment,
deciding whether to break or not existing bindings is something to be
decided by the maintainer of this platform, judging what is the best
option depending on whether there are already many users of the DT for
this platform or not, for example.

Best regards,

Thomas
-- 
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-07-14  8:04   ` Josh Wu
@ 2013-07-17  7:58     ` Nicolas Ferre
  -1 siblings, 0 replies; 85+ messages in thread
From: Nicolas Ferre @ 2013-07-17  7:58 UTC (permalink / raw)
  To: Josh Wu; +Cc: jic23, linux-arm-kernel, linux-iio, maxime.ripard, plagnioj

On 14/07/2013 10:04, Josh Wu :
> For at91 boards, there are different IPs for adc. Different IPs has different
> STARTUP & PRESCAL mask in ADC_MR.
>
> This patch can change the masks according to the different IP version.
>
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> ---
>   arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
>   drivers/iio/adc/at91_adc.c                 |   48 ++++++++++++++++++++++++++--
>   2 files changed, 53 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 8e7ed5c..ab273ee 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	(0xff << 8)	/* Prescalar Rate Selection */
> +#define		AT91_ADC_PRESCAL_9260	(0x3f << 8)
>   #define			AT91_ADC_PRESCAL_(x)	((x) << 8)
> -#define		AT91_ADC_STARTUP	(0x1f << 16)	/* Startup Up Time */
> +#define		AT91_ADC_STARTUP	(0xf << 16)	/* Startup Up Time */

Which product has this kind of startup mask: 0xf? Compared with 9260 and 
9g45 values, it seems strange to me: maybe a little comment should be added.


> +#define		AT91_ADC_STARTUP_9260	(0x1f << 16)
> +#define		AT91_ADC_STARTUP_9G45	(0x7f << 16)
>   #define			AT91_ADC_STARTUP_(x)	((x) << 16)
>   #define		AT91_ADC_SHTIM		(0xf  << 24)	/* Sample & Hold Time */
>   #define			AT91_ADC_SHTIM_(x)	((x) << 24)
> @@ -58,4 +61,6 @@
>   #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
>   #define		AT91_ADC_DATA		(0x3ff)
>
> +#define AT91_ADC_VERSION	0xFC
> +
>   #endif
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index 18bd54f..14e99ba 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -39,6 +39,12 @@
>   #define at91_adc_writel(st, reg, val) \
>   	(writel_relaxed(val, st->reg_base + reg))
>
> +struct at91_adc_caps {
> +	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
> +	u32	mr_prescal_mask;
> +	u32	mr_startup_mask;
> +};
> +

If we move to DT and compatible string for these values, maybe a 
separate structure won't be needed....


>   struct at91_adc_state {
>   	struct clk		*adc_clk;
>   	u16			*buffer;
> @@ -62,6 +68,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)
> @@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
>   	.read_raw = &at91_adc_read_raw,
>   };
>
> +/*
> + * Since atmel adc support different ip for touchscreen mode. Through the
> + * IP check, we will know the touchscreen capbilities.
> + */
> +static void atmel_adc_get_cap(struct at91_adc_state *st)
> +{
> +	unsigned int version;
> +	struct iio_dev *idev = iio_priv_to_dev(st);
> +
> +	version = at91_adc_readl(st, AT91_ADC_VERSION);
> +	dev_dbg(&idev->dev, "version: 0x%x\n", version);
> +
> +	st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
> +	st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
> +
> +	/* keep only major version number */
> +	switch (version & 0xf00) {
> +	case 0x500:	/* SAMA5D3 */
> +	case 0x400:	/* AT91SAM9X5/9N12 */
> +		st->caps.has_tsmr = 1;
> +		st->caps.mr_startup_mask = AT91_ADC_STARTUP;

Here is where AT91_ADC_STARTUP may need another name: what about 
AT91_ADC_STARTUP_9x5 to match the "compatibility" of this value?


> +	case 0x200:	/* AT91SAM9M10/9G45 */
> +		st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
> +
> +		if ((version & 0xf00) == 0x200)

Sorry but I do not understand this test in a switch/case entry where it 
should always be true...


> +			st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
> +	case 0x100:	/* AT91SAM9260/9G20 */
> +		break;
> +	default:
> +		dev_warn(&idev->dev,
> +				"Unmanaged adc version, use minimal capabilities\n");
> +		break;
> +	};
> +}
> +
>   static int at91_adc_probe(struct platform_device *pdev)
>   {
>   	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
> @@ -645,6 +687,8 @@ static int at91_adc_probe(struct platform_device *pdev)
>   		goto error_free_device;
>   	}
>
> +	atmel_adc_get_cap(st);
> +
>   	st->clk = devm_clk_get(&pdev->dev, "adc_clk");
>   	if (IS_ERR(st->clk)) {
>   		dev_err(&pdev->dev, "Failed to get the clock.\n");
> @@ -704,8 +748,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->caps.mr_prescal_mask;
> +	reg |= AT91_ADC_STARTUP_(ticks) & st->caps.mr_startup_mask;
>   	if (st->low_res)
>   		reg |= AT91_ADC_LOWRES;
>   	if (st->sleep_mode)
>


-- 
Nicolas Ferre

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

* [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-17  7:58     ` Nicolas Ferre
  0 siblings, 0 replies; 85+ messages in thread
From: Nicolas Ferre @ 2013-07-17  7:58 UTC (permalink / raw)
  To: linux-arm-kernel

On 14/07/2013 10:04, Josh Wu :
> For at91 boards, there are different IPs for adc. Different IPs has different
> STARTUP & PRESCAL mask in ADC_MR.
>
> This patch can change the masks according to the different IP version.
>
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> ---
>   arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
>   drivers/iio/adc/at91_adc.c                 |   48 ++++++++++++++++++++++++++--
>   2 files changed, 53 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 8e7ed5c..ab273ee 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	(0xff << 8)	/* Prescalar Rate Selection */
> +#define		AT91_ADC_PRESCAL_9260	(0x3f << 8)
>   #define			AT91_ADC_PRESCAL_(x)	((x) << 8)
> -#define		AT91_ADC_STARTUP	(0x1f << 16)	/* Startup Up Time */
> +#define		AT91_ADC_STARTUP	(0xf << 16)	/* Startup Up Time */

Which product has this kind of startup mask: 0xf? Compared with 9260 and 
9g45 values, it seems strange to me: maybe a little comment should be added.


> +#define		AT91_ADC_STARTUP_9260	(0x1f << 16)
> +#define		AT91_ADC_STARTUP_9G45	(0x7f << 16)
>   #define			AT91_ADC_STARTUP_(x)	((x) << 16)
>   #define		AT91_ADC_SHTIM		(0xf  << 24)	/* Sample & Hold Time */
>   #define			AT91_ADC_SHTIM_(x)	((x) << 24)
> @@ -58,4 +61,6 @@
>   #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
>   #define		AT91_ADC_DATA		(0x3ff)
>
> +#define AT91_ADC_VERSION	0xFC
> +
>   #endif
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index 18bd54f..14e99ba 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -39,6 +39,12 @@
>   #define at91_adc_writel(st, reg, val) \
>   	(writel_relaxed(val, st->reg_base + reg))
>
> +struct at91_adc_caps {
> +	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
> +	u32	mr_prescal_mask;
> +	u32	mr_startup_mask;
> +};
> +

If we move to DT and compatible string for these values, maybe a 
separate structure won't be needed....


>   struct at91_adc_state {
>   	struct clk		*adc_clk;
>   	u16			*buffer;
> @@ -62,6 +68,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)
> @@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
>   	.read_raw = &at91_adc_read_raw,
>   };
>
> +/*
> + * Since atmel adc support different ip for touchscreen mode. Through the
> + * IP check, we will know the touchscreen capbilities.
> + */
> +static void atmel_adc_get_cap(struct at91_adc_state *st)
> +{
> +	unsigned int version;
> +	struct iio_dev *idev = iio_priv_to_dev(st);
> +
> +	version = at91_adc_readl(st, AT91_ADC_VERSION);
> +	dev_dbg(&idev->dev, "version: 0x%x\n", version);
> +
> +	st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
> +	st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
> +
> +	/* keep only major version number */
> +	switch (version & 0xf00) {
> +	case 0x500:	/* SAMA5D3 */
> +	case 0x400:	/* AT91SAM9X5/9N12 */
> +		st->caps.has_tsmr = 1;
> +		st->caps.mr_startup_mask = AT91_ADC_STARTUP;

Here is where AT91_ADC_STARTUP may need another name: what about 
AT91_ADC_STARTUP_9x5 to match the "compatibility" of this value?


> +	case 0x200:	/* AT91SAM9M10/9G45 */
> +		st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
> +
> +		if ((version & 0xf00) == 0x200)

Sorry but I do not understand this test in a switch/case entry where it 
should always be true...


> +			st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
> +	case 0x100:	/* AT91SAM9260/9G20 */
> +		break;
> +	default:
> +		dev_warn(&idev->dev,
> +				"Unmanaged adc version, use minimal capabilities\n");
> +		break;
> +	};
> +}
> +
>   static int at91_adc_probe(struct platform_device *pdev)
>   {
>   	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
> @@ -645,6 +687,8 @@ static int at91_adc_probe(struct platform_device *pdev)
>   		goto error_free_device;
>   	}
>
> +	atmel_adc_get_cap(st);
> +
>   	st->clk = devm_clk_get(&pdev->dev, "adc_clk");
>   	if (IS_ERR(st->clk)) {
>   		dev_err(&pdev->dev, "Failed to get the clock.\n");
> @@ -704,8 +748,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->caps.mr_prescal_mask;
> +	reg |= AT91_ADC_STARTUP_(ticks) & st->caps.mr_startup_mask;
>   	if (st->low_res)
>   		reg |= AT91_ADC_LOWRES;
>   	if (st->sleep_mode)
>


-- 
Nicolas Ferre

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-07-15 12:58     ` Maxime Ripard
@ 2013-07-17  8:12       ` Nicolas Ferre
  -1 siblings, 0 replies; 85+ messages in thread
From: Nicolas Ferre @ 2013-07-17  8:12 UTC (permalink / raw)
  To: Maxime Ripard, Josh Wu; +Cc: jic23, linux-arm-kernel, linux-iio, plagnioj

On 15/07/2013 14:58, Maxime Ripard :
> Hi Josh,
>
> On Sun, Jul 14, 2013 at 04:04:26PM +0800, Josh Wu wrote:
>> For at91 boards, there are different IPs for adc. Different IPs has different
>> STARTUP & PRESCAL mask in ADC_MR.
>>
>> This patch can change the masks according to the different IP version.
>>
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>> ---
>>   arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
>>   drivers/iio/adc/at91_adc.c                 |   48 ++++++++++++++++++++++++++--
>>   2 files changed, 53 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 8e7ed5c..ab273ee 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	(0xff << 8)	/* Prescalar Rate Selection */
>> +#define		AT91_ADC_PRESCAL_9260	(0x3f << 8)
>>   #define			AT91_ADC_PRESCAL_(x)	((x) << 8)
>> -#define		AT91_ADC_STARTUP	(0x1f << 16)	/* Startup Up Time */
>> +#define		AT91_ADC_STARTUP	(0xf << 16)	/* Startup Up Time */
>> +#define		AT91_ADC_STARTUP_9260	(0x1f << 16)
>> +#define		AT91_ADC_STARTUP_9G45	(0x7f << 16)
>>   #define			AT91_ADC_STARTUP_(x)	((x) << 16)
>>   #define		AT91_ADC_SHTIM		(0xf  << 24)	/* Sample & Hold Time */
>>   #define			AT91_ADC_SHTIM_(x)	((x) << 24)
>> @@ -58,4 +61,6 @@
>>   #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
>>   #define		AT91_ADC_DATA		(0x3ff)
>>
>> +#define AT91_ADC_VERSION	0xFC
>> +
>>   #endif
>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>> index 18bd54f..14e99ba 100644
>> --- a/drivers/iio/adc/at91_adc.c
>> +++ b/drivers/iio/adc/at91_adc.c
>> @@ -39,6 +39,12 @@
>>   #define at91_adc_writel(st, reg, val) \
>>   	(writel_relaxed(val, st->reg_base + reg))
>>
>> +struct at91_adc_caps {
>> +	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
>> +	u32	mr_prescal_mask;
>> +	u32	mr_startup_mask;
>> +};
>> +
>>   struct at91_adc_state {
>>   	struct clk		*adc_clk;
>>   	u16			*buffer;
>> @@ -62,6 +68,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)
>> @@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
>>   	.read_raw = &at91_adc_read_raw,
>>   };
>>
>> +/*
>> + * Since atmel adc support different ip for touchscreen mode. Through the
>> + * IP check, we will know the touchscreen capbilities.
>> + */
>> +static void atmel_adc_get_cap(struct at91_adc_state *st)
>> +{
>> +	unsigned int version;
>> +	struct iio_dev *idev = iio_priv_to_dev(st);
>> +
>> +	version = at91_adc_readl(st, AT91_ADC_VERSION);
>> +	dev_dbg(&idev->dev, "version: 0x%x\n", version);
>> +
>> +	st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
>> +	st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
>> +
>> +	/* keep only major version number */
>> +	switch (version & 0xf00) {
>> +	case 0x500:	/* SAMA5D3 */
>> +	case 0x400:	/* AT91SAM9X5/9N12 */
>> +		st->caps.has_tsmr = 1;
>> +		st->caps.mr_startup_mask = AT91_ADC_STARTUP;
>> +	case 0x200:	/* AT91SAM9M10/9G45 */
>> +		st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
>> +
>> +		if ((version & 0xf00) == 0x200)
>> +			st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
>> +	case 0x100:	/* AT91SAM9260/9G20 */
>> +		break;
>> +	default:
>> +		dev_warn(&idev->dev,
>> +				"Unmanaged adc version, use minimal capabilities\n");
>> +		break;
>> +	};
>> +}
>
> Why don't you use different compatible names and derive your
> capabilities from which compatible is declared.

Do not forget that we still have a handful of platforms that do not 
support DT (and never will).

Josh, do you think that we can deal with this with different compatible 
string instead of checking the IP revision?

Bye,
-- 
Nicolas Ferre

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

* [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-17  8:12       ` Nicolas Ferre
  0 siblings, 0 replies; 85+ messages in thread
From: Nicolas Ferre @ 2013-07-17  8:12 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/07/2013 14:58, Maxime Ripard :
> Hi Josh,
>
> On Sun, Jul 14, 2013 at 04:04:26PM +0800, Josh Wu wrote:
>> For at91 boards, there are different IPs for adc. Different IPs has different
>> STARTUP & PRESCAL mask in ADC_MR.
>>
>> This patch can change the masks according to the different IP version.
>>
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>> ---
>>   arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
>>   drivers/iio/adc/at91_adc.c                 |   48 ++++++++++++++++++++++++++--
>>   2 files changed, 53 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 8e7ed5c..ab273ee 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	(0xff << 8)	/* Prescalar Rate Selection */
>> +#define		AT91_ADC_PRESCAL_9260	(0x3f << 8)
>>   #define			AT91_ADC_PRESCAL_(x)	((x) << 8)
>> -#define		AT91_ADC_STARTUP	(0x1f << 16)	/* Startup Up Time */
>> +#define		AT91_ADC_STARTUP	(0xf << 16)	/* Startup Up Time */
>> +#define		AT91_ADC_STARTUP_9260	(0x1f << 16)
>> +#define		AT91_ADC_STARTUP_9G45	(0x7f << 16)
>>   #define			AT91_ADC_STARTUP_(x)	((x) << 16)
>>   #define		AT91_ADC_SHTIM		(0xf  << 24)	/* Sample & Hold Time */
>>   #define			AT91_ADC_SHTIM_(x)	((x) << 24)
>> @@ -58,4 +61,6 @@
>>   #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
>>   #define		AT91_ADC_DATA		(0x3ff)
>>
>> +#define AT91_ADC_VERSION	0xFC
>> +
>>   #endif
>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>> index 18bd54f..14e99ba 100644
>> --- a/drivers/iio/adc/at91_adc.c
>> +++ b/drivers/iio/adc/at91_adc.c
>> @@ -39,6 +39,12 @@
>>   #define at91_adc_writel(st, reg, val) \
>>   	(writel_relaxed(val, st->reg_base + reg))
>>
>> +struct at91_adc_caps {
>> +	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
>> +	u32	mr_prescal_mask;
>> +	u32	mr_startup_mask;
>> +};
>> +
>>   struct at91_adc_state {
>>   	struct clk		*adc_clk;
>>   	u16			*buffer;
>> @@ -62,6 +68,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)
>> @@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
>>   	.read_raw = &at91_adc_read_raw,
>>   };
>>
>> +/*
>> + * Since atmel adc support different ip for touchscreen mode. Through the
>> + * IP check, we will know the touchscreen capbilities.
>> + */
>> +static void atmel_adc_get_cap(struct at91_adc_state *st)
>> +{
>> +	unsigned int version;
>> +	struct iio_dev *idev = iio_priv_to_dev(st);
>> +
>> +	version = at91_adc_readl(st, AT91_ADC_VERSION);
>> +	dev_dbg(&idev->dev, "version: 0x%x\n", version);
>> +
>> +	st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
>> +	st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
>> +
>> +	/* keep only major version number */
>> +	switch (version & 0xf00) {
>> +	case 0x500:	/* SAMA5D3 */
>> +	case 0x400:	/* AT91SAM9X5/9N12 */
>> +		st->caps.has_tsmr = 1;
>> +		st->caps.mr_startup_mask = AT91_ADC_STARTUP;
>> +	case 0x200:	/* AT91SAM9M10/9G45 */
>> +		st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
>> +
>> +		if ((version & 0xf00) == 0x200)
>> +			st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
>> +	case 0x100:	/* AT91SAM9260/9G20 */
>> +		break;
>> +	default:
>> +		dev_warn(&idev->dev,
>> +				"Unmanaged adc version, use minimal capabilities\n");
>> +		break;
>> +	};
>> +}
>
> Why don't you use different compatible names and derive your
> capabilities from which compatible is declared.

Do not forget that we still have a handful of platforms that do not 
support DT (and never will).

Josh, do you think that we can deal with this with different compatible 
string instead of checking the IP revision?

Bye,
-- 
Nicolas Ferre

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-07-16 19:17                   ` Thomas Petazzoni
  (?)
@ 2013-07-17  8:23                     ` Nicolas Ferre
  -1 siblings, 0 replies; 85+ messages in thread
From: Nicolas Ferre @ 2013-07-17  8:23 UTC (permalink / raw)
  To: Thomas Petazzoni, Jonathan Cameron
  Cc: Josh Wu, Maxime Ripard, plagnioj-sclMFOaUSTBWk0Htik3J/w,
	linux-iio-u79uwXL29TY76Z2rM5mHXA, jic23-KWPb1pKIrIJaa/9Udqfwiw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

On 16/07/2013 21:17, Thomas Petazzoni :
> Dear Jonathan Cameron,
>
> On Tue, 16 Jul 2013 20:03:38 +0100, Jonathan Cameron wrote:
>
>> On 07/16/2013 12:30 PM, Thomas Petazzoni wrote:
>>> I've asked exactly this question last week at Linaro Connect during the
>>> ARM SoC consolidation panel/discussion, where Grant Likely, Arnd
>>> Bergmann, Olof and others were answering Device Tree related questions.
>>>
>>> My question, which precisely had the at91-adc DT binding in mind was
>>> precisely whether we should use different compatible properties to
>>> identify different revisions of an IP block and let the driver handle
>>> those differences, or whether the DT binding should provide sufficient
>>> properties (register offsets, bit numbers, etc.) to make the driver
>>> independent of the IP revisions. And clearly, the answer was that
>>> different compatible properties should be used to identify the
>>> different versions of the IP block, and the driver should abstract out
>>> the differences. I.e, was has been done for at91-adc is completely the
>>> opposite of the best practices for Device Tree on ARM.
>>>
>>> See
>>> http://www.youtube.com/watch?v=zF_AXLgkFy4&feature=player_detailpage#t=1581s
>>> where I ask exactly this question, and get answers from Olof Johansson
>>> and Grant Likely. They clearly say that the solution of having separate
>>> compatible properties and a driver that handles the differences is the
>>> way to go. So the way at91-adc (and possibly other at91 drivers) is
>>> using the Device Tree is wrong, there should have been multiple
>>> compatible properties. It's a shame because this is something we did say
>>> when we submitted at91-adc and during the reviews, but the maintainer
>>> wasn't listening to our comments...
>>>
>>
>> Thanks for getting some clarity on this Thomas.  So I'll ask the somewhat obvious
>> question - how do we unwind from where we are to where we want to be wrt to the
>> bindings?
>
> During Linaro Connect last week, there was some discussion about
> marking DT bindings as unstable for a little while, once they get
> reviewed by a group of DT "experts" that mark them as stable. Until
> they are stable, the kernel does not offer any ABI guarantees, and we
> are free to change the DT bindings as needed.
>
> Now, since this unstable/stable thing is not in place at the moment,
> deciding whether to break or not existing bindings is something to be
> decided by the maintainer of this platform, judging what is the best
> option depending on whether there are already many users of the DT for
> this platform or not, for example.

I didn't had in mind that the current discussion about the addition of 
some properties could cast doubt on the entire at91-adc binding!

The binding itself has several drawbacks and is kind of over engineered, 
I agree with that. Some register offsets in particular have nothing to 
do in a DT binding.
On the other hand, some values are highly dependent on the SoC process 
itself and can't be stored in the driver because it would require to 
change the driver for each new SoC, depending on the electrical 
characteristics.
In conclusion, we have to be cautious with this binding and make sure 
that we don't throw the baby out with the bath water.

Moreover, at the time we are just beginning to be comfortable with DT on 
AT91 and beginning to overcome the difficulty of converting our 
platforms, I see this new step on the path to "mainline + DT stable" as 
another slowdown.

Bye,
-- 
Nicolas Ferre

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-17  8:23                     ` Nicolas Ferre
  0 siblings, 0 replies; 85+ messages in thread
From: Nicolas Ferre @ 2013-07-17  8:23 UTC (permalink / raw)
  To: Thomas Petazzoni, Jonathan Cameron
  Cc: Josh Wu, Maxime Ripard, plagnioj, linux-iio, jic23,
	linux-arm-kernel, devicetree-discuss

On 16/07/2013 21:17, Thomas Petazzoni :
> Dear Jonathan Cameron,
>
> On Tue, 16 Jul 2013 20:03:38 +0100, Jonathan Cameron wrote:
>
>> On 07/16/2013 12:30 PM, Thomas Petazzoni wrote:
>>> I've asked exactly this question last week at Linaro Connect during the
>>> ARM SoC consolidation panel/discussion, where Grant Likely, Arnd
>>> Bergmann, Olof and others were answering Device Tree related questions.
>>>
>>> My question, which precisely had the at91-adc DT binding in mind was
>>> precisely whether we should use different compatible properties to
>>> identify different revisions of an IP block and let the driver handle
>>> those differences, or whether the DT binding should provide sufficient
>>> properties (register offsets, bit numbers, etc.) to make the driver
>>> independent of the IP revisions. And clearly, the answer was that
>>> different compatible properties should be used to identify the
>>> different versions of the IP block, and the driver should abstract out
>>> the differences. I.e, was has been done for at91-adc is completely the
>>> opposite of the best practices for Device Tree on ARM.
>>>
>>> See
>>> http://www.youtube.com/watch?v=zF_AXLgkFy4&feature=player_detailpage#t=1581s
>>> where I ask exactly this question, and get answers from Olof Johansson
>>> and Grant Likely. They clearly say that the solution of having separate
>>> compatible properties and a driver that handles the differences is the
>>> way to go. So the way at91-adc (and possibly other at91 drivers) is
>>> using the Device Tree is wrong, there should have been multiple
>>> compatible properties. It's a shame because this is something we did say
>>> when we submitted at91-adc and during the reviews, but the maintainer
>>> wasn't listening to our comments...
>>>
>>
>> Thanks for getting some clarity on this Thomas.  So I'll ask the somewhat obvious
>> question - how do we unwind from where we are to where we want to be wrt to the
>> bindings?
>
> During Linaro Connect last week, there was some discussion about
> marking DT bindings as unstable for a little while, once they get
> reviewed by a group of DT "experts" that mark them as stable. Until
> they are stable, the kernel does not offer any ABI guarantees, and we
> are free to change the DT bindings as needed.
>
> Now, since this unstable/stable thing is not in place at the moment,
> deciding whether to break or not existing bindings is something to be
> decided by the maintainer of this platform, judging what is the best
> option depending on whether there are already many users of the DT for
> this platform or not, for example.

I didn't had in mind that the current discussion about the addition of 
some properties could cast doubt on the entire at91-adc binding!

The binding itself has several drawbacks and is kind of over engineered, 
I agree with that. Some register offsets in particular have nothing to 
do in a DT binding.
On the other hand, some values are highly dependent on the SoC process 
itself and can't be stored in the driver because it would require to 
change the driver for each new SoC, depending on the electrical 
characteristics.
In conclusion, we have to be cautious with this binding and make sure 
that we don't throw the baby out with the bath water.

Moreover, at the time we are just beginning to be comfortable with DT on 
AT91 and beginning to overcome the difficulty of converting our 
platforms, I see this new step on the path to "mainline + DT stable" as 
another slowdown.

Bye,
-- 
Nicolas Ferre

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

* [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-17  8:23                     ` Nicolas Ferre
  0 siblings, 0 replies; 85+ messages in thread
From: Nicolas Ferre @ 2013-07-17  8:23 UTC (permalink / raw)
  To: linux-arm-kernel

On 16/07/2013 21:17, Thomas Petazzoni :
> Dear Jonathan Cameron,
>
> On Tue, 16 Jul 2013 20:03:38 +0100, Jonathan Cameron wrote:
>
>> On 07/16/2013 12:30 PM, Thomas Petazzoni wrote:
>>> I've asked exactly this question last week at Linaro Connect during the
>>> ARM SoC consolidation panel/discussion, where Grant Likely, Arnd
>>> Bergmann, Olof and others were answering Device Tree related questions.
>>>
>>> My question, which precisely had the at91-adc DT binding in mind was
>>> precisely whether we should use different compatible properties to
>>> identify different revisions of an IP block and let the driver handle
>>> those differences, or whether the DT binding should provide sufficient
>>> properties (register offsets, bit numbers, etc.) to make the driver
>>> independent of the IP revisions. And clearly, the answer was that
>>> different compatible properties should be used to identify the
>>> different versions of the IP block, and the driver should abstract out
>>> the differences. I.e, was has been done for at91-adc is completely the
>>> opposite of the best practices for Device Tree on ARM.
>>>
>>> See
>>> http://www.youtube.com/watch?v=zF_AXLgkFy4&feature=player_detailpage#t=1581s
>>> where I ask exactly this question, and get answers from Olof Johansson
>>> and Grant Likely. They clearly say that the solution of having separate
>>> compatible properties and a driver that handles the differences is the
>>> way to go. So the way at91-adc (and possibly other at91 drivers) is
>>> using the Device Tree is wrong, there should have been multiple
>>> compatible properties. It's a shame because this is something we did say
>>> when we submitted at91-adc and during the reviews, but the maintainer
>>> wasn't listening to our comments...
>>>
>>
>> Thanks for getting some clarity on this Thomas.  So I'll ask the somewhat obvious
>> question - how do we unwind from where we are to where we want to be wrt to the
>> bindings?
>
> During Linaro Connect last week, there was some discussion about
> marking DT bindings as unstable for a little while, once they get
> reviewed by a group of DT "experts" that mark them as stable. Until
> they are stable, the kernel does not offer any ABI guarantees, and we
> are free to change the DT bindings as needed.
>
> Now, since this unstable/stable thing is not in place at the moment,
> deciding whether to break or not existing bindings is something to be
> decided by the maintainer of this platform, judging what is the best
> option depending on whether there are already many users of the DT for
> this platform or not, for example.

I didn't had in mind that the current discussion about the addition of 
some properties could cast doubt on the entire at91-adc binding!

The binding itself has several drawbacks and is kind of over engineered, 
I agree with that. Some register offsets in particular have nothing to 
do in a DT binding.
On the other hand, some values are highly dependent on the SoC process 
itself and can't be stored in the driver because it would require to 
change the driver for each new SoC, depending on the electrical 
characteristics.
In conclusion, we have to be cautious with this binding and make sure 
that we don't throw the baby out with the bath water.

Moreover, at the time we are just beginning to be comfortable with DT on 
AT91 and beginning to overcome the difficulty of converting our 
platforms, I see this new step on the path to "mainline + DT stable" as 
another slowdown.

Bye,
-- 
Nicolas Ferre

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-07-17  8:12       ` Nicolas Ferre
@ 2013-07-17  9:07         ` Josh Wu
  -1 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-17  9:07 UTC (permalink / raw)
  To: Nicolas Ferre; +Cc: Maxime Ripard, jic23, linux-arm-kernel, linux-iio, plagnioj

Hi, Nicolas

On 7/17/2013 4:12 PM, Nicolas Ferre wrote:
> On 15/07/2013 14:58, Maxime Ripard :
>> Hi Josh,
>>
>> On Sun, Jul 14, 2013 at 04:04:26PM +0800, Josh Wu wrote:
>>> For at91 boards, there are different IPs for adc. Different IPs has 
>>> different
>>> STARTUP & PRESCAL mask in ADC_MR.
>>>
>>> This patch can change the masks according to the different IP version.
>>>
>>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>>> ---
>>>   arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
>>>   drivers/iio/adc/at91_adc.c                 |   48 
>>> ++++++++++++++++++++++++++--
>>>   2 files changed, 53 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 8e7ed5c..ab273ee 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    (0xff << 8)    /* Prescalar Rate 
>>> Selection */
>>> +#define        AT91_ADC_PRESCAL_9260    (0x3f << 8)
>>>   #define            AT91_ADC_PRESCAL_(x)    ((x) << 8)
>>> -#define        AT91_ADC_STARTUP    (0x1f << 16)    /* Startup Up 
>>> Time */
>>> +#define        AT91_ADC_STARTUP    (0xf << 16)    /* Startup Up 
>>> Time */
>>> +#define        AT91_ADC_STARTUP_9260    (0x1f << 16)
>>> +#define        AT91_ADC_STARTUP_9G45    (0x7f << 16)
>>>   #define            AT91_ADC_STARTUP_(x)    ((x) << 16)
>>>   #define        AT91_ADC_SHTIM        (0xf  << 24) /* Sample & Hold 
>>> Time */
>>>   #define            AT91_ADC_SHTIM_(x)    ((x) << 24)
>>> @@ -58,4 +61,6 @@
>>>   #define AT91_ADC_CHR(n)        (0x30 + ((n) * 4))    /* Channel 
>>> Data Register N */
>>>   #define        AT91_ADC_DATA        (0x3ff)
>>>
>>> +#define AT91_ADC_VERSION    0xFC
>>> +
>>>   #endif
>>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>>> index 18bd54f..14e99ba 100644
>>> --- a/drivers/iio/adc/at91_adc.c
>>> +++ b/drivers/iio/adc/at91_adc.c
>>> @@ -39,6 +39,12 @@
>>>   #define at91_adc_writel(st, reg, val) \
>>>       (writel_relaxed(val, st->reg_base + reg))
>>>
>>> +struct at91_adc_caps {
>>> +    bool    has_tsmr;    /* only at91sam9x5, sama5d3 have TSMR reg */
>>> +    u32    mr_prescal_mask;
>>> +    u32    mr_startup_mask;
>>> +};
>>> +
>>>   struct at91_adc_state {
>>>       struct clk        *adc_clk;
>>>       u16            *buffer;
>>> @@ -62,6 +68,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)
>>> @@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
>>>       .read_raw = &at91_adc_read_raw,
>>>   };
>>>
>>> +/*
>>> + * Since atmel adc support different ip for touchscreen mode. 
>>> Through the
>>> + * IP check, we will know the touchscreen capbilities.
>>> + */
>>> +static void atmel_adc_get_cap(struct at91_adc_state *st)
>>> +{
>>> +    unsigned int version;
>>> +    struct iio_dev *idev = iio_priv_to_dev(st);
>>> +
>>> +    version = at91_adc_readl(st, AT91_ADC_VERSION);
>>> +    dev_dbg(&idev->dev, "version: 0x%x\n", version);
>>> +
>>> +    st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
>>> +    st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
>>> +
>>> +    /* keep only major version number */
>>> +    switch (version & 0xf00) {
>>> +    case 0x500:    /* SAMA5D3 */
>>> +    case 0x400:    /* AT91SAM9X5/9N12 */
>>> +        st->caps.has_tsmr = 1;
>>> +        st->caps.mr_startup_mask = AT91_ADC_STARTUP;
>>> +    case 0x200:    /* AT91SAM9M10/9G45 */
>>> +        st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
>>> +
>>> +        if ((version & 0xf00) == 0x200)
>>> +            st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
>>> +    case 0x100:    /* AT91SAM9260/9G20 */
>>> +        break;
>>> +    default:
>>> +        dev_warn(&idev->dev,
>>> +                "Unmanaged adc version, use minimal capabilities\n");
>>> +        break;
>>> +    };
>>> +}
>>
>> Why don't you use different compatible names and derive your
>> capabilities from which compatible is declared.
>
> Do not forget that we still have a handful of platforms that do not 
> support DT (and never will).
>
> Josh, do you think that we can deal with this with different 
> compatible string instead of checking the IP revision?

yes, the simplest way is define additional adc_cap structure for 
different compatible string.
like following:

static const struct of_device_id at91_adc_dt_ids[] = {
     { .compatible = "atmel,at91sam9260-adc", .data 
=&at91sam9260-adc-caps },
     { .compatible = "atmel,at91sam9x5-adc", .data =&at91sam9x5-adc-caps },
     {},
};

Then we can define the capability for different chip very easy.

>
> Bye,

Best Regards,
Josh Wu

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

* [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-17  9:07         ` Josh Wu
  0 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-17  9:07 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, Nicolas

On 7/17/2013 4:12 PM, Nicolas Ferre wrote:
> On 15/07/2013 14:58, Maxime Ripard :
>> Hi Josh,
>>
>> On Sun, Jul 14, 2013 at 04:04:26PM +0800, Josh Wu wrote:
>>> For at91 boards, there are different IPs for adc. Different IPs has 
>>> different
>>> STARTUP & PRESCAL mask in ADC_MR.
>>>
>>> This patch can change the masks according to the different IP version.
>>>
>>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>>> ---
>>>   arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
>>>   drivers/iio/adc/at91_adc.c                 |   48 
>>> ++++++++++++++++++++++++++--
>>>   2 files changed, 53 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 8e7ed5c..ab273ee 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    (0xff << 8)    /* Prescalar Rate 
>>> Selection */
>>> +#define        AT91_ADC_PRESCAL_9260    (0x3f << 8)
>>>   #define            AT91_ADC_PRESCAL_(x)    ((x) << 8)
>>> -#define        AT91_ADC_STARTUP    (0x1f << 16)    /* Startup Up 
>>> Time */
>>> +#define        AT91_ADC_STARTUP    (0xf << 16)    /* Startup Up 
>>> Time */
>>> +#define        AT91_ADC_STARTUP_9260    (0x1f << 16)
>>> +#define        AT91_ADC_STARTUP_9G45    (0x7f << 16)
>>>   #define            AT91_ADC_STARTUP_(x)    ((x) << 16)
>>>   #define        AT91_ADC_SHTIM        (0xf  << 24) /* Sample & Hold 
>>> Time */
>>>   #define            AT91_ADC_SHTIM_(x)    ((x) << 24)
>>> @@ -58,4 +61,6 @@
>>>   #define AT91_ADC_CHR(n)        (0x30 + ((n) * 4))    /* Channel 
>>> Data Register N */
>>>   #define        AT91_ADC_DATA        (0x3ff)
>>>
>>> +#define AT91_ADC_VERSION    0xFC
>>> +
>>>   #endif
>>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>>> index 18bd54f..14e99ba 100644
>>> --- a/drivers/iio/adc/at91_adc.c
>>> +++ b/drivers/iio/adc/at91_adc.c
>>> @@ -39,6 +39,12 @@
>>>   #define at91_adc_writel(st, reg, val) \
>>>       (writel_relaxed(val, st->reg_base + reg))
>>>
>>> +struct at91_adc_caps {
>>> +    bool    has_tsmr;    /* only at91sam9x5, sama5d3 have TSMR reg */
>>> +    u32    mr_prescal_mask;
>>> +    u32    mr_startup_mask;
>>> +};
>>> +
>>>   struct at91_adc_state {
>>>       struct clk        *adc_clk;
>>>       u16            *buffer;
>>> @@ -62,6 +68,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)
>>> @@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
>>>       .read_raw = &at91_adc_read_raw,
>>>   };
>>>
>>> +/*
>>> + * Since atmel adc support different ip for touchscreen mode. 
>>> Through the
>>> + * IP check, we will know the touchscreen capbilities.
>>> + */
>>> +static void atmel_adc_get_cap(struct at91_adc_state *st)
>>> +{
>>> +    unsigned int version;
>>> +    struct iio_dev *idev = iio_priv_to_dev(st);
>>> +
>>> +    version = at91_adc_readl(st, AT91_ADC_VERSION);
>>> +    dev_dbg(&idev->dev, "version: 0x%x\n", version);
>>> +
>>> +    st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
>>> +    st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
>>> +
>>> +    /* keep only major version number */
>>> +    switch (version & 0xf00) {
>>> +    case 0x500:    /* SAMA5D3 */
>>> +    case 0x400:    /* AT91SAM9X5/9N12 */
>>> +        st->caps.has_tsmr = 1;
>>> +        st->caps.mr_startup_mask = AT91_ADC_STARTUP;
>>> +    case 0x200:    /* AT91SAM9M10/9G45 */
>>> +        st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
>>> +
>>> +        if ((version & 0xf00) == 0x200)
>>> +            st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
>>> +    case 0x100:    /* AT91SAM9260/9G20 */
>>> +        break;
>>> +    default:
>>> +        dev_warn(&idev->dev,
>>> +                "Unmanaged adc version, use minimal capabilities\n");
>>> +        break;
>>> +    };
>>> +}
>>
>> Why don't you use different compatible names and derive your
>> capabilities from which compatible is declared.
>
> Do not forget that we still have a handful of platforms that do not 
> support DT (and never will).
>
> Josh, do you think that we can deal with this with different 
> compatible string instead of checking the IP revision?

yes, the simplest way is define additional adc_cap structure for 
different compatible string.
like following:

static const struct of_device_id at91_adc_dt_ids[] = {
     { .compatible = "atmel,at91sam9260-adc", .data 
=&at91sam9260-adc-caps },
     { .compatible = "atmel,at91sam9x5-adc", .data =&at91sam9x5-adc-caps },
     {},
};

Then we can define the capability for different chip very easy.

>
> Bye,

Best Regards,
Josh Wu

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-07-17  7:58     ` Nicolas Ferre
@ 2013-07-17 10:09       ` Josh Wu
  -1 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-17 10:09 UTC (permalink / raw)
  To: Nicolas Ferre; +Cc: jic23, linux-arm-kernel, linux-iio, maxime.ripard, plagnioj

Hi, Nicolas

Thanks for your review.

On 7/17/2013 3:58 PM, Nicolas Ferre wrote:
> On 14/07/2013 10:04, Josh Wu :
>> For at91 boards, there are different IPs for adc. Different IPs has 
>> different
>> STARTUP & PRESCAL mask in ADC_MR.
>>
>> This patch can change the masks according to the different IP version.
>>
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>> ---
>>   arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
>>   drivers/iio/adc/at91_adc.c                 |   48 
>> ++++++++++++++++++++++++++--
>>   2 files changed, 53 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 8e7ed5c..ab273ee 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    (0xff << 8)    /* Prescalar Rate 
>> Selection */
>> +#define        AT91_ADC_PRESCAL_9260    (0x3f << 8)
>>   #define            AT91_ADC_PRESCAL_(x)    ((x) << 8)
>> -#define        AT91_ADC_STARTUP    (0x1f << 16)    /* Startup Up 
>> Time */
>> +#define        AT91_ADC_STARTUP    (0xf << 16)    /* Startup Up Time */
>
> Which product has this kind of startup mask: 0xf? Compared with 9260 
> and 9g45 values, it seems strange to me: maybe a little comment should 
> be added.

 From the datasheet, In at91sam9x5 and sama5d3x, the startup time mask 
is become 0xf. In meanwhile, the startup time calculation method is also 
changed.

Before at91sam9x5, Startup Time = (STARTUP+1) * 8/ADCCLK

Since at91sam9x5,  Startup Time = <find the following lookup table>
         0 SUT0 0 periods of ADCClock
         1 SUT8 8 periods of ADCClock
         2 SUT16 16 periods of ADCClock
         3 SUT24 24 periods of ADCClock
         4 SUT64 64 periods of ADCClock
         5 SUT80 80 periods of ADCClock
         ...    ...
         14 SUT896 896 periods of ADCClock
         15 SUT960 960 periods of ADCClock

so only 4bits, it still can define < 960's ADC clock.

In my 3/5 patch, it implement this calculation method.

>
>
>> +#define        AT91_ADC_STARTUP_9260 (0x1f << 16)
>> +#define        AT91_ADC_STARTUP_9G45    (0x7f << 16)
>>   #define            AT91_ADC_STARTUP_(x)    ((x) << 16)
>>   #define        AT91_ADC_SHTIM        (0xf  << 24)    /* Sample & 
>> Hold Time */
>>   #define            AT91_ADC_SHTIM_(x)    ((x) << 24)
>> @@ -58,4 +61,6 @@
>>   #define AT91_ADC_CHR(n)        (0x30 + ((n) * 4))    /* Channel 
>> Data Register N */
>>   #define        AT91_ADC_DATA        (0x3ff)
>>
>> +#define AT91_ADC_VERSION    0xFC
>> +
>>   #endif
>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>> index 18bd54f..14e99ba 100644
>> --- a/drivers/iio/adc/at91_adc.c
>> +++ b/drivers/iio/adc/at91_adc.c
>> @@ -39,6 +39,12 @@
>>   #define at91_adc_writel(st, reg, val) \
>>       (writel_relaxed(val, st->reg_base + reg))
>>
>> +struct at91_adc_caps {
>> +    bool    has_tsmr;    /* only at91sam9x5, sama5d3 have TSMR reg */
>> +    u32    mr_prescal_mask;
>> +    u32    mr_startup_mask;
>> +};
>> +
>
> If we move to DT and compatible string for these values, maybe a 
> separate structure won't be needed....

yes, if we move the mask as DT property.
But another way is define above structure in driver. Driver will load 
the correct mask by checking the compatible string. In this way, we 
don't exposure all IP details out to DT.
I prefer the second way in the moment.

By answer this question, I just had a second thought of the ADC 
compatible implementation:
For touch ADC, there should have 3 catalogs:
   9260/9g20: not support touch.
   9g45: support touch, but no average, no TSMR. Need a software filter
   9x5, sama5: support touch, with average, TSMR. Sample data function 
changed a lot from 9g45.

>
>
>>   struct at91_adc_state {
>>       struct clk        *adc_clk;
>>       u16            *buffer;
>> @@ -62,6 +68,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)
>> @@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
>>       .read_raw = &at91_adc_read_raw,
>>   };
>>
>> +/*
>> + * Since atmel adc support different ip for touchscreen mode. 
>> Through the
>> + * IP check, we will know the touchscreen capbilities.
>> + */
>> +static void atmel_adc_get_cap(struct at91_adc_state *st)
>> +{
>> +    unsigned int version;
>> +    struct iio_dev *idev = iio_priv_to_dev(st);
>> +
>> +    version = at91_adc_readl(st, AT91_ADC_VERSION);
>> +    dev_dbg(&idev->dev, "version: 0x%x\n", version);
>> +
>> +    st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
>> +    st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
>> +
>> +    /* keep only major version number */
>> +    switch (version & 0xf00) {
>> +    case 0x500:    /* SAMA5D3 */
>> +    case 0x400:    /* AT91SAM9X5/9N12 */
>> +        st->caps.has_tsmr = 1;
>> +        st->caps.mr_startup_mask = AT91_ADC_STARTUP;
>
> Here is where AT91_ADC_STARTUP may need another name: what about 
> AT91_ADC_STARTUP_9x5 to match the "compatibility" of this value?

ok.

>
>
>> +    case 0x200:    /* AT91SAM9M10/9G45 */
>> +        st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
>> +
>> +        if ((version & 0xf00) == 0x200)
>
> Sorry but I do not understand this test in a switch/case entry where 
> it should always be true...

Since the switch case is fall through, that means the higher IP 
(at91sam9x5, sama5) will also running this check, but this line only for 
9G45 chip.

a little bit hard to read  :)

>
>
>> +            st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
>> +    case 0x100:    /* AT91SAM9260/9G20 */
>> +        break;
>> +    default:
>> +        dev_warn(&idev->dev,
>> +                "Unmanaged adc version, use minimal capabilities\n");
>> +        break;
>> +    };
>> +}
>> +
>>   static int at91_adc_probe(struct platform_device *pdev)
>>   {
>>       unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
>> @@ -645,6 +687,8 @@ static int at91_adc_probe(struct platform_device 
>> *pdev)
>>           goto error_free_device;
>>       }
>>
>> +    atmel_adc_get_cap(st);
>> +
>>       st->clk = devm_clk_get(&pdev->dev, "adc_clk");
>>       if (IS_ERR(st->clk)) {
>>           dev_err(&pdev->dev, "Failed to get the clock.\n");
>> @@ -704,8 +748,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->caps.mr_prescal_mask;
>> +    reg |= AT91_ADC_STARTUP_(ticks) & st->caps.mr_startup_mask;
>>       if (st->low_res)
>>           reg |= AT91_ADC_LOWRES;
>>       if (st->sleep_mode)
>>
>
>

Thanks again.
Best Regards,
Josh Wu

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

* [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-17 10:09       ` Josh Wu
  0 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-17 10:09 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, Nicolas

Thanks for your review.

On 7/17/2013 3:58 PM, Nicolas Ferre wrote:
> On 14/07/2013 10:04, Josh Wu :
>> For at91 boards, there are different IPs for adc. Different IPs has 
>> different
>> STARTUP & PRESCAL mask in ADC_MR.
>>
>> This patch can change the masks according to the different IP version.
>>
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>> ---
>>   arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
>>   drivers/iio/adc/at91_adc.c                 |   48 
>> ++++++++++++++++++++++++++--
>>   2 files changed, 53 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 8e7ed5c..ab273ee 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    (0xff << 8)    /* Prescalar Rate 
>> Selection */
>> +#define        AT91_ADC_PRESCAL_9260    (0x3f << 8)
>>   #define            AT91_ADC_PRESCAL_(x)    ((x) << 8)
>> -#define        AT91_ADC_STARTUP    (0x1f << 16)    /* Startup Up 
>> Time */
>> +#define        AT91_ADC_STARTUP    (0xf << 16)    /* Startup Up Time */
>
> Which product has this kind of startup mask: 0xf? Compared with 9260 
> and 9g45 values, it seems strange to me: maybe a little comment should 
> be added.

 From the datasheet, In at91sam9x5 and sama5d3x, the startup time mask 
is become 0xf. In meanwhile, the startup time calculation method is also 
changed.

Before at91sam9x5, Startup Time = (STARTUP+1) * 8/ADCCLK

Since at91sam9x5,  Startup Time = <find the following lookup table>
         0 SUT0 0 periods of ADCClock
         1 SUT8 8 periods of ADCClock
         2 SUT16 16 periods of ADCClock
         3 SUT24 24 periods of ADCClock
         4 SUT64 64 periods of ADCClock
         5 SUT80 80 periods of ADCClock
         ...    ...
         14 SUT896 896 periods of ADCClock
         15 SUT960 960 periods of ADCClock

so only 4bits, it still can define < 960's ADC clock.

In my 3/5 patch, it implement this calculation method.

>
>
>> +#define        AT91_ADC_STARTUP_9260 (0x1f << 16)
>> +#define        AT91_ADC_STARTUP_9G45    (0x7f << 16)
>>   #define            AT91_ADC_STARTUP_(x)    ((x) << 16)
>>   #define        AT91_ADC_SHTIM        (0xf  << 24)    /* Sample & 
>> Hold Time */
>>   #define            AT91_ADC_SHTIM_(x)    ((x) << 24)
>> @@ -58,4 +61,6 @@
>>   #define AT91_ADC_CHR(n)        (0x30 + ((n) * 4))    /* Channel 
>> Data Register N */
>>   #define        AT91_ADC_DATA        (0x3ff)
>>
>> +#define AT91_ADC_VERSION    0xFC
>> +
>>   #endif
>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>> index 18bd54f..14e99ba 100644
>> --- a/drivers/iio/adc/at91_adc.c
>> +++ b/drivers/iio/adc/at91_adc.c
>> @@ -39,6 +39,12 @@
>>   #define at91_adc_writel(st, reg, val) \
>>       (writel_relaxed(val, st->reg_base + reg))
>>
>> +struct at91_adc_caps {
>> +    bool    has_tsmr;    /* only at91sam9x5, sama5d3 have TSMR reg */
>> +    u32    mr_prescal_mask;
>> +    u32    mr_startup_mask;
>> +};
>> +
>
> If we move to DT and compatible string for these values, maybe a 
> separate structure won't be needed....

yes, if we move the mask as DT property.
But another way is define above structure in driver. Driver will load 
the correct mask by checking the compatible string. In this way, we 
don't exposure all IP details out to DT.
I prefer the second way in the moment.

By answer this question, I just had a second thought of the ADC 
compatible implementation:
For touch ADC, there should have 3 catalogs:
   9260/9g20: not support touch.
   9g45: support touch, but no average, no TSMR. Need a software filter
   9x5, sama5: support touch, with average, TSMR. Sample data function 
changed a lot from 9g45.

>
>
>>   struct at91_adc_state {
>>       struct clk        *adc_clk;
>>       u16            *buffer;
>> @@ -62,6 +68,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)
>> @@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
>>       .read_raw = &at91_adc_read_raw,
>>   };
>>
>> +/*
>> + * Since atmel adc support different ip for touchscreen mode. 
>> Through the
>> + * IP check, we will know the touchscreen capbilities.
>> + */
>> +static void atmel_adc_get_cap(struct at91_adc_state *st)
>> +{
>> +    unsigned int version;
>> +    struct iio_dev *idev = iio_priv_to_dev(st);
>> +
>> +    version = at91_adc_readl(st, AT91_ADC_VERSION);
>> +    dev_dbg(&idev->dev, "version: 0x%x\n", version);
>> +
>> +    st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
>> +    st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
>> +
>> +    /* keep only major version number */
>> +    switch (version & 0xf00) {
>> +    case 0x500:    /* SAMA5D3 */
>> +    case 0x400:    /* AT91SAM9X5/9N12 */
>> +        st->caps.has_tsmr = 1;
>> +        st->caps.mr_startup_mask = AT91_ADC_STARTUP;
>
> Here is where AT91_ADC_STARTUP may need another name: what about 
> AT91_ADC_STARTUP_9x5 to match the "compatibility" of this value?

ok.

>
>
>> +    case 0x200:    /* AT91SAM9M10/9G45 */
>> +        st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
>> +
>> +        if ((version & 0xf00) == 0x200)
>
> Sorry but I do not understand this test in a switch/case entry where 
> it should always be true...

Since the switch case is fall through, that means the higher IP 
(at91sam9x5, sama5) will also running this check, but this line only for 
9G45 chip.

a little bit hard to read  :)

>
>
>> +            st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
>> +    case 0x100:    /* AT91SAM9260/9G20 */
>> +        break;
>> +    default:
>> +        dev_warn(&idev->dev,
>> +                "Unmanaged adc version, use minimal capabilities\n");
>> +        break;
>> +    };
>> +}
>> +
>>   static int at91_adc_probe(struct platform_device *pdev)
>>   {
>>       unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
>> @@ -645,6 +687,8 @@ static int at91_adc_probe(struct platform_device 
>> *pdev)
>>           goto error_free_device;
>>       }
>>
>> +    atmel_adc_get_cap(st);
>> +
>>       st->clk = devm_clk_get(&pdev->dev, "adc_clk");
>>       if (IS_ERR(st->clk)) {
>>           dev_err(&pdev->dev, "Failed to get the clock.\n");
>> @@ -704,8 +748,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->caps.mr_prescal_mask;
>> +    reg |= AT91_ADC_STARTUP_(ticks) & st->caps.mr_startup_mask;
>>       if (st->low_res)
>>           reg |= AT91_ADC_LOWRES;
>>       if (st->sleep_mode)
>>
>
>

Thanks again.
Best Regards,
Josh Wu

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-07-17  8:12       ` Nicolas Ferre
@ 2013-07-17 15:40         ` Maxime Ripard
  -1 siblings, 0 replies; 85+ messages in thread
From: Maxime Ripard @ 2013-07-17 15:40 UTC (permalink / raw)
  To: Nicolas Ferre; +Cc: Josh Wu, jic23, linux-arm-kernel, linux-iio, plagnioj

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

Hi Nicolas,

On Wed, Jul 17, 2013 at 10:12:05AM +0200, Nicolas Ferre wrote:
> On 15/07/2013 14:58, Maxime Ripard :
> >On Sun, Jul 14, 2013 at 04:04:26PM +0800, Josh Wu wrote:
> >>+/*
> >>+ * Since atmel adc support different ip for touchscreen mode. Through the
> >>+ * IP check, we will know the touchscreen capbilities.
> >>+ */
> >>+static void atmel_adc_get_cap(struct at91_adc_state *st)
> >>+{
> >>+	unsigned int version;
> >>+	struct iio_dev *idev = iio_priv_to_dev(st);
> >>+
> >>+	version = at91_adc_readl(st, AT91_ADC_VERSION);
> >>+	dev_dbg(&idev->dev, "version: 0x%x\n", version);
> >>+
> >>+	st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
> >>+	st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
> >>+
> >>+	/* keep only major version number */
> >>+	switch (version & 0xf00) {
> >>+	case 0x500:	/* SAMA5D3 */
> >>+	case 0x400:	/* AT91SAM9X5/9N12 */
> >>+		st->caps.has_tsmr = 1;
> >>+		st->caps.mr_startup_mask = AT91_ADC_STARTUP;
> >>+	case 0x200:	/* AT91SAM9M10/9G45 */
> >>+		st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
> >>+
> >>+		if ((version & 0xf00) == 0x200)
> >>+			st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
> >>+	case 0x100:	/* AT91SAM9260/9G20 */
> >>+		break;
> >>+	default:
> >>+		dev_warn(&idev->dev,
> >>+				"Unmanaged adc version, use minimal capabilities\n");
> >>+		break;
> >>+	};
> >>+}
> >
> >Why don't you use different compatible names and derive your
> >capabilities from which compatible is declared.
> 
> Do not forget that we still have a handful of platforms that do not
> support DT (and never will).

You can do pretty much the same thing with board-file-probed device
drivers, using the id_table field of the platform_driver structure and
use the driver_data field of the associated platform_device_id array to
store the needed values.

(see for example drivers/gpio/gpio-mxs.c)

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] 85+ messages in thread

* [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-17 15:40         ` Maxime Ripard
  0 siblings, 0 replies; 85+ messages in thread
From: Maxime Ripard @ 2013-07-17 15:40 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Nicolas,

On Wed, Jul 17, 2013 at 10:12:05AM +0200, Nicolas Ferre wrote:
> On 15/07/2013 14:58, Maxime Ripard :
> >On Sun, Jul 14, 2013 at 04:04:26PM +0800, Josh Wu wrote:
> >>+/*
> >>+ * Since atmel adc support different ip for touchscreen mode. Through the
> >>+ * IP check, we will know the touchscreen capbilities.
> >>+ */
> >>+static void atmel_adc_get_cap(struct at91_adc_state *st)
> >>+{
> >>+	unsigned int version;
> >>+	struct iio_dev *idev = iio_priv_to_dev(st);
> >>+
> >>+	version = at91_adc_readl(st, AT91_ADC_VERSION);
> >>+	dev_dbg(&idev->dev, "version: 0x%x\n", version);
> >>+
> >>+	st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
> >>+	st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
> >>+
> >>+	/* keep only major version number */
> >>+	switch (version & 0xf00) {
> >>+	case 0x500:	/* SAMA5D3 */
> >>+	case 0x400:	/* AT91SAM9X5/9N12 */
> >>+		st->caps.has_tsmr = 1;
> >>+		st->caps.mr_startup_mask = AT91_ADC_STARTUP;
> >>+	case 0x200:	/* AT91SAM9M10/9G45 */
> >>+		st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
> >>+
> >>+		if ((version & 0xf00) == 0x200)
> >>+			st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
> >>+	case 0x100:	/* AT91SAM9260/9G20 */
> >>+		break;
> >>+	default:
> >>+		dev_warn(&idev->dev,
> >>+				"Unmanaged adc version, use minimal capabilities\n");
> >>+		break;
> >>+	};
> >>+}
> >
> >Why don't you use different compatible names and derive your
> >capabilities from which compatible is declared.
> 
> Do not forget that we still have a handful of platforms that do not
> support DT (and never will).

You can do pretty much the same thing with board-file-probed device
drivers, using the id_table field of the platform_driver structure and
use the driver_data field of the associated platform_device_id array to
store the needed values.

(see for example drivers/gpio/gpio-mxs.c)

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/20130717/71912aca/attachment-0001.sig>

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

* Re: [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
  2013-07-17 10:09       ` Josh Wu
@ 2013-07-20  9:35         ` Jonathan Cameron
  -1 siblings, 0 replies; 85+ messages in thread
From: Jonathan Cameron @ 2013-07-20  9:35 UTC (permalink / raw)
  To: Josh Wu
  Cc: Nicolas Ferre, linux-arm-kernel, linux-iio, maxime.ripard, plagnioj

On 07/17/2013 11:09 AM, Josh Wu wrote:
> Hi, Nicolas
> 
> Thanks for your review.
> 
> On 7/17/2013 3:58 PM, Nicolas Ferre wrote:
>> On 14/07/2013 10:04, Josh Wu :
>>> For at91 boards, there are different IPs for adc. Different IPs has different
>>> STARTUP & PRESCAL mask in ADC_MR.
>>>
>>> This patch can change the masks according to the different IP version.
>>>
>>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>>> ---
>>>   arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
>>>   drivers/iio/adc/at91_adc.c                 |   48 ++++++++++++++++++++++++++--
>>>   2 files changed, 53 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 8e7ed5c..ab273ee 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    (0xff << 8)    /* Prescalar Rate Selection */
>>> +#define        AT91_ADC_PRESCAL_9260    (0x3f << 8)
>>>   #define            AT91_ADC_PRESCAL_(x)    ((x) << 8)
>>> -#define        AT91_ADC_STARTUP    (0x1f << 16)    /* Startup Up Time */
>>> +#define        AT91_ADC_STARTUP    (0xf << 16)    /* Startup Up Time */
>>
>> Which product has this kind of startup mask: 0xf? Compared with 9260 and 9g45 values, it seems strange to me: maybe a
>> little comment should be added.
> 
> From the datasheet, In at91sam9x5 and sama5d3x, the startup time mask is become 0xf. In meanwhile, the startup time
> calculation method is also changed.
> 
> Before at91sam9x5, Startup Time = (STARTUP+1) * 8/ADCCLK
> 
> Since at91sam9x5,  Startup Time = <find the following lookup table>
>         0 SUT0 0 periods of ADCClock
>         1 SUT8 8 periods of ADCClock
>         2 SUT16 16 periods of ADCClock
>         3 SUT24 24 periods of ADCClock
>         4 SUT64 64 periods of ADCClock
>         5 SUT80 80 periods of ADCClock
>         ...    ...
>         14 SUT896 896 periods of ADCClock
>         15 SUT960 960 periods of ADCClock
> 
> so only 4bits, it still can define < 960's ADC clock.
> 
> In my 3/5 patch, it implement this calculation method.
> 
>>
>>
>>> +#define        AT91_ADC_STARTUP_9260 (0x1f << 16)
>>> +#define        AT91_ADC_STARTUP_9G45    (0x7f << 16)
>>>   #define            AT91_ADC_STARTUP_(x)    ((x) << 16)
>>>   #define        AT91_ADC_SHTIM        (0xf  << 24)    /* Sample & Hold Time */
>>>   #define            AT91_ADC_SHTIM_(x)    ((x) << 24)
>>> @@ -58,4 +61,6 @@
>>>   #define AT91_ADC_CHR(n)        (0x30 + ((n) * 4))    /* Channel Data Register N */
>>>   #define        AT91_ADC_DATA        (0x3ff)
>>>
>>> +#define AT91_ADC_VERSION    0xFC
>>> +
>>>   #endif
>>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>>> index 18bd54f..14e99ba 100644
>>> --- a/drivers/iio/adc/at91_adc.c
>>> +++ b/drivers/iio/adc/at91_adc.c
>>> @@ -39,6 +39,12 @@
>>>   #define at91_adc_writel(st, reg, val) \
>>>       (writel_relaxed(val, st->reg_base + reg))
>>>
>>> +struct at91_adc_caps {
>>> +    bool    has_tsmr;    /* only at91sam9x5, sama5d3 have TSMR reg */
>>> +    u32    mr_prescal_mask;
>>> +    u32    mr_startup_mask;
>>> +};
>>> +
>>
>> If we move to DT and compatible string for these values, maybe a separate structure won't be needed....
> 
> yes, if we move the mask as DT property.
> But another way is define above structure in driver. Driver will load the correct mask by checking the compatible
> string. In this way, we don't exposure all IP details out to DT.
> I prefer the second way in the moment.
> 
> By answer this question, I just had a second thought of the ADC compatible implementation:
> For touch ADC, there should have 3 catalogs:
>   9260/9g20: not support touch.
>   9g45: support touch, but no average, no TSMR. Need a software filter
>   9x5, sama5: support touch, with average, TSMR. Sample data function changed a lot from 9g45.
> 
>>
>>
>>>   struct at91_adc_state {
>>>       struct clk        *adc_clk;
>>>       u16            *buffer;
>>> @@ -62,6 +68,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)
>>> @@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
>>>       .read_raw = &at91_adc_read_raw,
>>>   };
>>>
>>> +/*
>>> + * Since atmel adc support different ip for touchscreen mode. Through the
>>> + * IP check, we will know the touchscreen capbilities.
>>> + */
>>> +static void atmel_adc_get_cap(struct at91_adc_state *st)
>>> +{
>>> +    unsigned int version;
>>> +    struct iio_dev *idev = iio_priv_to_dev(st);
>>> +
>>> +    version = at91_adc_readl(st, AT91_ADC_VERSION);
>>> +    dev_dbg(&idev->dev, "version: 0x%x\n", version);
>>> +
>>> +    st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
>>> +    st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
>>> +
>>> +    /* keep only major version number */
>>> +    switch (version & 0xf00) {
>>> +    case 0x500:    /* SAMA5D3 */
>>> +    case 0x400:    /* AT91SAM9X5/9N12 */
>>> +        st->caps.has_tsmr = 1;
>>> +        st->caps.mr_startup_mask = AT91_ADC_STARTUP;
>>
>> Here is where AT91_ADC_STARTUP may need another name: what about AT91_ADC_STARTUP_9x5 to match the "compatibility" of
>> this value?
> 
> ok.
> 
>>
>>
>>> +    case 0x200:    /* AT91SAM9M10/9G45 */
>>> +        st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
>>> +
>>> +        if ((version & 0xf00) == 0x200)
>>
>> Sorry but I do not understand this test in a switch/case entry where it should always be true...
> 
> Since the switch case is fall through, that means the higher IP (at91sam9x5, sama5) will also running this check, but
> this line only for 9G45 chip.
> 
> a little bit hard to read  :)

Indeed. Write the case statements out long hand without the full throughs.
It'll take a couple more lines but be much easer to read.
> 
>>
>>
>>> +            st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
>>> +    case 0x100:    /* AT91SAM9260/9G20 */
>>> +        break;
>>> +    default:
>>> +        dev_warn(&idev->dev,
>>> +                "Unmanaged adc version, use minimal capabilities\n");
>>> +        break;
>>> +    };
>>> +}
>>> +
>>>   static int at91_adc_probe(struct platform_device *pdev)
>>>   {
>>>       unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
>>> @@ -645,6 +687,8 @@ static int at91_adc_probe(struct platform_device *pdev)
>>>           goto error_free_device;
>>>       }
>>>
>>> +    atmel_adc_get_cap(st);
>>> +
>>>       st->clk = devm_clk_get(&pdev->dev, "adc_clk");
>>>       if (IS_ERR(st->clk)) {
>>>           dev_err(&pdev->dev, "Failed to get the clock.\n");
>>> @@ -704,8 +748,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->caps.mr_prescal_mask;
>>> +    reg |= AT91_ADC_STARTUP_(ticks) & st->caps.mr_startup_mask;
>>>       if (st->low_res)
>>>           reg |= AT91_ADC_LOWRES;
>>>       if (st->sleep_mode)
>>>
>>
>>
> 
> Thanks again.
> Best Regards,
> Josh Wu
> -- 
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP
@ 2013-07-20  9:35         ` Jonathan Cameron
  0 siblings, 0 replies; 85+ messages in thread
From: Jonathan Cameron @ 2013-07-20  9:35 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/17/2013 11:09 AM, Josh Wu wrote:
> Hi, Nicolas
> 
> Thanks for your review.
> 
> On 7/17/2013 3:58 PM, Nicolas Ferre wrote:
>> On 14/07/2013 10:04, Josh Wu :
>>> For at91 boards, there are different IPs for adc. Different IPs has different
>>> STARTUP & PRESCAL mask in ADC_MR.
>>>
>>> This patch can change the masks according to the different IP version.
>>>
>>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>>> ---
>>>   arch/arm/mach-at91/include/mach/at91_adc.h |    9 ++++--
>>>   drivers/iio/adc/at91_adc.c                 |   48 ++++++++++++++++++++++++++--
>>>   2 files changed, 53 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 8e7ed5c..ab273ee 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    (0xff << 8)    /* Prescalar Rate Selection */
>>> +#define        AT91_ADC_PRESCAL_9260    (0x3f << 8)
>>>   #define            AT91_ADC_PRESCAL_(x)    ((x) << 8)
>>> -#define        AT91_ADC_STARTUP    (0x1f << 16)    /* Startup Up Time */
>>> +#define        AT91_ADC_STARTUP    (0xf << 16)    /* Startup Up Time */
>>
>> Which product has this kind of startup mask: 0xf? Compared with 9260 and 9g45 values, it seems strange to me: maybe a
>> little comment should be added.
> 
> From the datasheet, In at91sam9x5 and sama5d3x, the startup time mask is become 0xf. In meanwhile, the startup time
> calculation method is also changed.
> 
> Before at91sam9x5, Startup Time = (STARTUP+1) * 8/ADCCLK
> 
> Since at91sam9x5,  Startup Time = <find the following lookup table>
>         0 SUT0 0 periods of ADCClock
>         1 SUT8 8 periods of ADCClock
>         2 SUT16 16 periods of ADCClock
>         3 SUT24 24 periods of ADCClock
>         4 SUT64 64 periods of ADCClock
>         5 SUT80 80 periods of ADCClock
>         ...    ...
>         14 SUT896 896 periods of ADCClock
>         15 SUT960 960 periods of ADCClock
> 
> so only 4bits, it still can define < 960's ADC clock.
> 
> In my 3/5 patch, it implement this calculation method.
> 
>>
>>
>>> +#define        AT91_ADC_STARTUP_9260 (0x1f << 16)
>>> +#define        AT91_ADC_STARTUP_9G45    (0x7f << 16)
>>>   #define            AT91_ADC_STARTUP_(x)    ((x) << 16)
>>>   #define        AT91_ADC_SHTIM        (0xf  << 24)    /* Sample & Hold Time */
>>>   #define            AT91_ADC_SHTIM_(x)    ((x) << 24)
>>> @@ -58,4 +61,6 @@
>>>   #define AT91_ADC_CHR(n)        (0x30 + ((n) * 4))    /* Channel Data Register N */
>>>   #define        AT91_ADC_DATA        (0x3ff)
>>>
>>> +#define AT91_ADC_VERSION    0xFC
>>> +
>>>   #endif
>>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>>> index 18bd54f..14e99ba 100644
>>> --- a/drivers/iio/adc/at91_adc.c
>>> +++ b/drivers/iio/adc/at91_adc.c
>>> @@ -39,6 +39,12 @@
>>>   #define at91_adc_writel(st, reg, val) \
>>>       (writel_relaxed(val, st->reg_base + reg))
>>>
>>> +struct at91_adc_caps {
>>> +    bool    has_tsmr;    /* only at91sam9x5, sama5d3 have TSMR reg */
>>> +    u32    mr_prescal_mask;
>>> +    u32    mr_startup_mask;
>>> +};
>>> +
>>
>> If we move to DT and compatible string for these values, maybe a separate structure won't be needed....
> 
> yes, if we move the mask as DT property.
> But another way is define above structure in driver. Driver will load the correct mask by checking the compatible
> string. In this way, we don't exposure all IP details out to DT.
> I prefer the second way in the moment.
> 
> By answer this question, I just had a second thought of the ADC compatible implementation:
> For touch ADC, there should have 3 catalogs:
>   9260/9g20: not support touch.
>   9g45: support touch, but no average, no TSMR. Need a software filter
>   9x5, sama5: support touch, with average, TSMR. Sample data function changed a lot from 9g45.
> 
>>
>>
>>>   struct at91_adc_state {
>>>       struct clk        *adc_clk;
>>>       u16            *buffer;
>>> @@ -62,6 +68,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)
>>> @@ -580,6 +587,41 @@ static const struct iio_info at91_adc_info = {
>>>       .read_raw = &at91_adc_read_raw,
>>>   };
>>>
>>> +/*
>>> + * Since atmel adc support different ip for touchscreen mode. Through the
>>> + * IP check, we will know the touchscreen capbilities.
>>> + */
>>> +static void atmel_adc_get_cap(struct at91_adc_state *st)
>>> +{
>>> +    unsigned int version;
>>> +    struct iio_dev *idev = iio_priv_to_dev(st);
>>> +
>>> +    version = at91_adc_readl(st, AT91_ADC_VERSION);
>>> +    dev_dbg(&idev->dev, "version: 0x%x\n", version);
>>> +
>>> +    st->caps.mr_prescal_mask = AT91_ADC_PRESCAL_9260;
>>> +    st->caps.mr_startup_mask = AT91_ADC_STARTUP_9260;
>>> +
>>> +    /* keep only major version number */
>>> +    switch (version & 0xf00) {
>>> +    case 0x500:    /* SAMA5D3 */
>>> +    case 0x400:    /* AT91SAM9X5/9N12 */
>>> +        st->caps.has_tsmr = 1;
>>> +        st->caps.mr_startup_mask = AT91_ADC_STARTUP;
>>
>> Here is where AT91_ADC_STARTUP may need another name: what about AT91_ADC_STARTUP_9x5 to match the "compatibility" of
>> this value?
> 
> ok.
> 
>>
>>
>>> +    case 0x200:    /* AT91SAM9M10/9G45 */
>>> +        st->caps.mr_prescal_mask = AT91_ADC_PRESCAL;
>>> +
>>> +        if ((version & 0xf00) == 0x200)
>>
>> Sorry but I do not understand this test in a switch/case entry where it should always be true...
> 
> Since the switch case is fall through, that means the higher IP (at91sam9x5, sama5) will also running this check, but
> this line only for 9G45 chip.
> 
> a little bit hard to read  :)

Indeed. Write the case statements out long hand without the full throughs.
It'll take a couple more lines but be much easer to read.
> 
>>
>>
>>> +            st->caps.mr_startup_mask = AT91_ADC_STARTUP_9G45;
>>> +    case 0x100:    /* AT91SAM9260/9G20 */
>>> +        break;
>>> +    default:
>>> +        dev_warn(&idev->dev,
>>> +                "Unmanaged adc version, use minimal capabilities\n");
>>> +        break;
>>> +    };
>>> +}
>>> +
>>>   static int at91_adc_probe(struct platform_device *pdev)
>>>   {
>>>       unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
>>> @@ -645,6 +687,8 @@ static int at91_adc_probe(struct platform_device *pdev)
>>>           goto error_free_device;
>>>       }
>>>
>>> +    atmel_adc_get_cap(st);
>>> +
>>>       st->clk = devm_clk_get(&pdev->dev, "adc_clk");
>>>       if (IS_ERR(st->clk)) {
>>>           dev_err(&pdev->dev, "Failed to get the clock.\n");
>>> @@ -704,8 +748,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->caps.mr_prescal_mask;
>>> +    reg |= AT91_ADC_STARTUP_(ticks) & st->caps.mr_startup_mask;
>>>       if (st->low_res)
>>>           reg |= AT91_ADC_LOWRES;
>>>       if (st->sleep_mode)
>>>
>>
>>
> 
> Thanks again.
> Best Regards,
> Josh Wu
> -- 
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 3/5] iio: at91: ADC start-up time calculation changed since at91sam9x5
  2013-07-14  8:04   ` Josh Wu
@ 2013-07-20  9:39     ` Jonathan Cameron
  -1 siblings, 0 replies; 85+ messages in thread
From: Jonathan Cameron @ 2013-07-20  9:39 UTC (permalink / raw)
  To: Josh Wu
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj, nicolas.ferre

On 07/14/2013 09:04 AM, Josh Wu wrote:
> Since in at91sam9x5, sama5d3x chip. the start up time calucation is changed.
> And these two chips also have TSMR, so we check whether ADC has TSMR, then
> choose different start up time calculation formula.
If this doesn't have anything directly to do with the TSMR and this is just
coincidence, then do this separately with it's own flag as it will be
easier to maintain in the long run.

Jonathan
> 
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> ---
>  drivers/iio/adc/at91_adc.c |   40 +++++++++++++++++++++++++++++++++-------
>  1 file changed, 33 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index 14e99ba..e93a075 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -733,13 +733,39 @@ static int at91_adc_probe(struct platform_device *pdev)
>  		goto error_disable_adc_clk;
>  	}
>  
> -	/*
> -	 * 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;
> +	if (!st->caps.has_tsmr) {
> +		/*
> +		 * 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;
> +	} else {
> +		/*
> +		 * 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);
> +		ticks = st->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;
> +	}
> +
>  	/*
>  	 * a minimal Sample and Hold Time is necessary for the ADC to guarantee
>  	 * the best converted final value between two channels selection
> 

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

* [PATCH 3/5] iio: at91: ADC start-up time calculation changed since at91sam9x5
@ 2013-07-20  9:39     ` Jonathan Cameron
  0 siblings, 0 replies; 85+ messages in thread
From: Jonathan Cameron @ 2013-07-20  9:39 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/14/2013 09:04 AM, Josh Wu wrote:
> Since in at91sam9x5, sama5d3x chip. the start up time calucation is changed.
> And these two chips also have TSMR, so we check whether ADC has TSMR, then
> choose different start up time calculation formula.
If this doesn't have anything directly to do with the TSMR and this is just
coincidence, then do this separately with it's own flag as it will be
easier to maintain in the long run.

Jonathan
> 
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> ---
>  drivers/iio/adc/at91_adc.c |   40 +++++++++++++++++++++++++++++++++-------
>  1 file changed, 33 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index 14e99ba..e93a075 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -733,13 +733,39 @@ static int at91_adc_probe(struct platform_device *pdev)
>  		goto error_disable_adc_clk;
>  	}
>  
> -	/*
> -	 * 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;
> +	if (!st->caps.has_tsmr) {
> +		/*
> +		 * 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;
> +	} else {
> +		/*
> +		 * 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);
> +		ticks = st->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;
> +	}
> +
>  	/*
>  	 * a minimal Sample and Hold Time is necessary for the ADC to guarantee
>  	 * the best converted final value between two channels selection
> 

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

* Re: [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
  2013-07-14  8:04   ` Josh Wu
  (?)
@ 2013-07-20  9:57       ` Jonathan Cameron
  -1 siblings, 0 replies; 85+ messages in thread
From: Jonathan Cameron @ 2013-07-20  9:57 UTC (permalink / raw)
  To: Josh Wu
  Cc: jic23-KWPb1pKIrIJaa/9Udqfwiw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	plagnioj-sclMFOaUSTBWk0Htik3J/w,
	nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w, Dmitry Torokhov,
	linux-input-u79uwXL29TY76Z2rM5mHXA

On 07/14/2013 09:04 AM, 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:
>   which type of touch are used? (4 or 5 wires), sample period time,
>   pen detect debounce time, average samples and pen detect resistor.
>
> 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.

Firstly, this is adding input subsystem stuff inside an iio driver.  Generally we
are very anti this sort of combination, but I agree that right now the support for
doing it any other way is not really present.

The next bit of text is actually largely irrelevant here as I actually read the driver after
I wrote it and discovered the hardware handles all the nastiness of touch screen processing here.
I'll leave it here for reference of anyone working on parts where it is relevant ;)

     When I had more time to work on IIO I was working on an iio to input
     bridge driver (similar to iio-hwmon, but using the buffered interface hooks instead).
     It was fundamentally working, but I never quite got around to cleaning it up for submission.
     I'd appreciate any comments on what is missing or does not work for this case.

     http://marc.info/?l=linux-iio&m=135167944813803&w=2

     Ulitimately what I would love to see is a generic touch screen consumer driver for IIO
     adc's but appreciate that is a big and complex job given all the different varieties of
     touch screen and trying to abstract the control of the various channels.

So back to this part.  My immediate thought is that this really ought to have an mfd
underneath separate IIO and input drivers.

Dmitry, what do you think?

>
> Signed-off-by: Josh Wu <josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
> Cc: Dmitry Torokhov <dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
>  .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
>  arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>  drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
>  3 files changed, 412 insertions(+), 24 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> index 0db2945..925d656 100644
> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> @@ -29,6 +29,19 @@ Optional properties:
>    - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
>    - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
>  			  adc_op_clk.
> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
> +				 4 and 5 wires touch screen.
> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> +          disabled. Since touch screen will occupied the trigger register.
> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
> +				  detect.
> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
> +				     touch screen
> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
> +    0 means no average. 1 means average two samples. 2 means average four
> +    samples. 3 means average eight samples.
> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
> +    It can be 0, 1, 2, 3.
>
>  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 ab273ee..6d6cc14 100644
> --- a/arch/arm/mach-at91/include/mach/at91_adc.h
> +++ b/arch/arm/mach-at91/include/mach/at91_adc.h
> @@ -57,10 +57,44 @@
>  #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_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_VERSION	0xFC
>
> +/* 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 8f1386f..ffc0e42 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,12 +40,24 @@
>  #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 ZTHRESHOLD		9000
> +
>  struct at91_adc_caps {
> +	bool	has_12bits_xy;	/* true means use 12 bits. Otherwise 10 bits */
>  	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
>  	u32	mr_prescal_mask;
>  	u32	mr_startup_mask;
>  };
>
> +enum atmel_adc_ts_type {
> +	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
> +	ATMEL_ADC_TOUCHSCREEN_4WIRE,
> +	ATMEL_ADC_TOUCHSCREEN_5WIRE,
> +};
> +
>  struct at91_adc_state {
>  	struct clk		*adc_clk;
>  	u32			adc_clk_rate;
> @@ -70,6 +83,29 @@ 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;
> +
> +	u8			ts_filter_average;
> +	u16			ts_pen_detect_debounce;
> +	u8			ts_pen_detect_sensitivity;
> +	u16			ts_sample_period_time;
> +	u16			ts_sample_period_val;
>  };
>
>  static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
> @@ -104,14 +140,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);
> @@ -121,6 +153,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->caps.has_12bits_xy ? 12 : 10;
> +	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)
> +		x /= xscale;
> +	else
> +		dev_err(&idev->dev, "xscale == 0!!!\n");
> +
> +	/* 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)
> +		y /= yscale;
> +	else
> +		dev_err(&idev->dev, "yscale == 0!!!\n");
> +
> +	/* 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 = ZTHRESHOLD;	/* 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 < ZTHRESHOLD) {
> +		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;
>  }
> @@ -130,6 +271,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;
> @@ -561,6 +712,57 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>  		i++;
>  	}
>
> +	/* Check if touchscreen is enabled in DT. */
> +	ret = of_property_read_u32(node, "atmel,adc-touchscreen-wires", &prop);
> +	if (ret)
> +		dev_info(&idev->dev, "Touchscreen not enabled.\n");
> +	else if (prop == 4)
> +		st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_4WIRE;
> +	else if (prop == 5)
> +		st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_5WIRE;
> +	else
> +		dev_warn(&idev->dev, "Unsupported number of touchscreen wires (%d)\n",
> +				prop);
> +
> +	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_NONE)
> +		return 0;
> +
> +	/* Touch screen is enabled, so check touch screen dt parameters */
> +	if (of_property_read_u32(node, "atmel,adc-ts-filter-average", &prop)) {
> +		dev_err(&idev->dev, "Missing atmel,adc-ts-filtering-average property in the DT.\n");
> +		ret = -EINVAL;
> +		goto error_ret;
> +	}
> +	st->ts_filter_average = prop;
> +	if (st->ts_filter_average > 3) {
> +		dev_err(&idev->dev, "Invalid atmel,adc-ts-filtering-average property in the DT.\n");
> +		ret = -EINVAL;
> +		goto error_ret;
> +	}
> +
> +	prop = 0;
> +	of_property_read_u32(node, "atmel,adc-ts-pendet-debounce", &prop);
> +	st->ts_pen_detect_debounce = prop;
> +
> +	/* default sample period is 2ms. The real touch sample period should be
> +	 * this period * TSFREQ.
> +	 */
> +	prop = 2000;
> +	of_property_read_u32(node, "atmel,adc-ts-sample-period-time", &prop);
> +	st->ts_sample_period_time = prop;
> +
> +	if (of_property_read_u32(node, "atmel,adc-ts-pendet-sensitivity", &prop)) {
> +		dev_err(&idev->dev, "Missing atmel,adc-ts-pendet-sensitivity property in the DT.\n");
> +		ret = -EINVAL;
> +		goto error_ret;
> +	}
> +	st->ts_pen_detect_sensitivity = prop;
> +	if (st->ts_pen_detect_sensitivity > 3) {
> +		dev_err(&idev->dev, "Invalid atmel,adc-ts-pendet-sensitivity property in the DT.\n");
> +		ret = -EINVAL;
> +		goto error_ret;
> +	}
> +
>  	return 0;
>
>  error_ret:
> @@ -592,6 +794,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(st->ts_pen_detect_debounce * 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->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->ts_pen_detect_sensitivity
> +			& AT91_ADC_ACR_PENDETSENS);
> +
> +	/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
> +	st->ts_sample_period_val = round_up((st->ts_sample_period_time *
> +			adc_clk_khz / 1000) - 1, 1);
> +
> +	return 0;
> +}
> +
> +static int at91_ts_register(struct at91_adc_state *st)
> +{
> +	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 = idev->dev.parent;
> +	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);
> +	input_free_device(st->ts_input);
> +}
> +
>  /*
>   * Since atmel adc support different ip for touchscreen mode. Through the
>   * IP check, we will know the touchscreen capbilities.
> @@ -610,6 +920,7 @@ static void atmel_adc_get_cap(struct at91_adc_state *st)
>  	/* keep only major version number */
>  	switch (version & 0xf00) {
>  	case 0x500:	/* SAMA5D3 */
> +		st->caps.has_12bits_xy = 1;
>  	case 0x400:	/* AT91SAM9X5/9N12 */
>  		st->caps.has_tsmr = 1;
>  		st->caps.mr_startup_mask = AT91_ADC_STARTUP;
> @@ -683,7 +994,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);
> @@ -731,6 +1042,10 @@ static int at91_adc_probe(struct platform_device *pdev)
>  	adc_clk = st->adc_clk_rate ?
>  		st->adc_clk_rate : 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) {
> @@ -799,30 +1114,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);
> +		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:
> @@ -841,8 +1178,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);
> @@ -861,7 +1202,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] 85+ messages in thread

* Re: [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
@ 2013-07-20  9:57       ` Jonathan Cameron
  0 siblings, 0 replies; 85+ messages in thread
From: Jonathan Cameron @ 2013-07-20  9:57 UTC (permalink / raw)
  To: Josh Wu
  Cc: jic23, linux-arm-kernel, linux-iio, maxime.ripard, plagnioj,
	nicolas.ferre, Dmitry Torokhov, linux-input

On 07/14/2013 09:04 AM, 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:
>   which type of touch are used? (4 or 5 wires), sample period time,
>   pen detect debounce time, average samples and pen detect resistor.
>
> 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.

Firstly, this is adding input subsystem stuff inside an iio driver.  Generally we
are very anti this sort of combination, but I agree that right now the support for
doing it any other way is not really present.

The next bit of text is actually largely irrelevant here as I actually read the driver after
I wrote it and discovered the hardware handles all the nastiness of touch screen processing here.
I'll leave it here for reference of anyone working on parts where it is relevant ;)

     When I had more time to work on IIO I was working on an iio to input
     bridge driver (similar to iio-hwmon, but using the buffered interface hooks instead).
     It was fundamentally working, but I never quite got around to cleaning it up for submission.
     I'd appreciate any comments on what is missing or does not work for this case.

     http://marc.info/?l=linux-iio&m=135167944813803&w=2

     Ulitimately what I would love to see is a generic touch screen consumer driver for IIO
     adc's but appreciate that is a big and complex job given all the different varieties of
     touch screen and trying to abstract the control of the various channels.

So back to this part.  My immediate thought is that this really ought to have an mfd
underneath separate IIO and input drivers.

Dmitry, what do you think?

>
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> ---
>  .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
>  arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>  drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
>  3 files changed, 412 insertions(+), 24 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> index 0db2945..925d656 100644
> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> @@ -29,6 +29,19 @@ Optional properties:
>    - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
>    - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
>  			  adc_op_clk.
> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
> +				 4 and 5 wires touch screen.
> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> +          disabled. Since touch screen will occupied the trigger register.
> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
> +				  detect.
> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
> +				     touch screen
> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
> +    0 means no average. 1 means average two samples. 2 means average four
> +    samples. 3 means average eight samples.
> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
> +    It can be 0, 1, 2, 3.
>
>  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 ab273ee..6d6cc14 100644
> --- a/arch/arm/mach-at91/include/mach/at91_adc.h
> +++ b/arch/arm/mach-at91/include/mach/at91_adc.h
> @@ -57,10 +57,44 @@
>  #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_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_VERSION	0xFC
>
> +/* 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 8f1386f..ffc0e42 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,12 +40,24 @@
>  #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 ZTHRESHOLD		9000
> +
>  struct at91_adc_caps {
> +	bool	has_12bits_xy;	/* true means use 12 bits. Otherwise 10 bits */
>  	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
>  	u32	mr_prescal_mask;
>  	u32	mr_startup_mask;
>  };
>
> +enum atmel_adc_ts_type {
> +	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
> +	ATMEL_ADC_TOUCHSCREEN_4WIRE,
> +	ATMEL_ADC_TOUCHSCREEN_5WIRE,
> +};
> +
>  struct at91_adc_state {
>  	struct clk		*adc_clk;
>  	u32			adc_clk_rate;
> @@ -70,6 +83,29 @@ 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;
> +
> +	u8			ts_filter_average;
> +	u16			ts_pen_detect_debounce;
> +	u8			ts_pen_detect_sensitivity;
> +	u16			ts_sample_period_time;
> +	u16			ts_sample_period_val;
>  };
>
>  static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
> @@ -104,14 +140,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);
> @@ -121,6 +153,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->caps.has_12bits_xy ? 12 : 10;
> +	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)
> +		x /= xscale;
> +	else
> +		dev_err(&idev->dev, "xscale == 0!!!\n");
> +
> +	/* 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)
> +		y /= yscale;
> +	else
> +		dev_err(&idev->dev, "yscale == 0!!!\n");
> +
> +	/* 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 = ZTHRESHOLD;	/* 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 < ZTHRESHOLD) {
> +		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;
>  }
> @@ -130,6 +271,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;
> @@ -561,6 +712,57 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>  		i++;
>  	}
>
> +	/* Check if touchscreen is enabled in DT. */
> +	ret = of_property_read_u32(node, "atmel,adc-touchscreen-wires", &prop);
> +	if (ret)
> +		dev_info(&idev->dev, "Touchscreen not enabled.\n");
> +	else if (prop == 4)
> +		st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_4WIRE;
> +	else if (prop == 5)
> +		st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_5WIRE;
> +	else
> +		dev_warn(&idev->dev, "Unsupported number of touchscreen wires (%d)\n",
> +				prop);
> +
> +	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_NONE)
> +		return 0;
> +
> +	/* Touch screen is enabled, so check touch screen dt parameters */
> +	if (of_property_read_u32(node, "atmel,adc-ts-filter-average", &prop)) {
> +		dev_err(&idev->dev, "Missing atmel,adc-ts-filtering-average property in the DT.\n");
> +		ret = -EINVAL;
> +		goto error_ret;
> +	}
> +	st->ts_filter_average = prop;
> +	if (st->ts_filter_average > 3) {
> +		dev_err(&idev->dev, "Invalid atmel,adc-ts-filtering-average property in the DT.\n");
> +		ret = -EINVAL;
> +		goto error_ret;
> +	}
> +
> +	prop = 0;
> +	of_property_read_u32(node, "atmel,adc-ts-pendet-debounce", &prop);
> +	st->ts_pen_detect_debounce = prop;
> +
> +	/* default sample period is 2ms. The real touch sample period should be
> +	 * this period * TSFREQ.
> +	 */
> +	prop = 2000;
> +	of_property_read_u32(node, "atmel,adc-ts-sample-period-time", &prop);
> +	st->ts_sample_period_time = prop;
> +
> +	if (of_property_read_u32(node, "atmel,adc-ts-pendet-sensitivity", &prop)) {
> +		dev_err(&idev->dev, "Missing atmel,adc-ts-pendet-sensitivity property in the DT.\n");
> +		ret = -EINVAL;
> +		goto error_ret;
> +	}
> +	st->ts_pen_detect_sensitivity = prop;
> +	if (st->ts_pen_detect_sensitivity > 3) {
> +		dev_err(&idev->dev, "Invalid atmel,adc-ts-pendet-sensitivity property in the DT.\n");
> +		ret = -EINVAL;
> +		goto error_ret;
> +	}
> +
>  	return 0;
>
>  error_ret:
> @@ -592,6 +794,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(st->ts_pen_detect_debounce * 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->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->ts_pen_detect_sensitivity
> +			& AT91_ADC_ACR_PENDETSENS);
> +
> +	/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
> +	st->ts_sample_period_val = round_up((st->ts_sample_period_time *
> +			adc_clk_khz / 1000) - 1, 1);
> +
> +	return 0;
> +}
> +
> +static int at91_ts_register(struct at91_adc_state *st)
> +{
> +	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 = idev->dev.parent;
> +	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);
> +	input_free_device(st->ts_input);
> +}
> +
>  /*
>   * Since atmel adc support different ip for touchscreen mode. Through the
>   * IP check, we will know the touchscreen capbilities.
> @@ -610,6 +920,7 @@ static void atmel_adc_get_cap(struct at91_adc_state *st)
>  	/* keep only major version number */
>  	switch (version & 0xf00) {
>  	case 0x500:	/* SAMA5D3 */
> +		st->caps.has_12bits_xy = 1;
>  	case 0x400:	/* AT91SAM9X5/9N12 */
>  		st->caps.has_tsmr = 1;
>  		st->caps.mr_startup_mask = AT91_ADC_STARTUP;
> @@ -683,7 +994,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);
> @@ -731,6 +1042,10 @@ static int at91_adc_probe(struct platform_device *pdev)
>  	adc_clk = st->adc_clk_rate ?
>  		st->adc_clk_rate : 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) {
> @@ -799,30 +1114,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);
> +		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:
> @@ -841,8 +1178,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);
> @@ -861,7 +1202,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] 85+ messages in thread

* [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
@ 2013-07-20  9:57       ` Jonathan Cameron
  0 siblings, 0 replies; 85+ messages in thread
From: Jonathan Cameron @ 2013-07-20  9:57 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/14/2013 09:04 AM, 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:
>   which type of touch are used? (4 or 5 wires), sample period time,
>   pen detect debounce time, average samples and pen detect resistor.
>
> 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.

Firstly, this is adding input subsystem stuff inside an iio driver.  Generally we
are very anti this sort of combination, but I agree that right now the support for
doing it any other way is not really present.

The next bit of text is actually largely irrelevant here as I actually read the driver after
I wrote it and discovered the hardware handles all the nastiness of touch screen processing here.
I'll leave it here for reference of anyone working on parts where it is relevant ;)

     When I had more time to work on IIO I was working on an iio to input
     bridge driver (similar to iio-hwmon, but using the buffered interface hooks instead).
     It was fundamentally working, but I never quite got around to cleaning it up for submission.
     I'd appreciate any comments on what is missing or does not work for this case.

     http://marc.info/?l=linux-iio&m=135167944813803&w=2

     Ulitimately what I would love to see is a generic touch screen consumer driver for IIO
     adc's but appreciate that is a big and complex job given all the different varieties of
     touch screen and trying to abstract the control of the various channels.

So back to this part.  My immediate thought is that this really ought to have an mfd
underneath separate IIO and input drivers.

Dmitry, what do you think?

>
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> ---
>  .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
>  arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>  drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
>  3 files changed, 412 insertions(+), 24 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> index 0db2945..925d656 100644
> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> @@ -29,6 +29,19 @@ Optional properties:
>    - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
>    - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
>  			  adc_op_clk.
> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
> +				 4 and 5 wires touch screen.
> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> +          disabled. Since touch screen will occupied the trigger register.
> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
> +				  detect.
> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
> +				     touch screen
> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
> +    0 means no average. 1 means average two samples. 2 means average four
> +    samples. 3 means average eight samples.
> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
> +    It can be 0, 1, 2, 3.
>
>  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 ab273ee..6d6cc14 100644
> --- a/arch/arm/mach-at91/include/mach/at91_adc.h
> +++ b/arch/arm/mach-at91/include/mach/at91_adc.h
> @@ -57,10 +57,44 @@
>  #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_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_VERSION	0xFC
>
> +/* 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 8f1386f..ffc0e42 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,12 +40,24 @@
>  #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 ZTHRESHOLD		9000
> +
>  struct at91_adc_caps {
> +	bool	has_12bits_xy;	/* true means use 12 bits. Otherwise 10 bits */
>  	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
>  	u32	mr_prescal_mask;
>  	u32	mr_startup_mask;
>  };
>
> +enum atmel_adc_ts_type {
> +	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
> +	ATMEL_ADC_TOUCHSCREEN_4WIRE,
> +	ATMEL_ADC_TOUCHSCREEN_5WIRE,
> +};
> +
>  struct at91_adc_state {
>  	struct clk		*adc_clk;
>  	u32			adc_clk_rate;
> @@ -70,6 +83,29 @@ 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;
> +
> +	u8			ts_filter_average;
> +	u16			ts_pen_detect_debounce;
> +	u8			ts_pen_detect_sensitivity;
> +	u16			ts_sample_period_time;
> +	u16			ts_sample_period_val;
>  };
>
>  static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
> @@ -104,14 +140,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);
> @@ -121,6 +153,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->caps.has_12bits_xy ? 12 : 10;
> +	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)
> +		x /= xscale;
> +	else
> +		dev_err(&idev->dev, "xscale == 0!!!\n");
> +
> +	/* 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)
> +		y /= yscale;
> +	else
> +		dev_err(&idev->dev, "yscale == 0!!!\n");
> +
> +	/* 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 = ZTHRESHOLD;	/* 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 < ZTHRESHOLD) {
> +		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;
>  }
> @@ -130,6 +271,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;
> @@ -561,6 +712,57 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>  		i++;
>  	}
>
> +	/* Check if touchscreen is enabled in DT. */
> +	ret = of_property_read_u32(node, "atmel,adc-touchscreen-wires", &prop);
> +	if (ret)
> +		dev_info(&idev->dev, "Touchscreen not enabled.\n");
> +	else if (prop == 4)
> +		st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_4WIRE;
> +	else if (prop == 5)
> +		st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_5WIRE;
> +	else
> +		dev_warn(&idev->dev, "Unsupported number of touchscreen wires (%d)\n",
> +				prop);
> +
> +	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_NONE)
> +		return 0;
> +
> +	/* Touch screen is enabled, so check touch screen dt parameters */
> +	if (of_property_read_u32(node, "atmel,adc-ts-filter-average", &prop)) {
> +		dev_err(&idev->dev, "Missing atmel,adc-ts-filtering-average property in the DT.\n");
> +		ret = -EINVAL;
> +		goto error_ret;
> +	}
> +	st->ts_filter_average = prop;
> +	if (st->ts_filter_average > 3) {
> +		dev_err(&idev->dev, "Invalid atmel,adc-ts-filtering-average property in the DT.\n");
> +		ret = -EINVAL;
> +		goto error_ret;
> +	}
> +
> +	prop = 0;
> +	of_property_read_u32(node, "atmel,adc-ts-pendet-debounce", &prop);
> +	st->ts_pen_detect_debounce = prop;
> +
> +	/* default sample period is 2ms. The real touch sample period should be
> +	 * this period * TSFREQ.
> +	 */
> +	prop = 2000;
> +	of_property_read_u32(node, "atmel,adc-ts-sample-period-time", &prop);
> +	st->ts_sample_period_time = prop;
> +
> +	if (of_property_read_u32(node, "atmel,adc-ts-pendet-sensitivity", &prop)) {
> +		dev_err(&idev->dev, "Missing atmel,adc-ts-pendet-sensitivity property in the DT.\n");
> +		ret = -EINVAL;
> +		goto error_ret;
> +	}
> +	st->ts_pen_detect_sensitivity = prop;
> +	if (st->ts_pen_detect_sensitivity > 3) {
> +		dev_err(&idev->dev, "Invalid atmel,adc-ts-pendet-sensitivity property in the DT.\n");
> +		ret = -EINVAL;
> +		goto error_ret;
> +	}
> +
>  	return 0;
>
>  error_ret:
> @@ -592,6 +794,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(st->ts_pen_detect_debounce * 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->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->ts_pen_detect_sensitivity
> +			& AT91_ADC_ACR_PENDETSENS);
> +
> +	/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
> +	st->ts_sample_period_val = round_up((st->ts_sample_period_time *
> +			adc_clk_khz / 1000) - 1, 1);
> +
> +	return 0;
> +}
> +
> +static int at91_ts_register(struct at91_adc_state *st)
> +{
> +	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 = idev->dev.parent;
> +	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);
> +	input_free_device(st->ts_input);
> +}
> +
>  /*
>   * Since atmel adc support different ip for touchscreen mode. Through the
>   * IP check, we will know the touchscreen capbilities.
> @@ -610,6 +920,7 @@ static void atmel_adc_get_cap(struct at91_adc_state *st)
>  	/* keep only major version number */
>  	switch (version & 0xf00) {
>  	case 0x500:	/* SAMA5D3 */
> +		st->caps.has_12bits_xy = 1;
>  	case 0x400:	/* AT91SAM9X5/9N12 */
>  		st->caps.has_tsmr = 1;
>  		st->caps.mr_startup_mask = AT91_ADC_STARTUP;
> @@ -683,7 +994,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);
> @@ -731,6 +1042,10 @@ static int at91_adc_probe(struct platform_device *pdev)
>  	adc_clk = st->adc_clk_rate ?
>  		st->adc_clk_rate : 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) {
> @@ -799,30 +1114,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);
> +		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:
> @@ -841,8 +1178,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);
> @@ -861,7 +1202,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] 85+ messages in thread

* Re: [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
  2013-07-14  8:04   ` Josh Wu
@ 2013-07-22 13:17     ` Mark Rutland
  -1 siblings, 0 replies; 85+ messages in thread
From: Mark Rutland @ 2013-07-22 13:17 UTC (permalink / raw)
  To: Josh Wu
  Cc: jic23, linux-iio, Dmitry Torokhov, nicolas.ferre, maxime.ripard,
	plagnioj, linux-arm-kernel

On Sun, Jul 14, 2013 at 09:04:29AM +0100, 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:
>   which type of touch are used? (4 or 5 wires), sample period time,
>   pen detect debounce time, average samples and pen detect resistor.
> 
> 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>
> ---
>  .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
>  arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>  drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
>  3 files changed, 412 insertions(+), 24 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> index 0db2945..925d656 100644
> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> @@ -29,6 +29,19 @@ Optional properties:
>    - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
>    - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
>                           adc_op_clk.
> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
> +                                4 and 5 wires touch screen.

Are 4 and 5 wire configurations that can exist, or the only ones
supported by the driver?

> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> +          disabled. Since touch screen will occupied the trigger register.
> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
> +                                 detect.

For consistency with the adc-touchscreen-wires property, and  other
properties with timing information, how about
atmel,adc-touchscreen-debounce-delay-us ?

> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
> +                                    touch screen

Again, please be consistent with ts or touchscreen. It may also be good
to have -us to make the units explicit (though it does leave the
property name being quite a mothful):

atmel,adc-touchscreen-sample-period-us ?

> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
> +    0 means no average. 1 means average two samples. 2 means average four
> +    samples. 3 means average eight samples.

Is this averaging done in the hardware, or the kernel driver?

If it's the latter, this can be left for the kernel to decide.

> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
> +    It can be 0, 1, 2, 3.

I think "pendet" is a bit opaque. "pen-detect" may be better. What
physical property does this represent (are these discrete values, or an
enumeration)?

Thanks,
Mark.

> 
>  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 ab273ee..6d6cc14 100644
> --- a/arch/arm/mach-at91/include/mach/at91_adc.h
> +++ b/arch/arm/mach-at91/include/mach/at91_adc.h
> @@ -57,10 +57,44 @@
>  #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_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_VERSION       0xFC
> 
> +/* 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 8f1386f..ffc0e42 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,12 +40,24 @@
>  #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 ZTHRESHOLD             9000
> +
>  struct at91_adc_caps {
> +       bool    has_12bits_xy;  /* true means use 12 bits. Otherwise 10 bits */
>         bool    has_tsmr;       /* only at91sam9x5, sama5d3 have TSMR reg */
>         u32     mr_prescal_mask;
>         u32     mr_startup_mask;
>  };
> 
> +enum atmel_adc_ts_type {
> +       ATMEL_ADC_TOUCHSCREEN_NONE = 0,
> +       ATMEL_ADC_TOUCHSCREEN_4WIRE,
> +       ATMEL_ADC_TOUCHSCREEN_5WIRE,
> +};
> +
>  struct at91_adc_state {
>         struct clk              *adc_clk;
>         u32                     adc_clk_rate;
> @@ -70,6 +83,29 @@ 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;
> +
> +       u8                      ts_filter_average;
> +       u16                     ts_pen_detect_debounce;
> +       u8                      ts_pen_detect_sensitivity;
> +       u16                     ts_sample_period_time;
> +       u16                     ts_sample_period_val;
>  };
> 
>  static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
> @@ -104,14 +140,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);
> @@ -121,6 +153,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->caps.has_12bits_xy ? 12 : 10;
> +       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)
> +               x /= xscale;
> +       else
> +               dev_err(&idev->dev, "xscale == 0!!!\n");
> +
> +       /* 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)
> +               y /= yscale;
> +       else
> +               dev_err(&idev->dev, "yscale == 0!!!\n");
> +
> +       /* 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 = ZTHRESHOLD;      /* 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 < ZTHRESHOLD) {
> +               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;
>  }
> @@ -130,6 +271,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;
> @@ -561,6 +712,57 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>                 i++;
>         }
> 
> +       /* Check if touchscreen is enabled in DT. */
> +       ret = of_property_read_u32(node, "atmel,adc-touchscreen-wires", &prop);
> +       if (ret)
> +               dev_info(&idev->dev, "Touchscreen not enabled.\n");
> +       else if (prop == 4)
> +               st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_4WIRE;
> +       else if (prop == 5)
> +               st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_5WIRE;
> +       else
> +               dev_warn(&idev->dev, "Unsupported number of touchscreen wires (%d)\n",
> +                               prop);
> +
> +       if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_NONE)
> +               return 0;
> +
> +       /* Touch screen is enabled, so check touch screen dt parameters */
> +       if (of_property_read_u32(node, "atmel,adc-ts-filter-average", &prop)) {
> +               dev_err(&idev->dev, "Missing atmel,adc-ts-filtering-average property in the DT.\n");
> +               ret = -EINVAL;
> +               goto error_ret;
> +       }
> +       st->ts_filter_average = prop;
> +       if (st->ts_filter_average > 3) {
> +               dev_err(&idev->dev, "Invalid atmel,adc-ts-filtering-average property in the DT.\n");
> +               ret = -EINVAL;
> +               goto error_ret;
> +       }
> +
> +       prop = 0;
> +       of_property_read_u32(node, "atmel,adc-ts-pendet-debounce", &prop);
> +       st->ts_pen_detect_debounce = prop;
> +
> +       /* default sample period is 2ms. The real touch sample period should be
> +        * this period * TSFREQ.
> +        */
> +       prop = 2000;
> +       of_property_read_u32(node, "atmel,adc-ts-sample-period-time", &prop);
> +       st->ts_sample_period_time = prop;
> +
> +       if (of_property_read_u32(node, "atmel,adc-ts-pendet-sensitivity", &prop)) {
> +               dev_err(&idev->dev, "Missing atmel,adc-ts-pendet-sensitivity property in the DT.\n");
> +               ret = -EINVAL;
> +               goto error_ret;
> +       }
> +       st->ts_pen_detect_sensitivity = prop;
> +       if (st->ts_pen_detect_sensitivity > 3) {
> +               dev_err(&idev->dev, "Invalid atmel,adc-ts-pendet-sensitivity property in the DT.\n");
> +               ret = -EINVAL;
> +               goto error_ret;
> +       }
> +
>         return 0;
> 
>  error_ret:
> @@ -592,6 +794,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(st->ts_pen_detect_debounce * 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->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->ts_pen_detect_sensitivity
> +                       & AT91_ADC_ACR_PENDETSENS);
> +
> +       /* Sample Peroid Time = (TRGPER + 1) / ADCClock */
> +       st->ts_sample_period_val = round_up((st->ts_sample_period_time *
> +                       adc_clk_khz / 1000) - 1, 1);
> +
> +       return 0;
> +}
> +
> +static int at91_ts_register(struct at91_adc_state *st)
> +{
> +       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 = idev->dev.parent;
> +       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);
> +       input_free_device(st->ts_input);
> +}
> +
>  /*
>   * Since atmel adc support different ip for touchscreen mode. Through the
>   * IP check, we will know the touchscreen capbilities.
> @@ -610,6 +920,7 @@ static void atmel_adc_get_cap(struct at91_adc_state *st)
>         /* keep only major version number */
>         switch (version & 0xf00) {
>         case 0x500:     /* SAMA5D3 */
> +               st->caps.has_12bits_xy = 1;
>         case 0x400:     /* AT91SAM9X5/9N12 */
>                 st->caps.has_tsmr = 1;
>                 st->caps.mr_startup_mask = AT91_ADC_STARTUP;
> @@ -683,7 +994,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);
> @@ -731,6 +1042,10 @@ static int at91_adc_probe(struct platform_device *pdev)
>         adc_clk = st->adc_clk_rate ?
>                 st->adc_clk_rate : 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) {
> @@ -799,30 +1114,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);
> +               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:
> @@ -841,8 +1178,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);
> @@ -861,7 +1202,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
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

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

* [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
@ 2013-07-22 13:17     ` Mark Rutland
  0 siblings, 0 replies; 85+ messages in thread
From: Mark Rutland @ 2013-07-22 13:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Jul 14, 2013 at 09:04:29AM +0100, 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:
>   which type of touch are used? (4 or 5 wires), sample period time,
>   pen detect debounce time, average samples and pen detect resistor.
> 
> 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>
> ---
>  .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
>  arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>  drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
>  3 files changed, 412 insertions(+), 24 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> index 0db2945..925d656 100644
> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> @@ -29,6 +29,19 @@ Optional properties:
>    - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
>    - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
>                           adc_op_clk.
> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
> +                                4 and 5 wires touch screen.

Are 4 and 5 wire configurations that can exist, or the only ones
supported by the driver?

> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> +          disabled. Since touch screen will occupied the trigger register.
> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
> +                                 detect.

For consistency with the adc-touchscreen-wires property, and  other
properties with timing information, how about
atmel,adc-touchscreen-debounce-delay-us ?

> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
> +                                    touch screen

Again, please be consistent with ts or touchscreen. It may also be good
to have -us to make the units explicit (though it does leave the
property name being quite a mothful):

atmel,adc-touchscreen-sample-period-us ?

> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
> +    0 means no average. 1 means average two samples. 2 means average four
> +    samples. 3 means average eight samples.

Is this averaging done in the hardware, or the kernel driver?

If it's the latter, this can be left for the kernel to decide.

> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
> +    It can be 0, 1, 2, 3.

I think "pendet" is a bit opaque. "pen-detect" may be better. What
physical property does this represent (are these discrete values, or an
enumeration)?

Thanks,
Mark.

> 
>  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 ab273ee..6d6cc14 100644
> --- a/arch/arm/mach-at91/include/mach/at91_adc.h
> +++ b/arch/arm/mach-at91/include/mach/at91_adc.h
> @@ -57,10 +57,44 @@
>  #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_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_VERSION       0xFC
> 
> +/* 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 8f1386f..ffc0e42 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,12 +40,24 @@
>  #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 ZTHRESHOLD             9000
> +
>  struct at91_adc_caps {
> +       bool    has_12bits_xy;  /* true means use 12 bits. Otherwise 10 bits */
>         bool    has_tsmr;       /* only at91sam9x5, sama5d3 have TSMR reg */
>         u32     mr_prescal_mask;
>         u32     mr_startup_mask;
>  };
> 
> +enum atmel_adc_ts_type {
> +       ATMEL_ADC_TOUCHSCREEN_NONE = 0,
> +       ATMEL_ADC_TOUCHSCREEN_4WIRE,
> +       ATMEL_ADC_TOUCHSCREEN_5WIRE,
> +};
> +
>  struct at91_adc_state {
>         struct clk              *adc_clk;
>         u32                     adc_clk_rate;
> @@ -70,6 +83,29 @@ 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;
> +
> +       u8                      ts_filter_average;
> +       u16                     ts_pen_detect_debounce;
> +       u8                      ts_pen_detect_sensitivity;
> +       u16                     ts_sample_period_time;
> +       u16                     ts_sample_period_val;
>  };
> 
>  static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
> @@ -104,14 +140,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);
> @@ -121,6 +153,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->caps.has_12bits_xy ? 12 : 10;
> +       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)
> +               x /= xscale;
> +       else
> +               dev_err(&idev->dev, "xscale == 0!!!\n");
> +
> +       /* 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)
> +               y /= yscale;
> +       else
> +               dev_err(&idev->dev, "yscale == 0!!!\n");
> +
> +       /* 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 = ZTHRESHOLD;      /* 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 < ZTHRESHOLD) {
> +               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;
>  }
> @@ -130,6 +271,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;
> @@ -561,6 +712,57 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>                 i++;
>         }
> 
> +       /* Check if touchscreen is enabled in DT. */
> +       ret = of_property_read_u32(node, "atmel,adc-touchscreen-wires", &prop);
> +       if (ret)
> +               dev_info(&idev->dev, "Touchscreen not enabled.\n");
> +       else if (prop == 4)
> +               st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_4WIRE;
> +       else if (prop == 5)
> +               st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_5WIRE;
> +       else
> +               dev_warn(&idev->dev, "Unsupported number of touchscreen wires (%d)\n",
> +                               prop);
> +
> +       if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_NONE)
> +               return 0;
> +
> +       /* Touch screen is enabled, so check touch screen dt parameters */
> +       if (of_property_read_u32(node, "atmel,adc-ts-filter-average", &prop)) {
> +               dev_err(&idev->dev, "Missing atmel,adc-ts-filtering-average property in the DT.\n");
> +               ret = -EINVAL;
> +               goto error_ret;
> +       }
> +       st->ts_filter_average = prop;
> +       if (st->ts_filter_average > 3) {
> +               dev_err(&idev->dev, "Invalid atmel,adc-ts-filtering-average property in the DT.\n");
> +               ret = -EINVAL;
> +               goto error_ret;
> +       }
> +
> +       prop = 0;
> +       of_property_read_u32(node, "atmel,adc-ts-pendet-debounce", &prop);
> +       st->ts_pen_detect_debounce = prop;
> +
> +       /* default sample period is 2ms. The real touch sample period should be
> +        * this period * TSFREQ.
> +        */
> +       prop = 2000;
> +       of_property_read_u32(node, "atmel,adc-ts-sample-period-time", &prop);
> +       st->ts_sample_period_time = prop;
> +
> +       if (of_property_read_u32(node, "atmel,adc-ts-pendet-sensitivity", &prop)) {
> +               dev_err(&idev->dev, "Missing atmel,adc-ts-pendet-sensitivity property in the DT.\n");
> +               ret = -EINVAL;
> +               goto error_ret;
> +       }
> +       st->ts_pen_detect_sensitivity = prop;
> +       if (st->ts_pen_detect_sensitivity > 3) {
> +               dev_err(&idev->dev, "Invalid atmel,adc-ts-pendet-sensitivity property in the DT.\n");
> +               ret = -EINVAL;
> +               goto error_ret;
> +       }
> +
>         return 0;
> 
>  error_ret:
> @@ -592,6 +794,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(st->ts_pen_detect_debounce * 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->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->ts_pen_detect_sensitivity
> +                       & AT91_ADC_ACR_PENDETSENS);
> +
> +       /* Sample Peroid Time = (TRGPER + 1) / ADCClock */
> +       st->ts_sample_period_val = round_up((st->ts_sample_period_time *
> +                       adc_clk_khz / 1000) - 1, 1);
> +
> +       return 0;
> +}
> +
> +static int at91_ts_register(struct at91_adc_state *st)
> +{
> +       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 = idev->dev.parent;
> +       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);
> +       input_free_device(st->ts_input);
> +}
> +
>  /*
>   * Since atmel adc support different ip for touchscreen mode. Through the
>   * IP check, we will know the touchscreen capbilities.
> @@ -610,6 +920,7 @@ static void atmel_adc_get_cap(struct at91_adc_state *st)
>         /* keep only major version number */
>         switch (version & 0xf00) {
>         case 0x500:     /* SAMA5D3 */
> +               st->caps.has_12bits_xy = 1;
>         case 0x400:     /* AT91SAM9X5/9N12 */
>                 st->caps.has_tsmr = 1;
>                 st->caps.mr_startup_mask = AT91_ADC_STARTUP;
> @@ -683,7 +994,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);
> @@ -731,6 +1042,10 @@ static int at91_adc_probe(struct platform_device *pdev)
>         adc_clk = st->adc_clk_rate ?
>                 st->adc_clk_rate : 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) {
> @@ -799,30 +1114,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);
> +               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:
> @@ -841,8 +1178,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);
> @@ -861,7 +1202,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
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

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

* Re: [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz.
  2013-07-16 11:16           ` Lars-Peter Clausen
@ 2013-07-25  7:29             ` Josh Wu
  -1 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-25  7:29 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Maxime Ripard, jic23, linux-arm-kernel, linux-iio, plagnioj,
	nicolas.ferre

On 7/16/2013 7:16 PM, Lars-Peter Clausen wrote:
> On 07/16/2013 12:30 PM, Maxime Ripard wrote:
> [...]
>>> After a further thinking of this, maybe remove the adc_op_clk is
>>> better since it is a fake clock, and only used to specify the clock
>>> rate.
>>> To specify the clock rate use a dt property or platform data
>>> parameter is better.
>> No, to specify *any* clock, the common clock framework is the better
>> solution.
> Yep, this patch is not the right approach. It's trying to work around the
> limitations of the platforms clock API implementation. Please fix the at91
> clock implementation instead (e.g. by switching to the common clock framework).

Thank you and Maxime for the clarify. I will drop this patch in next 
version.
Just FYI. The at91 clock common framework is in implementation by Boris 
Brezillion.

>
> - Lars
>

Best Regards,
Josh Wu

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

* [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz.
@ 2013-07-25  7:29             ` Josh Wu
  0 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-25  7:29 UTC (permalink / raw)
  To: linux-arm-kernel

On 7/16/2013 7:16 PM, Lars-Peter Clausen wrote:
> On 07/16/2013 12:30 PM, Maxime Ripard wrote:
> [...]
>>> After a further thinking of this, maybe remove the adc_op_clk is
>>> better since it is a fake clock, and only used to specify the clock
>>> rate.
>>> To specify the clock rate use a dt property or platform data
>>> parameter is better.
>> No, to specify *any* clock, the common clock framework is the better
>> solution.
> Yep, this patch is not the right approach. It's trying to work around the
> limitations of the platforms clock API implementation. Please fix the at91
> clock implementation instead (e.g. by switching to the common clock framework).

Thank you and Maxime for the clarify. I will drop this patch in next 
version.
Just FYI. The at91 clock common framework is in implementation by Boris 
Brezillion.

>
> - Lars
>

Best Regards,
Josh Wu

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

* Re: [PATCH 3/5] iio: at91: ADC start-up time calculation changed since at91sam9x5
  2013-07-20  9:39     ` Jonathan Cameron
@ 2013-07-25  7:35       ` Josh Wu
  -1 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-25  7:35 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: linux-arm-kernel, linux-iio, maxime.ripard, plagnioj, nicolas.ferre

On 7/20/2013 5:39 PM, Jonathan Cameron wrote:
> On 07/14/2013 09:04 AM, Josh Wu wrote:
>> Since in at91sam9x5, sama5d3x chip. the start up time calucation is changed.
>> And these two chips also have TSMR, so we check whether ADC has TSMR, then
>> choose different start up time calculation formula.
> If this doesn't have anything directly to do with the TSMR and this is just
> coincidence, then do this separately with it's own flag as it will be
> easier to maintain in the long run.

Agreed. I will fix it in next version.

Best Regards,
Josh Wu

>
> Jonathan
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>> ---
>>   drivers/iio/adc/at91_adc.c |   40 +++++++++++++++++++++++++++++++++-------
>>   1 file changed, 33 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>> index 14e99ba..e93a075 100644
>> --- a/drivers/iio/adc/at91_adc.c
>> +++ b/drivers/iio/adc/at91_adc.c
>> @@ -733,13 +733,39 @@ static int at91_adc_probe(struct platform_device *pdev)
>>   		goto error_disable_adc_clk;
>>   	}
>>   
>> -	/*
>> -	 * 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;
>> +	if (!st->caps.has_tsmr) {
>> +		/*
>> +		 * 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;
>> +	} else {
>> +		/*
>> +		 * 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);
>> +		ticks = st->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;
>> +	}
>> +
>>   	/*
>>   	 * a minimal Sample and Hold Time is necessary for the ADC to guarantee
>>   	 * the best converted final value between two channels selection
>>


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

* [PATCH 3/5] iio: at91: ADC start-up time calculation changed since at91sam9x5
@ 2013-07-25  7:35       ` Josh Wu
  0 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-25  7:35 UTC (permalink / raw)
  To: linux-arm-kernel

On 7/20/2013 5:39 PM, Jonathan Cameron wrote:
> On 07/14/2013 09:04 AM, Josh Wu wrote:
>> Since in at91sam9x5, sama5d3x chip. the start up time calucation is changed.
>> And these two chips also have TSMR, so we check whether ADC has TSMR, then
>> choose different start up time calculation formula.
> If this doesn't have anything directly to do with the TSMR and this is just
> coincidence, then do this separately with it's own flag as it will be
> easier to maintain in the long run.

Agreed. I will fix it in next version.

Best Regards,
Josh Wu

>
> Jonathan
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>> ---
>>   drivers/iio/adc/at91_adc.c |   40 +++++++++++++++++++++++++++++++++-------
>>   1 file changed, 33 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>> index 14e99ba..e93a075 100644
>> --- a/drivers/iio/adc/at91_adc.c
>> +++ b/drivers/iio/adc/at91_adc.c
>> @@ -733,13 +733,39 @@ static int at91_adc_probe(struct platform_device *pdev)
>>   		goto error_disable_adc_clk;
>>   	}
>>   
>> -	/*
>> -	 * 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;
>> +	if (!st->caps.has_tsmr) {
>> +		/*
>> +		 * 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;
>> +	} else {
>> +		/*
>> +		 * 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);
>> +		ticks = st->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;
>> +	}
>> +
>>   	/*
>>   	 * a minimal Sample and Hold Time is necessary for the ADC to guarantee
>>   	 * the best converted final value between two channels selection
>>

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

* Re: [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
  2013-07-22 13:17     ` Mark Rutland
@ 2013-07-25  7:56       ` Josh Wu
  -1 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-25  7:56 UTC (permalink / raw)
  To: Mark Rutland
  Cc: jic23, linux-iio, Dmitry Torokhov, nicolas.ferre, maxime.ripard,
	plagnioj, linux-arm-kernel

Hi, Dear Mark

On 7/22/2013 9:17 PM, Mark Rutland wrote:
> On Sun, Jul 14, 2013 at 09:04:29AM +0100, 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:
>>    which type of touch are used? (4 or 5 wires), sample period time,
>>    pen detect debounce time, average samples and pen detect resistor.
>>
>> 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>
>> ---
>>   .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
>>   arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>>   drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
>>   3 files changed, 412 insertions(+), 24 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> index 0db2945..925d656 100644
>> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> @@ -29,6 +29,19 @@ Optional properties:
>>     - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
>>     - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
>>                            adc_op_clk.
>> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
>> +                                4 and 5 wires touch screen.
> Are 4 and 5 wire configurations that can exist, or the only ones
> supported by the driver?

It can be set:

atmel,adc-touchscreen-wires = <4>;
or
atmel,adc-touchscreen-wires = <5>;

according to your touch screen.

>
>> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
>> +          disabled. Since touch screen will occupied the trigger register.
>> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
>> +                                 detect.
> For consistency with the adc-touchscreen-wires property, and  other
> properties with timing information, how about
> atmel,adc-touchscreen-debounce-delay-us ?

sound nice to me.

>
>> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
>> +                                    touch screen
> Again, please be consistent with ts or touchscreen. It may also be good
> to have -us to make the units explicit (though it does leave the
> property name being quite a mothful):
>
> atmel,adc-touchscreen-sample-period-us ?

nice. I will use this one.

>
>> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
>> +    0 means no average. 1 means average two samples. 2 means average four
>> +    samples. 3 means average eight samples.
> Is this averaging done in the hardware, or the kernel driver?

It is done in the hardware.
But for some soc, like AT91SAM9G45, hardware doesn't support hardware 
average.
So I am wondering use it as for both hardware and softer average.

BTW, you mentioned the kernel driver, do you mean a filter algorithm is 
already implemented in kernel library?

>
> If it's the latter, this can be left for the kernel to decide.
>
>> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
>> +    It can be 0, 1, 2, 3.
> I think "pendet" is a bit opaque. "pen-detect" may be better.

yes. I'll change this.

> What
> physical property does this represent (are these discrete values, or an
> enumeration)?

This property is supported by hardware, it can change the adc internal 
resistor value for better pen detection,
      * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
In general, we just use default value 2 for 100kOhm.

I think I need add more detail infomation in the dt document.

Thanks again,
Best Regards,
Josh Wu

>
> Thanks,
> Mark.
>
>>   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 ab273ee..6d6cc14 100644
>> --- a/arch/arm/mach-at91/include/mach/at91_adc.h
>> +++ b/arch/arm/mach-at91/include/mach/at91_adc.h
>> @@ -57,10 +57,44 @@
>>   #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_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_VERSION       0xFC
>>
>> +/* 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 8f1386f..ffc0e42 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,12 +40,24 @@
>>   #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 ZTHRESHOLD             9000
>> +
>>   struct at91_adc_caps {
>> +       bool    has_12bits_xy;  /* true means use 12 bits. Otherwise 10 bits */
>>          bool    has_tsmr;       /* only at91sam9x5, sama5d3 have TSMR reg */
>>          u32     mr_prescal_mask;
>>          u32     mr_startup_mask;
>>   };
>>
>> +enum atmel_adc_ts_type {
>> +       ATMEL_ADC_TOUCHSCREEN_NONE = 0,
>> +       ATMEL_ADC_TOUCHSCREEN_4WIRE,
>> +       ATMEL_ADC_TOUCHSCREEN_5WIRE,
>> +};
>> +
>>   struct at91_adc_state {
>>          struct clk              *adc_clk;
>>          u32                     adc_clk_rate;
>> @@ -70,6 +83,29 @@ 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;
>> +
>> +       u8                      ts_filter_average;
>> +       u16                     ts_pen_detect_debounce;
>> +       u8                      ts_pen_detect_sensitivity;
>> +       u16                     ts_sample_period_time;
>> +       u16                     ts_sample_period_val;
>>   };
>>
>>   static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
>> @@ -104,14 +140,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);
>> @@ -121,6 +153,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->caps.has_12bits_xy ? 12 : 10;
>> +       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)
>> +               x /= xscale;
>> +       else
>> +               dev_err(&idev->dev, "xscale == 0!!!\n");
>> +
>> +       /* 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)
>> +               y /= yscale;
>> +       else
>> +               dev_err(&idev->dev, "yscale == 0!!!\n");
>> +
>> +       /* 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 = ZTHRESHOLD;      /* 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 < ZTHRESHOLD) {
>> +               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;
>>   }
>> @@ -130,6 +271,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;
>> @@ -561,6 +712,57 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>>                  i++;
>>          }
>>
>> +       /* Check if touchscreen is enabled in DT. */
>> +       ret = of_property_read_u32(node, "atmel,adc-touchscreen-wires", &prop);
>> +       if (ret)
>> +               dev_info(&idev->dev, "Touchscreen not enabled.\n");
>> +       else if (prop == 4)
>> +               st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_4WIRE;
>> +       else if (prop == 5)
>> +               st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_5WIRE;
>> +       else
>> +               dev_warn(&idev->dev, "Unsupported number of touchscreen wires (%d)\n",
>> +                               prop);
>> +
>> +       if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_NONE)
>> +               return 0;
>> +
>> +       /* Touch screen is enabled, so check touch screen dt parameters */
>> +       if (of_property_read_u32(node, "atmel,adc-ts-filter-average", &prop)) {
>> +               dev_err(&idev->dev, "Missing atmel,adc-ts-filtering-average property in the DT.\n");
>> +               ret = -EINVAL;
>> +               goto error_ret;
>> +       }
>> +       st->ts_filter_average = prop;
>> +       if (st->ts_filter_average > 3) {
>> +               dev_err(&idev->dev, "Invalid atmel,adc-ts-filtering-average property in the DT.\n");
>> +               ret = -EINVAL;
>> +               goto error_ret;
>> +       }
>> +
>> +       prop = 0;
>> +       of_property_read_u32(node, "atmel,adc-ts-pendet-debounce", &prop);
>> +       st->ts_pen_detect_debounce = prop;
>> +
>> +       /* default sample period is 2ms. The real touch sample period should be
>> +        * this period * TSFREQ.
>> +        */
>> +       prop = 2000;
>> +       of_property_read_u32(node, "atmel,adc-ts-sample-period-time", &prop);
>> +       st->ts_sample_period_time = prop;
>> +
>> +       if (of_property_read_u32(node, "atmel,adc-ts-pendet-sensitivity", &prop)) {
>> +               dev_err(&idev->dev, "Missing atmel,adc-ts-pendet-sensitivity property in the DT.\n");
>> +               ret = -EINVAL;
>> +               goto error_ret;
>> +       }
>> +       st->ts_pen_detect_sensitivity = prop;
>> +       if (st->ts_pen_detect_sensitivity > 3) {
>> +               dev_err(&idev->dev, "Invalid atmel,adc-ts-pendet-sensitivity property in the DT.\n");
>> +               ret = -EINVAL;
>> +               goto error_ret;
>> +       }
>> +
>>          return 0;
>>
>>   error_ret:
>> @@ -592,6 +794,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(st->ts_pen_detect_debounce * 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->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->ts_pen_detect_sensitivity
>> +                       & AT91_ADC_ACR_PENDETSENS);
>> +
>> +       /* Sample Peroid Time = (TRGPER + 1) / ADCClock */
>> +       st->ts_sample_period_val = round_up((st->ts_sample_period_time *
>> +                       adc_clk_khz / 1000) - 1, 1);
>> +
>> +       return 0;
>> +}
>> +
>> +static int at91_ts_register(struct at91_adc_state *st)
>> +{
>> +       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 = idev->dev.parent;
>> +       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);
>> +       input_free_device(st->ts_input);
>> +}
>> +
>>   /*
>>    * Since atmel adc support different ip for touchscreen mode. Through the
>>    * IP check, we will know the touchscreen capbilities.
>> @@ -610,6 +920,7 @@ static void atmel_adc_get_cap(struct at91_adc_state *st)
>>          /* keep only major version number */
>>          switch (version & 0xf00) {
>>          case 0x500:     /* SAMA5D3 */
>> +               st->caps.has_12bits_xy = 1;
>>          case 0x400:     /* AT91SAM9X5/9N12 */
>>                  st->caps.has_tsmr = 1;
>>                  st->caps.mr_startup_mask = AT91_ADC_STARTUP;
>> @@ -683,7 +994,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);
>> @@ -731,6 +1042,10 @@ static int at91_adc_probe(struct platform_device *pdev)
>>          adc_clk = st->adc_clk_rate ?
>>                  st->adc_clk_rate : 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) {
>> @@ -799,30 +1114,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);
>> +               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:
>> @@ -841,8 +1178,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);
>> @@ -861,7 +1202,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
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>

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

* [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
@ 2013-07-25  7:56       ` Josh Wu
  0 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-07-25  7:56 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, Dear Mark

On 7/22/2013 9:17 PM, Mark Rutland wrote:
> On Sun, Jul 14, 2013 at 09:04:29AM +0100, 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:
>>    which type of touch are used? (4 or 5 wires), sample period time,
>>    pen detect debounce time, average samples and pen detect resistor.
>>
>> 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>
>> ---
>>   .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
>>   arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>>   drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
>>   3 files changed, 412 insertions(+), 24 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> index 0db2945..925d656 100644
>> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> @@ -29,6 +29,19 @@ Optional properties:
>>     - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
>>     - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
>>                            adc_op_clk.
>> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
>> +                                4 and 5 wires touch screen.
> Are 4 and 5 wire configurations that can exist, or the only ones
> supported by the driver?

It can be set:

atmel,adc-touchscreen-wires = <4>;
or
atmel,adc-touchscreen-wires = <5>;

according to your touch screen.

>
>> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
>> +          disabled. Since touch screen will occupied the trigger register.
>> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
>> +                                 detect.
> For consistency with the adc-touchscreen-wires property, and  other
> properties with timing information, how about
> atmel,adc-touchscreen-debounce-delay-us ?

sound nice to me.

>
>> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
>> +                                    touch screen
> Again, please be consistent with ts or touchscreen. It may also be good
> to have -us to make the units explicit (though it does leave the
> property name being quite a mothful):
>
> atmel,adc-touchscreen-sample-period-us ?

nice. I will use this one.

>
>> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
>> +    0 means no average. 1 means average two samples. 2 means average four
>> +    samples. 3 means average eight samples.
> Is this averaging done in the hardware, or the kernel driver?

It is done in the hardware.
But for some soc, like AT91SAM9G45, hardware doesn't support hardware 
average.
So I am wondering use it as for both hardware and softer average.

BTW, you mentioned the kernel driver, do you mean a filter algorithm is 
already implemented in kernel library?

>
> If it's the latter, this can be left for the kernel to decide.
>
>> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
>> +    It can be 0, 1, 2, 3.
> I think "pendet" is a bit opaque. "pen-detect" may be better.

yes. I'll change this.

> What
> physical property does this represent (are these discrete values, or an
> enumeration)?

This property is supported by hardware, it can change the adc internal 
resistor value for better pen detection,
      * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
In general, we just use default value 2 for 100kOhm.

I think I need add more detail infomation in the dt document.

Thanks again,
Best Regards,
Josh Wu

>
> Thanks,
> Mark.
>
>>   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 ab273ee..6d6cc14 100644
>> --- a/arch/arm/mach-at91/include/mach/at91_adc.h
>> +++ b/arch/arm/mach-at91/include/mach/at91_adc.h
>> @@ -57,10 +57,44 @@
>>   #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_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_VERSION       0xFC
>>
>> +/* 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 8f1386f..ffc0e42 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,12 +40,24 @@
>>   #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 ZTHRESHOLD             9000
>> +
>>   struct at91_adc_caps {
>> +       bool    has_12bits_xy;  /* true means use 12 bits. Otherwise 10 bits */
>>          bool    has_tsmr;       /* only at91sam9x5, sama5d3 have TSMR reg */
>>          u32     mr_prescal_mask;
>>          u32     mr_startup_mask;
>>   };
>>
>> +enum atmel_adc_ts_type {
>> +       ATMEL_ADC_TOUCHSCREEN_NONE = 0,
>> +       ATMEL_ADC_TOUCHSCREEN_4WIRE,
>> +       ATMEL_ADC_TOUCHSCREEN_5WIRE,
>> +};
>> +
>>   struct at91_adc_state {
>>          struct clk              *adc_clk;
>>          u32                     adc_clk_rate;
>> @@ -70,6 +83,29 @@ 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;
>> +
>> +       u8                      ts_filter_average;
>> +       u16                     ts_pen_detect_debounce;
>> +       u8                      ts_pen_detect_sensitivity;
>> +       u16                     ts_sample_period_time;
>> +       u16                     ts_sample_period_val;
>>   };
>>
>>   static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
>> @@ -104,14 +140,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);
>> @@ -121,6 +153,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->caps.has_12bits_xy ? 12 : 10;
>> +       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)
>> +               x /= xscale;
>> +       else
>> +               dev_err(&idev->dev, "xscale == 0!!!\n");
>> +
>> +       /* 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)
>> +               y /= yscale;
>> +       else
>> +               dev_err(&idev->dev, "yscale == 0!!!\n");
>> +
>> +       /* 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 = ZTHRESHOLD;      /* 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 < ZTHRESHOLD) {
>> +               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;
>>   }
>> @@ -130,6 +271,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;
>> @@ -561,6 +712,57 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>>                  i++;
>>          }
>>
>> +       /* Check if touchscreen is enabled in DT. */
>> +       ret = of_property_read_u32(node, "atmel,adc-touchscreen-wires", &prop);
>> +       if (ret)
>> +               dev_info(&idev->dev, "Touchscreen not enabled.\n");
>> +       else if (prop == 4)
>> +               st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_4WIRE;
>> +       else if (prop == 5)
>> +               st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_5WIRE;
>> +       else
>> +               dev_warn(&idev->dev, "Unsupported number of touchscreen wires (%d)\n",
>> +                               prop);
>> +
>> +       if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_NONE)
>> +               return 0;
>> +
>> +       /* Touch screen is enabled, so check touch screen dt parameters */
>> +       if (of_property_read_u32(node, "atmel,adc-ts-filter-average", &prop)) {
>> +               dev_err(&idev->dev, "Missing atmel,adc-ts-filtering-average property in the DT.\n");
>> +               ret = -EINVAL;
>> +               goto error_ret;
>> +       }
>> +       st->ts_filter_average = prop;
>> +       if (st->ts_filter_average > 3) {
>> +               dev_err(&idev->dev, "Invalid atmel,adc-ts-filtering-average property in the DT.\n");
>> +               ret = -EINVAL;
>> +               goto error_ret;
>> +       }
>> +
>> +       prop = 0;
>> +       of_property_read_u32(node, "atmel,adc-ts-pendet-debounce", &prop);
>> +       st->ts_pen_detect_debounce = prop;
>> +
>> +       /* default sample period is 2ms. The real touch sample period should be
>> +        * this period * TSFREQ.
>> +        */
>> +       prop = 2000;
>> +       of_property_read_u32(node, "atmel,adc-ts-sample-period-time", &prop);
>> +       st->ts_sample_period_time = prop;
>> +
>> +       if (of_property_read_u32(node, "atmel,adc-ts-pendet-sensitivity", &prop)) {
>> +               dev_err(&idev->dev, "Missing atmel,adc-ts-pendet-sensitivity property in the DT.\n");
>> +               ret = -EINVAL;
>> +               goto error_ret;
>> +       }
>> +       st->ts_pen_detect_sensitivity = prop;
>> +       if (st->ts_pen_detect_sensitivity > 3) {
>> +               dev_err(&idev->dev, "Invalid atmel,adc-ts-pendet-sensitivity property in the DT.\n");
>> +               ret = -EINVAL;
>> +               goto error_ret;
>> +       }
>> +
>>          return 0;
>>
>>   error_ret:
>> @@ -592,6 +794,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(st->ts_pen_detect_debounce * 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->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->ts_pen_detect_sensitivity
>> +                       & AT91_ADC_ACR_PENDETSENS);
>> +
>> +       /* Sample Peroid Time = (TRGPER + 1) / ADCClock */
>> +       st->ts_sample_period_val = round_up((st->ts_sample_period_time *
>> +                       adc_clk_khz / 1000) - 1, 1);
>> +
>> +       return 0;
>> +}
>> +
>> +static int at91_ts_register(struct at91_adc_state *st)
>> +{
>> +       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 = idev->dev.parent;
>> +       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);
>> +       input_free_device(st->ts_input);
>> +}
>> +
>>   /*
>>    * Since atmel adc support different ip for touchscreen mode. Through the
>>    * IP check, we will know the touchscreen capbilities.
>> @@ -610,6 +920,7 @@ static void atmel_adc_get_cap(struct at91_adc_state *st)
>>          /* keep only major version number */
>>          switch (version & 0xf00) {
>>          case 0x500:     /* SAMA5D3 */
>> +               st->caps.has_12bits_xy = 1;
>>          case 0x400:     /* AT91SAM9X5/9N12 */
>>                  st->caps.has_tsmr = 1;
>>                  st->caps.mr_startup_mask = AT91_ADC_STARTUP;
>> @@ -683,7 +994,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);
>> @@ -731,6 +1042,10 @@ static int at91_adc_probe(struct platform_device *pdev)
>>          adc_clk = st->adc_clk_rate ?
>>                  st->adc_clk_rate : 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) {
>> @@ -799,30 +1114,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);
>> +               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:
>> @@ -841,8 +1178,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);
>> @@ -861,7 +1202,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
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>

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

* Re: [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz.
  2013-07-14  8:04   ` Josh Wu
@ 2013-07-25 12:01     ` boris brezillon
  -1 siblings, 0 replies; 85+ messages in thread
From: boris brezillon @ 2013-07-25 12:01 UTC (permalink / raw)
  To: Josh Wu
  Cc: jic23, linux-iio, nicolas.ferre, maxime.ripard, plagnioj,
	linux-arm-kernel

Hi Josh,

On 14/07/2013 10:04, Josh Wu wrote:
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> ---
>   Documentation/devicetree/bindings/arm/atmel-adc.txt |    2 ++
>   drivers/iio/adc/at91_adc.c                          |    8 +++++++-
>   2 files changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> index 16769d9..0db2945 100644
> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> @@ -27,6 +27,8 @@ 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-clock-rate: ADC clock rate. If not specified, use the default
> +			  adc_op_clk.
>
>   Optional trigger Nodes:
>     - Required properties:
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index e93a075..8f1386f 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -47,6 +47,7 @@ struct at91_adc_caps {
>
>   struct at91_adc_state {
>   	struct clk		*adc_clk;
> +	u32			adc_clk_rate;
>   	u16			*buffer;
>   	unsigned long		channels_mask;
>   	struct clk		*clk;
> @@ -448,6 +449,10 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>   	if (!node)
>   		return -EINVAL;
>
> +	prop = 0;
> +	of_property_read_u32(node, "atmel,adc-clock-rate", &prop);
> +	st->adc_clk_rate = prop;
> +
>   	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
>
>   	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
> @@ -723,7 +728,8 @@ static int at91_adc_probe(struct platform_device *pdev)
>   	 * specified by the electrical characteristics of the board.
>   	 */
>   	mstrclk = clk_get_rate(st->clk);
> -	adc_clk = clk_get_rate(st->adc_clk);
> +	adc_clk = st->adc_clk_rate ?
> +		st->adc_clk_rate : clk_get_rate(st->adc_clk);
>   	adc_clk_khz = adc_clk / 1000;
>   	prsc = (mstrclk / (2 * adc_clk)) - 1;
>
>

As said by Maxime and Lars-Peter, I think this should be handled by a 
proper clock implementation (adc_clock ?) using common clock framework.

IMO the fake adc_op_clk should not exist. Instead the adc clock binding 
should define properties describing the adc clock characteristics (see 
pll implementation in at91 common clk series).
These characteristics can be found in 'ADC characteristics' chapter in 
atmel's datasheets.

The adc clock binding would look like this (based on sama5 datasheet):

adc_clk {
	compatible = "sama5d3-adc-clk";
	output = <1000000 20000000>; /* output clock frequency range */
};

It is up to the clk user (adc driver) to choose the appropriate 
frequency to use (maximum rate ?) and configure it with clk_set_rate 
function.
The adc clk implem will take care of PRESCAL field config in ADC_MR 
according to parent rate (mck rate) and requested rate. It will also 
check if the requested rate is in the output clk range.

These are just thought, feel free to comment it.

Best Regards,

Boris

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

* [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz.
@ 2013-07-25 12:01     ` boris brezillon
  0 siblings, 0 replies; 85+ messages in thread
From: boris brezillon @ 2013-07-25 12:01 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Josh,

On 14/07/2013 10:04, Josh Wu wrote:
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> ---
>   Documentation/devicetree/bindings/arm/atmel-adc.txt |    2 ++
>   drivers/iio/adc/at91_adc.c                          |    8 +++++++-
>   2 files changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> index 16769d9..0db2945 100644
> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> @@ -27,6 +27,8 @@ 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-clock-rate: ADC clock rate. If not specified, use the default
> +			  adc_op_clk.
>
>   Optional trigger Nodes:
>     - Required properties:
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index e93a075..8f1386f 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -47,6 +47,7 @@ struct at91_adc_caps {
>
>   struct at91_adc_state {
>   	struct clk		*adc_clk;
> +	u32			adc_clk_rate;
>   	u16			*buffer;
>   	unsigned long		channels_mask;
>   	struct clk		*clk;
> @@ -448,6 +449,10 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>   	if (!node)
>   		return -EINVAL;
>
> +	prop = 0;
> +	of_property_read_u32(node, "atmel,adc-clock-rate", &prop);
> +	st->adc_clk_rate = prop;
> +
>   	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
>
>   	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
> @@ -723,7 +728,8 @@ static int at91_adc_probe(struct platform_device *pdev)
>   	 * specified by the electrical characteristics of the board.
>   	 */
>   	mstrclk = clk_get_rate(st->clk);
> -	adc_clk = clk_get_rate(st->adc_clk);
> +	adc_clk = st->adc_clk_rate ?
> +		st->adc_clk_rate : clk_get_rate(st->adc_clk);
>   	adc_clk_khz = adc_clk / 1000;
>   	prsc = (mstrclk / (2 * adc_clk)) - 1;
>
>

As said by Maxime and Lars-Peter, I think this should be handled by a 
proper clock implementation (adc_clock ?) using common clock framework.

IMO the fake adc_op_clk should not exist. Instead the adc clock binding 
should define properties describing the adc clock characteristics (see 
pll implementation in at91 common clk series).
These characteristics can be found in 'ADC characteristics' chapter in 
atmel's datasheets.

The adc clock binding would look like this (based on sama5 datasheet):

adc_clk {
	compatible = "sama5d3-adc-clk";
	output = <1000000 20000000>; /* output clock frequency range */
};

It is up to the clk user (adc driver) to choose the appropriate 
frequency to use (maximum rate ?) and configure it with clk_set_rate 
function.
The adc clk implem will take care of PRESCAL field config in ADC_MR 
according to parent rate (mck rate) and requested rate. It will also 
check if the requested rate is in the output clk range.

These are just thought, feel free to comment it.

Best Regards,

Boris

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

* Re: [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz.
  2013-07-25 12:01     ` boris brezillon
@ 2013-07-25 12:11       ` boris brezillon
  -1 siblings, 0 replies; 85+ messages in thread
From: boris brezillon @ 2013-07-25 12:11 UTC (permalink / raw)
  To: boris brezillon
  Cc: Josh Wu, linux-iio, nicolas.ferre, jic23, maxime.ripard,
	plagnioj, linux-arm-kernel

On 25/07/2013 14:01, boris brezillon wrote:
> Hi Josh,
>
> On 14/07/2013 10:04, Josh Wu wrote:
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>> ---
>>   Documentation/devicetree/bindings/arm/atmel-adc.txt |    2 ++
>>   drivers/iio/adc/at91_adc.c                          |    8 +++++++-
>>   2 files changed, 9 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> index 16769d9..0db2945 100644
>> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> @@ -27,6 +27,8 @@ 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-clock-rate: ADC clock rate. If not specified, use the
>> default
>> +              adc_op_clk.
>>
>>   Optional trigger Nodes:
>>     - Required properties:
>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>> index e93a075..8f1386f 100644
>> --- a/drivers/iio/adc/at91_adc.c
>> +++ b/drivers/iio/adc/at91_adc.c
>> @@ -47,6 +47,7 @@ struct at91_adc_caps {
>>
>>   struct at91_adc_state {
>>       struct clk        *adc_clk;
>> +    u32            adc_clk_rate;
>>       u16            *buffer;
>>       unsigned long        channels_mask;
>>       struct clk        *clk;
>> @@ -448,6 +449,10 @@ static int at91_adc_probe_dt(struct
>> at91_adc_state *st,
>>       if (!node)
>>           return -EINVAL;
>>
>> +    prop = 0;
>> +    of_property_read_u32(node, "atmel,adc-clock-rate", &prop);
>> +    st->adc_clk_rate = prop;
>> +
>>       st->use_external = of_property_read_bool(node,
>> "atmel,adc-use-external-triggers");
>>
>>       if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
>> @@ -723,7 +728,8 @@ static int at91_adc_probe(struct platform_device
>> *pdev)
>>        * specified by the electrical characteristics of the board.
>>        */
>>       mstrclk = clk_get_rate(st->clk);
>> -    adc_clk = clk_get_rate(st->adc_clk);
>> +    adc_clk = st->adc_clk_rate ?
>> +        st->adc_clk_rate : clk_get_rate(st->adc_clk);
>>       adc_clk_khz = adc_clk / 1000;
>>       prsc = (mstrclk / (2 * adc_clk)) - 1;
>>
>>
>
> As said by Maxime and Lars-Peter, I think this should be handled by a
> proper clock implementation (adc_clock ?) using common clock framework.
>
> IMO the fake adc_op_clk should not exist. Instead the adc clock binding
> should define properties describing the adc clock characteristics (see
> pll implementation in at91 common clk series).
> These characteristics can be found in 'ADC characteristics' chapter in
> atmel's datasheets.
>
> The adc clock binding would look like this (based on sama5 datasheet):
>
> adc_clk {
>      compatible = "sama5d3-adc-clk";
>      output = <1000000 20000000>; /* output clock frequency range */
> };

or more like this:

adc_clk {
	compatible = "xxx-adc-clk";
	#clock-cells = <0>;
	clocks = <&mck>;
	output = <1000000 20000000>; /* output clock frequency range */
};
>
> It is up to the clk user (adc driver) to choose the appropriate
> frequency to use (maximum rate ?) and configure it with clk_set_rate
> function.
> The adc clk implem will take care of PRESCAL field config in ADC_MR
> according to parent rate (mck rate) and requested rate. It will also
> check if the requested rate is in the output clk range.
>
> These are just thought, feel free to comment it.
>
> Best Regards,
>
> Boris
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz.
@ 2013-07-25 12:11       ` boris brezillon
  0 siblings, 0 replies; 85+ messages in thread
From: boris brezillon @ 2013-07-25 12:11 UTC (permalink / raw)
  To: linux-arm-kernel

On 25/07/2013 14:01, boris brezillon wrote:
> Hi Josh,
>
> On 14/07/2013 10:04, Josh Wu wrote:
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>> ---
>>   Documentation/devicetree/bindings/arm/atmel-adc.txt |    2 ++
>>   drivers/iio/adc/at91_adc.c                          |    8 +++++++-
>>   2 files changed, 9 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> index 16769d9..0db2945 100644
>> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> @@ -27,6 +27,8 @@ 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-clock-rate: ADC clock rate. If not specified, use the
>> default
>> +              adc_op_clk.
>>
>>   Optional trigger Nodes:
>>     - Required properties:
>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>> index e93a075..8f1386f 100644
>> --- a/drivers/iio/adc/at91_adc.c
>> +++ b/drivers/iio/adc/at91_adc.c
>> @@ -47,6 +47,7 @@ struct at91_adc_caps {
>>
>>   struct at91_adc_state {
>>       struct clk        *adc_clk;
>> +    u32            adc_clk_rate;
>>       u16            *buffer;
>>       unsigned long        channels_mask;
>>       struct clk        *clk;
>> @@ -448,6 +449,10 @@ static int at91_adc_probe_dt(struct
>> at91_adc_state *st,
>>       if (!node)
>>           return -EINVAL;
>>
>> +    prop = 0;
>> +    of_property_read_u32(node, "atmel,adc-clock-rate", &prop);
>> +    st->adc_clk_rate = prop;
>> +
>>       st->use_external = of_property_read_bool(node,
>> "atmel,adc-use-external-triggers");
>>
>>       if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
>> @@ -723,7 +728,8 @@ static int at91_adc_probe(struct platform_device
>> *pdev)
>>        * specified by the electrical characteristics of the board.
>>        */
>>       mstrclk = clk_get_rate(st->clk);
>> -    adc_clk = clk_get_rate(st->adc_clk);
>> +    adc_clk = st->adc_clk_rate ?
>> +        st->adc_clk_rate : clk_get_rate(st->adc_clk);
>>       adc_clk_khz = adc_clk / 1000;
>>       prsc = (mstrclk / (2 * adc_clk)) - 1;
>>
>>
>
> As said by Maxime and Lars-Peter, I think this should be handled by a
> proper clock implementation (adc_clock ?) using common clock framework.
>
> IMO the fake adc_op_clk should not exist. Instead the adc clock binding
> should define properties describing the adc clock characteristics (see
> pll implementation in at91 common clk series).
> These characteristics can be found in 'ADC characteristics' chapter in
> atmel's datasheets.
>
> The adc clock binding would look like this (based on sama5 datasheet):
>
> adc_clk {
>      compatible = "sama5d3-adc-clk";
>      output = <1000000 20000000>; /* output clock frequency range */
> };

or more like this:

adc_clk {
	compatible = "xxx-adc-clk";
	#clock-cells = <0>;
	clocks = <&mck>;
	output = <1000000 20000000>; /* output clock frequency range */
};
>
> It is up to the clk user (adc driver) to choose the appropriate
> frequency to use (maximum rate ?) and configure it with clk_set_rate
> function.
> The adc clk implem will take care of PRESCAL field config in ADC_MR
> according to parent rate (mck rate) and requested rate. It will also
> check if the requested rate is in the output clk range.
>
> These are just thought, feel free to comment it.
>
> Best Regards,
>
> Boris
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
  2013-07-25  7:56       ` Josh Wu
@ 2013-07-25 16:45         ` Mark Rutland
  -1 siblings, 0 replies; 85+ messages in thread
From: Mark Rutland @ 2013-07-25 16:45 UTC (permalink / raw)
  To: Josh Wu
  Cc: linux-iio, Dmitry Torokhov, nicolas.ferre, jic23, maxime.ripard,
	plagnioj, linux-arm-kernel

On Thu, Jul 25, 2013 at 08:56:38AM +0100, Josh Wu wrote:
> Hi, Dear Mark
> 
> On 7/22/2013 9:17 PM, Mark Rutland wrote:
> > On Sun, Jul 14, 2013 at 09:04:29AM +0100, 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:
> >>    which type of touch are used? (4 or 5 wires), sample period time,
> >>    pen detect debounce time, average samples and pen detect resistor.
> >>
> >> 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>
> >> ---
> >>   .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
> >>   arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
> >>   drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
> >>   3 files changed, 412 insertions(+), 24 deletions(-)
> >>
> >> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >> index 0db2945..925d656 100644
> >> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >> @@ -29,6 +29,19 @@ Optional properties:
> >>     - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
> >>     - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
> >>                            adc_op_clk.
> >> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
> >> +                                4 and 5 wires touch screen.
> > Are 4 and 5 wire configurations that can exist, or the only ones
> > supported by the driver?
> 
> It can be set:
> 
> atmel,adc-touchscreen-wires = <4>;
> or
> atmel,adc-touchscreen-wires = <5>;
> 
> according to your touch screen.

That doesn't answer my question.

Is it possible that 3 or 6 wire configurations might exist, for example,
even if not supported by this driver? Or does the design of the adc
prevent this?

Is there any documentation that might make this clearer?

> 
> >
> >> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> >> +          disabled. Since touch screen will occupied the trigger register.
> >> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
> >> +                                 detect.
> > For consistency with the adc-touchscreen-wires property, and  other
> > properties with timing information, how about
> > atmel,adc-touchscreen-debounce-delay-us ?
> 
> sound nice to me.

Additionally, is this likely to vary from board to board? This feels
like configuration that could be done based on the compatible string...

> 
> >
> >> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
> >> +                                    touch screen
> > Again, please be consistent with ts or touchscreen. It may also be good
> > to have -us to make the units explicit (though it does leave the
> > property name being quite a mothful):
> >
> > atmel,adc-touchscreen-sample-period-us ?
> 
> nice. I will use this one.

Looking again at the driver code, it looks like a value derived from
this eventually gets written to the hardware. Is this a fixed value at
integration time, or is this a configuration value? If it's the latter,
can the driver not derive a good value for this itself?

> 
> >
> >> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
> >> +    0 means no average. 1 means average two samples. 2 means average four
> >> +    samples. 3 means average eight samples.
> > Is this averaging done in the hardware, or the kernel driver?
> 
> It is done in the hardware.

Similarly, this seems to eventually get written to hardware, and thus
seems more like configuration than hardware description. Why does this
need to be in the DT?

As an aside, in general it's nicer to describe a property as a logical
value rather than the raw value that gets programmed into hardware (e.g.
this property could by 2, 4, or 8 rather than 1, 2, or 4).

> But for some soc, like AT91SAM9G45, hardware doesn't support hardware
> average.
> So I am wondering use it as for both hardware and softer average.
> 
> BTW, you mentioned the kernel driver, do you mean a filter algorithm is
> already implemented in kernel library?

I do not know of any such filter algorithm in the kernel, though there
may be one. I was simply confused as to what this was used for.

> 
> >
> > If it's the latter, this can be left for the kernel to decide.
> >
> >> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
> >> +    It can be 0, 1, 2, 3.
> > I think "pendet" is a bit opaque. "pen-detect" may be better.
> 
> yes. I'll change this.
> 
> > What
> > physical property does this represent (are these discrete values, or an
> > enumeration)?
> 
> This property is supported by hardware, it can change the adc internal
> resistor value for better pen detection,
>       * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
> In general, we just use default value 2 for 100kOhm.

This value eventually gets written to hardware, and seems more like
configuration than hardware description. Why does this need to be in the
DT?

Thanks,
Mark.

> I think I need add more detail infomation in the dt document.
> 
> Thanks again,
> Best Regards,
> Josh Wu
> 
> >
> > Thanks,
> > Mark.
> >
> >>   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 ab273ee..6d6cc14 100644
> >> --- a/arch/arm/mach-at91/include/mach/at91_adc.h
> >> +++ b/arch/arm/mach-at91/include/mach/at91_adc.h
> >> @@ -57,10 +57,44 @@
> >>   #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_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_VERSION       0xFC
> >>
> >> +/* 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 8f1386f..ffc0e42 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,12 +40,24 @@
> >>   #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 ZTHRESHOLD             9000
> >> +
> >>   struct at91_adc_caps {
> >> +       bool    has_12bits_xy;  /* true means use 12 bits. Otherwise 10 bits */
> >>          bool    has_tsmr;       /* only at91sam9x5, sama5d3 have TSMR reg */
> >>          u32     mr_prescal_mask;
> >>          u32     mr_startup_mask;
> >>   };
> >>
> >> +enum atmel_adc_ts_type {
> >> +       ATMEL_ADC_TOUCHSCREEN_NONE = 0,
> >> +       ATMEL_ADC_TOUCHSCREEN_4WIRE,
> >> +       ATMEL_ADC_TOUCHSCREEN_5WIRE,
> >> +};
> >> +
> >>   struct at91_adc_state {
> >>          struct clk              *adc_clk;
> >>          u32                     adc_clk_rate;
> >> @@ -70,6 +83,29 @@ 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;
> >> +
> >> +       u8                      ts_filter_average;
> >> +       u16                     ts_pen_detect_debounce;
> >> +       u8                      ts_pen_detect_sensitivity;
> >> +       u16                     ts_sample_period_time;
> >> +       u16                     ts_sample_period_val;
> >>   };
> >>
> >>   static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
> >> @@ -104,14 +140,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);
> >> @@ -121,6 +153,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->caps.has_12bits_xy ? 12 : 10;
> >> +       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)
> >> +               x /= xscale;
> >> +       else
> >> +               dev_err(&idev->dev, "xscale == 0!!!\n");
> >> +
> >> +       /* 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)
> >> +               y /= yscale;
> >> +       else
> >> +               dev_err(&idev->dev, "yscale == 0!!!\n");
> >> +
> >> +       /* 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 = ZTHRESHOLD;      /* 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 < ZTHRESHOLD) {
> >> +               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;
> >>   }
> >> @@ -130,6 +271,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;
> >> @@ -561,6 +712,57 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
> >>                  i++;
> >>          }
> >>
> >> +       /* Check if touchscreen is enabled in DT. */
> >> +       ret = of_property_read_u32(node, "atmel,adc-touchscreen-wires", &prop);
> >> +       if (ret)
> >> +               dev_info(&idev->dev, "Touchscreen not enabled.\n");
> >> +       else if (prop == 4)
> >> +               st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_4WIRE;
> >> +       else if (prop == 5)
> >> +               st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_5WIRE;
> >> +       else
> >> +               dev_warn(&idev->dev, "Unsupported number of touchscreen wires (%d)\n",
> >> +                               prop);
> >> +
> >> +       if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_NONE)
> >> +               return 0;
> >> +
> >> +       /* Touch screen is enabled, so check touch screen dt parameters */
> >> +       if (of_property_read_u32(node, "atmel,adc-ts-filter-average", &prop)) {
> >> +               dev_err(&idev->dev, "Missing atmel,adc-ts-filtering-average property in the DT.\n");
> >> +               ret = -EINVAL;
> >> +               goto error_ret;
> >> +       }
> >> +       st->ts_filter_average = prop;
> >> +       if (st->ts_filter_average > 3) {
> >> +               dev_err(&idev->dev, "Invalid atmel,adc-ts-filtering-average property in the DT.\n");
> >> +               ret = -EINVAL;
> >> +               goto error_ret;
> >> +       }
> >> +
> >> +       prop = 0;
> >> +       of_property_read_u32(node, "atmel,adc-ts-pendet-debounce", &prop);
> >> +       st->ts_pen_detect_debounce = prop;
> >> +
> >> +       /* default sample period is 2ms. The real touch sample period should be
> >> +        * this period * TSFREQ.
> >> +        */
> >> +       prop = 2000;
> >> +       of_property_read_u32(node, "atmel,adc-ts-sample-period-time", &prop);
> >> +       st->ts_sample_period_time = prop;
> >> +
> >> +       if (of_property_read_u32(node, "atmel,adc-ts-pendet-sensitivity", &prop)) {
> >> +               dev_err(&idev->dev, "Missing atmel,adc-ts-pendet-sensitivity property in the DT.\n");
> >> +               ret = -EINVAL;
> >> +               goto error_ret;
> >> +       }
> >> +       st->ts_pen_detect_sensitivity = prop;
> >> +       if (st->ts_pen_detect_sensitivity > 3) {
> >> +               dev_err(&idev->dev, "Invalid atmel,adc-ts-pendet-sensitivity property in the DT.\n");
> >> +               ret = -EINVAL;
> >> +               goto error_ret;
> >> +       }
> >> +
> >>          return 0;
> >>
> >>   error_ret:
> >> @@ -592,6 +794,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(st->ts_pen_detect_debounce * 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->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->ts_pen_detect_sensitivity
> >> +                       & AT91_ADC_ACR_PENDETSENS);
> >> +
> >> +       /* Sample Peroid Time = (TRGPER + 1) / ADCClock */
> >> +       st->ts_sample_period_val = round_up((st->ts_sample_period_time *
> >> +                       adc_clk_khz / 1000) - 1, 1);
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int at91_ts_register(struct at91_adc_state *st)
> >> +{
> >> +       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 = idev->dev.parent;
> >> +       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);
> >> +       input_free_device(st->ts_input);
> >> +}
> >> +
> >>   /*
> >>    * Since atmel adc support different ip for touchscreen mode. Through the
> >>    * IP check, we will know the touchscreen capbilities.
> >> @@ -610,6 +920,7 @@ static void atmel_adc_get_cap(struct at91_adc_state *st)
> >>          /* keep only major version number */
> >>          switch (version & 0xf00) {
> >>          case 0x500:     /* SAMA5D3 */
> >> +               st->caps.has_12bits_xy = 1;
> >>          case 0x400:     /* AT91SAM9X5/9N12 */
> >>                  st->caps.has_tsmr = 1;
> >>                  st->caps.mr_startup_mask = AT91_ADC_STARTUP;
> >> @@ -683,7 +994,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);
> >> @@ -731,6 +1042,10 @@ static int at91_adc_probe(struct platform_device *pdev)
> >>          adc_clk = st->adc_clk_rate ?
> >>                  st->adc_clk_rate : 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) {
> >> @@ -799,30 +1114,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);
> >> +               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:
> >> @@ -841,8 +1178,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);
> >> @@ -861,7 +1202,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
> >>
> >>
> >> _______________________________________________
> >> linux-arm-kernel mailing list
> >> linux-arm-kernel@lists.infradead.org
> >> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> >>
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

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

* [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
@ 2013-07-25 16:45         ` Mark Rutland
  0 siblings, 0 replies; 85+ messages in thread
From: Mark Rutland @ 2013-07-25 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jul 25, 2013 at 08:56:38AM +0100, Josh Wu wrote:
> Hi, Dear Mark
> 
> On 7/22/2013 9:17 PM, Mark Rutland wrote:
> > On Sun, Jul 14, 2013 at 09:04:29AM +0100, 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:
> >>    which type of touch are used? (4 or 5 wires), sample period time,
> >>    pen detect debounce time, average samples and pen detect resistor.
> >>
> >> 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>
> >> ---
> >>   .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
> >>   arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
> >>   drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
> >>   3 files changed, 412 insertions(+), 24 deletions(-)
> >>
> >> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >> index 0db2945..925d656 100644
> >> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >> @@ -29,6 +29,19 @@ Optional properties:
> >>     - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
> >>     - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
> >>                            adc_op_clk.
> >> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
> >> +                                4 and 5 wires touch screen.
> > Are 4 and 5 wire configurations that can exist, or the only ones
> > supported by the driver?
> 
> It can be set:
> 
> atmel,adc-touchscreen-wires = <4>;
> or
> atmel,adc-touchscreen-wires = <5>;
> 
> according to your touch screen.

That doesn't answer my question.

Is it possible that 3 or 6 wire configurations might exist, for example,
even if not supported by this driver? Or does the design of the adc
prevent this?

Is there any documentation that might make this clearer?

> 
> >
> >> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> >> +          disabled. Since touch screen will occupied the trigger register.
> >> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
> >> +                                 detect.
> > For consistency with the adc-touchscreen-wires property, and  other
> > properties with timing information, how about
> > atmel,adc-touchscreen-debounce-delay-us ?
> 
> sound nice to me.

Additionally, is this likely to vary from board to board? This feels
like configuration that could be done based on the compatible string...

> 
> >
> >> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
> >> +                                    touch screen
> > Again, please be consistent with ts or touchscreen. It may also be good
> > to have -us to make the units explicit (though it does leave the
> > property name being quite a mothful):
> >
> > atmel,adc-touchscreen-sample-period-us ?
> 
> nice. I will use this one.

Looking again at the driver code, it looks like a value derived from
this eventually gets written to the hardware. Is this a fixed value at
integration time, or is this a configuration value? If it's the latter,
can the driver not derive a good value for this itself?

> 
> >
> >> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
> >> +    0 means no average. 1 means average two samples. 2 means average four
> >> +    samples. 3 means average eight samples.
> > Is this averaging done in the hardware, or the kernel driver?
> 
> It is done in the hardware.

Similarly, this seems to eventually get written to hardware, and thus
seems more like configuration than hardware description. Why does this
need to be in the DT?

As an aside, in general it's nicer to describe a property as a logical
value rather than the raw value that gets programmed into hardware (e.g.
this property could by 2, 4, or 8 rather than 1, 2, or 4).

> But for some soc, like AT91SAM9G45, hardware doesn't support hardware
> average.
> So I am wondering use it as for both hardware and softer average.
> 
> BTW, you mentioned the kernel driver, do you mean a filter algorithm is
> already implemented in kernel library?

I do not know of any such filter algorithm in the kernel, though there
may be one. I was simply confused as to what this was used for.

> 
> >
> > If it's the latter, this can be left for the kernel to decide.
> >
> >> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
> >> +    It can be 0, 1, 2, 3.
> > I think "pendet" is a bit opaque. "pen-detect" may be better.
> 
> yes. I'll change this.
> 
> > What
> > physical property does this represent (are these discrete values, or an
> > enumeration)?
> 
> This property is supported by hardware, it can change the adc internal
> resistor value for better pen detection,
>       * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
> In general, we just use default value 2 for 100kOhm.

This value eventually gets written to hardware, and seems more like
configuration than hardware description. Why does this need to be in the
DT?

Thanks,
Mark.

> I think I need add more detail infomation in the dt document.
> 
> Thanks again,
> Best Regards,
> Josh Wu
> 
> >
> > Thanks,
> > Mark.
> >
> >>   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 ab273ee..6d6cc14 100644
> >> --- a/arch/arm/mach-at91/include/mach/at91_adc.h
> >> +++ b/arch/arm/mach-at91/include/mach/at91_adc.h
> >> @@ -57,10 +57,44 @@
> >>   #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_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_VERSION       0xFC
> >>
> >> +/* 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 8f1386f..ffc0e42 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,12 +40,24 @@
> >>   #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 ZTHRESHOLD             9000
> >> +
> >>   struct at91_adc_caps {
> >> +       bool    has_12bits_xy;  /* true means use 12 bits. Otherwise 10 bits */
> >>          bool    has_tsmr;       /* only at91sam9x5, sama5d3 have TSMR reg */
> >>          u32     mr_prescal_mask;
> >>          u32     mr_startup_mask;
> >>   };
> >>
> >> +enum atmel_adc_ts_type {
> >> +       ATMEL_ADC_TOUCHSCREEN_NONE = 0,
> >> +       ATMEL_ADC_TOUCHSCREEN_4WIRE,
> >> +       ATMEL_ADC_TOUCHSCREEN_5WIRE,
> >> +};
> >> +
> >>   struct at91_adc_state {
> >>          struct clk              *adc_clk;
> >>          u32                     adc_clk_rate;
> >> @@ -70,6 +83,29 @@ 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;
> >> +
> >> +       u8                      ts_filter_average;
> >> +       u16                     ts_pen_detect_debounce;
> >> +       u8                      ts_pen_detect_sensitivity;
> >> +       u16                     ts_sample_period_time;
> >> +       u16                     ts_sample_period_val;
> >>   };
> >>
> >>   static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
> >> @@ -104,14 +140,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);
> >> @@ -121,6 +153,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->caps.has_12bits_xy ? 12 : 10;
> >> +       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)
> >> +               x /= xscale;
> >> +       else
> >> +               dev_err(&idev->dev, "xscale == 0!!!\n");
> >> +
> >> +       /* 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)
> >> +               y /= yscale;
> >> +       else
> >> +               dev_err(&idev->dev, "yscale == 0!!!\n");
> >> +
> >> +       /* 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 = ZTHRESHOLD;      /* 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 < ZTHRESHOLD) {
> >> +               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;
> >>   }
> >> @@ -130,6 +271,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;
> >> @@ -561,6 +712,57 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
> >>                  i++;
> >>          }
> >>
> >> +       /* Check if touchscreen is enabled in DT. */
> >> +       ret = of_property_read_u32(node, "atmel,adc-touchscreen-wires", &prop);
> >> +       if (ret)
> >> +               dev_info(&idev->dev, "Touchscreen not enabled.\n");
> >> +       else if (prop == 4)
> >> +               st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_4WIRE;
> >> +       else if (prop == 5)
> >> +               st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_5WIRE;
> >> +       else
> >> +               dev_warn(&idev->dev, "Unsupported number of touchscreen wires (%d)\n",
> >> +                               prop);
> >> +
> >> +       if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_NONE)
> >> +               return 0;
> >> +
> >> +       /* Touch screen is enabled, so check touch screen dt parameters */
> >> +       if (of_property_read_u32(node, "atmel,adc-ts-filter-average", &prop)) {
> >> +               dev_err(&idev->dev, "Missing atmel,adc-ts-filtering-average property in the DT.\n");
> >> +               ret = -EINVAL;
> >> +               goto error_ret;
> >> +       }
> >> +       st->ts_filter_average = prop;
> >> +       if (st->ts_filter_average > 3) {
> >> +               dev_err(&idev->dev, "Invalid atmel,adc-ts-filtering-average property in the DT.\n");
> >> +               ret = -EINVAL;
> >> +               goto error_ret;
> >> +       }
> >> +
> >> +       prop = 0;
> >> +       of_property_read_u32(node, "atmel,adc-ts-pendet-debounce", &prop);
> >> +       st->ts_pen_detect_debounce = prop;
> >> +
> >> +       /* default sample period is 2ms. The real touch sample period should be
> >> +        * this period * TSFREQ.
> >> +        */
> >> +       prop = 2000;
> >> +       of_property_read_u32(node, "atmel,adc-ts-sample-period-time", &prop);
> >> +       st->ts_sample_period_time = prop;
> >> +
> >> +       if (of_property_read_u32(node, "atmel,adc-ts-pendet-sensitivity", &prop)) {
> >> +               dev_err(&idev->dev, "Missing atmel,adc-ts-pendet-sensitivity property in the DT.\n");
> >> +               ret = -EINVAL;
> >> +               goto error_ret;
> >> +       }
> >> +       st->ts_pen_detect_sensitivity = prop;
> >> +       if (st->ts_pen_detect_sensitivity > 3) {
> >> +               dev_err(&idev->dev, "Invalid atmel,adc-ts-pendet-sensitivity property in the DT.\n");
> >> +               ret = -EINVAL;
> >> +               goto error_ret;
> >> +       }
> >> +
> >>          return 0;
> >>
> >>   error_ret:
> >> @@ -592,6 +794,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(st->ts_pen_detect_debounce * 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->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->ts_pen_detect_sensitivity
> >> +                       & AT91_ADC_ACR_PENDETSENS);
> >> +
> >> +       /* Sample Peroid Time = (TRGPER + 1) / ADCClock */
> >> +       st->ts_sample_period_val = round_up((st->ts_sample_period_time *
> >> +                       adc_clk_khz / 1000) - 1, 1);
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int at91_ts_register(struct at91_adc_state *st)
> >> +{
> >> +       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 = idev->dev.parent;
> >> +       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);
> >> +       input_free_device(st->ts_input);
> >> +}
> >> +
> >>   /*
> >>    * Since atmel adc support different ip for touchscreen mode. Through the
> >>    * IP check, we will know the touchscreen capbilities.
> >> @@ -610,6 +920,7 @@ static void atmel_adc_get_cap(struct at91_adc_state *st)
> >>          /* keep only major version number */
> >>          switch (version & 0xf00) {
> >>          case 0x500:     /* SAMA5D3 */
> >> +               st->caps.has_12bits_xy = 1;
> >>          case 0x400:     /* AT91SAM9X5/9N12 */
> >>                  st->caps.has_tsmr = 1;
> >>                  st->caps.mr_startup_mask = AT91_ADC_STARTUP;
> >> @@ -683,7 +994,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);
> >> @@ -731,6 +1042,10 @@ static int at91_adc_probe(struct platform_device *pdev)
> >>          adc_clk = st->adc_clk_rate ?
> >>                  st->adc_clk_rate : 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) {
> >> @@ -799,30 +1114,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);
> >> +               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:
> >> @@ -841,8 +1178,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);
> >> @@ -861,7 +1202,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
> >>
> >>
> >> _______________________________________________
> >> linux-arm-kernel mailing list
> >> linux-arm-kernel at lists.infradead.org
> >> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> >>
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

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

* Re: [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
  2013-07-25 16:45         ` Mark Rutland
@ 2013-08-06 10:24           ` Josh Wu
  -1 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-08-06 10:24 UTC (permalink / raw)
  To: Mark Rutland
  Cc: linux-iio, Dmitry Torokhov, nicolas.ferre, jic23, maxime.ripard,
	plagnioj, linux-arm-kernel

Dear Mark

Thanks for the detailed comment. Check mine in below:

On 7/26/2013 12:45 AM, Mark Rutland wrote:
> On Thu, Jul 25, 2013 at 08:56:38AM +0100, Josh Wu wrote:
>> Hi, Dear Mark
>>
>> On 7/22/2013 9:17 PM, Mark Rutland wrote:
>>> On Sun, Jul 14, 2013 at 09:04:29AM +0100, 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:
>>>>     which type of touch are used? (4 or 5 wires), sample period time,
>>>>     pen detect debounce time, average samples and pen detect resistor.
>>>>
>>>> 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>
>>>> ---
>>>>    .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
>>>>    arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>>>>    drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
>>>>    3 files changed, 412 insertions(+), 24 deletions(-)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>>>> index 0db2945..925d656 100644
>>>> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
>>>> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>>>> @@ -29,6 +29,19 @@ Optional properties:
>>>>      - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
>>>>      - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
>>>>                             adc_op_clk.
>>>> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
>>>> +                                4 and 5 wires touch screen.
>>> Are 4 and 5 wire configurations that can exist, or the only ones
>>> supported by the driver?
>> It can be set:
>>
>> atmel,adc-touchscreen-wires = <4>;
>> or
>> atmel,adc-touchscreen-wires = <5>;
>>
>> according to your touch screen.
> That doesn't answer my question.
>
> Is it possible that 3 or 6 wire configurations might exist, for example,
> even if not supported by this driver? Or does the design of the adc
> prevent this?

No, only 4-wire or 5-wire touch screen support in market so far.

>
> Is there any documentation that might make this clearer?
>
>>>> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
>>>> +          disabled. Since touch screen will occupied the trigger register.
>>>> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
>>>> +                                 detect.
>>> For consistency with the adc-touchscreen-wires property, and  other
>>> properties with timing information, how about
>>> atmel,adc-touchscreen-debounce-delay-us ?
>> sound nice to me.
> Additionally, is this likely to vary from board to board? This feels
> like configuration that could be done based on the compatible string...
>
>>>> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
>>>> +                                    touch screen
>>> Again, please be consistent with ts or touchscreen. It may also be good
>>> to have -us to make the units explicit (though it does leave the
>>> property name being quite a mothful):
>>>
>>> atmel,adc-touchscreen-sample-period-us ?
>> nice. I will use this one.
> Looking again at the driver code, it looks like a value derived from
> this eventually gets written to the hardware. Is this a fixed value at
> integration time, or is this a configuration value? If it's the latter,
> can the driver not derive a good value for this itself?

After a further thinking, I think it is better to remove this sample 
period us & pen detect debouce us.
Since it is a fixed value and no need to change it so far (in 
at91sam9x5ek, sama5d3xek).

>
>>>> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
>>>> +    0 means no average. 1 means average two samples. 2 means average four
>>>> +    samples. 3 means average eight samples.
>>> Is this averaging done in the hardware, or the kernel driver?
>> It is done in the hardware.
> Similarly, this seems to eventually get written to hardware, and thus
> seems more like configuration than hardware description. Why does this
> need to be in the DT?
>
> As an aside, in general it's nicer to describe a property as a logical
> value rather than the raw value that gets programmed into hardware (e.g.
> this property could by 2, 4, or 8 rather than 1, 2, or 4).
>
>> But for some soc, like AT91SAM9G45, hardware doesn't support hardware
>> average.
>> So I am wondering use it as for both hardware and softer average.
>>
>> BTW, you mentioned the kernel driver, do you mean a filter algorithm is
>> already implemented in kernel library?
> I do not know of any such filter algorithm in the kernel, though there
> may be one. I was simply confused as to what this was used for.
>
>>> If it's the latter, this can be left for the kernel to decide.
>>>
>>>> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
>>>> +    It can be 0, 1, 2, 3.
>>> I think "pendet" is a bit opaque. "pen-detect" may be better.
>> yes. I'll change this.
>>
>>> What
>>> physical property does this represent (are these discrete values, or an
>>> enumeration)?
>> This property is supported by hardware, it can change the adc internal
>> resistor value for better pen detection,
>>        * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
>> In general, we just use default value 2 for 100kOhm.
> This value eventually gets written to hardware, and seems more like
> configuration than hardware description. Why does this need to be in the
> DT?

I am a little bit confused by the hardware configuration and hardware 
description.
It seems I prefer to put all the hardware configurable value to DT. 
Since I think this can be changed in DT.
But as you mentioned above, only the hardware description can be in DT.
Could you give me a more detail about the difference between hardware 
configuration and hardware description?

Thanks in advance.

>
> Thanks,
> Mark.

[... ...]

Best Regards,
Josh Wu

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

* [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
@ 2013-08-06 10:24           ` Josh Wu
  0 siblings, 0 replies; 85+ messages in thread
From: Josh Wu @ 2013-08-06 10:24 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Mark

Thanks for the detailed comment. Check mine in below:

On 7/26/2013 12:45 AM, Mark Rutland wrote:
> On Thu, Jul 25, 2013 at 08:56:38AM +0100, Josh Wu wrote:
>> Hi, Dear Mark
>>
>> On 7/22/2013 9:17 PM, Mark Rutland wrote:
>>> On Sun, Jul 14, 2013 at 09:04:29AM +0100, 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:
>>>>     which type of touch are used? (4 or 5 wires), sample period time,
>>>>     pen detect debounce time, average samples and pen detect resistor.
>>>>
>>>> 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>
>>>> ---
>>>>    .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
>>>>    arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>>>>    drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
>>>>    3 files changed, 412 insertions(+), 24 deletions(-)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>>>> index 0db2945..925d656 100644
>>>> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
>>>> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>>>> @@ -29,6 +29,19 @@ Optional properties:
>>>>      - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
>>>>      - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
>>>>                             adc_op_clk.
>>>> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
>>>> +                                4 and 5 wires touch screen.
>>> Are 4 and 5 wire configurations that can exist, or the only ones
>>> supported by the driver?
>> It can be set:
>>
>> atmel,adc-touchscreen-wires = <4>;
>> or
>> atmel,adc-touchscreen-wires = <5>;
>>
>> according to your touch screen.
> That doesn't answer my question.
>
> Is it possible that 3 or 6 wire configurations might exist, for example,
> even if not supported by this driver? Or does the design of the adc
> prevent this?

No, only 4-wire or 5-wire touch screen support in market so far.

>
> Is there any documentation that might make this clearer?
>
>>>> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
>>>> +          disabled. Since touch screen will occupied the trigger register.
>>>> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
>>>> +                                 detect.
>>> For consistency with the adc-touchscreen-wires property, and  other
>>> properties with timing information, how about
>>> atmel,adc-touchscreen-debounce-delay-us ?
>> sound nice to me.
> Additionally, is this likely to vary from board to board? This feels
> like configuration that could be done based on the compatible string...
>
>>>> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
>>>> +                                    touch screen
>>> Again, please be consistent with ts or touchscreen. It may also be good
>>> to have -us to make the units explicit (though it does leave the
>>> property name being quite a mothful):
>>>
>>> atmel,adc-touchscreen-sample-period-us ?
>> nice. I will use this one.
> Looking again at the driver code, it looks like a value derived from
> this eventually gets written to the hardware. Is this a fixed value at
> integration time, or is this a configuration value? If it's the latter,
> can the driver not derive a good value for this itself?

After a further thinking, I think it is better to remove this sample 
period us & pen detect debouce us.
Since it is a fixed value and no need to change it so far (in 
at91sam9x5ek, sama5d3xek).

>
>>>> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
>>>> +    0 means no average. 1 means average two samples. 2 means average four
>>>> +    samples. 3 means average eight samples.
>>> Is this averaging done in the hardware, or the kernel driver?
>> It is done in the hardware.
> Similarly, this seems to eventually get written to hardware, and thus
> seems more like configuration than hardware description. Why does this
> need to be in the DT?
>
> As an aside, in general it's nicer to describe a property as a logical
> value rather than the raw value that gets programmed into hardware (e.g.
> this property could by 2, 4, or 8 rather than 1, 2, or 4).
>
>> But for some soc, like AT91SAM9G45, hardware doesn't support hardware
>> average.
>> So I am wondering use it as for both hardware and softer average.
>>
>> BTW, you mentioned the kernel driver, do you mean a filter algorithm is
>> already implemented in kernel library?
> I do not know of any such filter algorithm in the kernel, though there
> may be one. I was simply confused as to what this was used for.
>
>>> If it's the latter, this can be left for the kernel to decide.
>>>
>>>> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
>>>> +    It can be 0, 1, 2, 3.
>>> I think "pendet" is a bit opaque. "pen-detect" may be better.
>> yes. I'll change this.
>>
>>> What
>>> physical property does this represent (are these discrete values, or an
>>> enumeration)?
>> This property is supported by hardware, it can change the adc internal
>> resistor value for better pen detection,
>>        * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
>> In general, we just use default value 2 for 100kOhm.
> This value eventually gets written to hardware, and seems more like
> configuration than hardware description. Why does this need to be in the
> DT?

I am a little bit confused by the hardware configuration and hardware 
description.
It seems I prefer to put all the hardware configurable value to DT. 
Since I think this can be changed in DT.
But as you mentioned above, only the hardware description can be in DT.
Could you give me a more detail about the difference between hardware 
configuration and hardware description?

Thanks in advance.

>
> Thanks,
> Mark.

[... ...]

Best Regards,
Josh Wu

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

* Re: [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
  2013-08-06 10:24           ` Josh Wu
@ 2013-08-08 13:40             ` Mark Rutland
  -1 siblings, 0 replies; 85+ messages in thread
From: Mark Rutland @ 2013-08-08 13:40 UTC (permalink / raw)
  To: Josh Wu
  Cc: linux-iio, Dmitry Torokhov, nicolas.ferre, jic23, maxime.ripard,
	plagnioj, linux-arm-kernel

On Tue, Aug 06, 2013 at 11:24:14AM +0100, Josh Wu wrote:
> Dear Mark
> 
> Thanks for the detailed comment. Check mine in below:
> 
> On 7/26/2013 12:45 AM, Mark Rutland wrote:
> > On Thu, Jul 25, 2013 at 08:56:38AM +0100, Josh Wu wrote:
> >> Hi, Dear Mark
> >>
> >> On 7/22/2013 9:17 PM, Mark Rutland wrote:
> >>> On Sun, Jul 14, 2013 at 09:04:29AM +0100, 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:
> >>>>     which type of touch are used? (4 or 5 wires), sample period time,
> >>>>     pen detect debounce time, average samples and pen detect resistor.
> >>>>
> >>>> 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>
> >>>> ---
> >>>>    .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
> >>>>    arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
> >>>>    drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
> >>>>    3 files changed, 412 insertions(+), 24 deletions(-)
> >>>>
> >>>> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >>>> index 0db2945..925d656 100644
> >>>> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >>>> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >>>> @@ -29,6 +29,19 @@ Optional properties:
> >>>>      - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
> >>>>      - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
> >>>>                             adc_op_clk.
> >>>> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
> >>>> +                                4 and 5 wires touch screen.
> >>> Are 4 and 5 wire configurations that can exist, or the only ones
> >>> supported by the driver?
> >> It can be set:
> >>
> >> atmel,adc-touchscreen-wires = <4>;
> >> or
> >> atmel,adc-touchscreen-wires = <5>;
> >>
> >> according to your touch screen.
> > That doesn't answer my question.
> >
> > Is it possible that 3 or 6 wire configurations might exist, for example,
> > even if not supported by this driver? Or does the design of the adc
> > prevent this?
> 
> No, only 4-wire or 5-wire touch screen support in market so far.

Ok. The point that I was trying to get at was that "Only support 4 and 5
wires touch screen" seems to be a description of the driver rather than
a physical limitation that should limit what we can describe in dt.

> 
> >
> > Is there any documentation that might make this clearer?
> >
> >>>> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> >>>> +          disabled. Since touch screen will occupied the trigger register.
> >>>> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
> >>>> +                                 detect.
> >>> For consistency with the adc-touchscreen-wires property, and  other
> >>> properties with timing information, how about
> >>> atmel,adc-touchscreen-debounce-delay-us ?
> >> sound nice to me.
> > Additionally, is this likely to vary from board to board? This feels
> > like configuration that could be done based on the compatible string...
> >
> >>>> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
> >>>> +                                    touch screen
> >>> Again, please be consistent with ts or touchscreen. It may also be good
> >>> to have -us to make the units explicit (though it does leave the
> >>> property name being quite a mothful):
> >>>
> >>> atmel,adc-touchscreen-sample-period-us ?
> >> nice. I will use this one.
> > Looking again at the driver code, it looks like a value derived from
> > this eventually gets written to the hardware. Is this a fixed value at
> > integration time, or is this a configuration value? If it's the latter,
> > can the driver not derive a good value for this itself?
> 
> After a further thinking, I think it is better to remove this sample 
> period us & pen detect debouce us.
> Since it is a fixed value and no need to change it so far (in 
> at91sam9x5ek, sama5d3xek).

Ok.

> 
> >
> >>>> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
> >>>> +    0 means no average. 1 means average two samples. 2 means average four
> >>>> +    samples. 3 means average eight samples.
> >>> Is this averaging done in the hardware, or the kernel driver?
> >> It is done in the hardware.
> > Similarly, this seems to eventually get written to hardware, and thus
> > seems more like configuration than hardware description. Why does this
> > need to be in the DT?
> >
> > As an aside, in general it's nicer to describe a property as a logical
> > value rather than the raw value that gets programmed into hardware (e.g.
> > this property could by 2, 4, or 8 rather than 1, 2, or 4).
> >
> >> But for some soc, like AT91SAM9G45, hardware doesn't support hardware
> >> average.
> >> So I am wondering use it as for both hardware and softer average.
> >>
> >> BTW, you mentioned the kernel driver, do you mean a filter algorithm is
> >> already implemented in kernel library?
> > I do not know of any such filter algorithm in the kernel, though there
> > may be one. I was simply confused as to what this was used for.
> >
> >>> If it's the latter, this can be left for the kernel to decide.
> >>>
> >>>> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
> >>>> +    It can be 0, 1, 2, 3.
> >>> I think "pendet" is a bit opaque. "pen-detect" may be better.
> >> yes. I'll change this.
> >>
> >>> What
> >>> physical property does this represent (are these discrete values, or an
> >>> enumeration)?
> >> This property is supported by hardware, it can change the adc internal
> >> resistor value for better pen detection,
> >>        * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
> >> In general, we just use default value 2 for 100kOhm.
> > This value eventually gets written to hardware, and seems more like
> > configuration than hardware description. Why does this need to be in the
> > DT?
> 
> I am a little bit confused by the hardware configuration and hardware 
> description.
> It seems I prefer to put all the hardware configurable value to DT. 
> Since I think this can be changed in DT.
> But as you mentioned above, only the hardware description can be in DT.
> Could you give me a more detail about the difference between hardware 
> configuration and hardware description?

It's admittedly a gray area, but the basic idea would be that anything
we might feasibly want to change the value of later shouldn't go into
the DT, while properties of the hardware that might influence those
decisions should be in the DT. It seems to me that the pen detect
resistor value is something we might want to change later, if people
found a particular touchscreen were too sensitive, for instance.
However, maybe not.

Thanks,
Mark.

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

* [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
@ 2013-08-08 13:40             ` Mark Rutland
  0 siblings, 0 replies; 85+ messages in thread
From: Mark Rutland @ 2013-08-08 13:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Aug 06, 2013 at 11:24:14AM +0100, Josh Wu wrote:
> Dear Mark
> 
> Thanks for the detailed comment. Check mine in below:
> 
> On 7/26/2013 12:45 AM, Mark Rutland wrote:
> > On Thu, Jul 25, 2013 at 08:56:38AM +0100, Josh Wu wrote:
> >> Hi, Dear Mark
> >>
> >> On 7/22/2013 9:17 PM, Mark Rutland wrote:
> >>> On Sun, Jul 14, 2013 at 09:04:29AM +0100, 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:
> >>>>     which type of touch are used? (4 or 5 wires), sample period time,
> >>>>     pen detect debounce time, average samples and pen detect resistor.
> >>>>
> >>>> 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>
> >>>> ---
> >>>>    .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
> >>>>    arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
> >>>>    drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
> >>>>    3 files changed, 412 insertions(+), 24 deletions(-)
> >>>>
> >>>> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >>>> index 0db2945..925d656 100644
> >>>> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >>>> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> >>>> @@ -29,6 +29,19 @@ Optional properties:
> >>>>      - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
> >>>>      - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
> >>>>                             adc_op_clk.
> >>>> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
> >>>> +                                4 and 5 wires touch screen.
> >>> Are 4 and 5 wire configurations that can exist, or the only ones
> >>> supported by the driver?
> >> It can be set:
> >>
> >> atmel,adc-touchscreen-wires = <4>;
> >> or
> >> atmel,adc-touchscreen-wires = <5>;
> >>
> >> according to your touch screen.
> > That doesn't answer my question.
> >
> > Is it possible that 3 or 6 wire configurations might exist, for example,
> > even if not supported by this driver? Or does the design of the adc
> > prevent this?
> 
> No, only 4-wire or 5-wire touch screen support in market so far.

Ok. The point that I was trying to get at was that "Only support 4 and 5
wires touch screen" seems to be a description of the driver rather than
a physical limitation that should limit what we can describe in dt.

> 
> >
> > Is there any documentation that might make this clearer?
> >
> >>>> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> >>>> +          disabled. Since touch screen will occupied the trigger register.
> >>>> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
> >>>> +                                 detect.
> >>> For consistency with the adc-touchscreen-wires property, and  other
> >>> properties with timing information, how about
> >>> atmel,adc-touchscreen-debounce-delay-us ?
> >> sound nice to me.
> > Additionally, is this likely to vary from board to board? This feels
> > like configuration that could be done based on the compatible string...
> >
> >>>> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
> >>>> +                                    touch screen
> >>> Again, please be consistent with ts or touchscreen. It may also be good
> >>> to have -us to make the units explicit (though it does leave the
> >>> property name being quite a mothful):
> >>>
> >>> atmel,adc-touchscreen-sample-period-us ?
> >> nice. I will use this one.
> > Looking again at the driver code, it looks like a value derived from
> > this eventually gets written to the hardware. Is this a fixed value at
> > integration time, or is this a configuration value? If it's the latter,
> > can the driver not derive a good value for this itself?
> 
> After a further thinking, I think it is better to remove this sample 
> period us & pen detect debouce us.
> Since it is a fixed value and no need to change it so far (in 
> at91sam9x5ek, sama5d3xek).

Ok.

> 
> >
> >>>> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
> >>>> +    0 means no average. 1 means average two samples. 2 means average four
> >>>> +    samples. 3 means average eight samples.
> >>> Is this averaging done in the hardware, or the kernel driver?
> >> It is done in the hardware.
> > Similarly, this seems to eventually get written to hardware, and thus
> > seems more like configuration than hardware description. Why does this
> > need to be in the DT?
> >
> > As an aside, in general it's nicer to describe a property as a logical
> > value rather than the raw value that gets programmed into hardware (e.g.
> > this property could by 2, 4, or 8 rather than 1, 2, or 4).
> >
> >> But for some soc, like AT91SAM9G45, hardware doesn't support hardware
> >> average.
> >> So I am wondering use it as for both hardware and softer average.
> >>
> >> BTW, you mentioned the kernel driver, do you mean a filter algorithm is
> >> already implemented in kernel library?
> > I do not know of any such filter algorithm in the kernel, though there
> > may be one. I was simply confused as to what this was used for.
> >
> >>> If it's the latter, this can be left for the kernel to decide.
> >>>
> >>>> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
> >>>> +    It can be 0, 1, 2, 3.
> >>> I think "pendet" is a bit opaque. "pen-detect" may be better.
> >> yes. I'll change this.
> >>
> >>> What
> >>> physical property does this represent (are these discrete values, or an
> >>> enumeration)?
> >> This property is supported by hardware, it can change the adc internal
> >> resistor value for better pen detection,
> >>        * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
> >> In general, we just use default value 2 for 100kOhm.
> > This value eventually gets written to hardware, and seems more like
> > configuration than hardware description. Why does this need to be in the
> > DT?
> 
> I am a little bit confused by the hardware configuration and hardware 
> description.
> It seems I prefer to put all the hardware configurable value to DT. 
> Since I think this can be changed in DT.
> But as you mentioned above, only the hardware description can be in DT.
> Could you give me a more detail about the difference between hardware 
> configuration and hardware description?

It's admittedly a gray area, but the basic idea would be that anything
we might feasibly want to change the value of later shouldn't go into
the DT, while properties of the hardware that might influence those
decisions should be in the DT. It seems to me that the pen detect
resistor value is something we might want to change later, if people
found a particular touchscreen were too sensitive, for instance.
However, maybe not.

Thanks,
Mark.

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

end of thread, other threads:[~2013-08-08 13:40 UTC | newest]

Thread overview: 85+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-14  8:04 [PATCH 0/5] iio: at91: Add touch screen support in at91 adc Josh Wu
2013-07-14  8:04 ` Josh Wu
2013-07-14  8:04 ` [PATCH 1/5] iio: at91: use adc_clk_khz to make the calculation not easy to large than u32 Josh Wu
2013-07-14  8:04   ` Josh Wu
2013-07-15 12:52   ` Maxime Ripard
2013-07-15 12:52     ` Maxime Ripard
2013-07-16  7:54     ` Josh Wu
2013-07-16  7:54       ` Josh Wu
2013-07-14  8:04 ` [PATCH 2/5] iio: at91: Use different prescal, startup mask in MR for different IP Josh Wu
2013-07-14  8:04   ` Josh Wu
2013-07-15 12:58   ` Maxime Ripard
2013-07-15 12:58     ` Maxime Ripard
2013-07-16  8:35     ` Josh Wu
2013-07-16  8:35       ` Josh Wu
2013-07-16  8:46       ` Nicolas Ferre
2013-07-16  8:46         ` Nicolas Ferre
2013-07-16 11:20         ` Maxime Ripard
2013-07-16 11:20           ` Maxime Ripard
     [not found]         ` <51E50864.6020904-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2013-07-16 11:30           ` Thomas Petazzoni
2013-07-16 11:30             ` Thomas Petazzoni
2013-07-16 11:30             ` Thomas Petazzoni
2013-07-16 19:03             ` Jonathan Cameron
2013-07-16 19:03               ` Jonathan Cameron
2013-07-16 19:03               ` Jonathan Cameron
     [not found]               ` <51E5990A.4050709-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2013-07-16 19:17                 ` Thomas Petazzoni
2013-07-16 19:17                   ` Thomas Petazzoni
2013-07-16 19:17                   ` Thomas Petazzoni
2013-07-17  8:23                   ` Nicolas Ferre
2013-07-17  8:23                     ` Nicolas Ferre
2013-07-17  8:23                     ` Nicolas Ferre
2013-07-17  8:12     ` Nicolas Ferre
2013-07-17  8:12       ` Nicolas Ferre
2013-07-17  9:07       ` Josh Wu
2013-07-17  9:07         ` Josh Wu
2013-07-17 15:40       ` Maxime Ripard
2013-07-17 15:40         ` Maxime Ripard
2013-07-17  7:58   ` Nicolas Ferre
2013-07-17  7:58     ` Nicolas Ferre
2013-07-17 10:09     ` Josh Wu
2013-07-17 10:09       ` Josh Wu
2013-07-20  9:35       ` Jonathan Cameron
2013-07-20  9:35         ` Jonathan Cameron
2013-07-14  8:04 ` [PATCH 3/5] iio: at91: ADC start-up time calculation changed since at91sam9x5 Josh Wu
2013-07-14  8:04   ` Josh Wu
2013-07-20  9:39   ` Jonathan Cameron
2013-07-20  9:39     ` Jonathan Cameron
2013-07-25  7:35     ` Josh Wu
2013-07-25  7:35       ` Josh Wu
2013-07-14  8:04 ` [PATCH 4/5] iio: at91: add an optional dt property for for adc clock hz Josh Wu
2013-07-14  8:04   ` Josh Wu
2013-07-15 13:06   ` Maxime Ripard
2013-07-15 13:06     ` Maxime Ripard
2013-07-16  7:55     ` Josh Wu
2013-07-16  7:55       ` Josh Wu
2013-07-16 10:30       ` Maxime Ripard
2013-07-16 10:30         ` Maxime Ripard
2013-07-16 11:16         ` Lars-Peter Clausen
2013-07-16 11:16           ` Lars-Peter Clausen
2013-07-25  7:29           ` Josh Wu
2013-07-25  7:29             ` Josh Wu
2013-07-25 12:01   ` boris brezillon
2013-07-25 12:01     ` boris brezillon
2013-07-25 12:11     ` boris brezillon
2013-07-25 12:11       ` boris brezillon
2013-07-14  8:04 ` [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver Josh Wu
2013-07-14  8:04   ` Josh Wu
2013-07-15 13:15   ` Maxime Ripard
2013-07-15 13:15     ` Maxime Ripard
2013-07-16  9:09     ` Josh Wu
2013-07-16  9:09       ` Josh Wu
2013-07-16 11:43       ` Maxime Ripard
2013-07-16 11:43         ` Maxime Ripard
     [not found]   ` <1373789069-11604-6-git-send-email-josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2013-07-20  9:57     ` Jonathan Cameron
2013-07-20  9:57       ` Jonathan Cameron
2013-07-20  9:57       ` Jonathan Cameron
2013-07-22 13:17   ` Mark Rutland
2013-07-22 13:17     ` Mark Rutland
2013-07-25  7:56     ` Josh Wu
2013-07-25  7:56       ` Josh Wu
2013-07-25 16:45       ` Mark Rutland
2013-07-25 16:45         ` Mark Rutland
2013-08-06 10:24         ` Josh Wu
2013-08-06 10:24           ` Josh Wu
2013-08-08 13:40           ` Mark Rutland
2013-08-08 13:40             ` Mark Rutland

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.