All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/5] clk: ep93xx: Implement clk_get_parent()
       [not found] <56558B23.4080506@gmail.com>
@ 2015-11-25 11:50   ` Alexander Sverdlin
  2015-11-25 11:50   ` Alexander Sverdlin
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 22+ messages in thread
From: Alexander Sverdlin @ 2015-11-25 11:50 UTC (permalink / raw)
  To: Hartley Sweeten, Ryan Mallon, linux-arm-kernel, linux-iio
  Cc: Russell King, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald

Trivial implementation of clk_get_parent(), but necessary for some drivers,
such as ADC.

Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
---
 arch/arm/mach-ep93xx/clock.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index 39ef3b6..b9cd9d7 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -475,6 +475,12 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
 }
 EXPORT_SYMBOL(clk_set_rate);

+struct clk *clk_get_parent(struct clk *clk)
+{
+	return clk->parent;
+}
+EXPORT_SYMBOL(clk_get_parent);
+

 static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 };
 static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 };

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

* [PATCH 1/5] clk: ep93xx: Implement clk_get_parent()
@ 2015-11-25 11:50   ` Alexander Sverdlin
  0 siblings, 0 replies; 22+ messages in thread
From: Alexander Sverdlin @ 2015-11-25 11:50 UTC (permalink / raw)
  To: linux-arm-kernel

Trivial implementation of clk_get_parent(), but necessary for some drivers,
such as ADC.

Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
---
 arch/arm/mach-ep93xx/clock.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index 39ef3b6..b9cd9d7 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -475,6 +475,12 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
 }
 EXPORT_SYMBOL(clk_set_rate);

+struct clk *clk_get_parent(struct clk *clk)
+{
+	return clk->parent;
+}
+EXPORT_SYMBOL(clk_get_parent);
+

 static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 };
 static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 };

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

* [PATCH 2/5] clk: ep93xx: Add ADC clock
       [not found] <56558B23.4080506@gmail.com>
@ 2015-11-25 11:50   ` Alexander Sverdlin
  2015-11-25 11:50   ` Alexander Sverdlin
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 22+ messages in thread
From: Alexander Sverdlin @ 2015-11-25 11:50 UTC (permalink / raw)
  To: Hartley Sweeten, Ryan Mallon, linux-arm-kernel, linux-iio
  Cc: Russell King, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald

ADC and keypad controller clocks share the same control register, so use the
existing infrastructure to add ADC clock support for Cirrus Logic EP93xx SoCs.

Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
---
 arch/arm/mach-ep93xx/clock.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index b9cd9d7..4253426 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -98,6 +98,13 @@ static struct clk clk_keypad = {
 	.enable_mask	= EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
 	.set_rate	= set_keytchclk_rate,
 };
+static struct clk clk_adc = {
+	.parent		= &clk_xtali,
+	.sw_locked	= 1,
+	.enable_reg	= EP93XX_SYSCON_KEYTCHCLKDIV,
+	.enable_mask	= EP93XX_SYSCON_KEYTCHCLKDIV_TSEN,
+	.set_rate	= set_keytchclk_rate,
+};
 static struct clk clk_spi = {
 	.parent		= &clk_xtali,
 	.rate		= EP93XX_EXT_CLK_RATE,
@@ -214,6 +221,7 @@ static struct clk_lookup clocks[] = {
 	INIT_CK(NULL,			"pll2",		&clk_pll2),
 	INIT_CK("ohci-platform",	NULL,		&clk_usb_host),
 	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
+	INIT_CK("ep93xx-adc",		NULL,		&clk_adc),
 	INIT_CK("ep93xx-fb",		NULL,		&clk_video),
 	INIT_CK("ep93xx-spi.0",		NULL,		&clk_spi),
 	INIT_CK("ep93xx-i2s",		"mclk",		&clk_i2s_mclk),

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

* [PATCH 2/5] clk: ep93xx: Add ADC clock
@ 2015-11-25 11:50   ` Alexander Sverdlin
  0 siblings, 0 replies; 22+ messages in thread
From: Alexander Sverdlin @ 2015-11-25 11:50 UTC (permalink / raw)
  To: linux-arm-kernel

ADC and keypad controller clocks share the same control register, so use the
existing infrastructure to add ADC clock support for Cirrus Logic EP93xx SoCs.

Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
---
 arch/arm/mach-ep93xx/clock.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index b9cd9d7..4253426 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -98,6 +98,13 @@ static struct clk clk_keypad = {
 	.enable_mask	= EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
 	.set_rate	= set_keytchclk_rate,
 };
+static struct clk clk_adc = {
+	.parent		= &clk_xtali,
+	.sw_locked	= 1,
+	.enable_reg	= EP93XX_SYSCON_KEYTCHCLKDIV,
+	.enable_mask	= EP93XX_SYSCON_KEYTCHCLKDIV_TSEN,
+	.set_rate	= set_keytchclk_rate,
+};
 static struct clk clk_spi = {
 	.parent		= &clk_xtali,
 	.rate		= EP93XX_EXT_CLK_RATE,
@@ -214,6 +221,7 @@ static struct clk_lookup clocks[] = {
 	INIT_CK(NULL,			"pll2",		&clk_pll2),
 	INIT_CK("ohci-platform",	NULL,		&clk_usb_host),
 	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
+	INIT_CK("ep93xx-adc",		NULL,		&clk_adc),
 	INIT_CK("ep93xx-fb",		NULL,		&clk_video),
 	INIT_CK("ep93xx-spi.0",		NULL,		&clk_spi),
 	INIT_CK("ep93xx-i2s",		"mclk",		&clk_i2s_mclk),

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

* [PATCH 3/5] ep93xx: Add ADC platform device support to core
       [not found] <56558B23.4080506@gmail.com>
@ 2015-11-25 11:50   ` Alexander Sverdlin
  2015-11-25 11:50   ` Alexander Sverdlin
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 22+ messages in thread
From: Alexander Sverdlin @ 2015-11-25 11:50 UTC (permalink / raw)
  To: Hartley Sweeten, Ryan Mallon, linux-arm-kernel, linux-iio
  Cc: Russell King, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald

Newly provided ep93xx_register_adc() could be used by machine-specific code
to create ADC platform device on Cirrus Logic EP93xx SoC-based machines.

Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
---
 arch/arm/mach-ep93xx/core.c                  | 24 ++++++++++++++++++++++++
 arch/arm/mach-ep93xx/include/mach/platform.h |  1 +
 arch/arm/mach-ep93xx/soc.h                   |  1 +
 3 files changed, 26 insertions(+)

diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index c393b1b..f53c618 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -821,6 +821,30 @@ void ep93xx_ide_release_gpio(struct platform_device *pdev)
 EXPORT_SYMBOL(ep93xx_ide_release_gpio);

 /*************************************************************************
+ * EP93xx ADC
+ *************************************************************************/
+static struct resource ep93xx_adc_resources[] = {
+	DEFINE_RES_MEM(EP93XX_ADC_PHYS_BASE, 0x28),
+	DEFINE_RES_IRQ(IRQ_EP93XX_TOUCH),
+};
+
+static struct platform_device ep93xx_adc_device = {
+	.name		= "ep93xx-adc",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(ep93xx_adc_resources),
+	.resource	= ep93xx_adc_resources,
+};
+
+void __init ep93xx_register_adc(void)
+{
+	/* Power up ADC, deactivate Touch Screen Controller */
+	ep93xx_devcfg_set_clear(EP93XX_SYSCON_DEVCFG_TIN,
+				EP93XX_SYSCON_DEVCFG_ADCPD);
+
+	platform_device_register(&ep93xx_adc_device);
+}
+
+/*************************************************************************
  * EP93xx Security peripheral
  *************************************************************************/

diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index 4c0bbd9..db08396 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -52,6 +52,7 @@ int ep93xx_i2s_acquire(void);
 void ep93xx_i2s_release(void);
 void ep93xx_register_ac97(void);
 void ep93xx_register_ide(void);
+void ep93xx_register_adc(void);
 int ep93xx_ide_acquire_gpio(struct platform_device *pdev);
 void ep93xx_ide_release_gpio(struct platform_device *pdev);

diff --git a/arch/arm/mach-ep93xx/soc.h b/arch/arm/mach-ep93xx/soc.h
index 7bf7ff8..d20e631 100644
--- a/arch/arm/mach-ep93xx/soc.h
+++ b/arch/arm/mach-ep93xx/soc.h
@@ -95,6 +95,7 @@
 #define EP93XX_KEY_MATRIX_PHYS_BASE	EP93XX_APB_PHYS(0x000f0000)
 #define EP93XX_KEY_MATRIX_BASE		EP93XX_APB_IOMEM(0x000f0000)

+#define EP93XX_ADC_PHYS_BASE		EP93XX_APB_PHYS(0x00100000)
 #define EP93XX_ADC_BASE			EP93XX_APB_IOMEM(0x00100000)
 #define EP93XX_TOUCHSCREEN_BASE		EP93XX_APB_IOMEM(0x00100000)


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

* [PATCH 3/5] ep93xx: Add ADC platform device support to core
@ 2015-11-25 11:50   ` Alexander Sverdlin
  0 siblings, 0 replies; 22+ messages in thread
From: Alexander Sverdlin @ 2015-11-25 11:50 UTC (permalink / raw)
  To: linux-arm-kernel

Newly provided ep93xx_register_adc() could be used by machine-specific code
to create ADC platform device on Cirrus Logic EP93xx SoC-based machines.

Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
---
 arch/arm/mach-ep93xx/core.c                  | 24 ++++++++++++++++++++++++
 arch/arm/mach-ep93xx/include/mach/platform.h |  1 +
 arch/arm/mach-ep93xx/soc.h                   |  1 +
 3 files changed, 26 insertions(+)

diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index c393b1b..f53c618 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -821,6 +821,30 @@ void ep93xx_ide_release_gpio(struct platform_device *pdev)
 EXPORT_SYMBOL(ep93xx_ide_release_gpio);

 /*************************************************************************
+ * EP93xx ADC
+ *************************************************************************/
+static struct resource ep93xx_adc_resources[] = {
+	DEFINE_RES_MEM(EP93XX_ADC_PHYS_BASE, 0x28),
+	DEFINE_RES_IRQ(IRQ_EP93XX_TOUCH),
+};
+
+static struct platform_device ep93xx_adc_device = {
+	.name		= "ep93xx-adc",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(ep93xx_adc_resources),
+	.resource	= ep93xx_adc_resources,
+};
+
+void __init ep93xx_register_adc(void)
+{
+	/* Power up ADC, deactivate Touch Screen Controller */
+	ep93xx_devcfg_set_clear(EP93XX_SYSCON_DEVCFG_TIN,
+				EP93XX_SYSCON_DEVCFG_ADCPD);
+
+	platform_device_register(&ep93xx_adc_device);
+}
+
+/*************************************************************************
  * EP93xx Security peripheral
  *************************************************************************/

diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index 4c0bbd9..db08396 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -52,6 +52,7 @@ int ep93xx_i2s_acquire(void);
 void ep93xx_i2s_release(void);
 void ep93xx_register_ac97(void);
 void ep93xx_register_ide(void);
+void ep93xx_register_adc(void);
 int ep93xx_ide_acquire_gpio(struct platform_device *pdev);
 void ep93xx_ide_release_gpio(struct platform_device *pdev);

diff --git a/arch/arm/mach-ep93xx/soc.h b/arch/arm/mach-ep93xx/soc.h
index 7bf7ff8..d20e631 100644
--- a/arch/arm/mach-ep93xx/soc.h
+++ b/arch/arm/mach-ep93xx/soc.h
@@ -95,6 +95,7 @@
 #define EP93XX_KEY_MATRIX_PHYS_BASE	EP93XX_APB_PHYS(0x000f0000)
 #define EP93XX_KEY_MATRIX_BASE		EP93XX_APB_IOMEM(0x000f0000)

+#define EP93XX_ADC_PHYS_BASE		EP93XX_APB_PHYS(0x00100000)
 #define EP93XX_ADC_BASE			EP93XX_APB_IOMEM(0x00100000)
 #define EP93XX_TOUCHSCREEN_BASE		EP93XX_APB_IOMEM(0x00100000)

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

* [PATCH 4/5] edb93xx: Add ADC platform device
       [not found] <56558B23.4080506@gmail.com>
@ 2015-11-25 11:50   ` Alexander Sverdlin
  2015-11-25 11:50   ` Alexander Sverdlin
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 22+ messages in thread
From: Alexander Sverdlin @ 2015-11-25 11:50 UTC (permalink / raw)
  To: Hartley Sweeten, Ryan Mallon, linux-arm-kernel, linux-iio
  Cc: Russell King, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald

This enables the creation of ADC platform device on EDB93xx series of Cirrus
Logic evaluation boards. The driver for this device must be enabled separately,
either as built-in, or a module.

Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
---
 arch/arm/mach-ep93xx/edb93xx.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c
index ad92d9f..8da0127 100644
--- a/arch/arm/mach-ep93xx/edb93xx.c
+++ b/arch/arm/mach-ep93xx/edb93xx.c
@@ -264,6 +264,7 @@ static void __init edb93xx_init_machine(void)
 	edb93xx_register_pwm();
 	edb93xx_register_fb();
 	edb93xx_register_ide();
+	ep93xx_register_adc();
 }



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

* [PATCH 4/5] edb93xx: Add ADC platform device
@ 2015-11-25 11:50   ` Alexander Sverdlin
  0 siblings, 0 replies; 22+ messages in thread
From: Alexander Sverdlin @ 2015-11-25 11:50 UTC (permalink / raw)
  To: linux-arm-kernel

This enables the creation of ADC platform device on EDB93xx series of Cirrus
Logic evaluation boards. The driver for this device must be enabled separately,
either as built-in, or a module.

Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
---
 arch/arm/mach-ep93xx/edb93xx.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c
index ad92d9f..8da0127 100644
--- a/arch/arm/mach-ep93xx/edb93xx.c
+++ b/arch/arm/mach-ep93xx/edb93xx.c
@@ -264,6 +264,7 @@ static void __init edb93xx_init_machine(void)
 	edb93xx_register_pwm();
 	edb93xx_register_fb();
 	edb93xx_register_ide();
+	ep93xx_register_adc();
 }

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

* [PATCH 5/5] iio: adc: New driver for Cirrus Logic EP93xx ADC
       [not found] <56558B23.4080506@gmail.com>
@ 2015-11-25 11:51   ` Alexander Sverdlin
  2015-11-25 11:50   ` Alexander Sverdlin
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 22+ messages in thread
From: Alexander Sverdlin @ 2015-11-25 11:51 UTC (permalink / raw)
  To: Hartley Sweeten, Ryan Mallon, linux-arm-kernel, linux-iio
  Cc: Russell King, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald

New driver adding support for ADC found on Cirrus Logic EP93xx series of SoCs.
Board specific code must take care to create platform device with all necessary
resources.

Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
---
 drivers/iio/adc/Kconfig      |  11 ++
 drivers/iio/adc/Makefile     |   1 +
 drivers/iio/adc/ep93xx_adc.c | 253 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 265 insertions(+)
 create mode 100644 drivers/iio/adc/ep93xx_adc.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 7868c74..2ee8b8b 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -172,6 +172,17 @@ config DA9150_GPADC
 	  To compile this driver as a module, choose M here: the module will be
 	  called berlin2-adc.

+config EP93XX_ADC
+	tristate "Cirrus Logic EP93XX ADC driver"
+	depends on ARCH_EP93XX
+	help
+	  Driver for the ADC module on the EP93XX series of SoC from Cirrus Logic.
+	  It's recommended to switch on CONFIG_HIGH_RES_TIMERS option, in this
+	  case driver will reduce its CPU usage by 70% in some use cases.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called ep93xx_adc.
+
 config EXYNOS_ADC
 	tristate "Exynos ADC driver support"
 	depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 99b37a9..5481b42 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
 obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
 obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
 obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
+obj-$(CONFIG_EP93XX_ADC) += ep93xx_adc.o
 obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
 obj-$(CONFIG_HI8435) += hi8435.o
 obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c
new file mode 100644
index 0000000..ebaacb9
--- /dev/null
+++ b/drivers/iio/adc/ep93xx_adc.c
@@ -0,0 +1,253 @@
+/*
+ * Driver for ADC module on the Cirrus Logic EP93xx series of SoCs
+ *
+ * Copyright (C) 2015 Alexander Sverdlin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The driver uses polling to get the conversion status. According to EP93xx
+ * datasheets, reading ADCResult register starts the conversion, but user also
+ * responsible for ensuring that delay between adjacent conversion triggers is
+ * long enough so that maximum allowed conversion rate is not exceeded. This
+ * basically renders IRQ mode unusable.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/io.h>
+#include <linux/irqflags.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+#define EP93XX_NUM_CHANNELS 8
+
+#define ep93xx_adc_reg_read(reg)	__raw_readl(reg)
+#define ep93xx_adc_reg_write(val, reg)	__raw_writel(val, reg)
+
+/*
+ * This code could benefit from real HR Timers, but jiffy granularity would
+ * lower ADC conversion rate down to CONFIG_HZ, so we fallback to busy wait
+ * in such case.
+ *
+ * HR Timers-based version loads CPU only up to 30% during back to back ADC
+ * conversion, while busy wait-based version consumes whole CPU power.
+ */
+#ifdef CONFIG_HIGH_RES_TIMERS
+#define ep93xx_adc_delay(usmin, usmax) usleep_range(usmin, usmax)
+#else
+#define ep93xx_adc_delay(usmin, usmax) udelay(usmin)
+#endif
+
+#define EP93XX_ADC_RESULT	0x08
+#define   EP93XX_ADC_SDR	BIT(31)
+#define EP93XX_ADC_SWITCH	0x18
+#define EP93XX_ADC_SW_LOCK	0x20
+#define EP93XX_ADC_INT_EN	0x24
+#define   EP93XX_ADC_RINTEN	BIT(11)
+
+struct ep93xx_adc_priv {
+	struct clk *clk;
+	void __iomem *base;
+	int lastch;
+	struct mutex lock;
+};
+
+#define EP93XX_ADC_CH(index, dname, ename, swcfg) {		\
+	.type = IIO_VOLTAGE,					\
+	.indexed = 1,						\
+	.channel = index,					\
+	.address = swcfg,					\
+	.datasheet_name = dname,				\
+	.extend_name = ename,					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) |	\
+				   BIT(IIO_CHAN_INFO_OFFSET),	\
+}
+
+/*
+ * Numbering scheme for channels 0..4 is defined in EP9301 and EP9302 datasheets.
+ * EP9307, EP9312 and EP9312 have 3 channels more (total 8), but the numering is
+ * not defined. So the last three are numbered randomly, let's say.
+ */
+static const struct iio_chan_spec ep93xx_adc_channels[EP93XX_NUM_CHANNELS] = {
+	EP93XX_ADC_CH(0, "YM",	"ym",	0x608),
+	EP93XX_ADC_CH(1, "SXP",	"sxp",	0x680),
+	EP93XX_ADC_CH(2, "SXM",	"sxm",	0x640),
+	EP93XX_ADC_CH(3, "SYP",	"syp",	0x620),
+	EP93XX_ADC_CH(4, "SYM",	"sym",	0x610),
+	EP93XX_ADC_CH(5, "XP",	"xp",	0x601),
+	EP93XX_ADC_CH(6, "XM",	"xm",	0x602),
+	EP93XX_ADC_CH(7, "YP",	"yp",	0x604),
+};
+
+static int ep93xx_read_raw(struct iio_dev *iiodev,
+			   struct iio_chan_spec const *channel, int *value,
+			   int *shift, long mask)
+{
+	struct ep93xx_adc_priv *priv = iio_priv(iiodev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&priv->lock);
+		if (priv->lastch != channel->channel) {
+			priv->lastch = channel->channel;
+			/*
+			 * Switch register is software-locked, unlocking must be
+			 * immediately followed by write
+			 */
+			local_irq_disable();
+			ep93xx_adc_reg_write(0xAA,
+					     priv->base + EP93XX_ADC_SW_LOCK);
+			ep93xx_adc_reg_write(channel->address,
+					     priv->base + EP93XX_ADC_SWITCH);
+			local_irq_enable();
+			/*
+			 * Settling delay depends on module clock and could be
+			 * 2ms or 500us
+			 */
+			ep93xx_adc_delay(2000, 2000);
+		}
+		/* Start the conversion, eventually discarding old result */
+		ep93xx_adc_reg_read(priv->base + EP93XX_ADC_RESULT);
+		/* Ensure maximun conversion rate is not exceeded */
+		ep93xx_adc_delay(DIV_ROUND_UP(1000000, 925),
+				 DIV_ROUND_UP(1000000, 925));
+		/* At this point conversion must be completed, but anyway... */
+		while (1) {
+			u32 t;
+
+			t = ep93xx_adc_reg_read(priv->base + EP93XX_ADC_RESULT);
+			if (t & EP93XX_ADC_SDR) {
+				/* Sign extend lower 16 bits */
+				*value = (s16)t;
+				break;
+			}
+		}
+		mutex_unlock(&priv->lock);
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_OFFSET:
+		/* According to datasheet, range is -25000..25000 */
+		*value = 25000;
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		/* Typical supply voltage is 3.3v */
+		*value = (1ULL << 32) * 3300 / 50000;
+		*shift = 32;
+		return IIO_VAL_FRACTIONAL_LOG2;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info ep93xx_adc_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = ep93xx_read_raw,
+};
+
+static int ep93xx_adc_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct iio_dev *iiodev;
+	struct ep93xx_adc_priv *priv;
+	struct clk *pclk;
+	struct resource *res;
+
+	iiodev = devm_iio_device_alloc(&pdev->dev,
+				       sizeof(struct ep93xx_adc_priv));
+	if (!iiodev)
+		return -ENOMEM;
+	priv = iio_priv(iiodev);
+
+	priv->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(priv->clk)) {
+		dev_err(&pdev->dev, "Cannot obtain clock");
+		return PTR_ERR(priv->clk);
+	}
+
+	pclk = clk_get_parent(priv->clk);
+	if (!pclk) {
+		dev_warn(&pdev->dev, "Cannot obtain parent clock");
+	} else {
+		/*
+		 * This is actually a place for improvement:
+		 * EP93xx ADC supports two clock divisors -- 4 and 16,
+		 * resulting in conversion rates 3750 and 925 samples per second
+		 * respectively with 500uS or 2ms settling time respectively.
+		 * One might find this interesting enough to be configurable.
+		 */
+		ret = clk_set_rate(priv->clk, clk_get_rate(pclk) / 16);
+		if (ret)
+			dev_warn(&pdev->dev, "Cannot set clock rate");
+		/*
+		 * We can tolerate rate setting failure because the module should
+		 * work in any case.
+		 */
+	}
+
+	ret = clk_enable(priv->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Cannot enable clock");
+		return ret;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Cannot obtain memory resource");
+		return -ENXIO;
+	}
+	priv->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->base)) {
+		dev_err(&pdev->dev, "Cannot map memory resource");
+		return PTR_ERR(priv->base);
+	}
+
+	iiodev->dev.parent = &pdev->dev;
+	iiodev->name = dev_name(&pdev->dev);
+	iiodev->modes = INDIO_DIRECT_MODE;
+	iiodev->info = &ep93xx_adc_info;
+	iiodev->num_channels = ARRAY_SIZE(ep93xx_adc_channels);
+	iiodev->channels = ep93xx_adc_channels;
+
+	priv->lastch = -1;
+	mutex_init(&priv->lock);
+
+	ret = devm_iio_device_register(&pdev->dev, iiodev);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, iiodev);
+
+	return 0;
+}
+
+static int ep93xx_adc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *iiodev = platform_get_drvdata(pdev);
+	struct ep93xx_adc_priv *priv = iio_priv(iiodev);
+
+	clk_disable(priv->clk);
+
+	return 0;
+}
+
+static struct platform_driver ep93xx_adc_driver = {
+	.driver = {
+		.name = "ep93xx-adc",
+	},
+	.probe = ep93xx_adc_probe,
+	.remove = ep93xx_adc_remove,
+};
+module_platform_driver(ep93xx_adc_driver);
+
+MODULE_AUTHOR("Alexander Sverdlin <alexander.sverdlin@gmail.com>");
+MODULE_DESCRIPTION("Cirrus Logic EP93XX ADC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-adc");

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

* [PATCH 5/5] iio: adc: New driver for Cirrus Logic EP93xx ADC
@ 2015-11-25 11:51   ` Alexander Sverdlin
  0 siblings, 0 replies; 22+ messages in thread
From: Alexander Sverdlin @ 2015-11-25 11:51 UTC (permalink / raw)
  To: linux-arm-kernel

New driver adding support for ADC found on Cirrus Logic EP93xx series of SoCs.
Board specific code must take care to create platform device with all necessary
resources.

Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
---
 drivers/iio/adc/Kconfig      |  11 ++
 drivers/iio/adc/Makefile     |   1 +
 drivers/iio/adc/ep93xx_adc.c | 253 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 265 insertions(+)
 create mode 100644 drivers/iio/adc/ep93xx_adc.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 7868c74..2ee8b8b 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -172,6 +172,17 @@ config DA9150_GPADC
 	  To compile this driver as a module, choose M here: the module will be
 	  called berlin2-adc.

+config EP93XX_ADC
+	tristate "Cirrus Logic EP93XX ADC driver"
+	depends on ARCH_EP93XX
+	help
+	  Driver for the ADC module on the EP93XX series of SoC from Cirrus Logic.
+	  It's recommended to switch on CONFIG_HIGH_RES_TIMERS option, in this
+	  case driver will reduce its CPU usage by 70% in some use cases.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called ep93xx_adc.
+
 config EXYNOS_ADC
 	tristate "Exynos ADC driver support"
 	depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 99b37a9..5481b42 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
 obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
 obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
 obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
+obj-$(CONFIG_EP93XX_ADC) += ep93xx_adc.o
 obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
 obj-$(CONFIG_HI8435) += hi8435.o
 obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c
new file mode 100644
index 0000000..ebaacb9
--- /dev/null
+++ b/drivers/iio/adc/ep93xx_adc.c
@@ -0,0 +1,253 @@
+/*
+ * Driver for ADC module on the Cirrus Logic EP93xx series of SoCs
+ *
+ * Copyright (C) 2015 Alexander Sverdlin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The driver uses polling to get the conversion status. According to EP93xx
+ * datasheets, reading ADCResult register starts the conversion, but user also
+ * responsible for ensuring that delay between adjacent conversion triggers is
+ * long enough so that maximum allowed conversion rate is not exceeded. This
+ * basically renders IRQ mode unusable.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/io.h>
+#include <linux/irqflags.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+#define EP93XX_NUM_CHANNELS 8
+
+#define ep93xx_adc_reg_read(reg)	__raw_readl(reg)
+#define ep93xx_adc_reg_write(val, reg)	__raw_writel(val, reg)
+
+/*
+ * This code could benefit from real HR Timers, but jiffy granularity would
+ * lower ADC conversion rate down to CONFIG_HZ, so we fallback to busy wait
+ * in such case.
+ *
+ * HR Timers-based version loads CPU only up to 30% during back to back ADC
+ * conversion, while busy wait-based version consumes whole CPU power.
+ */
+#ifdef CONFIG_HIGH_RES_TIMERS
+#define ep93xx_adc_delay(usmin, usmax) usleep_range(usmin, usmax)
+#else
+#define ep93xx_adc_delay(usmin, usmax) udelay(usmin)
+#endif
+
+#define EP93XX_ADC_RESULT	0x08
+#define   EP93XX_ADC_SDR	BIT(31)
+#define EP93XX_ADC_SWITCH	0x18
+#define EP93XX_ADC_SW_LOCK	0x20
+#define EP93XX_ADC_INT_EN	0x24
+#define   EP93XX_ADC_RINTEN	BIT(11)
+
+struct ep93xx_adc_priv {
+	struct clk *clk;
+	void __iomem *base;
+	int lastch;
+	struct mutex lock;
+};
+
+#define EP93XX_ADC_CH(index, dname, ename, swcfg) {		\
+	.type = IIO_VOLTAGE,					\
+	.indexed = 1,						\
+	.channel = index,					\
+	.address = swcfg,					\
+	.datasheet_name = dname,				\
+	.extend_name = ename,					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) |	\
+				   BIT(IIO_CHAN_INFO_OFFSET),	\
+}
+
+/*
+ * Numbering scheme for channels 0..4 is defined in EP9301 and EP9302 datasheets.
+ * EP9307, EP9312 and EP9312 have 3 channels more (total 8), but the numering is
+ * not defined. So the last three are numbered randomly, let's say.
+ */
+static const struct iio_chan_spec ep93xx_adc_channels[EP93XX_NUM_CHANNELS] = {
+	EP93XX_ADC_CH(0, "YM",	"ym",	0x608),
+	EP93XX_ADC_CH(1, "SXP",	"sxp",	0x680),
+	EP93XX_ADC_CH(2, "SXM",	"sxm",	0x640),
+	EP93XX_ADC_CH(3, "SYP",	"syp",	0x620),
+	EP93XX_ADC_CH(4, "SYM",	"sym",	0x610),
+	EP93XX_ADC_CH(5, "XP",	"xp",	0x601),
+	EP93XX_ADC_CH(6, "XM",	"xm",	0x602),
+	EP93XX_ADC_CH(7, "YP",	"yp",	0x604),
+};
+
+static int ep93xx_read_raw(struct iio_dev *iiodev,
+			   struct iio_chan_spec const *channel, int *value,
+			   int *shift, long mask)
+{
+	struct ep93xx_adc_priv *priv = iio_priv(iiodev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&priv->lock);
+		if (priv->lastch != channel->channel) {
+			priv->lastch = channel->channel;
+			/*
+			 * Switch register is software-locked, unlocking must be
+			 * immediately followed by write
+			 */
+			local_irq_disable();
+			ep93xx_adc_reg_write(0xAA,
+					     priv->base + EP93XX_ADC_SW_LOCK);
+			ep93xx_adc_reg_write(channel->address,
+					     priv->base + EP93XX_ADC_SWITCH);
+			local_irq_enable();
+			/*
+			 * Settling delay depends on module clock and could be
+			 * 2ms or 500us
+			 */
+			ep93xx_adc_delay(2000, 2000);
+		}
+		/* Start the conversion, eventually discarding old result */
+		ep93xx_adc_reg_read(priv->base + EP93XX_ADC_RESULT);
+		/* Ensure maximun conversion rate is not exceeded */
+		ep93xx_adc_delay(DIV_ROUND_UP(1000000, 925),
+				 DIV_ROUND_UP(1000000, 925));
+		/* At this point conversion must be completed, but anyway... */
+		while (1) {
+			u32 t;
+
+			t = ep93xx_adc_reg_read(priv->base + EP93XX_ADC_RESULT);
+			if (t & EP93XX_ADC_SDR) {
+				/* Sign extend lower 16 bits */
+				*value = (s16)t;
+				break;
+			}
+		}
+		mutex_unlock(&priv->lock);
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_OFFSET:
+		/* According to datasheet, range is -25000..25000 */
+		*value = 25000;
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		/* Typical supply voltage is 3.3v */
+		*value = (1ULL << 32) * 3300 / 50000;
+		*shift = 32;
+		return IIO_VAL_FRACTIONAL_LOG2;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info ep93xx_adc_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = ep93xx_read_raw,
+};
+
+static int ep93xx_adc_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct iio_dev *iiodev;
+	struct ep93xx_adc_priv *priv;
+	struct clk *pclk;
+	struct resource *res;
+
+	iiodev = devm_iio_device_alloc(&pdev->dev,
+				       sizeof(struct ep93xx_adc_priv));
+	if (!iiodev)
+		return -ENOMEM;
+	priv = iio_priv(iiodev);
+
+	priv->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(priv->clk)) {
+		dev_err(&pdev->dev, "Cannot obtain clock");
+		return PTR_ERR(priv->clk);
+	}
+
+	pclk = clk_get_parent(priv->clk);
+	if (!pclk) {
+		dev_warn(&pdev->dev, "Cannot obtain parent clock");
+	} else {
+		/*
+		 * This is actually a place for improvement:
+		 * EP93xx ADC supports two clock divisors -- 4 and 16,
+		 * resulting in conversion rates 3750 and 925 samples per second
+		 * respectively with 500uS or 2ms settling time respectively.
+		 * One might find this interesting enough to be configurable.
+		 */
+		ret = clk_set_rate(priv->clk, clk_get_rate(pclk) / 16);
+		if (ret)
+			dev_warn(&pdev->dev, "Cannot set clock rate");
+		/*
+		 * We can tolerate rate setting failure because the module should
+		 * work in any case.
+		 */
+	}
+
+	ret = clk_enable(priv->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Cannot enable clock");
+		return ret;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Cannot obtain memory resource");
+		return -ENXIO;
+	}
+	priv->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->base)) {
+		dev_err(&pdev->dev, "Cannot map memory resource");
+		return PTR_ERR(priv->base);
+	}
+
+	iiodev->dev.parent = &pdev->dev;
+	iiodev->name = dev_name(&pdev->dev);
+	iiodev->modes = INDIO_DIRECT_MODE;
+	iiodev->info = &ep93xx_adc_info;
+	iiodev->num_channels = ARRAY_SIZE(ep93xx_adc_channels);
+	iiodev->channels = ep93xx_adc_channels;
+
+	priv->lastch = -1;
+	mutex_init(&priv->lock);
+
+	ret = devm_iio_device_register(&pdev->dev, iiodev);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, iiodev);
+
+	return 0;
+}
+
+static int ep93xx_adc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *iiodev = platform_get_drvdata(pdev);
+	struct ep93xx_adc_priv *priv = iio_priv(iiodev);
+
+	clk_disable(priv->clk);
+
+	return 0;
+}
+
+static struct platform_driver ep93xx_adc_driver = {
+	.driver = {
+		.name = "ep93xx-adc",
+	},
+	.probe = ep93xx_adc_probe,
+	.remove = ep93xx_adc_remove,
+};
+module_platform_driver(ep93xx_adc_driver);
+
+MODULE_AUTHOR("Alexander Sverdlin <alexander.sverdlin@gmail.com>");
+MODULE_DESCRIPTION("Cirrus Logic EP93XX ADC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-adc");

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

* Re: [PATCH 5/5] iio: adc: New driver for Cirrus Logic EP93xx ADC
  2015-11-25 11:51   ` Alexander Sverdlin
  (?)
@ 2015-11-25 12:43   ` Peter Meerwald-Stadler
  2015-11-25 13:01     ` Alexander Sverdlin
  -1 siblings, 1 reply; 22+ messages in thread
From: Peter Meerwald-Stadler @ 2015-11-25 12:43 UTC (permalink / raw)
  To: Alexander Sverdlin
  Cc: linux-iio, Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen


> New driver adding support for ADC found on Cirrus Logic EP93xx series of SoCs.
> Board specific code must take care to create platform device with all necessary
> resources.

comments below
 
> Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
> ---
>  drivers/iio/adc/Kconfig      |  11 ++
>  drivers/iio/adc/Makefile     |   1 +
>  drivers/iio/adc/ep93xx_adc.c | 253 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 265 insertions(+)
>  create mode 100644 drivers/iio/adc/ep93xx_adc.c
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 7868c74..2ee8b8b 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -172,6 +172,17 @@ config DA9150_GPADC
>  	  To compile this driver as a module, choose M here: the module will be
>  	  called berlin2-adc.
> 
> +config EP93XX_ADC
> +	tristate "Cirrus Logic EP93XX ADC driver"
> +	depends on ARCH_EP93XX
> +	help
> +	  Driver for the ADC module on the EP93XX series of SoC from Cirrus Logic.
> +	  It's recommended to switch on CONFIG_HIGH_RES_TIMERS option, in this
> +	  case driver will reduce its CPU usage by 70% in some use cases.
> +
> +	  To compile this driver as a module, choose M here: the module will be
> +	  called ep93xx_adc.
> +
>  config EXYNOS_ADC
>  	tristate "Exynos ADC driver support"
>  	depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index 99b37a9..5481b42 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -18,6 +18,7 @@ obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
>  obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
>  obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
>  obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
> +obj-$(CONFIG_EP93XX_ADC) += ep93xx_adc.o
>  obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
>  obj-$(CONFIG_HI8435) += hi8435.o
>  obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
> diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c
> new file mode 100644
> index 0000000..ebaacb9
> --- /dev/null
> +++ b/drivers/iio/adc/ep93xx_adc.c
> @@ -0,0 +1,253 @@
> +/*
> + * Driver for ADC module on the Cirrus Logic EP93xx series of SoCs
> + *
> + * Copyright (C) 2015 Alexander Sverdlin
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * The driver uses polling to get the conversion status. According to EP93xx
> + * datasheets, reading ADCResult register starts the conversion, but user also

is also

> + * responsible for ensuring that delay between adjacent conversion triggers is
> + * long enough so that maximum allowed conversion rate is not exceeded. This
> + * basically renders IRQ mode unusable.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/iio/iio.h>
> +#include <linux/io.h>
> +#include <linux/irqflags.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_device.h>
> +
> +#define EP93XX_NUM_CHANNELS 8
> +
> +#define ep93xx_adc_reg_read(reg)	__raw_readl(reg)
> +#define ep93xx_adc_reg_write(val, reg)	__raw_writel(val, reg)
> +
> +/*
> + * This code could benefit from real HR Timers, but jiffy granularity would
> + * lower ADC conversion rate down to CONFIG_HZ, so we fallback to busy wait
> + * in such case.
> + *
> + * HR Timers-based version loads CPU only up to 30% during back to back ADC
> + * conversion, while busy wait-based version consumes whole CPU power.
> + */
> +#ifdef CONFIG_HIGH_RES_TIMERS
> +#define ep93xx_adc_delay(usmin, usmax) usleep_range(usmin, usmax)
> +#else
> +#define ep93xx_adc_delay(usmin, usmax) udelay(usmin)
> +#endif
> +
> +#define EP93XX_ADC_RESULT	0x08
> +#define   EP93XX_ADC_SDR	BIT(31)
> +#define EP93XX_ADC_SWITCH	0x18
> +#define EP93XX_ADC_SW_LOCK	0x20
> +#define EP93XX_ADC_INT_EN	0x24
> +#define   EP93XX_ADC_RINTEN	BIT(11)
> +
> +struct ep93xx_adc_priv {
> +	struct clk *clk;
> +	void __iomem *base;
> +	int lastch;
> +	struct mutex lock;
> +};
> +
> +#define EP93XX_ADC_CH(index, dname, ename, swcfg) {		\
> +	.type = IIO_VOLTAGE,					\
> +	.indexed = 1,						\
> +	.channel = index,					\
> +	.address = swcfg,					\
> +	.datasheet_name = dname,				\
> +	.extend_name = ename,					\
> +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
> +	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) |	\
> +				   BIT(IIO_CHAN_INFO_OFFSET),	\
> +}
> +
> +/*
> + * Numbering scheme for channels 0..4 is defined in EP9301 and EP9302 datasheets.
> + * EP9307, EP9312 and EP9312 have 3 channels more (total 8), but the numering is

numbering

> + * not defined. So the last three are numbered randomly, let's say.
> + */
> +static const struct iio_chan_spec ep93xx_adc_channels[EP93XX_NUM_CHANNELS] = {
> +	EP93XX_ADC_CH(0, "YM",	"ym",	0x608),
> +	EP93XX_ADC_CH(1, "SXP",	"sxp",	0x680),
> +	EP93XX_ADC_CH(2, "SXM",	"sxm",	0x640),
> +	EP93XX_ADC_CH(3, "SYP",	"syp",	0x620),
> +	EP93XX_ADC_CH(4, "SYM",	"sym",	0x610),
> +	EP93XX_ADC_CH(5, "XP",	"xp",	0x601),
> +	EP93XX_ADC_CH(6, "XM",	"xm",	0x602),
> +	EP93XX_ADC_CH(7, "YP",	"yp",	0x604),
> +};
> +
> +static int ep93xx_read_raw(struct iio_dev *iiodev,
> +			   struct iio_chan_spec const *channel, int *value,
> +			   int *shift, long mask)
> +{
> +	struct ep93xx_adc_priv *priv = iio_priv(iiodev);
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		mutex_lock(&priv->lock);
> +		if (priv->lastch != channel->channel) {
> +			priv->lastch = channel->channel;
> +			/*
> +			 * Switch register is software-locked, unlocking must be
> +			 * immediately followed by write
> +			 */
> +			local_irq_disable();
> +			ep93xx_adc_reg_write(0xAA,
> +					     priv->base + EP93XX_ADC_SW_LOCK);
> +			ep93xx_adc_reg_write(channel->address,
> +					     priv->base + EP93XX_ADC_SWITCH);
> +			local_irq_enable();
> +			/*
> +			 * Settling delay depends on module clock and could be
> +			 * 2ms or 500us
> +			 */
> +			ep93xx_adc_delay(2000, 2000);
> +		}
> +		/* Start the conversion, eventually discarding old result */
> +		ep93xx_adc_reg_read(priv->base + EP93XX_ADC_RESULT);
> +		/* Ensure maximun conversion rate is not exceeded */
> +		ep93xx_adc_delay(DIV_ROUND_UP(1000000, 925),
> +				 DIV_ROUND_UP(1000000, 925));
> +		/* At this point conversion must be completed, but anyway... */
> +		while (1) {
> +			u32 t;
> +
> +			t = ep93xx_adc_reg_read(priv->base + EP93XX_ADC_RESULT);
> +			if (t & EP93XX_ADC_SDR) {
> +				/* Sign extend lower 16 bits */
> +				*value = (s16)t;

there would be a nice sign_extend function
maybe have a timeout?

> +				break;
> +			}
> +		}
> +		mutex_unlock(&priv->lock);
> +		return IIO_VAL_INT;
> +
> +	case IIO_CHAN_INFO_OFFSET:
> +		/* According to datasheet, range is -25000..25000 */

huh? so 0 V returns what value?

> +		*value = 25000;
> +		return IIO_VAL_INT;
> +
> +	case IIO_CHAN_INFO_SCALE:
> +		/* Typical supply voltage is 3.3v */
> +		*value = (1ULL << 32) * 3300 / 50000;
> +		*shift = 32;
> +		return IIO_VAL_FRACTIONAL_LOG2;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static const struct iio_info ep93xx_adc_info = {
> +	.driver_module = THIS_MODULE,
> +	.read_raw = ep93xx_read_raw,
> +};
> +
> +static int ep93xx_adc_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	struct iio_dev *iiodev;
> +	struct ep93xx_adc_priv *priv;
> +	struct clk *pclk;
> +	struct resource *res;
> +
> +	iiodev = devm_iio_device_alloc(&pdev->dev,
> +				       sizeof(struct ep93xx_adc_priv));
> +	if (!iiodev)
> +		return -ENOMEM;
> +	priv = iio_priv(iiodev);
> +
> +	priv->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(priv->clk)) {
> +		dev_err(&pdev->dev, "Cannot obtain clock");

put \n at the end of the message

> +		return PTR_ERR(priv->clk);
> +	}
> +
> +	pclk = clk_get_parent(priv->clk);
> +	if (!pclk) {
> +		dev_warn(&pdev->dev, "Cannot obtain parent clock");

put \n at the end of the message, here and elsewhere

> +	} else {
> +		/*
> +		 * This is actually a place for improvement:
> +		 * EP93xx ADC supports two clock divisors -- 4 and 16,
> +		 * resulting in conversion rates 3750 and 925 samples per second
> +		 * respectively with 500uS or 2ms settling time respectively.
> +		 * One might find this interesting enough to be configurable.
> +		 */
> +		ret = clk_set_rate(priv->clk, clk_get_rate(pclk) / 16);
> +		if (ret)
> +			dev_warn(&pdev->dev, "Cannot set clock rate");
> +		/*
> +		 * We can tolerate rate setting failure because the module should
> +		 * work in any case.
> +		 */
> +	}
> +
> +	ret = clk_enable(priv->clk);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Cannot enable clock");
> +		return ret;
> +	}
> +

clock should be disabled on error in the following error path

> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(&pdev->dev, "Cannot obtain memory resource");
> +		return -ENXIO;
> +	}
> +	priv->base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(priv->base)) {
> +		dev_err(&pdev->dev, "Cannot map memory resource");
> +		return PTR_ERR(priv->base);
> +	}
> +
> +	iiodev->dev.parent = &pdev->dev;
> +	iiodev->name = dev_name(&pdev->dev);
> +	iiodev->modes = INDIO_DIRECT_MODE;
> +	iiodev->info = &ep93xx_adc_info;
> +	iiodev->num_channels = ARRAY_SIZE(ep93xx_adc_channels);
> +	iiodev->channels = ep93xx_adc_channels;
> +
> +	priv->lastch = -1;
> +	mutex_init(&priv->lock);
> +
> +	ret = devm_iio_device_register(&pdev->dev, iiodev);
> +	if (ret)
> +		return ret;
> +
> +	platform_set_drvdata(pdev, iiodev);

this should be done before _register()

just do
return devm_iio_device_register(..)

> +
> +	return 0;
> +}
> +
> +static int ep93xx_adc_remove(struct platform_device *pdev)
> +{
> +	struct iio_dev *iiodev = platform_get_drvdata(pdev);
> +	struct ep93xx_adc_priv *priv = iio_priv(iiodev);
> +
> +	clk_disable(priv->clk);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver ep93xx_adc_driver = {
> +	.driver = {
> +		.name = "ep93xx-adc",
> +	},
> +	.probe = ep93xx_adc_probe,
> +	.remove = ep93xx_adc_remove,
> +};
> +module_platform_driver(ep93xx_adc_driver);
> +
> +MODULE_AUTHOR("Alexander Sverdlin <alexander.sverdlin@gmail.com>");
> +MODULE_DESCRIPTION("Cirrus Logic EP93XX ADC driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:ep93xx-adc");
> --
> 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
> 

-- 

Peter Meerwald-Stadler
+43-664-2444418 (mobile)

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

* Re: [PATCH 5/5] iio: adc: New driver for Cirrus Logic EP93xx ADC
  2015-11-25 12:43   ` Peter Meerwald-Stadler
@ 2015-11-25 13:01     ` Alexander Sverdlin
  0 siblings, 0 replies; 22+ messages in thread
From: Alexander Sverdlin @ 2015-11-25 13:01 UTC (permalink / raw)
  To: Peter Meerwald-Stadler
  Cc: linux-iio, Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen

Hi!

On 25/11/15 13:43, Peter Meerwald-Stadler wrote:
>> New driver adding support for ADC found on Cirrus Logic EP93xx series of SoCs.
>> > Board specific code must take care to create platform device with all necessary
>> > resources.
> comments below

Thanks for spelling corrections :)

[...]

>> > +		/* At this point conversion must be completed, but anyway... */
>> > +		while (1) {
>> > +			u32 t;
>> > +
>> > +			t = ep93xx_adc_reg_read(priv->base + EP93XX_ADC_RESULT);
>> > +			if (t & EP93XX_ADC_SDR) {
>> > +				/* Sign extend lower 16 bits */
>> > +				*value = (s16)t;
> there would be a nice sign_extend function

Yes, but we don't need its flexibility for the 16 bit case?

> maybe have a timeout?

Maybe... I'll add it...

>> > +				break;
>> > +			}
>> > +		}
>> > +		mutex_unlock(&priv->lock);
>> > +		return IIO_VAL_INT;
>> > +
>> > +	case IIO_CHAN_INFO_OFFSET:
>> > +		/* According to datasheet, range is -25000..25000 */
> huh? so 0 V returns what value?

Manual says it returns ~-25000. This seems to be true in reality, but I cannot tell
you now if it could be even below -25000. But as I've understood, all the relevant
calculations in IIO core are signed, so this should not be a problem.

[...]

>> > +		dev_err(&pdev->dev, "Cannot obtain clock");
> put \n at the end of the message

Yes, thanks for that notice...

[...]

>> > +	ret = clk_enable(priv->clk);
>> > +	if (ret) {
>> > +		dev_err(&pdev->dev, "Cannot enable clock");
>> > +		return ret;
>> > +	}
>> > +
> clock should be disabled on error in the following error path

True... I'll try to postpone clock enabling to the very end...

[...]

>> > +	ret = devm_iio_device_register(&pdev->dev, iiodev);
>> > +	if (ret)
>> > +		return ret;
>> > +
>> > +	platform_set_drvdata(pdev, iiodev);
> this should be done before _register()

I don't agree here, because this is for platform device only and is
only used in _remove() below, not for IIO device.

> just do
> return devm_iio_device_register(..)

Thanks for review!

Regards,
Alexander.

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

* Re: [PATCH 5/5] iio: adc: New driver for Cirrus Logic EP93xx ADC
  2015-11-25 11:51   ` Alexander Sverdlin
@ 2015-11-29 16:12     ` Jonathan Cameron
  -1 siblings, 0 replies; 22+ messages in thread
From: Jonathan Cameron @ 2015-11-29 16:12 UTC (permalink / raw)
  To: Alexander Sverdlin, Hartley Sweeten, Ryan Mallon,
	linux-arm-kernel, linux-iio
  Cc: Russell King, Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald

On 25/11/15 11:51, Alexander Sverdlin wrote:
> New driver adding support for ADC found on Cirrus Logic EP93xx series of SoCs.
> Board specific code must take care to create platform device with all necessary
> resources.
> 
> Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
Datasheet links always appreciated if available.

Right now Cirrus' website is fighting back so I can't get to any
of their docs - hence bare with me!

A few bits inline.  Primary question which is hard to answer without the
datasheets is what meaning the channel names actually have?  THe brief
says they are general purpose.  If so then it's not really valid
to given them extended names suggesting anything more.

Jonathan
> ---
>  drivers/iio/adc/Kconfig      |  11 ++
>  drivers/iio/adc/Makefile     |   1 +
>  drivers/iio/adc/ep93xx_adc.c | 253 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 265 insertions(+)
>  create mode 100644 drivers/iio/adc/ep93xx_adc.c
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 7868c74..2ee8b8b 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -172,6 +172,17 @@ config DA9150_GPADC
>  	  To compile this driver as a module, choose M here: the module will be
>  	  called berlin2-adc.
> 
> +config EP93XX_ADC
> +	tristate "Cirrus Logic EP93XX ADC driver"
> +	depends on ARCH_EP93XX
> +	help
> +	  Driver for the ADC module on the EP93XX series of SoC from Cirrus Logic.
> +	  It's recommended to switch on CONFIG_HIGH_RES_TIMERS option, in this
> +	  case driver will reduce its CPU usage by 70% in some use cases.
> +
> +	  To compile this driver as a module, choose M here: the module will be
> +	  called ep93xx_adc.
> +
>  config EXYNOS_ADC
>  	tristate "Exynos ADC driver support"
>  	depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index 99b37a9..5481b42 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -18,6 +18,7 @@ obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
>  obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
>  obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
>  obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
> +obj-$(CONFIG_EP93XX_ADC) += ep93xx_adc.o
>  obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
>  obj-$(CONFIG_HI8435) += hi8435.o
>  obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
> diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c
> new file mode 100644
> index 0000000..ebaacb9
> --- /dev/null
> +++ b/drivers/iio/adc/ep93xx_adc.c
> @@ -0,0 +1,253 @@
> +/*
> + * Driver for ADC module on the Cirrus Logic EP93xx series of SoCs
> + *
> + * Copyright (C) 2015 Alexander Sverdlin
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * The driver uses polling to get the conversion status. According to EP93xx
> + * datasheets, reading ADCResult register starts the conversion, but user also
> + * responsible for ensuring that delay between adjacent conversion triggers is
> + * long enough so that maximum allowed conversion rate is not exceeded. This
> + * basically renders IRQ mode unusable.
Genius!
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/iio/iio.h>
> +#include <linux/io.h>
> +#include <linux/irqflags.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_device.h>
> +
> +#define EP93XX_NUM_CHANNELS 8
> +
> +#define ep93xx_adc_reg_read(reg)	__raw_readl(reg)
> +#define ep93xx_adc_reg_write(val, reg)	__raw_writel(val, reg)
> +
> +/*
> + * This code could benefit from real HR Timers, but jiffy granularity would
> + * lower ADC conversion rate down to CONFIG_HZ, so we fallback to busy wait
> + * in such case.
> + *
> + * HR Timers-based version loads CPU only up to 30% during back to back ADC
> + * conversion, while busy wait-based version consumes whole CPU power.
> + */
> +#ifdef CONFIG_HIGH_RES_TIMERS
> +#define ep93xx_adc_delay(usmin, usmax) usleep_range(usmin, usmax)
> +#else
> +#define ep93xx_adc_delay(usmin, usmax) udelay(usmin)
> +#endif
> +
> +#define EP93XX_ADC_RESULT	0x08
> +#define   EP93XX_ADC_SDR	BIT(31)
> +#define EP93XX_ADC_SWITCH	0x18
> +#define EP93XX_ADC_SW_LOCK	0x20
> +#define EP93XX_ADC_INT_EN	0x24
> +#define   EP93XX_ADC_RINTEN	BIT(11)
> +
> +struct ep93xx_adc_priv {
> +	struct clk *clk;
> +	void __iomem *base;
> +	int lastch;
> +	struct mutex lock;
> +};
> +
> +#define EP93XX_ADC_CH(index, dname, ename, swcfg) {		\
> +	.type = IIO_VOLTAGE,					\
> +	.indexed = 1,						\
> +	.channel = index,					\
> +	.address = swcfg,					\
> +	.datasheet_name = dname,				\
> +	.extend_name = ename,					\
> +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
> +	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) |	\
> +				   BIT(IIO_CHAN_INFO_OFFSET),	\
> +}
> +
> +/*
> + * Numbering scheme for channels 0..4 is defined in EP9301 and EP9302 datasheets.
> + * EP9307, EP9312 and EP9312 have 3 channels more (total 8), but the numering is
> + * not defined. So the last three are numbered randomly, let's say.
> + */
> +static const struct iio_chan_spec ep93xx_adc_channels[EP93XX_NUM_CHANNELS] = {
> +	EP93XX_ADC_CH(0, "YM",	"ym",	0x608),
> +	EP93XX_ADC_CH(1, "SXP",	"sxp",	0x680),
> +	EP93XX_ADC_CH(2, "SXM",	"sxm",	0x640),
> +	EP93XX_ADC_CH(3, "SYP",	"syp",	0x620),
> +	EP93XX_ADC_CH(4, "SYM",	"sym",	0x610),
> +	EP93XX_ADC_CH(5, "XP",	"xp",	0x601),
> +	EP93XX_ADC_CH(6, "XM",	"xm",	0x602),
> +	EP93XX_ADC_CH(7, "YP",	"yp",	0x604),
> +};
Hmm.  I'm a little dubious about the extended names.  What in the device
acutally restricts them to these uses?  This naming is probably something
to do with touch screens?  If there is no special purpose hardware then
I'd just drop the extended names (datasheet names obviously fine if thats
what they are called on the datasheet!)
> +
> +static int ep93xx_read_raw(struct iio_dev *iiodev,
> +			   struct iio_chan_spec const *channel, int *value,
> +			   int *shift, long mask)
> +{
> +	struct ep93xx_adc_priv *priv = iio_priv(iiodev);
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		mutex_lock(&priv->lock);
> +		if (priv->lastch != channel->channel) {
> +			priv->lastch = channel->channel;
> +			/*
> +			 * Switch register is software-locked, unlocking must be
> +			 * immediately followed by write
> +			 */
> +			local_irq_disable();
> +			ep93xx_adc_reg_write(0xAA,
> +					     priv->base + EP93XX_ADC_SW_LOCK);
> +			ep93xx_adc_reg_write(channel->address,
> +					     priv->base + EP93XX_ADC_SWITCH);
> +			local_irq_enable();
> +			/*
> +			 * Settling delay depends on module clock and could be
> +			 * 2ms or 500us
> +			 */
> +			ep93xx_adc_delay(2000, 2000);
> +		}
> +		/* Start the conversion, eventually discarding old result */
> +		ep93xx_adc_reg_read(priv->base + EP93XX_ADC_RESULT);
> +		/* Ensure maximun conversion rate is not exceeded */
> +		ep93xx_adc_delay(DIV_ROUND_UP(1000000, 925),
> +				 DIV_ROUND_UP(1000000, 925));
> +		/* At this point conversion must be completed, but anyway... */
> +		while (1) {
Might be worth a timeout and adding a sleep in here to avoid a tight
spin.  Obviously it should always be fine, but who knows!
> +			u32 t;
> +
> +			t = ep93xx_adc_reg_read(priv->base + EP93XX_ADC_RESULT);
> +			if (t & EP93XX_ADC_SDR) {
> +				/* Sign extend lower 16 bits */
> +				*value = (s16)t;
> +				break;
> +			}
> +		}
> +		mutex_unlock(&priv->lock);
> +		return IIO_VAL_INT;
> +
> +	case IIO_CHAN_INFO_OFFSET:
> +		/* According to datasheet, range is -25000..25000 */
> +		*value = 25000;
> +		return IIO_VAL_INT;
> +
> +	case IIO_CHAN_INFO_SCALE:
> +		/* Typical supply voltage is 3.3v */
> +		*value = (1ULL << 32) * 3300 / 50000;
> +		*shift = 32;
> +		return IIO_VAL_FRACTIONAL_LOG2;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static const struct iio_info ep93xx_adc_info = {
> +	.driver_module = THIS_MODULE,
> +	.read_raw = ep93xx_read_raw,
> +};
> +
> +static int ep93xx_adc_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	struct iio_dev *iiodev;
> +	struct ep93xx_adc_priv *priv;
> +	struct clk *pclk;
> +	struct resource *res;
> +
> +	iiodev = devm_iio_device_alloc(&pdev->dev,
> +				       sizeof(struct ep93xx_adc_priv));
> +	if (!iiodev)
> +		return -ENOMEM;
> +	priv = iio_priv(iiodev);
> +
> +	priv->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(priv->clk)) {
> +		dev_err(&pdev->dev, "Cannot obtain clock");
> +		return PTR_ERR(priv->clk);
> +	}
> +
> +	pclk = clk_get_parent(priv->clk);
> +	if (!pclk) {
> +		dev_warn(&pdev->dev, "Cannot obtain parent clock");
> +	} else {
> +		/*
> +		 * This is actually a place for improvement:
> +		 * EP93xx ADC supports two clock divisors -- 4 and 16,
> +		 * resulting in conversion rates 3750 and 925 samples per second
> +		 * respectively with 500uS or 2ms settling time respectively.
> +		 * One might find this interesting enough to be configurable.
> +		 */
> +		ret = clk_set_rate(priv->clk, clk_get_rate(pclk) / 16);
> +		if (ret)
> +			dev_warn(&pdev->dev, "Cannot set clock rate");
> +		/*
> +		 * We can tolerate rate setting failure because the module should
> +		 * work in any case.
> +		 */
> +	}
> +
> +	ret = clk_enable(priv->clk);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Cannot enable clock");
> +		return ret;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(&pdev->dev, "Cannot obtain memory resource");
> +		return -ENXIO;
> +	}
> +	priv->base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(priv->base)) {
> +		dev_err(&pdev->dev, "Cannot map memory resource");
> +		return PTR_ERR(priv->base);
> +	}
> +
> +	iiodev->dev.parent = &pdev->dev;
> +	iiodev->name = dev_name(&pdev->dev);
> +	iiodev->modes = INDIO_DIRECT_MODE;
> +	iiodev->info = &ep93xx_adc_info;
> +	iiodev->num_channels = ARRAY_SIZE(ep93xx_adc_channels);
> +	iiodev->channels = ep93xx_adc_channels;
> +
> +	priv->lastch = -1;
> +	mutex_init(&priv->lock);
> +
> +	ret = devm_iio_device_register(&pdev->dev, iiodev);
> +	if (ret)
> +		return ret;
> +
> +	platform_set_drvdata(pdev, iiodev);
I'd reorder as Peter suggested - it doesn't mater obviously but
you could then do return devm_iio_device_register and save
a few lines of code without a lost of functionality.

However, this is racey as the userspace interface will be removed
'after' the clk_disable below.  Basic rule of thumb is that if
you do anything at all in the remove, you can't use devm_iio_device_register
as if it makes sense to do it it must effect device functionality of a
device still exposed to userspace.

> +
> +	return 0;
> +}
> +
> +static int ep93xx_adc_remove(struct platform_device *pdev)
> +{
> +	struct iio_dev *iiodev = platform_get_drvdata(pdev);
> +	struct ep93xx_adc_priv *priv = iio_priv(iiodev);
Personal taste, but I'd roll the above into one call as we never
use the iio_dev in this function..

> +
> +	clk_disable(priv->clk);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver ep93xx_adc_driver = {
> +	.driver = {
> +		.name = "ep93xx-adc",
> +	},
> +	.probe = ep93xx_adc_probe,
> +	.remove = ep93xx_adc_remove,
> +};
> +module_platform_driver(ep93xx_adc_driver);
> +
> +MODULE_AUTHOR("Alexander Sverdlin <alexander.sverdlin@gmail.com>");
> +MODULE_DESCRIPTION("Cirrus Logic EP93XX ADC driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:ep93xx-adc");
> --
> 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] 22+ messages in thread

* [PATCH 5/5] iio: adc: New driver for Cirrus Logic EP93xx ADC
@ 2015-11-29 16:12     ` Jonathan Cameron
  0 siblings, 0 replies; 22+ messages in thread
From: Jonathan Cameron @ 2015-11-29 16:12 UTC (permalink / raw)
  To: linux-arm-kernel

On 25/11/15 11:51, Alexander Sverdlin wrote:
> New driver adding support for ADC found on Cirrus Logic EP93xx series of SoCs.
> Board specific code must take care to create platform device with all necessary
> resources.
> 
> Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
Datasheet links always appreciated if available.

Right now Cirrus' website is fighting back so I can't get to any
of their docs - hence bare with me!

A few bits inline.  Primary question which is hard to answer without the
datasheets is what meaning the channel names actually have?  THe brief
says they are general purpose.  If so then it's not really valid
to given them extended names suggesting anything more.

Jonathan
> ---
>  drivers/iio/adc/Kconfig      |  11 ++
>  drivers/iio/adc/Makefile     |   1 +
>  drivers/iio/adc/ep93xx_adc.c | 253 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 265 insertions(+)
>  create mode 100644 drivers/iio/adc/ep93xx_adc.c
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 7868c74..2ee8b8b 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -172,6 +172,17 @@ config DA9150_GPADC
>  	  To compile this driver as a module, choose M here: the module will be
>  	  called berlin2-adc.
> 
> +config EP93XX_ADC
> +	tristate "Cirrus Logic EP93XX ADC driver"
> +	depends on ARCH_EP93XX
> +	help
> +	  Driver for the ADC module on the EP93XX series of SoC from Cirrus Logic.
> +	  It's recommended to switch on CONFIG_HIGH_RES_TIMERS option, in this
> +	  case driver will reduce its CPU usage by 70% in some use cases.
> +
> +	  To compile this driver as a module, choose M here: the module will be
> +	  called ep93xx_adc.
> +
>  config EXYNOS_ADC
>  	tristate "Exynos ADC driver support"
>  	depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index 99b37a9..5481b42 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -18,6 +18,7 @@ obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
>  obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
>  obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
>  obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
> +obj-$(CONFIG_EP93XX_ADC) += ep93xx_adc.o
>  obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
>  obj-$(CONFIG_HI8435) += hi8435.o
>  obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
> diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c
> new file mode 100644
> index 0000000..ebaacb9
> --- /dev/null
> +++ b/drivers/iio/adc/ep93xx_adc.c
> @@ -0,0 +1,253 @@
> +/*
> + * Driver for ADC module on the Cirrus Logic EP93xx series of SoCs
> + *
> + * Copyright (C) 2015 Alexander Sverdlin
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * The driver uses polling to get the conversion status. According to EP93xx
> + * datasheets, reading ADCResult register starts the conversion, but user also
> + * responsible for ensuring that delay between adjacent conversion triggers is
> + * long enough so that maximum allowed conversion rate is not exceeded. This
> + * basically renders IRQ mode unusable.
Genius!
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/iio/iio.h>
> +#include <linux/io.h>
> +#include <linux/irqflags.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_device.h>
> +
> +#define EP93XX_NUM_CHANNELS 8
> +
> +#define ep93xx_adc_reg_read(reg)	__raw_readl(reg)
> +#define ep93xx_adc_reg_write(val, reg)	__raw_writel(val, reg)
> +
> +/*
> + * This code could benefit from real HR Timers, but jiffy granularity would
> + * lower ADC conversion rate down to CONFIG_HZ, so we fallback to busy wait
> + * in such case.
> + *
> + * HR Timers-based version loads CPU only up to 30% during back to back ADC
> + * conversion, while busy wait-based version consumes whole CPU power.
> + */
> +#ifdef CONFIG_HIGH_RES_TIMERS
> +#define ep93xx_adc_delay(usmin, usmax) usleep_range(usmin, usmax)
> +#else
> +#define ep93xx_adc_delay(usmin, usmax) udelay(usmin)
> +#endif
> +
> +#define EP93XX_ADC_RESULT	0x08
> +#define   EP93XX_ADC_SDR	BIT(31)
> +#define EP93XX_ADC_SWITCH	0x18
> +#define EP93XX_ADC_SW_LOCK	0x20
> +#define EP93XX_ADC_INT_EN	0x24
> +#define   EP93XX_ADC_RINTEN	BIT(11)
> +
> +struct ep93xx_adc_priv {
> +	struct clk *clk;
> +	void __iomem *base;
> +	int lastch;
> +	struct mutex lock;
> +};
> +
> +#define EP93XX_ADC_CH(index, dname, ename, swcfg) {		\
> +	.type = IIO_VOLTAGE,					\
> +	.indexed = 1,						\
> +	.channel = index,					\
> +	.address = swcfg,					\
> +	.datasheet_name = dname,				\
> +	.extend_name = ename,					\
> +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
> +	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) |	\
> +				   BIT(IIO_CHAN_INFO_OFFSET),	\
> +}
> +
> +/*
> + * Numbering scheme for channels 0..4 is defined in EP9301 and EP9302 datasheets.
> + * EP9307, EP9312 and EP9312 have 3 channels more (total 8), but the numering is
> + * not defined. So the last three are numbered randomly, let's say.
> + */
> +static const struct iio_chan_spec ep93xx_adc_channels[EP93XX_NUM_CHANNELS] = {
> +	EP93XX_ADC_CH(0, "YM",	"ym",	0x608),
> +	EP93XX_ADC_CH(1, "SXP",	"sxp",	0x680),
> +	EP93XX_ADC_CH(2, "SXM",	"sxm",	0x640),
> +	EP93XX_ADC_CH(3, "SYP",	"syp",	0x620),
> +	EP93XX_ADC_CH(4, "SYM",	"sym",	0x610),
> +	EP93XX_ADC_CH(5, "XP",	"xp",	0x601),
> +	EP93XX_ADC_CH(6, "XM",	"xm",	0x602),
> +	EP93XX_ADC_CH(7, "YP",	"yp",	0x604),
> +};
Hmm.  I'm a little dubious about the extended names.  What in the device
acutally restricts them to these uses?  This naming is probably something
to do with touch screens?  If there is no special purpose hardware then
I'd just drop the extended names (datasheet names obviously fine if thats
what they are called on the datasheet!)
> +
> +static int ep93xx_read_raw(struct iio_dev *iiodev,
> +			   struct iio_chan_spec const *channel, int *value,
> +			   int *shift, long mask)
> +{
> +	struct ep93xx_adc_priv *priv = iio_priv(iiodev);
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		mutex_lock(&priv->lock);
> +		if (priv->lastch != channel->channel) {
> +			priv->lastch = channel->channel;
> +			/*
> +			 * Switch register is software-locked, unlocking must be
> +			 * immediately followed by write
> +			 */
> +			local_irq_disable();
> +			ep93xx_adc_reg_write(0xAA,
> +					     priv->base + EP93XX_ADC_SW_LOCK);
> +			ep93xx_adc_reg_write(channel->address,
> +					     priv->base + EP93XX_ADC_SWITCH);
> +			local_irq_enable();
> +			/*
> +			 * Settling delay depends on module clock and could be
> +			 * 2ms or 500us
> +			 */
> +			ep93xx_adc_delay(2000, 2000);
> +		}
> +		/* Start the conversion, eventually discarding old result */
> +		ep93xx_adc_reg_read(priv->base + EP93XX_ADC_RESULT);
> +		/* Ensure maximun conversion rate is not exceeded */
> +		ep93xx_adc_delay(DIV_ROUND_UP(1000000, 925),
> +				 DIV_ROUND_UP(1000000, 925));
> +		/* At this point conversion must be completed, but anyway... */
> +		while (1) {
Might be worth a timeout and adding a sleep in here to avoid a tight
spin.  Obviously it should always be fine, but who knows!
> +			u32 t;
> +
> +			t = ep93xx_adc_reg_read(priv->base + EP93XX_ADC_RESULT);
> +			if (t & EP93XX_ADC_SDR) {
> +				/* Sign extend lower 16 bits */
> +				*value = (s16)t;
> +				break;
> +			}
> +		}
> +		mutex_unlock(&priv->lock);
> +		return IIO_VAL_INT;
> +
> +	case IIO_CHAN_INFO_OFFSET:
> +		/* According to datasheet, range is -25000..25000 */
> +		*value = 25000;
> +		return IIO_VAL_INT;
> +
> +	case IIO_CHAN_INFO_SCALE:
> +		/* Typical supply voltage is 3.3v */
> +		*value = (1ULL << 32) * 3300 / 50000;
> +		*shift = 32;
> +		return IIO_VAL_FRACTIONAL_LOG2;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static const struct iio_info ep93xx_adc_info = {
> +	.driver_module = THIS_MODULE,
> +	.read_raw = ep93xx_read_raw,
> +};
> +
> +static int ep93xx_adc_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	struct iio_dev *iiodev;
> +	struct ep93xx_adc_priv *priv;
> +	struct clk *pclk;
> +	struct resource *res;
> +
> +	iiodev = devm_iio_device_alloc(&pdev->dev,
> +				       sizeof(struct ep93xx_adc_priv));
> +	if (!iiodev)
> +		return -ENOMEM;
> +	priv = iio_priv(iiodev);
> +
> +	priv->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(priv->clk)) {
> +		dev_err(&pdev->dev, "Cannot obtain clock");
> +		return PTR_ERR(priv->clk);
> +	}
> +
> +	pclk = clk_get_parent(priv->clk);
> +	if (!pclk) {
> +		dev_warn(&pdev->dev, "Cannot obtain parent clock");
> +	} else {
> +		/*
> +		 * This is actually a place for improvement:
> +		 * EP93xx ADC supports two clock divisors -- 4 and 16,
> +		 * resulting in conversion rates 3750 and 925 samples per second
> +		 * respectively with 500uS or 2ms settling time respectively.
> +		 * One might find this interesting enough to be configurable.
> +		 */
> +		ret = clk_set_rate(priv->clk, clk_get_rate(pclk) / 16);
> +		if (ret)
> +			dev_warn(&pdev->dev, "Cannot set clock rate");
> +		/*
> +		 * We can tolerate rate setting failure because the module should
> +		 * work in any case.
> +		 */
> +	}
> +
> +	ret = clk_enable(priv->clk);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Cannot enable clock");
> +		return ret;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(&pdev->dev, "Cannot obtain memory resource");
> +		return -ENXIO;
> +	}
> +	priv->base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(priv->base)) {
> +		dev_err(&pdev->dev, "Cannot map memory resource");
> +		return PTR_ERR(priv->base);
> +	}
> +
> +	iiodev->dev.parent = &pdev->dev;
> +	iiodev->name = dev_name(&pdev->dev);
> +	iiodev->modes = INDIO_DIRECT_MODE;
> +	iiodev->info = &ep93xx_adc_info;
> +	iiodev->num_channels = ARRAY_SIZE(ep93xx_adc_channels);
> +	iiodev->channels = ep93xx_adc_channels;
> +
> +	priv->lastch = -1;
> +	mutex_init(&priv->lock);
> +
> +	ret = devm_iio_device_register(&pdev->dev, iiodev);
> +	if (ret)
> +		return ret;
> +
> +	platform_set_drvdata(pdev, iiodev);
I'd reorder as Peter suggested - it doesn't mater obviously but
you could then do return devm_iio_device_register and save
a few lines of code without a lost of functionality.

However, this is racey as the userspace interface will be removed
'after' the clk_disable below.  Basic rule of thumb is that if
you do anything at all in the remove, you can't use devm_iio_device_register
as if it makes sense to do it it must effect device functionality of a
device still exposed to userspace.

> +
> +	return 0;
> +}
> +
> +static int ep93xx_adc_remove(struct platform_device *pdev)
> +{
> +	struct iio_dev *iiodev = platform_get_drvdata(pdev);
> +	struct ep93xx_adc_priv *priv = iio_priv(iiodev);
Personal taste, but I'd roll the above into one call as we never
use the iio_dev in this function..

> +
> +	clk_disable(priv->clk);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver ep93xx_adc_driver = {
> +	.driver = {
> +		.name = "ep93xx-adc",
> +	},
> +	.probe = ep93xx_adc_probe,
> +	.remove = ep93xx_adc_remove,
> +};
> +module_platform_driver(ep93xx_adc_driver);
> +
> +MODULE_AUTHOR("Alexander Sverdlin <alexander.sverdlin@gmail.com>");
> +MODULE_DESCRIPTION("Cirrus Logic EP93XX ADC driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:ep93xx-adc");
> --
> 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] 22+ messages in thread

* Re: [PATCH 5/5] iio: adc: New driver for Cirrus Logic EP93xx ADC
  2015-11-29 16:12     ` Jonathan Cameron
@ 2015-11-29 16:40       ` Alexander Sverdlin
  -1 siblings, 0 replies; 22+ messages in thread
From: Alexander Sverdlin @ 2015-11-29 16:40 UTC (permalink / raw)
  To: Jonathan Cameron, Hartley Sweeten, Ryan Mallon, linux-arm-kernel,
	linux-iio
  Cc: Russell King, Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald

Hello Jonathan!

Thanks for your review!

On 29/11/15 17:12, Jonathan Cameron wrote:
>> New driver adding support for ADC found on Cirrus Logic EP93xx series of SoCs.
>> > Board specific code must take care to create platform device with all necessary
>> > resources.
>> > 
>> > Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
> Datasheet links always appreciated if available.
> 
> Right now Cirrus' website is fighting back so I can't get to any
> of their docs - hence bare with me!

Yeah, with Cirrus one is served elsewhere much better than on the Cirrus's website.
First hit by Google (on "ep9301 user's guide") gives the document which is even
missing at Cirrus:
https://www.embeddedarm.com/documentation/third-party/ts-7000_ep9301-ug.pdf

> A few bits inline.  Primary question which is hard to answer without the
> datasheets is what meaning the channel names actually have?  THe brief
> says they are general purpose.  If so then it's not really valid
> to given them extended names suggesting anything more.

High end models (EP9307, EP9312, EP9315) have TS controller, which can operate
in general purpose ADC mode. In this mode these names are just ball names on the
pinout. They are all the same. There is only one issue -- I have not found any
official numbering for these devices, therefore wanted to expose this naming to
user space. Low end devices (EP9301, EP9302) have same hw block where TS mode is
not advertised, and even though the balls/pins are still named as in TS controller,
they are also referred as ADC0-ADC4 in datasheet. But there are only 5 of them,
so we do not know the numbers for other 3 in the bigger devices.

If this is not the purpose of extend_name, I'll drop them.

[...]

>> > +static const struct iio_chan_spec ep93xx_adc_channels[EP93XX_NUM_CHANNELS] = {
>> > +	EP93XX_ADC_CH(0, "YM",	"ym",	0x608),
>> > +	EP93XX_ADC_CH(1, "SXP",	"sxp",	0x680),
>> > +	EP93XX_ADC_CH(2, "SXM",	"sxm",	0x640),
>> > +	EP93XX_ADC_CH(3, "SYP",	"syp",	0x620),
>> > +	EP93XX_ADC_CH(4, "SYM",	"sym",	0x610),
>> > +	EP93XX_ADC_CH(5, "XP",	"xp",	0x601),
>> > +	EP93XX_ADC_CH(6, "XM",	"xm",	0x602),
>> > +	EP93XX_ADC_CH(7, "YP",	"yp",	0x604),
>> > +};
> Hmm.  I'm a little dubious about the extended names.  What in the device
> acutally restricts them to these uses?  This naming is probably something
> to do with touch screens?  If there is no special purpose hardware then
> I'd just drop the extended names (datasheet names obviously fine if thats
> what they are called on the datasheet!)

see above...

>> > +		ep93xx_adc_delay(DIV_ROUND_UP(1000000, 925),
>> > +				 DIV_ROUND_UP(1000000, 925));
>> > +		/* At this point conversion must be completed, but anyway... */
>> > +		while (1) {
> Might be worth a timeout and adding a sleep in here to avoid a tight
> spin.  Obviously it should always be fine, but who knows!

Yes, I've added a timeout for v2. We really don't need a second sleep here, the sleep
before should ensure polling ends up immediately. But timeout will ensure read
will not hang even if HW is exploded.

[...]

>> > +	ret = devm_iio_device_register(&pdev->dev, iiodev);
>> > +	if (ret)
>> > +		return ret;
>> > +
>> > +	platform_set_drvdata(pdev, iiodev);
> I'd reorder as Peter suggested - it doesn't mater obviously but
> you could then do return devm_iio_device_register and save
> a few lines of code without a lost of functionality.
> 
> However, this is racey as the userspace interface will be removed
> 'after' the clk_disable below.  Basic rule of thumb is that if
> you do anything at all in the remove, you can't use devm_iio_device_register
> as if it makes sense to do it it must effect device functionality of a
> device still exposed to userspace.

This is a valid point... Will drop devm_iio_device_register() usage in v2...

>> > +
>> > +	return 0;
>> > +}
>> > +
>> > +static int ep93xx_adc_remove(struct platform_device *pdev)
>> > +{
>> > +	struct iio_dev *iiodev = platform_get_drvdata(pdev);
>> > +	struct ep93xx_adc_priv *priv = iio_priv(iiodev);
> Personal taste, but I'd roll the above into one call as we never
> use the iio_dev in this function..

Well, dropping devm_iio_device_register() will require its usage...

>> > +
>> > +	clk_disable(priv->clk);
>> > +
>> > +	return 0;
>> > +}

[...]

Regards,
Alexander.

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

* [PATCH 5/5] iio: adc: New driver for Cirrus Logic EP93xx ADC
@ 2015-11-29 16:40       ` Alexander Sverdlin
  0 siblings, 0 replies; 22+ messages in thread
From: Alexander Sverdlin @ 2015-11-29 16:40 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Jonathan!

Thanks for your review!

On 29/11/15 17:12, Jonathan Cameron wrote:
>> New driver adding support for ADC found on Cirrus Logic EP93xx series of SoCs.
>> > Board specific code must take care to create platform device with all necessary
>> > resources.
>> > 
>> > Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
> Datasheet links always appreciated if available.
> 
> Right now Cirrus' website is fighting back so I can't get to any
> of their docs - hence bare with me!

Yeah, with Cirrus one is served elsewhere much better than on the Cirrus's website.
First hit by Google (on "ep9301 user's guide") gives the document which is even
missing at Cirrus:
https://www.embeddedarm.com/documentation/third-party/ts-7000_ep9301-ug.pdf

> A few bits inline.  Primary question which is hard to answer without the
> datasheets is what meaning the channel names actually have?  THe brief
> says they are general purpose.  If so then it's not really valid
> to given them extended names suggesting anything more.

High end models (EP9307, EP9312, EP9315) have TS controller, which can operate
in general purpose ADC mode. In this mode these names are just ball names on the
pinout. They are all the same. There is only one issue -- I have not found any
official numbering for these devices, therefore wanted to expose this naming to
user space. Low end devices (EP9301, EP9302) have same hw block where TS mode is
not advertised, and even though the balls/pins are still named as in TS controller,
they are also referred as ADC0-ADC4 in datasheet. But there are only 5 of them,
so we do not know the numbers for other 3 in the bigger devices.

If this is not the purpose of extend_name, I'll drop them.

[...]

>> > +static const struct iio_chan_spec ep93xx_adc_channels[EP93XX_NUM_CHANNELS] = {
>> > +	EP93XX_ADC_CH(0, "YM",	"ym",	0x608),
>> > +	EP93XX_ADC_CH(1, "SXP",	"sxp",	0x680),
>> > +	EP93XX_ADC_CH(2, "SXM",	"sxm",	0x640),
>> > +	EP93XX_ADC_CH(3, "SYP",	"syp",	0x620),
>> > +	EP93XX_ADC_CH(4, "SYM",	"sym",	0x610),
>> > +	EP93XX_ADC_CH(5, "XP",	"xp",	0x601),
>> > +	EP93XX_ADC_CH(6, "XM",	"xm",	0x602),
>> > +	EP93XX_ADC_CH(7, "YP",	"yp",	0x604),
>> > +};
> Hmm.  I'm a little dubious about the extended names.  What in the device
> acutally restricts them to these uses?  This naming is probably something
> to do with touch screens?  If there is no special purpose hardware then
> I'd just drop the extended names (datasheet names obviously fine if thats
> what they are called on the datasheet!)

see above...

>> > +		ep93xx_adc_delay(DIV_ROUND_UP(1000000, 925),
>> > +				 DIV_ROUND_UP(1000000, 925));
>> > +		/* At this point conversion must be completed, but anyway... */
>> > +		while (1) {
> Might be worth a timeout and adding a sleep in here to avoid a tight
> spin.  Obviously it should always be fine, but who knows!

Yes, I've added a timeout for v2. We really don't need a second sleep here, the sleep
before should ensure polling ends up immediately. But timeout will ensure read
will not hang even if HW is exploded.

[...]

>> > +	ret = devm_iio_device_register(&pdev->dev, iiodev);
>> > +	if (ret)
>> > +		return ret;
>> > +
>> > +	platform_set_drvdata(pdev, iiodev);
> I'd reorder as Peter suggested - it doesn't mater obviously but
> you could then do return devm_iio_device_register and save
> a few lines of code without a lost of functionality.
> 
> However, this is racey as the userspace interface will be removed
> 'after' the clk_disable below.  Basic rule of thumb is that if
> you do anything at all in the remove, you can't use devm_iio_device_register
> as if it makes sense to do it it must effect device functionality of a
> device still exposed to userspace.

This is a valid point... Will drop devm_iio_device_register() usage in v2...

>> > +
>> > +	return 0;
>> > +}
>> > +
>> > +static int ep93xx_adc_remove(struct platform_device *pdev)
>> > +{
>> > +	struct iio_dev *iiodev = platform_get_drvdata(pdev);
>> > +	struct ep93xx_adc_priv *priv = iio_priv(iiodev);
> Personal taste, but I'd roll the above into one call as we never
> use the iio_dev in this function..

Well, dropping devm_iio_device_register() will require its usage...

>> > +
>> > +	clk_disable(priv->clk);
>> > +
>> > +	return 0;
>> > +}

[...]

Regards,
Alexander.

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

* Re: [PATCH 5/5] iio: adc: New driver for Cirrus Logic EP93xx ADC
  2015-11-29 16:40       ` Alexander Sverdlin
@ 2015-11-29 17:19         ` Jonathan Cameron
  -1 siblings, 0 replies; 22+ messages in thread
From: Jonathan Cameron @ 2015-11-29 17:19 UTC (permalink / raw)
  To: Alexander Sverdlin, Hartley Sweeten, Ryan Mallon,
	linux-arm-kernel, linux-iio
  Cc: Russell King, Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald

On 29/11/15 16:40, Alexander Sverdlin wrote:
> Hello Jonathan!
> 
> Thanks for your review!
> 
> On 29/11/15 17:12, Jonathan Cameron wrote:
>>> New driver adding support for ADC found on Cirrus Logic EP93xx series of SoCs.
>>>> Board specific code must take care to create platform device with all necessary
>>>> resources.
>>>>
>>>> Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
>> Datasheet links always appreciated if available.
>>
>> Right now Cirrus' website is fighting back so I can't get to any
>> of their docs - hence bare with me!
> 
> Yeah, with Cirrus one is served elsewhere much better than on the Cirrus's website.
> First hit by Google (on "ep9301 user's guide") gives the document which is even
> missing at Cirrus:
> https://www.embeddedarm.com/documentation/third-party/ts-7000_ep9301-ug.pdf
> 
>> A few bits inline.  Primary question which is hard to answer without the
>> datasheets is what meaning the channel names actually have?  THe brief
>> says they are general purpose.  If so then it's not really valid
>> to given them extended names suggesting anything more.
> 
> High end models (EP9307, EP9312, EP9315) have TS controller, which can operate
> in general purpose ADC mode. In this mode these names are just ball names on the
> pinout. They are all the same. There is only one issue -- I have not found any
> official numbering for these devices, therefore wanted to expose this naming to
> user space. Low end devices (EP9301, EP9302) have same hw block where TS mode is
> not advertised, and even though the balls/pins are still named as in TS controller,
> they are also referred as ADC0-ADC4 in datasheet. But there are only 5 of them,
> so we do not know the numbers for other 3 in the bigger devices.
> 
> If this is not the purpose of extend_name, I'll drop them.
It's not.  We've had discussions about either exposing the datasheet names via
sysfs or perhaps allowing arbitrary labelling but nothing has come of it yet.

Perhaps in this case clear documentation of the mapping is the way to go in 
documentation for the driver.
> 
> [...]
> 
>>>> +static const struct iio_chan_spec ep93xx_adc_channels[EP93XX_NUM_CHANNELS] = {
>>>> +	EP93XX_ADC_CH(0, "YM",	"ym",	0x608),
>>>> +	EP93XX_ADC_CH(1, "SXP",	"sxp",	0x680),
>>>> +	EP93XX_ADC_CH(2, "SXM",	"sxm",	0x640),
>>>> +	EP93XX_ADC_CH(3, "SYP",	"syp",	0x620),
>>>> +	EP93XX_ADC_CH(4, "SYM",	"sym",	0x610),
>>>> +	EP93XX_ADC_CH(5, "XP",	"xp",	0x601),
>>>> +	EP93XX_ADC_CH(6, "XM",	"xm",	0x602),
>>>> +	EP93XX_ADC_CH(7, "YP",	"yp",	0x604),
>>>> +};
>> Hmm.  I'm a little dubious about the extended names.  What in the device
>> acutally restricts them to these uses?  This naming is probably something
>> to do with touch screens?  If there is no special purpose hardware then
>> I'd just drop the extended names (datasheet names obviously fine if thats
>> what they are called on the datasheet!)
> 
> see above...
> 
>>>> +		ep93xx_adc_delay(DIV_ROUND_UP(1000000, 925),
>>>> +				 DIV_ROUND_UP(1000000, 925));
>>>> +		/* At this point conversion must be completed, but anyway... */
>>>> +		while (1) {
>> Might be worth a timeout and adding a sleep in here to avoid a tight
>> spin.  Obviously it should always be fine, but who knows!
> 
> Yes, I've added a timeout for v2. We really don't need a second sleep here, the sleep
> before should ensure polling ends up immediately. But timeout will ensure read
> will not hang even if HW is exploded.
> 
> [...]
> 
>>>> +	ret = devm_iio_device_register(&pdev->dev, iiodev);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	platform_set_drvdata(pdev, iiodev);
>> I'd reorder as Peter suggested - it doesn't mater obviously but
>> you could then do return devm_iio_device_register and save
>> a few lines of code without a lost of functionality.
>>
>> However, this is racey as the userspace interface will be removed
>> 'after' the clk_disable below.  Basic rule of thumb is that if
>> you do anything at all in the remove, you can't use devm_iio_device_register
>> as if it makes sense to do it it must effect device functionality of a
>> device still exposed to userspace.
> 
> This is a valid point... Will drop devm_iio_device_register() usage in v2...
> 
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int ep93xx_adc_remove(struct platform_device *pdev)
>>>> +{
>>>> +	struct iio_dev *iiodev = platform_get_drvdata(pdev);
>>>> +	struct ep93xx_adc_priv *priv = iio_priv(iiodev);
>> Personal taste, but I'd roll the above into one call as we never
>> use the iio_dev in this function..
> 
> Well, dropping devm_iio_device_register() will require its usage...
> 
>>>> +
>>>> +	clk_disable(priv->clk);
>>>> +
>>>> +	return 0;
>>>> +}
> 
> [...]
> 
> Regards,
> Alexander.
> 


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

* [PATCH 5/5] iio: adc: New driver for Cirrus Logic EP93xx ADC
@ 2015-11-29 17:19         ` Jonathan Cameron
  0 siblings, 0 replies; 22+ messages in thread
From: Jonathan Cameron @ 2015-11-29 17:19 UTC (permalink / raw)
  To: linux-arm-kernel

On 29/11/15 16:40, Alexander Sverdlin wrote:
> Hello Jonathan!
> 
> Thanks for your review!
> 
> On 29/11/15 17:12, Jonathan Cameron wrote:
>>> New driver adding support for ADC found on Cirrus Logic EP93xx series of SoCs.
>>>> Board specific code must take care to create platform device with all necessary
>>>> resources.
>>>>
>>>> Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
>> Datasheet links always appreciated if available.
>>
>> Right now Cirrus' website is fighting back so I can't get to any
>> of their docs - hence bare with me!
> 
> Yeah, with Cirrus one is served elsewhere much better than on the Cirrus's website.
> First hit by Google (on "ep9301 user's guide") gives the document which is even
> missing at Cirrus:
> https://www.embeddedarm.com/documentation/third-party/ts-7000_ep9301-ug.pdf
> 
>> A few bits inline.  Primary question which is hard to answer without the
>> datasheets is what meaning the channel names actually have?  THe brief
>> says they are general purpose.  If so then it's not really valid
>> to given them extended names suggesting anything more.
> 
> High end models (EP9307, EP9312, EP9315) have TS controller, which can operate
> in general purpose ADC mode. In this mode these names are just ball names on the
> pinout. They are all the same. There is only one issue -- I have not found any
> official numbering for these devices, therefore wanted to expose this naming to
> user space. Low end devices (EP9301, EP9302) have same hw block where TS mode is
> not advertised, and even though the balls/pins are still named as in TS controller,
> they are also referred as ADC0-ADC4 in datasheet. But there are only 5 of them,
> so we do not know the numbers for other 3 in the bigger devices.
> 
> If this is not the purpose of extend_name, I'll drop them.
It's not.  We've had discussions about either exposing the datasheet names via
sysfs or perhaps allowing arbitrary labelling but nothing has come of it yet.

Perhaps in this case clear documentation of the mapping is the way to go in 
documentation for the driver.
> 
> [...]
> 
>>>> +static const struct iio_chan_spec ep93xx_adc_channels[EP93XX_NUM_CHANNELS] = {
>>>> +	EP93XX_ADC_CH(0, "YM",	"ym",	0x608),
>>>> +	EP93XX_ADC_CH(1, "SXP",	"sxp",	0x680),
>>>> +	EP93XX_ADC_CH(2, "SXM",	"sxm",	0x640),
>>>> +	EP93XX_ADC_CH(3, "SYP",	"syp",	0x620),
>>>> +	EP93XX_ADC_CH(4, "SYM",	"sym",	0x610),
>>>> +	EP93XX_ADC_CH(5, "XP",	"xp",	0x601),
>>>> +	EP93XX_ADC_CH(6, "XM",	"xm",	0x602),
>>>> +	EP93XX_ADC_CH(7, "YP",	"yp",	0x604),
>>>> +};
>> Hmm.  I'm a little dubious about the extended names.  What in the device
>> acutally restricts them to these uses?  This naming is probably something
>> to do with touch screens?  If there is no special purpose hardware then
>> I'd just drop the extended names (datasheet names obviously fine if thats
>> what they are called on the datasheet!)
> 
> see above...
> 
>>>> +		ep93xx_adc_delay(DIV_ROUND_UP(1000000, 925),
>>>> +				 DIV_ROUND_UP(1000000, 925));
>>>> +		/* At this point conversion must be completed, but anyway... */
>>>> +		while (1) {
>> Might be worth a timeout and adding a sleep in here to avoid a tight
>> spin.  Obviously it should always be fine, but who knows!
> 
> Yes, I've added a timeout for v2. We really don't need a second sleep here, the sleep
> before should ensure polling ends up immediately. But timeout will ensure read
> will not hang even if HW is exploded.
> 
> [...]
> 
>>>> +	ret = devm_iio_device_register(&pdev->dev, iiodev);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	platform_set_drvdata(pdev, iiodev);
>> I'd reorder as Peter suggested - it doesn't mater obviously but
>> you could then do return devm_iio_device_register and save
>> a few lines of code without a lost of functionality.
>>
>> However, this is racey as the userspace interface will be removed
>> 'after' the clk_disable below.  Basic rule of thumb is that if
>> you do anything at all in the remove, you can't use devm_iio_device_register
>> as if it makes sense to do it it must effect device functionality of a
>> device still exposed to userspace.
> 
> This is a valid point... Will drop devm_iio_device_register() usage in v2...
> 
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int ep93xx_adc_remove(struct platform_device *pdev)
>>>> +{
>>>> +	struct iio_dev *iiodev = platform_get_drvdata(pdev);
>>>> +	struct ep93xx_adc_priv *priv = iio_priv(iiodev);
>> Personal taste, but I'd roll the above into one call as we never
>> use the iio_dev in this function..
> 
> Well, dropping devm_iio_device_register() will require its usage...
> 
>>>> +
>>>> +	clk_disable(priv->clk);
>>>> +
>>>> +	return 0;
>>>> +}
> 
> [...]
> 
> Regards,
> Alexander.
> 

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

* Re: [PATCH 5/5] iio: adc: New driver for Cirrus Logic EP93xx ADC
  2015-11-29 17:19         ` Jonathan Cameron
@ 2015-11-29 18:27           ` Alexander Sverdlin
  -1 siblings, 0 replies; 22+ messages in thread
From: Alexander Sverdlin @ 2015-11-29 18:27 UTC (permalink / raw)
  To: Jonathan Cameron, Hartley Sweeten, Ryan Mallon, linux-arm-kernel,
	linux-iio
  Cc: Russell King, Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald

Hello Jonathan,

On 29/11/15 18:19, Jonathan Cameron wrote:
>> High end models (EP9307, EP9312, EP9315) have TS controller, which can operate
>> > in general purpose ADC mode. In this mode these names are just ball names on the
>> > pinout. They are all the same. There is only one issue -- I have not found any
>> > official numbering for these devices, therefore wanted to expose this naming to
>> > user space. Low end devices (EP9301, EP9302) have same hw block where TS mode is
>> > not advertised, and even though the balls/pins are still named as in TS controller,
>> > they are also referred as ADC0-ADC4 in datasheet. But there are only 5 of them,
>> > so we do not know the numbers for other 3 in the bigger devices.
>> > 
>> > If this is not the purpose of extend_name, I'll drop them.
> It's not.  We've had discussions about either exposing the datasheet names via
> sysfs or perhaps allowing arbitrary labelling but nothing has come of it yet.
> 
> Perhaps in this case clear documentation of the mapping is the way to go in 
> documentation for the driver.

Do you think something like Documentation/ABI/testing/sysfs-bus-iio-adc-ep93xx is a right
place?

Regards,
Alexander.

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

* [PATCH 5/5] iio: adc: New driver for Cirrus Logic EP93xx ADC
@ 2015-11-29 18:27           ` Alexander Sverdlin
  0 siblings, 0 replies; 22+ messages in thread
From: Alexander Sverdlin @ 2015-11-29 18:27 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Jonathan,

On 29/11/15 18:19, Jonathan Cameron wrote:
>> High end models (EP9307, EP9312, EP9315) have TS controller, which can operate
>> > in general purpose ADC mode. In this mode these names are just ball names on the
>> > pinout. They are all the same. There is only one issue -- I have not found any
>> > official numbering for these devices, therefore wanted to expose this naming to
>> > user space. Low end devices (EP9301, EP9302) have same hw block where TS mode is
>> > not advertised, and even though the balls/pins are still named as in TS controller,
>> > they are also referred as ADC0-ADC4 in datasheet. But there are only 5 of them,
>> > so we do not know the numbers for other 3 in the bigger devices.
>> > 
>> > If this is not the purpose of extend_name, I'll drop them.
> It's not.  We've had discussions about either exposing the datasheet names via
> sysfs or perhaps allowing arbitrary labelling but nothing has come of it yet.
> 
> Perhaps in this case clear documentation of the mapping is the way to go in 
> documentation for the driver.

Do you think something like Documentation/ABI/testing/sysfs-bus-iio-adc-ep93xx is a right
place?

Regards,
Alexander.

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

* Re: [PATCH 5/5] iio: adc: New driver for Cirrus Logic EP93xx ADC
  2015-11-29 18:27           ` Alexander Sverdlin
@ 2015-12-05 18:50             ` Jonathan Cameron
  -1 siblings, 0 replies; 22+ messages in thread
From: Jonathan Cameron @ 2015-12-05 18:50 UTC (permalink / raw)
  To: Alexander Sverdlin, Hartley Sweeten, Ryan Mallon,
	linux-arm-kernel, linux-iio
  Cc: Russell King, Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald

On 29/11/15 18:27, Alexander Sverdlin wrote:
> Hello Jonathan,
> 
> On 29/11/15 18:19, Jonathan Cameron wrote:
>>> High end models (EP9307, EP9312, EP9315) have TS controller, which can operate
>>>> in general purpose ADC mode. In this mode these names are just ball names on the
>>>> pinout. They are all the same. There is only one issue -- I have not found any
>>>> official numbering for these devices, therefore wanted to expose this naming to
>>>> user space. Low end devices (EP9301, EP9302) have same hw block where TS mode is
>>>> not advertised, and even though the balls/pins are still named as in TS controller,
>>>> they are also referred as ADC0-ADC4 in datasheet. But there are only 5 of them,
>>>> so we do not know the numbers for other 3 in the bigger devices.
>>>>
>>>> If this is not the purpose of extend_name, I'll drop them.
>> It's not.  We've had discussions about either exposing the datasheet names via
>> sysfs or perhaps allowing arbitrary labelling but nothing has come of it yet.
>>
>> Perhaps in this case clear documentation of the mapping is the way to go in 
>> documentation for the driver.
> 
> Do you think something like Documentation/ABI/testing/sysfs-bus-iio-adc-ep93xx is a right
> place?
Good question.  You could do it there by explicitly documenting how it ties up with the
sysfs attributes, but that's a bit messy.  I'd put a file
in Documentation/iio describing it.
> 
> Regards,
> Alexander.
> --
> 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] 22+ messages in thread

* [PATCH 5/5] iio: adc: New driver for Cirrus Logic EP93xx ADC
@ 2015-12-05 18:50             ` Jonathan Cameron
  0 siblings, 0 replies; 22+ messages in thread
From: Jonathan Cameron @ 2015-12-05 18:50 UTC (permalink / raw)
  To: linux-arm-kernel

On 29/11/15 18:27, Alexander Sverdlin wrote:
> Hello Jonathan,
> 
> On 29/11/15 18:19, Jonathan Cameron wrote:
>>> High end models (EP9307, EP9312, EP9315) have TS controller, which can operate
>>>> in general purpose ADC mode. In this mode these names are just ball names on the
>>>> pinout. They are all the same. There is only one issue -- I have not found any
>>>> official numbering for these devices, therefore wanted to expose this naming to
>>>> user space. Low end devices (EP9301, EP9302) have same hw block where TS mode is
>>>> not advertised, and even though the balls/pins are still named as in TS controller,
>>>> they are also referred as ADC0-ADC4 in datasheet. But there are only 5 of them,
>>>> so we do not know the numbers for other 3 in the bigger devices.
>>>>
>>>> If this is not the purpose of extend_name, I'll drop them.
>> It's not.  We've had discussions about either exposing the datasheet names via
>> sysfs or perhaps allowing arbitrary labelling but nothing has come of it yet.
>>
>> Perhaps in this case clear documentation of the mapping is the way to go in 
>> documentation for the driver.
> 
> Do you think something like Documentation/ABI/testing/sysfs-bus-iio-adc-ep93xx is a right
> place?
Good question.  You could do it there by explicitly documenting how it ties up with the
sysfs attributes, but that's a bit messy.  I'd put a file
in Documentation/iio describing it.
> 
> Regards,
> Alexander.
> --
> 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] 22+ messages in thread

end of thread, other threads:[~2015-12-05 18:51 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <56558B23.4080506@gmail.com>
2015-11-25 11:50 ` [PATCH 1/5] clk: ep93xx: Implement clk_get_parent() Alexander Sverdlin
2015-11-25 11:50   ` Alexander Sverdlin
2015-11-25 11:50 ` [PATCH 2/5] clk: ep93xx: Add ADC clock Alexander Sverdlin
2015-11-25 11:50   ` Alexander Sverdlin
2015-11-25 11:50 ` [PATCH 3/5] ep93xx: Add ADC platform device support to core Alexander Sverdlin
2015-11-25 11:50   ` Alexander Sverdlin
2015-11-25 11:50 ` [PATCH 4/5] edb93xx: Add ADC platform device Alexander Sverdlin
2015-11-25 11:50   ` Alexander Sverdlin
2015-11-25 11:51 ` [PATCH 5/5] iio: adc: New driver for Cirrus Logic EP93xx ADC Alexander Sverdlin
2015-11-25 11:51   ` Alexander Sverdlin
2015-11-25 12:43   ` Peter Meerwald-Stadler
2015-11-25 13:01     ` Alexander Sverdlin
2015-11-29 16:12   ` Jonathan Cameron
2015-11-29 16:12     ` Jonathan Cameron
2015-11-29 16:40     ` Alexander Sverdlin
2015-11-29 16:40       ` Alexander Sverdlin
2015-11-29 17:19       ` Jonathan Cameron
2015-11-29 17:19         ` Jonathan Cameron
2015-11-29 18:27         ` Alexander Sverdlin
2015-11-29 18:27           ` Alexander Sverdlin
2015-12-05 18:50           ` Jonathan Cameron
2015-12-05 18:50             ` Jonathan Cameron

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.