Devicetree
 help / color / mirror / Atom feed
* [PATCH 2/3] Documentation: devicetree: bindings: add bindings doc for ar1021 driver
From: Martin Kepplinger @ 2017-04-11 10:27 UTC (permalink / raw)
  To: dmitry.torokhov, christian.gmeiner
  Cc: linux, linux-input, linux-kernel, devicetree, Martin Kepplinger
In-Reply-To: <1491906479-17639-1-git-send-email-martin.kepplinger@ginzinger.com>

Add a simple binding document highlighting the supported devices and
I2C bus address.

Signed-off-by: Martin Kepplinger <martin.kepplinger@ginzinger.com>
---
 .../devicetree/bindings/input/touchscreen/ar1021.txt     | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/ar1021.txt

diff --git a/Documentation/devicetree/bindings/input/touchscreen/ar1021.txt b/Documentation/devicetree/bindings/input/touchscreen/ar1021.txt
new file mode 100644
index 0000000..87a8c72
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/ar1021.txt
@@ -0,0 +1,16 @@
+* Microchip AR1020 and AR1021 touchscreen interface (I2C)
+
+Required properties:
+- compatible		: use "microchip,ar1020-i2c" or "microchip,ar1021-i2c"
+- reg			: I2C slave address
+- interrupt-parent	: the phandle for the interrupt controller
+- interrupts		: touch controller interrupt
+
+Example:
+
+	ar1020: ar1020@4d {
+		compatible = "microchip,ar1020-i2c";
+		reg = <0x4d>;
+		interrupt-parent = <&gpio3>;
+		interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
+	};
-- 
2.1.4

^ permalink raw reply related

* [PATCH 1/3] input: touchscreen: ar1021_i2c: add support for AR1020
From: Martin Kepplinger @ 2017-04-11 10:27 UTC (permalink / raw)
  To: dmitry.torokhov, christian.gmeiner
  Cc: linux, linux-input, linux-kernel, devicetree, Martin Kepplinger

ar1021_i2c simply also supports the ar1020 device we use. This is tested.
They also share the same datasheet:

   http://ww1.microchip.com/downloads/en/DeviceDoc/40001393C.pdf

We differentiate not only to make it obvious that we support both devices,
but also to be able to implement the few model specific things in the
future.

Signed-off-by: Martin Kepplinger <martin.kepplinger@ginzinger.com>
---
 drivers/input/touchscreen/Kconfig      |  4 ++--
 drivers/input/touchscreen/ar1021_i2c.c | 13 ++++++++++---
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 33c62e5..535b91a 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -96,8 +96,8 @@ config TOUCHSCREEN_AR1021_I2C
 	tristate "Microchip AR1021 i2c touchscreen"
 	depends on I2C && OF
 	help
-	  Say Y here if you have the Microchip AR1021 touchscreen controller
-	  chip in your system.
+	  Say Y here if you have the Microchip AR1020 or AR1021 touchscreen
+	  controller chip in your system.
 
 	  If unsure, say N.
 
diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c
index 6562b17..1767257 100644
--- a/drivers/input/touchscreen/ar1021_i2c.c
+++ b/drivers/input/touchscreen/ar1021_i2c.c
@@ -1,5 +1,5 @@
 /*
- * Microchip AR1021 driver for I2C
+ * Microchip AR1020 and AR1021 driver for I2C
  *
  * Author: Christian Gmeiner <christian.gmeiner@gmail.com>
  *
@@ -24,6 +24,11 @@ struct ar1021_i2c {
 	u8 data[AR1021_TOCUH_PKG_SIZE];
 };
 
+enum {
+	ar1021,
+	ar1020,
+};
+
 static irqreturn_t ar1021_i2c_irq(int irq, void *dev_id)
 {
 	struct ar1021_i2c *ar1021 = dev_id;
@@ -151,13 +156,15 @@ static int __maybe_unused ar1021_i2c_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(ar1021_i2c_pm, ar1021_i2c_suspend, ar1021_i2c_resume);
 
 static const struct i2c_device_id ar1021_i2c_id[] = {
-	{ "MICROCHIP_AR1021_I2C", 0 },
+	{ "MICROCHIP_AR1021_I2C", ar1021 },
+	{ "MICROCHIP_AR1020_I2C", ar1020 },
 	{ },
 };
 MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id);
 
 static const struct of_device_id ar1021_i2c_of_match[] = {
 	{ .compatible = "microchip,ar1021-i2c", },
+	{ .compatible = "microchip,ar1020-i2c", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, ar1021_i2c_of_match);
@@ -175,5 +182,5 @@ static struct i2c_driver ar1021_i2c_driver = {
 module_i2c_driver(ar1021_i2c_driver);
 
 MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>");
-MODULE_DESCRIPTION("Microchip AR1021 I2C Driver");
+MODULE_DESCRIPTION("Microchip AR1020 and AR1021 I2C Driver");
 MODULE_LICENSE("GPL");
-- 
2.1.4

^ permalink raw reply related

* [GIT PULL] Immutable branch between MFD and IIO due for the v4.12 merge window
From: Lee Jones @ 2017-04-11 10:05 UTC (permalink / raw)
  To: Quentin Schulz
  Cc: sre-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, wens-jdAy2FN1RRM,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	jic23-DgEjT+Ai2ygdnm+yROfE0A, knaack.h-Mmb7MZpHnFY,
	lars-Qo5EllUWu/uELgA04lAiVw, pmeerw-jW+XmwGofnusTnJN9+BGXg,
	icenowy-ymACFijhrKM, liam-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn,
	thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	linux-pm-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <20170404063441.7656-1-quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Enjoy!

The following changes since commit c1ae3cfa0e89fa1a7ecc4c99031f5e9ae99d9201:

  Linux 4.11-rc1 (2017-03-05 12:59:56 -0800)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git ib-mfd-iio-v4.12

for you to fetch changes up to f2499ab450d3052097ba53a7d763f767935c0c59:

  iio: adc: add support for X-Powers AXP20X and AXP22X PMICs ADCs (2017-04-11 11:02:33 +0100)

----------------------------------------------------------------
Immutable branch between MFD and IIO due for the v4.12 merge window

----------------------------------------------------------------
Quentin Schulz (1):
      iio: adc: add support for X-Powers AXP20X and AXP22X PMICs ADCs

 drivers/iio/adc/Kconfig      |  10 +
 drivers/iio/adc/Makefile     |   1 +
 drivers/iio/adc/axp20x_adc.c | 617 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 628 insertions(+)
 create mode 100644 drivers/iio/adc/axp20x_adc.c

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

-- 
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.

^ permalink raw reply

* Re: [RESEND PATCH v4] iio: adc: add support for X-Powers AXP20X and AXP22X PMICs ADCs
From: Lee Jones @ 2017-04-11 10:01 UTC (permalink / raw)
  To: Quentin Schulz
  Cc: sre-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, wens-jdAy2FN1RRM,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	jic23-DgEjT+Ai2ygdnm+yROfE0A, knaack.h-Mmb7MZpHnFY,
	lars-Qo5EllUWu/uELgA04lAiVw, pmeerw-jW+XmwGofnusTnJN9+BGXg,
	icenowy-ymACFijhrKM, liam-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn,
	thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	linux-pm-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <20170411100053.np3zb74e4bo6ca6l@dell>

On Tue, 11 Apr 2017, Lee Jones wrote:

> On Tue, 04 Apr 2017, Quentin Schulz wrote:
> 
> > The X-Powers AXP20X and AXP22X PMICs have multiple ADCs. They expose the
> > battery voltage, battery charge and discharge currents, AC-in and VBUS
> > voltages and currents, 2 GPIOs muxable in ADC mode and PMIC temperature.
> > 
> > This adds support for most of AXP20X and AXP22X ADCs.
> > 
> > Signed-off-by: Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> > Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> > Acked-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
> > Reviewed-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> > ---
> > 
> > Lee, could you merge this through the mfd tree please?
> >  => https://lkml.org/lkml/2017/3/22/47
> 
> Applied, thanks.

Whoops, change of plan.  Since this touched the Makefile and Kconfig,
I'll have to send a pull-request.

> > v4:
> >  - added missing space at the beginning of a comment,
> >  - tidied axp20x_adc_offset_voltage and axp20x_write_raw to use switch case
> >  instead of if conditions,
> >  - added MODULE_DEVICE_TABLE for axp20x_adc_id_match for module autoloading,
> >  - merged two lines in axp20x_remove,
> > 
> > v3:
> >  - moved from switch to if condition in axp20x_adc_raw and
> >  axp22x_adc_raw,
> >  - removed DT support as DT node has been dropped,
> >    - use of platform_device_id
> >  - correctly defined the name of the iio device (name used to probe the
> >  driver),
> >  - added goto for errors in probe,
> >  - added iio_map_array_unregister to the remove function,
> > 
> > v2:
> >  - removed unused defines,
> >  - changed BIT(x) to 1 << x when describing bits purpose for which 2 <<
> >  x or 3 << x exists, to be consistent,
> >  - changed ADC rate defines to macro formulas,
> >  - reordered IIO channels, now different measures (current/voltage) of
> >  the same part of the PMIC (e.g. battery), have the same IIO channel in
> >  their respective IIO type. When a part of the PMIC have only one
> >  measure, a number is jumped,
> >  - left IIO channel mapping in DT to use iio_map structure,
> >  - removed indexing of ADC internal temperature,
> >  - removed unused iio_dev structure in axp20x_adc_iio,
> >  - added a structure for data specific to AXP20X or AXP22X PMICs instead
> >  of using an ID and an if condition when needing to separate the
> >  behaviour of both,
> >  - added a comment on batt_chrg_i really being on 12bits rather than
> >  what the Chinese datasheets say (13 bits),
> >  - corrected the offset for AXP22X PMIC temperature,
> >  - set the ADC rate to a value (100Hz) shared by the AXP20X and AXP22X,
> >  - created macro formulas to compute the ADC rate for each,
> >  - added a condition on presence of ADC_EN2 reg before setting/resetting
> >  it,
> >  - switched from devm_iio_device_unregister to the non-devm function
> >  because of the need for a remove function,
> >  - removed some dead code,
> > 
> >  drivers/iio/adc/Kconfig      |  10 +
> >  drivers/iio/adc/Makefile     |   1 +
> >  drivers/iio/adc/axp20x_adc.c | 617 +++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 628 insertions(+)
> >  create mode 100644 drivers/iio/adc/axp20x_adc.c
> > 
> > diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> > index d777a97..d15e1bd 100644
> > --- a/drivers/iio/adc/Kconfig
> > +++ b/drivers/iio/adc/Kconfig
> > @@ -154,6 +154,16 @@ config AT91_SAMA5D2_ADC
> >  	  To compile this driver as a module, choose M here: the module will be
> >  	  called at91-sama5d2_adc.
> >  
> > +config AXP20X_ADC
> > +	tristate "X-Powers AXP20X and AXP22X ADC driver"
> > +	depends on MFD_AXP20X
> > +	help
> > +	  Say yes here to have support for X-Powers power management IC (PMIC)
> > +	  AXP20X and AXP22X ADC devices.
> > +
> > +	  To compile this driver as a module, choose M here: the module will be
> > +	  called axp20x_adc.
> > +
> >  config AXP288_ADC
> >  	tristate "X-Powers AXP288 ADC driver"
> >  	depends on MFD_AXP20X
> > diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> > index b11bb57..17899b5 100644
> > --- a/drivers/iio/adc/Makefile
> > +++ b/drivers/iio/adc/Makefile
> > @@ -16,6 +16,7 @@ obj-$(CONFIG_AD7887) += ad7887.o
> >  obj-$(CONFIG_AD799X) += ad799x.o
> >  obj-$(CONFIG_AT91_ADC) += at91_adc.o
> >  obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o
> > +obj-$(CONFIG_AXP20X_ADC) += axp20x_adc.o
> >  obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
> >  obj-$(CONFIG_BCM_IPROC_ADC) += bcm_iproc_adc.o
> >  obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
> > diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
> > new file mode 100644
> > index 0000000..11e1771
> > --- /dev/null
> > +++ b/drivers/iio/adc/axp20x_adc.c
> > @@ -0,0 +1,617 @@
> > +/* ADC driver for AXP20X and AXP22X PMICs
> > + *
> > + * Copyright (c) 2016 Free Electrons NextThing Co.
> > + *	Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> > + *
> > + * 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.
> > + */
> > +
> > +#include <linux/completion.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_device.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/regmap.h>
> > +#include <linux/thermal.h>
> > +
> > +#include <linux/iio/iio.h>
> > +#include <linux/iio/driver.h>
> > +#include <linux/iio/machine.h>
> > +#include <linux/mfd/axp20x.h>
> > +
> > +#define AXP20X_ADC_EN1_MASK			GENMASK(7, 0)
> > +
> > +#define AXP20X_ADC_EN2_MASK			(GENMASK(3, 2) | BIT(7))
> > +#define AXP22X_ADC_EN1_MASK			(GENMASK(7, 5) | BIT(0))
> > +
> > +#define AXP20X_GPIO10_IN_RANGE_GPIO0		BIT(0)
> > +#define AXP20X_GPIO10_IN_RANGE_GPIO1		BIT(1)
> > +#define AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(x)	((x) & BIT(0))
> > +#define AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(x)	(((x) & BIT(0)) << 1)
> > +
> > +#define AXP20X_ADC_RATE_MASK			GENMASK(7, 6)
> > +#define AXP20X_ADC_RATE_HZ(x)			((ilog2((x) / 25) << 6) & AXP20X_ADC_RATE_MASK)
> > +#define AXP22X_ADC_RATE_HZ(x)			((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK)
> > +
> > +#define AXP20X_ADC_CHANNEL(_channel, _name, _type, _reg)	\
> > +	{							\
> > +		.type = _type,					\
> > +		.indexed = 1,					\
> > +		.channel = _channel,				\
> > +		.address = _reg,				\
> > +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	\
> > +				      BIT(IIO_CHAN_INFO_SCALE),	\
> > +		.datasheet_name = _name,			\
> > +	}
> > +
> > +#define AXP20X_ADC_CHANNEL_OFFSET(_channel, _name, _type, _reg) \
> > +	{							\
> > +		.type = _type,					\
> > +		.indexed = 1,					\
> > +		.channel = _channel,				\
> > +		.address = _reg,				\
> > +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	\
> > +				      BIT(IIO_CHAN_INFO_SCALE) |\
> > +				      BIT(IIO_CHAN_INFO_OFFSET),\
> > +		.datasheet_name = _name,			\
> > +	}
> > +
> > +struct axp_data;
> > +
> > +struct axp20x_adc_iio {
> > +	struct regmap		*regmap;
> > +	struct axp_data		*data;
> > +};
> > +
> > +enum axp20x_adc_channel_v {
> > +	AXP20X_ACIN_V = 0,
> > +	AXP20X_VBUS_V,
> > +	AXP20X_TS_IN,
> > +	AXP20X_GPIO0_V,
> > +	AXP20X_GPIO1_V,
> > +	AXP20X_IPSOUT_V,
> > +	AXP20X_BATT_V,
> > +};
> > +
> > +enum axp20x_adc_channel_i {
> > +	AXP20X_ACIN_I = 0,
> > +	AXP20X_VBUS_I,
> > +	AXP20X_BATT_CHRG_I,
> > +	AXP20X_BATT_DISCHRG_I,
> > +};
> > +
> > +enum axp22x_adc_channel_v {
> > +	AXP22X_TS_IN = 0,
> > +	AXP22X_BATT_V,
> > +};
> > +
> > +enum axp22x_adc_channel_i {
> > +	AXP22X_BATT_CHRG_I = 1,
> > +	AXP22X_BATT_DISCHRG_I,
> > +};
> > +
> > +static struct iio_map axp20x_maps[] = {
> > +	{
> > +		.consumer_dev_name = "axp20x-usb-power-supply",
> > +		.consumer_channel = "vbus_v",
> > +		.adc_channel_label = "vbus_v",
> > +	}, {
> > +		.consumer_dev_name = "axp20x-usb-power-supply",
> > +		.consumer_channel = "vbus_i",
> > +		.adc_channel_label = "vbus_i",
> > +	}, {
> > +		.consumer_dev_name = "axp20x-ac-power-supply",
> > +		.consumer_channel = "acin_v",
> > +		.adc_channel_label = "acin_v",
> > +	}, {
> > +		.consumer_dev_name = "axp20x-ac-power-supply",
> > +		.consumer_channel = "acin_i",
> > +		.adc_channel_label = "acin_i",
> > +	}, {
> > +		.consumer_dev_name = "axp20x-battery-power-supply",
> > +		.consumer_channel = "batt_v",
> > +		.adc_channel_label = "batt_v",
> > +	}, {
> > +		.consumer_dev_name = "axp20x-battery-power-supply",
> > +		.consumer_channel = "batt_chrg_i",
> > +		.adc_channel_label = "batt_chrg_i",
> > +	}, {
> > +		.consumer_dev_name = "axp20x-battery-power-supply",
> > +		.consumer_channel = "batt_dischrg_i",
> > +		.adc_channel_label = "batt_dischrg_i",
> > +	}, { /* sentinel */ }
> > +};
> > +
> > +static struct iio_map axp22x_maps[] = {
> > +	{
> > +		.consumer_dev_name = "axp20x-battery-power-supply",
> > +		.consumer_channel = "batt_v",
> > +		.adc_channel_label = "batt_v",
> > +	}, {
> > +		.consumer_dev_name = "axp20x-battery-power-supply",
> > +		.consumer_channel = "batt_chrg_i",
> > +		.adc_channel_label = "batt_chrg_i",
> > +	}, {
> > +		.consumer_dev_name = "axp20x-battery-power-supply",
> > +		.consumer_channel = "batt_dischrg_i",
> > +		.adc_channel_label = "batt_dischrg_i",
> > +	}, { /* sentinel */ }
> > +};
> > +
> > +/*
> > + * Channels are mapped by physical system. Their channels share the same index.
> > + * i.e. acin_i is in_current0_raw and acin_v is in_voltage0_raw.
> > + * The only exception is for the battery. batt_v will be in_voltage6_raw and
> > + * charge current in_current6_raw and discharge current will be in_current7_raw.
> > + */
> > +static const struct iio_chan_spec axp20x_adc_channels[] = {
> > +	AXP20X_ADC_CHANNEL(AXP20X_ACIN_V, "acin_v", IIO_VOLTAGE,
> > +			   AXP20X_ACIN_V_ADC_H),
> > +	AXP20X_ADC_CHANNEL(AXP20X_ACIN_I, "acin_i", IIO_CURRENT,
> > +			   AXP20X_ACIN_I_ADC_H),
> > +	AXP20X_ADC_CHANNEL(AXP20X_VBUS_V, "vbus_v", IIO_VOLTAGE,
> > +			   AXP20X_VBUS_V_ADC_H),
> > +	AXP20X_ADC_CHANNEL(AXP20X_VBUS_I, "vbus_i", IIO_CURRENT,
> > +			   AXP20X_VBUS_I_ADC_H),
> > +	{
> > +		.type = IIO_TEMP,
> > +		.address = AXP20X_TEMP_ADC_H,
> > +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> > +				      BIT(IIO_CHAN_INFO_SCALE) |
> > +				      BIT(IIO_CHAN_INFO_OFFSET),
> > +		.datasheet_name = "pmic_temp",
> > +	},
> > +	AXP20X_ADC_CHANNEL_OFFSET(AXP20X_GPIO0_V, "gpio0_v", IIO_VOLTAGE,
> > +				  AXP20X_GPIO0_V_ADC_H),
> > +	AXP20X_ADC_CHANNEL_OFFSET(AXP20X_GPIO1_V, "gpio1_v", IIO_VOLTAGE,
> > +				  AXP20X_GPIO1_V_ADC_H),
> > +	AXP20X_ADC_CHANNEL(AXP20X_IPSOUT_V, "ipsout_v", IIO_VOLTAGE,
> > +			   AXP20X_IPSOUT_V_HIGH_H),
> > +	AXP20X_ADC_CHANNEL(AXP20X_BATT_V, "batt_v", IIO_VOLTAGE,
> > +			   AXP20X_BATT_V_H),
> > +	AXP20X_ADC_CHANNEL(AXP20X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
> > +			   AXP20X_BATT_CHRG_I_H),
> > +	AXP20X_ADC_CHANNEL(AXP20X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
> > +			   AXP20X_BATT_DISCHRG_I_H),
> > +};
> > +
> > +static const struct iio_chan_spec axp22x_adc_channels[] = {
> > +	{
> > +		.type = IIO_TEMP,
> > +		.address = AXP22X_PMIC_TEMP_H,
> > +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> > +				      BIT(IIO_CHAN_INFO_SCALE) |
> > +				      BIT(IIO_CHAN_INFO_OFFSET),
> > +		.datasheet_name = "pmic_temp",
> > +	},
> > +	AXP20X_ADC_CHANNEL(AXP22X_BATT_V, "batt_v", IIO_VOLTAGE,
> > +			   AXP20X_BATT_V_H),
> > +	AXP20X_ADC_CHANNEL(AXP22X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
> > +			   AXP20X_BATT_CHRG_I_H),
> > +	AXP20X_ADC_CHANNEL(AXP22X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
> > +			   AXP20X_BATT_DISCHRG_I_H),
> > +};
> > +
> > +static int axp20x_adc_raw(struct iio_dev *indio_dev,
> > +			  struct iio_chan_spec const *chan, int *val)
> > +{
> > +	struct axp20x_adc_iio *info = iio_priv(indio_dev);
> > +	int size = 12;
> > +
> > +	/*
> > +	 * N.B.:  Unlike the Chinese datasheets tell, the charging current is
> > +	 * stored on 12 bits, not 13 bits. Only discharging current is on 13
> > +	 * bits.
> > +	 */
> > +	if (chan->type == IIO_CURRENT && chan->channel == AXP20X_BATT_DISCHRG_I)
> > +		size = 13;
> > +	else
> > +		size = 12;
> > +
> > +	*val = axp20x_read_variable_width(info->regmap, chan->address, size);
> > +	if (*val < 0)
> > +		return *val;
> > +
> > +	return IIO_VAL_INT;
> > +}
> > +
> > +static int axp22x_adc_raw(struct iio_dev *indio_dev,
> > +			  struct iio_chan_spec const *chan, int *val)
> > +{
> > +	struct axp20x_adc_iio *info = iio_priv(indio_dev);
> > +	int size;
> > +
> > +	/*
> > +	 * N.B.: Unlike the Chinese datasheets tell, the charging current is
> > +	 * stored on 12 bits, not 13 bits. Only discharging current is on 13
> > +	 * bits.
> > +	 */
> > +	if (chan->type == IIO_CURRENT && chan->channel == AXP22X_BATT_DISCHRG_I)
> > +		size = 13;
> > +	else
> > +		size = 12;
> > +
> > +	*val = axp20x_read_variable_width(info->regmap, chan->address, size);
> > +	if (*val < 0)
> > +		return *val;
> > +
> > +	return IIO_VAL_INT;
> > +}
> > +
> > +static int axp20x_adc_scale_voltage(int channel, int *val, int *val2)
> > +{
> > +	switch (channel) {
> > +	case AXP20X_ACIN_V:
> > +	case AXP20X_VBUS_V:
> > +		*val = 1;
> > +		*val2 = 700000;
> > +		return IIO_VAL_INT_PLUS_MICRO;
> > +
> > +	case AXP20X_GPIO0_V:
> > +	case AXP20X_GPIO1_V:
> > +		*val = 0;
> > +		*val2 = 500000;
> > +		return IIO_VAL_INT_PLUS_MICRO;
> > +
> > +	case AXP20X_BATT_V:
> > +		*val = 1;
> > +		*val2 = 100000;
> > +		return IIO_VAL_INT_PLUS_MICRO;
> > +
> > +	case AXP20X_IPSOUT_V:
> > +		*val = 1;
> > +		*val2 = 400000;
> > +		return IIO_VAL_INT_PLUS_MICRO;
> > +
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +static int axp20x_adc_scale_current(int channel, int *val, int *val2)
> > +{
> > +	switch (channel) {
> > +	case AXP20X_ACIN_I:
> > +		*val = 0;
> > +		*val2 = 625000;
> > +		return IIO_VAL_INT_PLUS_MICRO;
> > +
> > +	case AXP20X_VBUS_I:
> > +		*val = 0;
> > +		*val2 = 375000;
> > +		return IIO_VAL_INT_PLUS_MICRO;
> > +
> > +	case AXP20X_BATT_DISCHRG_I:
> > +	case AXP20X_BATT_CHRG_I:
> > +		*val = 0;
> > +		*val2 = 500000;
> > +		return IIO_VAL_INT_PLUS_MICRO;
> > +
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +static int axp20x_adc_scale(struct iio_chan_spec const *chan, int *val,
> > +			    int *val2)
> > +{
> > +	switch (chan->type) {
> > +	case IIO_VOLTAGE:
> > +		return axp20x_adc_scale_voltage(chan->channel, val, val2);
> > +
> > +	case IIO_CURRENT:
> > +		return axp20x_adc_scale_current(chan->channel, val, val2);
> > +
> > +	case IIO_TEMP:
> > +		*val = 100;
> > +		return IIO_VAL_INT;
> > +
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +static int axp22x_adc_scale(struct iio_chan_spec const *chan, int *val,
> > +			    int *val2)
> > +{
> > +	switch (chan->type) {
> > +	case IIO_VOLTAGE:
> > +		if (chan->channel != AXP22X_BATT_V)
> > +			return -EINVAL;
> > +
> > +		*val = 1;
> > +		*val2 = 100000;
> > +		return IIO_VAL_INT_PLUS_MICRO;
> > +
> > +	case IIO_CURRENT:
> > +		*val = 0;
> > +		*val2 = 500000;
> > +		return IIO_VAL_INT_PLUS_MICRO;
> > +
> > +	case IIO_TEMP:
> > +		*val = 100;
> > +		return IIO_VAL_INT;
> > +
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
> > +				     int *val)
> > +{
> > +	struct axp20x_adc_iio *info = iio_priv(indio_dev);
> > +	int ret;
> > +
> > +	ret = regmap_read(info->regmap, AXP20X_GPIO10_IN_RANGE, val);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	switch (channel) {
> > +	case AXP20X_GPIO0_V:
> > +		*val &= AXP20X_GPIO10_IN_RANGE_GPIO0;
> > +		break;
> > +
> > +	case AXP20X_GPIO1_V:
> > +		*val &= AXP20X_GPIO10_IN_RANGE_GPIO1;
> > +		break;
> > +
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +
> > +	*val = !!(*val) * 700000;
> > +
> > +	return IIO_VAL_INT;
> > +}
> > +
> > +static int axp20x_adc_offset(struct iio_dev *indio_dev,
> > +			     struct iio_chan_spec const *chan, int *val)
> > +{
> > +	switch (chan->type) {
> > +	case IIO_VOLTAGE:
> > +		return axp20x_adc_offset_voltage(indio_dev, chan->channel, val);
> > +
> > +	case IIO_TEMP:
> > +		*val = -1447;
> > +		return IIO_VAL_INT;
> > +
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +static int axp20x_read_raw(struct iio_dev *indio_dev,
> > +			   struct iio_chan_spec const *chan, int *val,
> > +			   int *val2, long mask)
> > +{
> > +	switch (mask) {
> > +	case IIO_CHAN_INFO_OFFSET:
> > +		return axp20x_adc_offset(indio_dev, chan, val);
> > +
> > +	case IIO_CHAN_INFO_SCALE:
> > +		return axp20x_adc_scale(chan, val, val2);
> > +
> > +	case IIO_CHAN_INFO_RAW:
> > +		return axp20x_adc_raw(indio_dev, chan, val);
> > +
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +static int axp22x_read_raw(struct iio_dev *indio_dev,
> > +			   struct iio_chan_spec const *chan, int *val,
> > +			   int *val2, long mask)
> > +{
> > +	switch (mask) {
> > +	case IIO_CHAN_INFO_OFFSET:
> > +		*val = -2677;
> > +		return IIO_VAL_INT;
> > +
> > +	case IIO_CHAN_INFO_SCALE:
> > +		return axp22x_adc_scale(chan, val, val2);
> > +
> > +	case IIO_CHAN_INFO_RAW:
> > +		return axp22x_adc_raw(indio_dev, chan, val);
> > +
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +static int axp20x_write_raw(struct iio_dev *indio_dev,
> > +			    struct iio_chan_spec const *chan, int val, int val2,
> > +			    long mask)
> > +{
> > +	struct axp20x_adc_iio *info = iio_priv(indio_dev);
> > +	unsigned int reg, regval;
> > +
> > +	/*
> > +	 * The AXP20X PMIC allows the user to choose between 0V and 0.7V offsets
> > +	 * for (independently) GPIO0 and GPIO1 when in ADC mode.
> > +	 */
> > +	if (mask != IIO_CHAN_INFO_OFFSET)
> > +		return -EINVAL;
> > +
> > +	if (val != 0 && val != 700000)
> > +		return -EINVAL;
> > +
> > +	switch (chan->channel) {
> > +	case AXP20X_GPIO0_V:
> > +		reg = AXP20X_GPIO10_IN_RANGE_GPIO0;
> > +		regval = AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(!!val);
> > +		break;
> > +
> > +	case AXP20X_GPIO1_V:
> > +		reg = AXP20X_GPIO10_IN_RANGE_GPIO1;
> > +		regval = AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(!!val);
> > +		break;
> > +
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +
> > +	return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE, reg,
> > +				  regval);
> > +}
> > +
> > +static const struct iio_info axp20x_adc_iio_info = {
> > +	.read_raw = axp20x_read_raw,
> > +	.write_raw = axp20x_write_raw,
> > +	.driver_module = THIS_MODULE,
> > +};
> > +
> > +static const struct iio_info axp22x_adc_iio_info = {
> > +	.read_raw = axp22x_read_raw,
> > +	.driver_module = THIS_MODULE,
> > +};
> > +
> > +static int axp20x_adc_rate(int rate)
> > +{
> > +	return AXP20X_ADC_RATE_HZ(rate);
> > +}
> > +
> > +static int axp22x_adc_rate(int rate)
> > +{
> > +	return AXP22X_ADC_RATE_HZ(rate);
> > +}
> > +
> > +struct axp_data {
> > +	const struct iio_info		*iio_info;
> > +	int				num_channels;
> > +	struct iio_chan_spec const	*channels;
> > +	unsigned long			adc_en1_mask;
> > +	int				(*adc_rate)(int rate);
> > +	bool				adc_en2;
> > +	struct iio_map			*maps;
> > +};
> > +
> > +static const struct axp_data axp20x_data = {
> > +	.iio_info = &axp20x_adc_iio_info,
> > +	.num_channels = ARRAY_SIZE(axp20x_adc_channels),
> > +	.channels = axp20x_adc_channels,
> > +	.adc_en1_mask = AXP20X_ADC_EN1_MASK,
> > +	.adc_rate = axp20x_adc_rate,
> > +	.adc_en2 = true,
> > +	.maps = axp20x_maps,
> > +};
> > +
> > +static const struct axp_data axp22x_data = {
> > +	.iio_info = &axp22x_adc_iio_info,
> > +	.num_channels = ARRAY_SIZE(axp22x_adc_channels),
> > +	.channels = axp22x_adc_channels,
> > +	.adc_en1_mask = AXP22X_ADC_EN1_MASK,
> > +	.adc_rate = axp22x_adc_rate,
> > +	.adc_en2 = false,
> > +	.maps = axp22x_maps,
> > +};
> > +
> > +static const struct platform_device_id axp20x_adc_id_match[] = {
> > +	{ .name = "axp20x-adc", .driver_data = (kernel_ulong_t)&axp20x_data, },
> > +	{ .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, },
> > +	{ /* sentinel */ },
> > +};
> > +MODULE_DEVICE_TABLE(platform, axp20x_adc_id_match);
> > +
> > +static int axp20x_probe(struct platform_device *pdev)
> > +{
> > +	struct axp20x_adc_iio *info;
> > +	struct iio_dev *indio_dev;
> > +	struct axp20x_dev *axp20x_dev;
> > +	int ret;
> > +
> > +	axp20x_dev = dev_get_drvdata(pdev->dev.parent);
> > +
> > +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
> > +	if (!indio_dev)
> > +		return -ENOMEM;
> > +
> > +	info = iio_priv(indio_dev);
> > +	platform_set_drvdata(pdev, indio_dev);
> > +
> > +	info->regmap = axp20x_dev->regmap;
> > +	indio_dev->dev.parent = &pdev->dev;
> > +	indio_dev->dev.of_node = pdev->dev.of_node;
> > +	indio_dev->modes = INDIO_DIRECT_MODE;
> > +
> > +	info->data = (struct axp_data *)platform_get_device_id(pdev)->driver_data;
> > +
> > +	indio_dev->name = platform_get_device_id(pdev)->name;
> > +	indio_dev->info = info->data->iio_info;
> > +	indio_dev->num_channels = info->data->num_channels;
> > +	indio_dev->channels = info->data->channels;
> > +
> > +	/* Enable the ADCs on IP */
> > +	regmap_write(info->regmap, AXP20X_ADC_EN1, info->data->adc_en1_mask);
> > +
> > +	if (info->data->adc_en2)
> > +		/* Enable GPIO0/1 and internal temperature ADCs */
> > +		regmap_update_bits(info->regmap, AXP20X_ADC_EN2,
> > +				   AXP20X_ADC_EN2_MASK, AXP20X_ADC_EN2_MASK);
> > +
> > +	/* Configure ADCs rate */
> > +	regmap_update_bits(info->regmap, AXP20X_ADC_RATE, AXP20X_ADC_RATE_MASK,
> > +			   info->data->adc_rate(100));
> > +
> > +	ret = iio_map_array_register(indio_dev, info->data->maps);
> > +	if (ret < 0) {
> > +		dev_err(&pdev->dev, "failed to register IIO maps: %d\n", ret);
> > +		goto fail_map;
> > +	}
> > +
> > +	ret = iio_device_register(indio_dev);
> > +	if (ret < 0) {
> > +		dev_err(&pdev->dev, "could not register the device\n");
> > +		goto fail_register;
> > +	}
> > +
> > +	return 0;
> > +
> > +fail_register:
> > +	iio_map_array_unregister(indio_dev);
> > +
> > +fail_map:
> > +	regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
> > +
> > +	if (info->data->adc_en2)
> > +		regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
> > +
> > +	return ret;
> > +}
> > +
> > +static int axp20x_remove(struct platform_device *pdev)
> > +{
> > +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> > +	struct axp20x_adc_iio *info = iio_priv(indio_dev);
> > +
> > +	iio_device_unregister(indio_dev);
> > +	iio_map_array_unregister(indio_dev);
> > +
> > +	regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
> > +
> > +	if (info->data->adc_en2)
> > +		regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
> > +
> > +	return 0;
> > +}
> > +
> > +static struct platform_driver axp20x_adc_driver = {
> > +	.driver = {
> > +		.name = "axp20x-adc",
> > +	},
> > +	.id_table = axp20x_adc_id_match,
> > +	.probe = axp20x_probe,
> > +	.remove = axp20x_remove,
> > +};
> > +
> > +module_platform_driver(axp20x_adc_driver);
> > +
> > +MODULE_DESCRIPTION("ADC driver for AXP20X and AXP22X PMICs");
> > +MODULE_AUTHOR("Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>");
> > +MODULE_LICENSE("GPL");
> 

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

-- 
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.

^ permalink raw reply

* Re: [RESEND PATCH v4] iio: adc: add support for X-Powers AXP20X and AXP22X PMICs ADCs
From: Lee Jones @ 2017-04-11 10:00 UTC (permalink / raw)
  To: Quentin Schulz
  Cc: sre-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, wens-jdAy2FN1RRM,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	jic23-DgEjT+Ai2ygdnm+yROfE0A, knaack.h-Mmb7MZpHnFY,
	lars-Qo5EllUWu/uELgA04lAiVw, pmeerw-jW+XmwGofnusTnJN9+BGXg,
	icenowy-ymACFijhrKM, liam-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn,
	thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	linux-pm-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <20170404063441.7656-1-quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

On Tue, 04 Apr 2017, Quentin Schulz wrote:

> The X-Powers AXP20X and AXP22X PMICs have multiple ADCs. They expose the
> battery voltage, battery charge and discharge currents, AC-in and VBUS
> voltages and currents, 2 GPIOs muxable in ADC mode and PMIC temperature.
> 
> This adds support for most of AXP20X and AXP22X ADCs.
> 
> Signed-off-by: Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> Acked-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
> Reviewed-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> ---
> 
> Lee, could you merge this through the mfd tree please?
>  => https://lkml.org/lkml/2017/3/22/47

Applied, thanks.

> v4:
>  - added missing space at the beginning of a comment,
>  - tidied axp20x_adc_offset_voltage and axp20x_write_raw to use switch case
>  instead of if conditions,
>  - added MODULE_DEVICE_TABLE for axp20x_adc_id_match for module autoloading,
>  - merged two lines in axp20x_remove,
> 
> v3:
>  - moved from switch to if condition in axp20x_adc_raw and
>  axp22x_adc_raw,
>  - removed DT support as DT node has been dropped,
>    - use of platform_device_id
>  - correctly defined the name of the iio device (name used to probe the
>  driver),
>  - added goto for errors in probe,
>  - added iio_map_array_unregister to the remove function,
> 
> v2:
>  - removed unused defines,
>  - changed BIT(x) to 1 << x when describing bits purpose for which 2 <<
>  x or 3 << x exists, to be consistent,
>  - changed ADC rate defines to macro formulas,
>  - reordered IIO channels, now different measures (current/voltage) of
>  the same part of the PMIC (e.g. battery), have the same IIO channel in
>  their respective IIO type. When a part of the PMIC have only one
>  measure, a number is jumped,
>  - left IIO channel mapping in DT to use iio_map structure,
>  - removed indexing of ADC internal temperature,
>  - removed unused iio_dev structure in axp20x_adc_iio,
>  - added a structure for data specific to AXP20X or AXP22X PMICs instead
>  of using an ID and an if condition when needing to separate the
>  behaviour of both,
>  - added a comment on batt_chrg_i really being on 12bits rather than
>  what the Chinese datasheets say (13 bits),
>  - corrected the offset for AXP22X PMIC temperature,
>  - set the ADC rate to a value (100Hz) shared by the AXP20X and AXP22X,
>  - created macro formulas to compute the ADC rate for each,
>  - added a condition on presence of ADC_EN2 reg before setting/resetting
>  it,
>  - switched from devm_iio_device_unregister to the non-devm function
>  because of the need for a remove function,
>  - removed some dead code,
> 
>  drivers/iio/adc/Kconfig      |  10 +
>  drivers/iio/adc/Makefile     |   1 +
>  drivers/iio/adc/axp20x_adc.c | 617 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 628 insertions(+)
>  create mode 100644 drivers/iio/adc/axp20x_adc.c
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index d777a97..d15e1bd 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -154,6 +154,16 @@ config AT91_SAMA5D2_ADC
>  	  To compile this driver as a module, choose M here: the module will be
>  	  called at91-sama5d2_adc.
>  
> +config AXP20X_ADC
> +	tristate "X-Powers AXP20X and AXP22X ADC driver"
> +	depends on MFD_AXP20X
> +	help
> +	  Say yes here to have support for X-Powers power management IC (PMIC)
> +	  AXP20X and AXP22X ADC devices.
> +
> +	  To compile this driver as a module, choose M here: the module will be
> +	  called axp20x_adc.
> +
>  config AXP288_ADC
>  	tristate "X-Powers AXP288 ADC driver"
>  	depends on MFD_AXP20X
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index b11bb57..17899b5 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -16,6 +16,7 @@ obj-$(CONFIG_AD7887) += ad7887.o
>  obj-$(CONFIG_AD799X) += ad799x.o
>  obj-$(CONFIG_AT91_ADC) += at91_adc.o
>  obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o
> +obj-$(CONFIG_AXP20X_ADC) += axp20x_adc.o
>  obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
>  obj-$(CONFIG_BCM_IPROC_ADC) += bcm_iproc_adc.o
>  obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
> diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
> new file mode 100644
> index 0000000..11e1771
> --- /dev/null
> +++ b/drivers/iio/adc/axp20x_adc.c
> @@ -0,0 +1,617 @@
> +/* ADC driver for AXP20X and AXP22X PMICs
> + *
> + * Copyright (c) 2016 Free Electrons NextThing Co.
> + *	Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> + *
> + * 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.
> + */
> +
> +#include <linux/completion.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <linux/thermal.h>
> +
> +#include <linux/iio/iio.h>
> +#include <linux/iio/driver.h>
> +#include <linux/iio/machine.h>
> +#include <linux/mfd/axp20x.h>
> +
> +#define AXP20X_ADC_EN1_MASK			GENMASK(7, 0)
> +
> +#define AXP20X_ADC_EN2_MASK			(GENMASK(3, 2) | BIT(7))
> +#define AXP22X_ADC_EN1_MASK			(GENMASK(7, 5) | BIT(0))
> +
> +#define AXP20X_GPIO10_IN_RANGE_GPIO0		BIT(0)
> +#define AXP20X_GPIO10_IN_RANGE_GPIO1		BIT(1)
> +#define AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(x)	((x) & BIT(0))
> +#define AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(x)	(((x) & BIT(0)) << 1)
> +
> +#define AXP20X_ADC_RATE_MASK			GENMASK(7, 6)
> +#define AXP20X_ADC_RATE_HZ(x)			((ilog2((x) / 25) << 6) & AXP20X_ADC_RATE_MASK)
> +#define AXP22X_ADC_RATE_HZ(x)			((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK)
> +
> +#define AXP20X_ADC_CHANNEL(_channel, _name, _type, _reg)	\
> +	{							\
> +		.type = _type,					\
> +		.indexed = 1,					\
> +		.channel = _channel,				\
> +		.address = _reg,				\
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	\
> +				      BIT(IIO_CHAN_INFO_SCALE),	\
> +		.datasheet_name = _name,			\
> +	}
> +
> +#define AXP20X_ADC_CHANNEL_OFFSET(_channel, _name, _type, _reg) \
> +	{							\
> +		.type = _type,					\
> +		.indexed = 1,					\
> +		.channel = _channel,				\
> +		.address = _reg,				\
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	\
> +				      BIT(IIO_CHAN_INFO_SCALE) |\
> +				      BIT(IIO_CHAN_INFO_OFFSET),\
> +		.datasheet_name = _name,			\
> +	}
> +
> +struct axp_data;
> +
> +struct axp20x_adc_iio {
> +	struct regmap		*regmap;
> +	struct axp_data		*data;
> +};
> +
> +enum axp20x_adc_channel_v {
> +	AXP20X_ACIN_V = 0,
> +	AXP20X_VBUS_V,
> +	AXP20X_TS_IN,
> +	AXP20X_GPIO0_V,
> +	AXP20X_GPIO1_V,
> +	AXP20X_IPSOUT_V,
> +	AXP20X_BATT_V,
> +};
> +
> +enum axp20x_adc_channel_i {
> +	AXP20X_ACIN_I = 0,
> +	AXP20X_VBUS_I,
> +	AXP20X_BATT_CHRG_I,
> +	AXP20X_BATT_DISCHRG_I,
> +};
> +
> +enum axp22x_adc_channel_v {
> +	AXP22X_TS_IN = 0,
> +	AXP22X_BATT_V,
> +};
> +
> +enum axp22x_adc_channel_i {
> +	AXP22X_BATT_CHRG_I = 1,
> +	AXP22X_BATT_DISCHRG_I,
> +};
> +
> +static struct iio_map axp20x_maps[] = {
> +	{
> +		.consumer_dev_name = "axp20x-usb-power-supply",
> +		.consumer_channel = "vbus_v",
> +		.adc_channel_label = "vbus_v",
> +	}, {
> +		.consumer_dev_name = "axp20x-usb-power-supply",
> +		.consumer_channel = "vbus_i",
> +		.adc_channel_label = "vbus_i",
> +	}, {
> +		.consumer_dev_name = "axp20x-ac-power-supply",
> +		.consumer_channel = "acin_v",
> +		.adc_channel_label = "acin_v",
> +	}, {
> +		.consumer_dev_name = "axp20x-ac-power-supply",
> +		.consumer_channel = "acin_i",
> +		.adc_channel_label = "acin_i",
> +	}, {
> +		.consumer_dev_name = "axp20x-battery-power-supply",
> +		.consumer_channel = "batt_v",
> +		.adc_channel_label = "batt_v",
> +	}, {
> +		.consumer_dev_name = "axp20x-battery-power-supply",
> +		.consumer_channel = "batt_chrg_i",
> +		.adc_channel_label = "batt_chrg_i",
> +	}, {
> +		.consumer_dev_name = "axp20x-battery-power-supply",
> +		.consumer_channel = "batt_dischrg_i",
> +		.adc_channel_label = "batt_dischrg_i",
> +	}, { /* sentinel */ }
> +};
> +
> +static struct iio_map axp22x_maps[] = {
> +	{
> +		.consumer_dev_name = "axp20x-battery-power-supply",
> +		.consumer_channel = "batt_v",
> +		.adc_channel_label = "batt_v",
> +	}, {
> +		.consumer_dev_name = "axp20x-battery-power-supply",
> +		.consumer_channel = "batt_chrg_i",
> +		.adc_channel_label = "batt_chrg_i",
> +	}, {
> +		.consumer_dev_name = "axp20x-battery-power-supply",
> +		.consumer_channel = "batt_dischrg_i",
> +		.adc_channel_label = "batt_dischrg_i",
> +	}, { /* sentinel */ }
> +};
> +
> +/*
> + * Channels are mapped by physical system. Their channels share the same index.
> + * i.e. acin_i is in_current0_raw and acin_v is in_voltage0_raw.
> + * The only exception is for the battery. batt_v will be in_voltage6_raw and
> + * charge current in_current6_raw and discharge current will be in_current7_raw.
> + */
> +static const struct iio_chan_spec axp20x_adc_channels[] = {
> +	AXP20X_ADC_CHANNEL(AXP20X_ACIN_V, "acin_v", IIO_VOLTAGE,
> +			   AXP20X_ACIN_V_ADC_H),
> +	AXP20X_ADC_CHANNEL(AXP20X_ACIN_I, "acin_i", IIO_CURRENT,
> +			   AXP20X_ACIN_I_ADC_H),
> +	AXP20X_ADC_CHANNEL(AXP20X_VBUS_V, "vbus_v", IIO_VOLTAGE,
> +			   AXP20X_VBUS_V_ADC_H),
> +	AXP20X_ADC_CHANNEL(AXP20X_VBUS_I, "vbus_i", IIO_CURRENT,
> +			   AXP20X_VBUS_I_ADC_H),
> +	{
> +		.type = IIO_TEMP,
> +		.address = AXP20X_TEMP_ADC_H,
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> +				      BIT(IIO_CHAN_INFO_SCALE) |
> +				      BIT(IIO_CHAN_INFO_OFFSET),
> +		.datasheet_name = "pmic_temp",
> +	},
> +	AXP20X_ADC_CHANNEL_OFFSET(AXP20X_GPIO0_V, "gpio0_v", IIO_VOLTAGE,
> +				  AXP20X_GPIO0_V_ADC_H),
> +	AXP20X_ADC_CHANNEL_OFFSET(AXP20X_GPIO1_V, "gpio1_v", IIO_VOLTAGE,
> +				  AXP20X_GPIO1_V_ADC_H),
> +	AXP20X_ADC_CHANNEL(AXP20X_IPSOUT_V, "ipsout_v", IIO_VOLTAGE,
> +			   AXP20X_IPSOUT_V_HIGH_H),
> +	AXP20X_ADC_CHANNEL(AXP20X_BATT_V, "batt_v", IIO_VOLTAGE,
> +			   AXP20X_BATT_V_H),
> +	AXP20X_ADC_CHANNEL(AXP20X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
> +			   AXP20X_BATT_CHRG_I_H),
> +	AXP20X_ADC_CHANNEL(AXP20X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
> +			   AXP20X_BATT_DISCHRG_I_H),
> +};
> +
> +static const struct iio_chan_spec axp22x_adc_channels[] = {
> +	{
> +		.type = IIO_TEMP,
> +		.address = AXP22X_PMIC_TEMP_H,
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> +				      BIT(IIO_CHAN_INFO_SCALE) |
> +				      BIT(IIO_CHAN_INFO_OFFSET),
> +		.datasheet_name = "pmic_temp",
> +	},
> +	AXP20X_ADC_CHANNEL(AXP22X_BATT_V, "batt_v", IIO_VOLTAGE,
> +			   AXP20X_BATT_V_H),
> +	AXP20X_ADC_CHANNEL(AXP22X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
> +			   AXP20X_BATT_CHRG_I_H),
> +	AXP20X_ADC_CHANNEL(AXP22X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
> +			   AXP20X_BATT_DISCHRG_I_H),
> +};
> +
> +static int axp20x_adc_raw(struct iio_dev *indio_dev,
> +			  struct iio_chan_spec const *chan, int *val)
> +{
> +	struct axp20x_adc_iio *info = iio_priv(indio_dev);
> +	int size = 12;
> +
> +	/*
> +	 * N.B.:  Unlike the Chinese datasheets tell, the charging current is
> +	 * stored on 12 bits, not 13 bits. Only discharging current is on 13
> +	 * bits.
> +	 */
> +	if (chan->type == IIO_CURRENT && chan->channel == AXP20X_BATT_DISCHRG_I)
> +		size = 13;
> +	else
> +		size = 12;
> +
> +	*val = axp20x_read_variable_width(info->regmap, chan->address, size);
> +	if (*val < 0)
> +		return *val;
> +
> +	return IIO_VAL_INT;
> +}
> +
> +static int axp22x_adc_raw(struct iio_dev *indio_dev,
> +			  struct iio_chan_spec const *chan, int *val)
> +{
> +	struct axp20x_adc_iio *info = iio_priv(indio_dev);
> +	int size;
> +
> +	/*
> +	 * N.B.: Unlike the Chinese datasheets tell, the charging current is
> +	 * stored on 12 bits, not 13 bits. Only discharging current is on 13
> +	 * bits.
> +	 */
> +	if (chan->type == IIO_CURRENT && chan->channel == AXP22X_BATT_DISCHRG_I)
> +		size = 13;
> +	else
> +		size = 12;
> +
> +	*val = axp20x_read_variable_width(info->regmap, chan->address, size);
> +	if (*val < 0)
> +		return *val;
> +
> +	return IIO_VAL_INT;
> +}
> +
> +static int axp20x_adc_scale_voltage(int channel, int *val, int *val2)
> +{
> +	switch (channel) {
> +	case AXP20X_ACIN_V:
> +	case AXP20X_VBUS_V:
> +		*val = 1;
> +		*val2 = 700000;
> +		return IIO_VAL_INT_PLUS_MICRO;
> +
> +	case AXP20X_GPIO0_V:
> +	case AXP20X_GPIO1_V:
> +		*val = 0;
> +		*val2 = 500000;
> +		return IIO_VAL_INT_PLUS_MICRO;
> +
> +	case AXP20X_BATT_V:
> +		*val = 1;
> +		*val2 = 100000;
> +		return IIO_VAL_INT_PLUS_MICRO;
> +
> +	case AXP20X_IPSOUT_V:
> +		*val = 1;
> +		*val2 = 400000;
> +		return IIO_VAL_INT_PLUS_MICRO;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int axp20x_adc_scale_current(int channel, int *val, int *val2)
> +{
> +	switch (channel) {
> +	case AXP20X_ACIN_I:
> +		*val = 0;
> +		*val2 = 625000;
> +		return IIO_VAL_INT_PLUS_MICRO;
> +
> +	case AXP20X_VBUS_I:
> +		*val = 0;
> +		*val2 = 375000;
> +		return IIO_VAL_INT_PLUS_MICRO;
> +
> +	case AXP20X_BATT_DISCHRG_I:
> +	case AXP20X_BATT_CHRG_I:
> +		*val = 0;
> +		*val2 = 500000;
> +		return IIO_VAL_INT_PLUS_MICRO;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int axp20x_adc_scale(struct iio_chan_spec const *chan, int *val,
> +			    int *val2)
> +{
> +	switch (chan->type) {
> +	case IIO_VOLTAGE:
> +		return axp20x_adc_scale_voltage(chan->channel, val, val2);
> +
> +	case IIO_CURRENT:
> +		return axp20x_adc_scale_current(chan->channel, val, val2);
> +
> +	case IIO_TEMP:
> +		*val = 100;
> +		return IIO_VAL_INT;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int axp22x_adc_scale(struct iio_chan_spec const *chan, int *val,
> +			    int *val2)
> +{
> +	switch (chan->type) {
> +	case IIO_VOLTAGE:
> +		if (chan->channel != AXP22X_BATT_V)
> +			return -EINVAL;
> +
> +		*val = 1;
> +		*val2 = 100000;
> +		return IIO_VAL_INT_PLUS_MICRO;
> +
> +	case IIO_CURRENT:
> +		*val = 0;
> +		*val2 = 500000;
> +		return IIO_VAL_INT_PLUS_MICRO;
> +
> +	case IIO_TEMP:
> +		*val = 100;
> +		return IIO_VAL_INT;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
> +				     int *val)
> +{
> +	struct axp20x_adc_iio *info = iio_priv(indio_dev);
> +	int ret;
> +
> +	ret = regmap_read(info->regmap, AXP20X_GPIO10_IN_RANGE, val);
> +	if (ret < 0)
> +		return ret;
> +
> +	switch (channel) {
> +	case AXP20X_GPIO0_V:
> +		*val &= AXP20X_GPIO10_IN_RANGE_GPIO0;
> +		break;
> +
> +	case AXP20X_GPIO1_V:
> +		*val &= AXP20X_GPIO10_IN_RANGE_GPIO1;
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	*val = !!(*val) * 700000;
> +
> +	return IIO_VAL_INT;
> +}
> +
> +static int axp20x_adc_offset(struct iio_dev *indio_dev,
> +			     struct iio_chan_spec const *chan, int *val)
> +{
> +	switch (chan->type) {
> +	case IIO_VOLTAGE:
> +		return axp20x_adc_offset_voltage(indio_dev, chan->channel, val);
> +
> +	case IIO_TEMP:
> +		*val = -1447;
> +		return IIO_VAL_INT;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int axp20x_read_raw(struct iio_dev *indio_dev,
> +			   struct iio_chan_spec const *chan, int *val,
> +			   int *val2, long mask)
> +{
> +	switch (mask) {
> +	case IIO_CHAN_INFO_OFFSET:
> +		return axp20x_adc_offset(indio_dev, chan, val);
> +
> +	case IIO_CHAN_INFO_SCALE:
> +		return axp20x_adc_scale(chan, val, val2);
> +
> +	case IIO_CHAN_INFO_RAW:
> +		return axp20x_adc_raw(indio_dev, chan, val);
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int axp22x_read_raw(struct iio_dev *indio_dev,
> +			   struct iio_chan_spec const *chan, int *val,
> +			   int *val2, long mask)
> +{
> +	switch (mask) {
> +	case IIO_CHAN_INFO_OFFSET:
> +		*val = -2677;
> +		return IIO_VAL_INT;
> +
> +	case IIO_CHAN_INFO_SCALE:
> +		return axp22x_adc_scale(chan, val, val2);
> +
> +	case IIO_CHAN_INFO_RAW:
> +		return axp22x_adc_raw(indio_dev, chan, val);
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int axp20x_write_raw(struct iio_dev *indio_dev,
> +			    struct iio_chan_spec const *chan, int val, int val2,
> +			    long mask)
> +{
> +	struct axp20x_adc_iio *info = iio_priv(indio_dev);
> +	unsigned int reg, regval;
> +
> +	/*
> +	 * The AXP20X PMIC allows the user to choose between 0V and 0.7V offsets
> +	 * for (independently) GPIO0 and GPIO1 when in ADC mode.
> +	 */
> +	if (mask != IIO_CHAN_INFO_OFFSET)
> +		return -EINVAL;
> +
> +	if (val != 0 && val != 700000)
> +		return -EINVAL;
> +
> +	switch (chan->channel) {
> +	case AXP20X_GPIO0_V:
> +		reg = AXP20X_GPIO10_IN_RANGE_GPIO0;
> +		regval = AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(!!val);
> +		break;
> +
> +	case AXP20X_GPIO1_V:
> +		reg = AXP20X_GPIO10_IN_RANGE_GPIO1;
> +		regval = AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(!!val);
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE, reg,
> +				  regval);
> +}
> +
> +static const struct iio_info axp20x_adc_iio_info = {
> +	.read_raw = axp20x_read_raw,
> +	.write_raw = axp20x_write_raw,
> +	.driver_module = THIS_MODULE,
> +};
> +
> +static const struct iio_info axp22x_adc_iio_info = {
> +	.read_raw = axp22x_read_raw,
> +	.driver_module = THIS_MODULE,
> +};
> +
> +static int axp20x_adc_rate(int rate)
> +{
> +	return AXP20X_ADC_RATE_HZ(rate);
> +}
> +
> +static int axp22x_adc_rate(int rate)
> +{
> +	return AXP22X_ADC_RATE_HZ(rate);
> +}
> +
> +struct axp_data {
> +	const struct iio_info		*iio_info;
> +	int				num_channels;
> +	struct iio_chan_spec const	*channels;
> +	unsigned long			adc_en1_mask;
> +	int				(*adc_rate)(int rate);
> +	bool				adc_en2;
> +	struct iio_map			*maps;
> +};
> +
> +static const struct axp_data axp20x_data = {
> +	.iio_info = &axp20x_adc_iio_info,
> +	.num_channels = ARRAY_SIZE(axp20x_adc_channels),
> +	.channels = axp20x_adc_channels,
> +	.adc_en1_mask = AXP20X_ADC_EN1_MASK,
> +	.adc_rate = axp20x_adc_rate,
> +	.adc_en2 = true,
> +	.maps = axp20x_maps,
> +};
> +
> +static const struct axp_data axp22x_data = {
> +	.iio_info = &axp22x_adc_iio_info,
> +	.num_channels = ARRAY_SIZE(axp22x_adc_channels),
> +	.channels = axp22x_adc_channels,
> +	.adc_en1_mask = AXP22X_ADC_EN1_MASK,
> +	.adc_rate = axp22x_adc_rate,
> +	.adc_en2 = false,
> +	.maps = axp22x_maps,
> +};
> +
> +static const struct platform_device_id axp20x_adc_id_match[] = {
> +	{ .name = "axp20x-adc", .driver_data = (kernel_ulong_t)&axp20x_data, },
> +	{ .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, },
> +	{ /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(platform, axp20x_adc_id_match);
> +
> +static int axp20x_probe(struct platform_device *pdev)
> +{
> +	struct axp20x_adc_iio *info;
> +	struct iio_dev *indio_dev;
> +	struct axp20x_dev *axp20x_dev;
> +	int ret;
> +
> +	axp20x_dev = dev_get_drvdata(pdev->dev.parent);
> +
> +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	info = iio_priv(indio_dev);
> +	platform_set_drvdata(pdev, indio_dev);
> +
> +	info->regmap = axp20x_dev->regmap;
> +	indio_dev->dev.parent = &pdev->dev;
> +	indio_dev->dev.of_node = pdev->dev.of_node;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +
> +	info->data = (struct axp_data *)platform_get_device_id(pdev)->driver_data;
> +
> +	indio_dev->name = platform_get_device_id(pdev)->name;
> +	indio_dev->info = info->data->iio_info;
> +	indio_dev->num_channels = info->data->num_channels;
> +	indio_dev->channels = info->data->channels;
> +
> +	/* Enable the ADCs on IP */
> +	regmap_write(info->regmap, AXP20X_ADC_EN1, info->data->adc_en1_mask);
> +
> +	if (info->data->adc_en2)
> +		/* Enable GPIO0/1 and internal temperature ADCs */
> +		regmap_update_bits(info->regmap, AXP20X_ADC_EN2,
> +				   AXP20X_ADC_EN2_MASK, AXP20X_ADC_EN2_MASK);
> +
> +	/* Configure ADCs rate */
> +	regmap_update_bits(info->regmap, AXP20X_ADC_RATE, AXP20X_ADC_RATE_MASK,
> +			   info->data->adc_rate(100));
> +
> +	ret = iio_map_array_register(indio_dev, info->data->maps);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to register IIO maps: %d\n", ret);
> +		goto fail_map;
> +	}
> +
> +	ret = iio_device_register(indio_dev);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "could not register the device\n");
> +		goto fail_register;
> +	}
> +
> +	return 0;
> +
> +fail_register:
> +	iio_map_array_unregister(indio_dev);
> +
> +fail_map:
> +	regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
> +
> +	if (info->data->adc_en2)
> +		regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
> +
> +	return ret;
> +}
> +
> +static int axp20x_remove(struct platform_device *pdev)
> +{
> +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> +	struct axp20x_adc_iio *info = iio_priv(indio_dev);
> +
> +	iio_device_unregister(indio_dev);
> +	iio_map_array_unregister(indio_dev);
> +
> +	regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
> +
> +	if (info->data->adc_en2)
> +		regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver axp20x_adc_driver = {
> +	.driver = {
> +		.name = "axp20x-adc",
> +	},
> +	.id_table = axp20x_adc_id_match,
> +	.probe = axp20x_probe,
> +	.remove = axp20x_remove,
> +};
> +
> +module_platform_driver(axp20x_adc_driver);
> +
> +MODULE_DESCRIPTION("ADC driver for AXP20X and AXP22X PMICs");
> +MODULE_AUTHOR("Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>");
> +MODULE_LICENSE("GPL");

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

-- 
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.

^ permalink raw reply

* RE: [PATCH v3 2/7] dt-bindings: media: Add MAX2175 binding description
From: Ramesh Shanmugasundaram @ 2017-04-11  9:57 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: robh+dt@kernel.org, mark.rutland@arm.com, mchehab@kernel.org,
	hverkuil@xs4all.nl, sakari.ailus@linux.intel.com, crope@iki.fi,
	Chris Paterson, geert+renesas@glider.be,
	linux-media@vger.kernel.org, devicetree@vger.kernel.org,
	linux-renesas-soc@vger.kernel.org
In-Reply-To: <14921696.qIuO4easis@avalon>

Hi Laurent,

Thanks for the review comments.

> 
> On Tuesday 07 Feb 2017 15:02:32 Ramesh Shanmugasundaram wrote:
> > Add device tree binding documentation for MAX2175 Rf to bits tuner
> > device.
> >
> > Signed-off-by: Ramesh Shanmugasundaram
> > <ramesh.shanmugasundaram@bp.renesas.com> ---
> >  .../devicetree/bindings/media/i2c/max2175.txt      | 61
> +++++++++++++++++++
> >  .../devicetree/bindings/property-units.txt         |  1 +
> >  2 files changed, 62 insertions(+)
> >  create mode 100644
> > Documentation/devicetree/bindings/media/i2c/max2175.txt
> >
> > diff --git a/Documentation/devicetree/bindings/media/i2c/max2175.txt
> > b/Documentation/devicetree/bindings/media/i2c/max2175.txt new file
> > mode
> > 100644
> > index 0000000..f591ab4
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/media/i2c/max2175.txt
> > @@ -0,0 +1,61 @@
> > +Maxim Integrated MAX2175 RF to Bits tuner
> > +-----------------------------------------
> > +
> > +The MAX2175 IC is an advanced analog/digital hybrid-radio receiver
> > +with RF to Bits(r) front-end designed for software-defined radio
> solutions.
> > +
> > +Required properties:
> > +--------------------
> > +- compatible: "maxim,max2175" for MAX2175 RF-to-bits tuner.
> > +- clocks: phandle to the fixed xtal clock.
> > +- clock-names: name of the fixed xtal clock.
> 
> I would mention that the name has to be "xtal". Maybe something like
> 
> - clock-names: name of the fixed xtal clock, shall be "xtal".

Agreed.

> 
> > +- port: child port node of a tuner that defines the local and remote
> > +  endpoints. The remote endpoint is assumed to be an SDR device
> > +  that is capable of receiving the digital samples from the tuner.
> 
> You should refer to the OF graphs bindings here. How about the following
> to document the port node ?
> 
> - port: child port node corresponding to the I2S output, in accordance
> with the video interface bindings defined in
> Documentation/devicetree/bindings/media/video-interfaces.txt. The port
> node must contain at least one endpoint.

Agreed.

> 
> > +Optional properties:
> > +--------------------
> > +- maxim,slave	      : phandle to the master tuner if it is a slave.
> This
> > +			is used to define two tuners in diversity mode
> > +			(1 master, 1 slave). By default each tuner is an
> > +			individual master.
> 
> It seems weird to me to name a property "slave" when it points to the
> master tuner. Shouldn't it be named "maxim,master" ?

Agreed.

> 
> > +- maxim,refout-load-pF: load capacitance value (in pF) on reference
> > +			output drive level. The possible load values are
> > +			 0 (default - refout disabled)
> > +			10
> > +			20
> > +			30
> > +			40
> > +			60
> > +			70
> > +- maxim,am-hiz	      : empty property indicates AM Hi-Z filter path
> is
> > +			selected for AM antenna input. By default this
> > +			filter path is not used.
> 
> Isn't this something that should be selected at runtime through a control
> ? Or does the hardware design dictate whether the filter has to be used or
> must not be used ?

This is dictated by the h/w design and not selectable at run-time. 
I will update these changes in the next patchset.

Thanks,
Ramesh

^ permalink raw reply

* Re: [PATCH v3 2/7] dt-bindings: media: Add MAX2175 binding description
From: Laurent Pinchart @ 2017-04-11  9:42 UTC (permalink / raw)
  To: Ramesh Shanmugasundaram
  Cc: robh+dt, mark.rutland, mchehab, hverkuil, sakari.ailus, crope,
	chris.paterson2, geert+renesas, linux-media, devicetree,
	linux-renesas-soc
In-Reply-To: <1486479757-32128-3-git-send-email-ramesh.shanmugasundaram@bp.renesas.com>

Hi Ramesh,

Thank you for the patch.

On Tuesday 07 Feb 2017 15:02:32 Ramesh Shanmugasundaram wrote:
> Add device tree binding documentation for MAX2175 Rf to bits tuner
> device.
> 
> Signed-off-by: Ramesh Shanmugasundaram
> <ramesh.shanmugasundaram@bp.renesas.com> ---
>  .../devicetree/bindings/media/i2c/max2175.txt      | 61 +++++++++++++++++++
>  .../devicetree/bindings/property-units.txt         |  1 +
>  2 files changed, 62 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/i2c/max2175.txt
> 
> diff --git a/Documentation/devicetree/bindings/media/i2c/max2175.txt
> b/Documentation/devicetree/bindings/media/i2c/max2175.txt new file mode
> 100644
> index 0000000..f591ab4
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/i2c/max2175.txt
> @@ -0,0 +1,61 @@
> +Maxim Integrated MAX2175 RF to Bits tuner
> +-----------------------------------------
> +
> +The MAX2175 IC is an advanced analog/digital hybrid-radio receiver with
> +RF to Bits® front-end designed for software-defined radio solutions.
> +
> +Required properties:
> +--------------------
> +- compatible: "maxim,max2175" for MAX2175 RF-to-bits tuner.
> +- clocks: phandle to the fixed xtal clock.
> +- clock-names: name of the fixed xtal clock.

I would mention that the name has to be "xtal". Maybe something like

- clock-names: name of the fixed xtal clock, shall be "xtal".

> +- port: child port node of a tuner that defines the local and remote
> +  endpoints. The remote endpoint is assumed to be an SDR device
> +  that is capable of receiving the digital samples from the tuner.

You should refer to the OF graphs bindings here. How about the following to 
document the port node ?

- port: child port node corresponding to the I2S output, in accordance with 
the video interface bindings defined in
Documentation/devicetree/bindings/media/video-interfaces.txt. The port node 
must contain at least one endpoint.

> +Optional properties:
> +--------------------
> +- maxim,slave	      : phandle to the master tuner if it is a slave. 
This
> +			is used to define two tuners in diversity mode
> +			(1 master, 1 slave). By default each tuner is an
> +			individual master.

It seems weird to me to name a property "slave" when it points to the master 
tuner. Shouldn't it be named "maxim,master" ?

> +- maxim,refout-load-pF: load capacitance value (in pF) on reference
> +			output drive level. The possible load values are
> +			 0 (default - refout disabled)
> +			10
> +			20
> +			30
> +			40
> +			60
> +			70
> +- maxim,am-hiz	      : empty property indicates AM Hi-Z filter path 
is
> +			selected for AM antenna input. By default this
> +			filter path is not used.

Isn't this something that should be selected at runtime through a control ? Or 
does the hardware design dictate whether the filter has to be used or must not 
be used ?

> +Example:
> +--------
> +
> +Board specific DTS file
> +
> +/* Fixed XTAL clock node */
> +maxim_xtal: clock {
> +	compatible = "fixed-clock";
> +	#clock-cells = <0>;
> +	clock-frequency = <36864000>;
> +};
> +
> +/* A tuner device instance under i2c bus */
> +max2175_0: tuner@60 {
> +	compatible = "maxim,max2175";
> +	reg = <0x60>;
> +	clocks = <&maxim_xtal>;
> +	clock-names = "xtal";
> +	maxim,refout-load-pF = <10>;
> +
> +	port {
> +		max2175_0_ep: endpoint {
> +			remote-endpoint = <&slave_rx_device>;
> +		};
> +	};
> +
> +};
> diff --git a/Documentation/devicetree/bindings/property-units.txt
> b/Documentation/devicetree/bindings/property-units.txt index
> 12278d7..f1f1c22 100644
> --- a/Documentation/devicetree/bindings/property-units.txt
> +++ b/Documentation/devicetree/bindings/property-units.txt
> @@ -28,6 +28,7 @@ Electricity
>  -ohms		: Ohms
>  -micro-ohms	: micro Ohms
>  -microvolt	: micro volts
> +-pF		: pico farads
> 
>  Temperature
>  ----------------------------------------

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* Re: [PATCH 1/2] mfd: arizona: Add GPIO maintain state flag
From: Richard Fitzgerald @ 2017-04-11  9:34 UTC (permalink / raw)
  To: Rob Herring
  Cc: Charles Keepax, linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	lee.jones-QSEj5FYQhm4dnm+yROfE0A, gnurou-Re5JQEeQqe8AvxtiuMwx3w,
	mark.rutland-5wv7dgnIgG8, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	patches-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E
In-Reply-To: <20170410201758.lobmtzxt2jgcwwvc@rob-hp-laptop>

On Mon, 2017-04-10 at 15:17 -0500, Rob Herring wrote:
> On Fri, Apr 07, 2017 at 01:38:44PM +0100, Charles Keepax wrote:
> > The Arizona devices only maintain the state of output GPIOs whilst the
> > CODEC is active, this can cause issues if the CODEC suspends whilst
> > something is relying on the state of one of its GPIOs. However, in
> > many systems the CODEC GPIOs are used for audio related features
> > and thus the state of the GPIOs is unimportant whilst the CODEC is
> > suspended. Often keeping the CODEC resumed in such a system would
> > incur a power impact that is unacceptable.
> > 
> > Add a flag through the second cell of the GPIO specifier in device
> > tree, to allow the user to select whether a GPIO being configured as
> > an output should keep the CODEC resumed.
> 
> If the whole codec can't be suspended, why does this need to be per 
> GPIO? You could just have a single boolean property.
> 

Three reasons I can think of:

1) The GPIO binding already provides for passing extra information
through the binding ("Exact meaning of each specifier cell is controller
specific" as it says in the main gpio binding doc) so why add yet
another custom property to do it?

2) Doing it through the gpio means that if ultimately the child DT node
that is using it gets disabled (status="disabled") or that driver isn't
in use the codec will be able to go to sleep. That won't happen with a
brute-force "big lock".

3) The codec only has to be kept awake while any such GPIO is actually
in use. See (2)

> > 
> > Signed-off-by: Charles Keepax <ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
> > ---
> >  Documentation/devicetree/bindings/mfd/arizona.txt | 5 ++++-
> >  include/dt-bindings/mfd/arizona.h                 | 3 +++
> >  2 files changed, 7 insertions(+), 1 deletion(-)


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v4 2/2] i2c: mux: ltc4306: LTC4306 and LTC4305 I2C multiplexer/switch
From: Michael Hennerich @ 2017-04-11  9:29 UTC (permalink / raw)
  To: Peter Rosin, wsa, robh+dt, mark.rutland, linus.walleij
  Cc: linux-i2c, devicetree, linux-gpio, linux-kernel
In-Reply-To: <67c557ae-f094-9fe4-d2f3-d7a2af2df9ca@axentia.se>

On 06.04.2017 22:03, Peter Rosin wrote:
> On 2017-04-06 13:31, Michael Hennerich wrote:
>> On 06.04.2017 10:39, Peter Rosin wrote:

Hi Peter,

again - thanks for your review.
Comments below.

>>>> +static const struct regmap_config ltc4306_regmap_config = {
>>>> +	.reg_bits = 8,
>>>> +	.val_bits = 8,
>>>> +	.max_register = LTC_REG_SWITCH,
>>>> +	.volatile_reg = ltc4306_is_volatile_reg,
>>>> +	.cache_type = REGCACHE_RBTREE,
>>>
>>> Did you consider REGCACHE_FLAT? There are very few registers and no hole
>>> in the map, and maintaining a tree seems like total overkill.
>>
>> There is no reason to use REGCACHE_FLAT, in our case it will be a single
>> node.
>
> Ok, so that makes me wonder what need REGCACHE_FLAT satisfies? To me,
> a flat regmap seems like a perfect fit here. Oh well...

https://lkml.org/lkml/2012/12/19/172

It's not worth arguing - if you prefer FLAT - then it's FLAT
While it's still round :-)


>>>> +static int ltc4306_gpio_init(struct ltc4306 *data)
>>>> +{
>>>> +	struct device *dev = regmap_get_device(data->regmap);
>>>> +
>>>> +	if (!data->chip->num_gpios)
>>>> +		return 0;
>>>> +
>>>> +	data->gpiochip.label = dev_name(dev);
>>>> +	data->gpiochip.base = -1;
>>>> +	data->gpiochip.ngpio = data->chip->num_gpios;
>>>> +	data->gpiochip.parent = dev;
>>>> +	data->gpiochip.can_sleep = true;
>>>> +	data->gpiochip.direction_input = ltc4306_gpio_direction_input;
>>>> +	data->gpiochip.direction_output = ltc4306_gpio_direction_output;
>>>
>>> I'm missing a get_direction op?
>>
>> No - its purely optional - the vast majority of gpiochips don't
>> implement it.
>>
>> linux/drivers/gpio$ grep -lr --include \*.c get_direction | wc
>>       36      36     523
>> linux/drivers/gpio$ grep -Lr --include \*.c get_direction | wc
>>      101     101    1461
>
> Ok, but while optional, why not provide it? The implementation would
> be about as simple as ltc4306_gpio_get, no?

ok - convinced me.


I'll send version 5 shortly.


-- 
Greetings,
Michael

--
Analog Devices GmbH      Otl-Aicher Strasse 60-64      80807 München
Sitz der Gesellschaft München, Registergericht München HRB 40368,
Geschäftsführer: Peter Kolberg, Ali Raza Husain, Eileen Wynne

^ permalink raw reply

* Re: [PATCH v4 0/9] Renesas RZ/A1 pin and gpio controller
From: Geert Uytterhoeven @ 2017-04-11  9:14 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Jacopo Mondi, Geert Uytterhoeven, Laurent Pinchart, Chris Brandt,
	Rob Herring, Mark Rutland, Russell King, Linux-Renesas,
	linux-gpio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <CACRpkdaxdDX71m4EGSHD2OV1gQsCwQeOCyeMDCndPxNpZU-oPw@mail.gmail.com>

Hi Linus,

On Tue, Apr 11, 2017 at 11:05 AM, Linus Walleij
<linus.walleij@linaro.org> wrote:
> On Wed, Apr 5, 2017 at 4:07 PM, Jacopo Mondi <jacopo+renesas@jmondi.org> wrote:
>> Hi Linus,
>>    this is 4th round of gpio/pincontroller for RZ/A1 devices.
>>
>> As you suggested in v3 review, I have now added what we called pinmux flags
>> to the list of standard pinconf generic properties, and we're now using
>> generic parsing routines to collect them and apply them when multiplexing
>> pins.
>
> I have merged patch 1/9 so you have the necessary infrastructure in place.
>
> If Geert want to send a pull request based on my devel branch that is fine
> (but a bit late) else the requirements are there for a merge in the early
> v4.12 kernel cycle.

I agree it's a bit late. Will queue for v4.13.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH v4 0/9] Renesas RZ/A1 pin and gpio controller
From: Linus Walleij @ 2017-04-11  9:05 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Geert Uytterhoeven, Laurent Pinchart, Chris Brandt, Rob Herring,
	Mark Rutland, Russell King, Linux-Renesas,
	linux-gpio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <1491401247-7030-1-git-send-email-jacopo+renesas@jmondi.org>

On Wed, Apr 5, 2017 at 4:07 PM, Jacopo Mondi <jacopo+renesas@jmondi.org> wrote:

> Hi Linus,
>    this is 4th round of gpio/pincontroller for RZ/A1 devices.
>
> As you suggested in v3 review, I have now added what we called pinmux flags
> to the list of standard pinconf generic properties, and we're now using
> generic parsing routines to collect them and apply them when multiplexing
> pins.

I have merged patch 1/9 so you have the necessary infrastructure in place.

If Geert want to send a pull request based on my devel branch that is fine
(but a bit late) else the requirements are there for a merge in the early
v4.12 kernel cycle.

Yours,
Linus Walleij

^ permalink raw reply

* Re: [git:media_tree/master] [media] ARM: dts: exynos: add HDMI controller phandle to exynos4.dtsi
From: Krzysztof Kozlowski @ 2017-04-11  9:02 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linuxtv-commits, Marek Szyprowski, linux-samsung-soc, devicetree,
	Hans Verkuil, linux-media
In-Reply-To: <20170411055413.07957d91@vento.lan>

On Tue, Apr 11, 2017 at 10:54 AM, Mauro Carvalho Chehab
<mchehab@s-opensource.com> wrote:
> Em Tue, 11 Apr 2017 10:36:58 +0200
> Krzysztof Kozlowski <krzk@kernel.org> escreveu:
>
>> On Mon, Apr 10, 2017 at 6:12 PM, Mauro Carvalho Chehab
>> <mchehab@s-opensource.com> wrote:
>> > This is an automatic generated email to let you know that the following patch were queued:
>> >
>> > Subject: [media] ARM: dts: exynos: add HDMI controller phandle to exynos4.dtsi
>> > Author:  Hans Verkuil <hans.verkuil@cisco.com>
>> > Date:    Tue Dec 13 12:37:16 2016 -0200
>> >
>> > Add the new hdmi phandle to exynos4.dtsi. This phandle is needed by the
>> > s5p-cec driver to initialize the CEC notifier framework.
>> >
>> > Tested with my Odroid U3.
>> >
>> > Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
>> > Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> > CC: linux-samsung-soc@vger.kernel.org
>> > CC: devicetree@vger.kernel.org
>> > CC: Krzysztof Kozlowski <krzk@kernel.org>
>> > Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
>> >
>> >  arch/arm/boot/dts/exynos4.dtsi | 1 +
>> >  1 file changed, 1 insertion(+)
>> >
>>
>> Mauro, you should not apply it. It is already going through samsung-soc [1].
>> if you need this patch for bisectability or any other reasons, I
>> provided a tag with it here:
>> https://www.spinics.net/lists/devicetree/msg171182.html
>>
>> Please drop the patch because now it will get duplicated.
>
> Having exactly the same patch applied on multiple trees usually is
> not a problem, provided that it doesn't rise a non-trivial
> conflict.
>
> I avoid rebase the tree where this patch is applied, as rebasing it
> affect the workflow of other developers.
>
> I'm afraid that, if I revert this patch, it will cause more harm than
> good.

Of course, revert is wrong. The patch should be dropped with rebase,
assuming that you accept the rebase itself. But if you do not
rebase... then it has to  stay.

> So, I guess the best solution to fix the issue would be to pull from
> a stable branch on your tree with has this patch and solve conflicts,
> if any. This way, nothing will popup when merging upstream.

This is why I provided it in separate tag, in first place!
That is a proper solution for avoiding any patch duplication and
conflicts. Indeed you are right that duplication of commits should not
do any harm... but it is not a proper way of development, right?

Anyway, it is up to you. I provided you a tag with it so you can merge
it if needed (which would require rebasing). If not, then of course
please do not revert it.

Best regards,
Krzysztof

^ permalink raw reply

* Re: [PATCH v4 1/9] pinctrl: generic: Add bi-directional and output-enable
From: Linus Walleij @ 2017-04-11  9:01 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Geert Uytterhoeven, Laurent Pinchart, Chris Brandt, Rob Herring,
	Mark Rutland, Russell King, Linux-Renesas,
	linux-gpio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <1491401247-7030-2-git-send-email-jacopo+renesas@jmondi.org>

On Wed, Apr 5, 2017 at 4:07 PM, Jacopo Mondi <jacopo+renesas@jmondi.org> wrote:

> Add bi-directional and output-enable pin configuration properties.
>
> bi-directional allows to specify when a pin shall operate in input and
> output mode at the same time. This is particularly useful in platforms
> where input and output buffers have to be manually enabled.
>
> output-enable is just syntactic sugar to specify that a pin shall
> operate in output mode, ignoring the provided argument.
> This pairs with input-enable pin configuration option.
>
> Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>

Patch applied with Rob's ACK.

Yours,
Linus Walleij

^ permalink raw reply

* Re: [git:media_tree/master] [media] ARM: dts: exynos: add HDMI controller phandle to exynos4.dtsi
From: Mauro Carvalho Chehab @ 2017-04-11  8:54 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: linuxtv-commits, Marek Szyprowski, linux-samsung-soc, devicetree,
	Hans Verkuil, linux-media
In-Reply-To: <CAJKOXPfbJpFu6r9rS8oCqxTH+s7y2wYKx9+TzGrv4Cd8DYaKew@mail.gmail.com>

Em Tue, 11 Apr 2017 10:36:58 +0200
Krzysztof Kozlowski <krzk@kernel.org> escreveu:

> On Mon, Apr 10, 2017 at 6:12 PM, Mauro Carvalho Chehab
> <mchehab@s-opensource.com> wrote:
> > This is an automatic generated email to let you know that the following patch were queued:
> >
> > Subject: [media] ARM: dts: exynos: add HDMI controller phandle to exynos4.dtsi
> > Author:  Hans Verkuil <hans.verkuil@cisco.com>
> > Date:    Tue Dec 13 12:37:16 2016 -0200
> >
> > Add the new hdmi phandle to exynos4.dtsi. This phandle is needed by the
> > s5p-cec driver to initialize the CEC notifier framework.
> >
> > Tested with my Odroid U3.
> >
> > Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> > Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
> > CC: linux-samsung-soc@vger.kernel.org
> > CC: devicetree@vger.kernel.org
> > CC: Krzysztof Kozlowski <krzk@kernel.org>
> > Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
> >
> >  arch/arm/boot/dts/exynos4.dtsi | 1 +
> >  1 file changed, 1 insertion(+)
> >  
> 
> Mauro, you should not apply it. It is already going through samsung-soc [1].
> if you need this patch for bisectability or any other reasons, I
> provided a tag with it here:
> https://www.spinics.net/lists/devicetree/msg171182.html
> 
> Please drop the patch because now it will get duplicated.

Having exactly the same patch applied on multiple trees usually is
not a problem, provided that it doesn't rise a non-trivial
conflict.

I avoid rebase the tree where this patch is applied, as rebasing it
affect the workflow of other developers.

I'm afraid that, if I revert this patch, it will cause more harm than
good. 

So, I guess the best solution to fix the issue would be to pull from 
a stable branch on your tree with has this patch and solve conflicts,
if any. This way, nothing will popup when merging upstream.

Regards,
Mauro

> 
> Best regards,
> Krzysztof
> 
> [1] https://www.spinics.net/lists/arm-kernel/msg575229.html



Thanks,
Mauro

^ permalink raw reply

* Re: [PATCH v4 2/2] i2c: mux: ltc4306: LTC4306 and LTC4305 I2C multiplexer/switch
From: Michael Hennerich @ 2017-04-11  8:46 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Wolfram Sang, Peter Rosin, Rob Herring, Mark Rutland,
	linux-i2c@vger.kernel.org, devicetree@vger.kernel.org,
	linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <CACRpkdbECyEpD7b4OFxwAo6USnK_DGEbASMdTzOO=FQ9BAzRQA@mail.gmail.com>

On 10.04.2017 22:04, Linus Walleij wrote:
> On Wed, Apr 5, 2017 at 3:07 PM,  <michael.hennerich@analog.com> wrote:
>
>> From: Michael Hennerich <michael.hennerich@analog.com>
>>
>> This patch adds support for the Analog Devices / Linear Technology
>> LTC4306 and LTC4305 4/2 Channel I2C Bus Multiplexer/Switches.
>> The LTC4306 optionally provides two general purpose input/output pins
>> (GPIOs) that can be configured as logic inputs, opendrain outputs or
>> push-pull outputs via the generic GPIOLIB framework.
>>
>> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
>
> Okay!

Hi Linus,

Thanks for your review.
Comments below.

>
>> +#include <linux/device.h>
>> +#include <linux/gpio.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/gpio/driver.h>
>
> Why are you including all these?
> Normally a GPIO driver should just include
> <linux/gpio/driver.h>

Well - this driver is also a gpio consumer.
But right I can drop gpio.h, and while gpio/driver.h also includes 
device.h - we don't need it here as well.

>
>> +#include <linux/i2c-mux.h>
>> +#include <linux/i2c.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/regmap.h>
>> +#include <linux/slab.h>
>
>> +static int ltc4306_gpio_get(struct gpio_chip *chip, unsigned int offset)
>> +{
>> +       struct ltc4306 *data = gpiochip_get_data(chip);
>> +       unsigned int val;
>> +       int ret;
>> +
>> +       ret = regmap_read(data->regmap, LTC_REG_CONFIG, &val);
>> +       if (ret < 0)
>> +               return ret;
>> +
>> +       return (val & BIT(1 - offset));
>
> Do this:
>
> return !!(val & BIT(1 - offset));
>
> So you clamp the return value to [0,1]

That's what I had in a previous version of the patch.
Then I noticed gpiolib is also doing this.
Anyways I'll add it back.

>
>> +static int ltc4306_gpio_set_config(struct gpio_chip *chip,
>> +                                  unsigned int offset, unsigned long config)
>> +{
>> +       struct ltc4306 *data = gpiochip_get_data(chip);
>> +       unsigned int val;
>> +
>> +       switch (pinconf_to_config_param(config)) {
>> +       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
>> +               val = 0;
>> +               break;
>> +       case PIN_CONFIG_DRIVE_PUSH_PULL:
>> +               val = BIT(4 - offset);
>> +               break;
>> +       default:
>> +               return -ENOTSUPP;
>> +       }
>> +
>> +       return regmap_update_bits(data->regmap, LTC_REG_MODE,
>> +                                 BIT(4 - offset), val);
>> +}
>
> Nice!
>
>> +       data->gpiochip.label = dev_name(dev);
>> +       data->gpiochip.base = -1;
>> +       data->gpiochip.ngpio = data->chip->num_gpios;
>> +       data->gpiochip.parent = dev;
>> +       data->gpiochip.can_sleep = true;
>> +       data->gpiochip.direction_input = ltc4306_gpio_direction_input;
>> +       data->gpiochip.direction_output = ltc4306_gpio_direction_output;
>> +       data->gpiochip.get = ltc4306_gpio_get;
>> +       data->gpiochip.set = ltc4306_gpio_set;
>> +       data->gpiochip.set_config = ltc4306_gpio_set_config;
>> +       data->gpiochip.owner = THIS_MODULE;
>
> Please implement .get_direction().
> This is very helpful to userspace, have you tested to use tools/gpio/*
> from the kernel? Like lsgpio?

Ok - convinced me.

>
> Yours,
> Linus Walleij
>

-- 
Greetings,
Michael

--
Analog Devices GmbH      Otl-Aicher Strasse 60-64      80807 München
Sitz der Gesellschaft München, Registergericht München HRB 40368,
Geschäftsführer: Peter Kolberg, Ali Raza Husain, Eileen Wynne

^ permalink raw reply

* Re: [git:media_tree/master] [media] ARM: dts: exynos: add HDMI controller phandle to exynos4.dtsi
From: Hans Verkuil @ 2017-04-11  8:39 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Mauro Carvalho Chehab
  Cc: linuxtv-commits-dJidKbW2IEtAfugRpC6u6w, Marek Szyprowski,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Hans Verkuil,
	linux-media-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <CAJKOXPfbJpFu6r9rS8oCqxTH+s7y2wYKx9+TzGrv4Cd8DYaKew-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On 04/11/17 10:36, Krzysztof Kozlowski wrote:
> On Mon, Apr 10, 2017 at 6:12 PM, Mauro Carvalho Chehab
> <mchehab-JsYNTwtnfakRB7SZvlqPiA@public.gmane.org> wrote:
>> This is an automatic generated email to let you know that the following patch were queued:
>>
>> Subject: [media] ARM: dts: exynos: add HDMI controller phandle to exynos4.dtsi
>> Author:  Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
>> Date:    Tue Dec 13 12:37:16 2016 -0200
>>
>> Add the new hdmi phandle to exynos4.dtsi. This phandle is needed by the
>> s5p-cec driver to initialize the CEC notifier framework.
>>
>> Tested with my Odroid U3.
>>
>> Signed-off-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
>> Tested-by: Marek Szyprowski <m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> CC: linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> CC: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> CC: Krzysztof Kozlowski <krzk-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>> Signed-off-by: Mauro Carvalho Chehab <mchehab-JsYNTwtnfakRB7SZvlqPiA@public.gmane.org>
>>
>>  arch/arm/boot/dts/exynos4.dtsi | 1 +
>>  1 file changed, 1 insertion(+)
>>
> 
> Mauro, you should not apply it. It is already going through samsung-soc [1].
> if you need this patch for bisectability or any other reasons, I
> provided a tag with it here:
> https://www.spinics.net/lists/devicetree/msg171182.html
> 
> Please drop the patch because now it will get duplicated.

I apologize for that. I realized that I shouldn't have included this in
my pull request when it was already merged.

My fault completely.

Regards,

	Hans

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [git:media_tree/master] [media] ARM: dts: exynos: add HDMI controller phandle to exynos4.dtsi
From: Krzysztof Kozlowski @ 2017-04-11  8:36 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linuxtv-commits, Marek Szyprowski, linux-samsung-soc, devicetree,
	Hans Verkuil, linux-media
In-Reply-To: <E1cxc0o-0003RE-PP@www.linuxtv.org>

On Mon, Apr 10, 2017 at 6:12 PM, Mauro Carvalho Chehab
<mchehab@s-opensource.com> wrote:
> This is an automatic generated email to let you know that the following patch were queued:
>
> Subject: [media] ARM: dts: exynos: add HDMI controller phandle to exynos4.dtsi
> Author:  Hans Verkuil <hans.verkuil@cisco.com>
> Date:    Tue Dec 13 12:37:16 2016 -0200
>
> Add the new hdmi phandle to exynos4.dtsi. This phandle is needed by the
> s5p-cec driver to initialize the CEC notifier framework.
>
> Tested with my Odroid U3.
>
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
> CC: linux-samsung-soc@vger.kernel.org
> CC: devicetree@vger.kernel.org
> CC: Krzysztof Kozlowski <krzk@kernel.org>
> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
>
>  arch/arm/boot/dts/exynos4.dtsi | 1 +
>  1 file changed, 1 insertion(+)
>

Mauro, you should not apply it. It is already going through samsung-soc [1].
if you need this patch for bisectability or any other reasons, I
provided a tag with it here:
https://www.spinics.net/lists/devicetree/msg171182.html

Please drop the patch because now it will get duplicated.

Best regards,
Krzysztof

[1] https://www.spinics.net/lists/arm-kernel/msg575229.html

^ permalink raw reply

* Re: [PATCH v3 1/7] media: v4l2-ctrls: Reserve controls for MAX217X
From: Laurent Pinchart @ 2017-04-11  8:28 UTC (permalink / raw)
  To: Ramesh Shanmugasundaram
  Cc: robh+dt, mark.rutland, mchehab, hverkuil, sakari.ailus, crope,
	chris.paterson2, geert+renesas, linux-media, devicetree,
	linux-renesas-soc
In-Reply-To: <1486479757-32128-2-git-send-email-ramesh.shanmugasundaram@bp.renesas.com>

Hi Ramesh,

Thank you for the patch.

On Tuesday 07 Feb 2017 15:02:31 Ramesh Shanmugasundaram wrote:
> Reserve controls for MAX217X RF to Bits tuner family. These hybrid
> radio receiver chips are highly programmable and hence reserving 32
> controls.
> 
> Signed-off-by: Ramesh Shanmugasundaram
> <ramesh.shanmugasundaram@bp.renesas.com>

Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> ---
>  include/uapi/linux/v4l2-controls.h | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/include/uapi/linux/v4l2-controls.h
> b/include/uapi/linux/v4l2-controls.h index 0d2e1e0..83b28b4 100644
> --- a/include/uapi/linux/v4l2-controls.h
> +++ b/include/uapi/linux/v4l2-controls.h
> @@ -180,6 +180,11 @@ enum v4l2_colorfx {
>   * We reserve 16 controls for this driver. */
>  #define V4L2_CID_USER_TC358743_BASE		(V4L2_CID_USER_BASE + 0x1080)
> 
> +/* The base for the max217x driver controls.
> + * We reserve 32 controls for this driver
> + */
> +#define V4L2_CID_USER_MAX217X_BASE		(V4L2_CID_USER_BASE + 0x1090)
> +
>  /* MPEG-class control IDs */
>  /* The MPEG controls are applicable to all codec controls
>   * and the 'MPEG' part of the define is historical */

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* Re: [PATCH v2] mmc: core: add mmc-card hardware reset enable support
From: Linus Walleij @ 2017-04-11  8:17 UTC (permalink / raw)
  To: Richard Leitner, Bart Van Assche, Luca Porzio
  Cc: Ulf Hansson, Rob Herring, Mark Rutland, Shawn Lin, Adrian Hunter,
	Jaehoon Chung, linux-mmc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	Richard Leitner
In-Reply-To: <1491895862-7952-1-git-send-email-richard.leitner@skidata.com>

On Tue, Apr 11, 2017 at 9:31 AM, Richard Leitner
<richard.leitner@skidata.com> wrote:

> Some eMMCs disable their hardware reset line (RST_N) by default. To enable
> it the host must set the corresponding bit in ECSD. An example for such
> a device is the Micron MTFCxGACAANA-4M.
>
> This patch adds a new mmc-card devicetree property to let the host enable
> this feature during card initialization.
>
> Signed-off-by: Richard Leitner <richard.leitner@skidata.com>

Do we know *WHY* these cards disable their hardware reset lines?

If it is just some random over-cautious panic thing we might consider
just force re-enableing it, maybe with a warning in the dmesg, so we can
always reset the card. No DT property needed.

Putting some people who work for eMMC vendors in the To: line so they
can say if they know about this.

Yours,
Linus Walleij

^ permalink raw reply

* Re: [RESEND PATCH v4] iio: adc: add support for X-Powers AXP20X and AXP22X PMICs ADCs
From: Lee Jones @ 2017-04-11  8:01 UTC (permalink / raw)
  To: Quentin Schulz
  Cc: sre-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, wens-jdAy2FN1RRM,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	jic23-DgEjT+Ai2ygdnm+yROfE0A, knaack.h-Mmb7MZpHnFY,
	lars-Qo5EllUWu/uELgA04lAiVw, pmeerw-jW+XmwGofnusTnJN9+BGXg,
	icenowy-ymACFijhrKM,
	thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	liam-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1800d928-d804-71db-cd0b-ec79cc504ee6-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

On Tue, 11 Apr 2017, Quentin Schulz wrote:
> On 10/04/2017 16:54, Lee Jones wrote:
> > On Mon, 10 Apr 2017, Quentin Schulz wrote:
> > 
> >> Hi Lee,
> >>
> >> Just to make sure you didn't miss that patch (can't find it in
> >> for-mfd-next and for-mfd-next-next).
> > 
> > It has not been missed, but is yet to be reviewed.
> > 
> 
> Hum.. What do you mean exactly? The maintainer of the AXP PMICs has
> given its Acked-by and the maintainer of the IIO subsystem has given its
> Reviewed-by. Is there something I'm missing (in your workflow maybe)?

I mean I haven't reviewed and picked it up yet.

I will get around to it shortly.

> >> On 04/04/2017 08:34, Quentin Schulz wrote:
> >>> The X-Powers AXP20X and AXP22X PMICs have multiple ADCs. They expose the
> >>> battery voltage, battery charge and discharge currents, AC-in and VBUS
> >>> voltages and currents, 2 GPIOs muxable in ADC mode and PMIC temperature.
> >>>
> >>> This adds support for most of AXP20X and AXP22X ADCs.
> >>>
> >>> Signed-off-by: Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> >>> Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> >>> Acked-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
> >>> Reviewed-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> >>> ---
> >>>
> >>> Lee, could you merge this through the mfd tree please?
> >>>  => https://lkml.org/lkml/2017/3/22/47
> >>>
> >>> v4:
> >>>  - added missing space at the beginning of a comment,
> >>>  - tidied axp20x_adc_offset_voltage and axp20x_write_raw to use switch case
> >>>  instead of if conditions,
> >>>  - added MODULE_DEVICE_TABLE for axp20x_adc_id_match for module autoloading,
> >>>  - merged two lines in axp20x_remove,
> >>>
> >>> v3:
> >>>  - moved from switch to if condition in axp20x_adc_raw and
> >>>  axp22x_adc_raw,
> >>>  - removed DT support as DT node has been dropped,
> >>>    - use of platform_device_id
> >>>  - correctly defined the name of the iio device (name used to probe the
> >>>  driver),
> >>>  - added goto for errors in probe,
> >>>  - added iio_map_array_unregister to the remove function,
> >>>
> >>> v2:
> >>>  - removed unused defines,
> >>>  - changed BIT(x) to 1 << x when describing bits purpose for which 2 <<
> >>>  x or 3 << x exists, to be consistent,
> >>>  - changed ADC rate defines to macro formulas,
> >>>  - reordered IIO channels, now different measures (current/voltage) of
> >>>  the same part of the PMIC (e.g. battery), have the same IIO channel in
> >>>  their respective IIO type. When a part of the PMIC have only one
> >>>  measure, a number is jumped,
> >>>  - left IIO channel mapping in DT to use iio_map structure,
> >>>  - removed indexing of ADC internal temperature,
> >>>  - removed unused iio_dev structure in axp20x_adc_iio,
> >>>  - added a structure for data specific to AXP20X or AXP22X PMICs instead
> >>>  of using an ID and an if condition when needing to separate the
> >>>  behaviour of both,
> >>>  - added a comment on batt_chrg_i really being on 12bits rather than
> >>>  what the Chinese datasheets say (13 bits),
> >>>  - corrected the offset for AXP22X PMIC temperature,
> >>>  - set the ADC rate to a value (100Hz) shared by the AXP20X and AXP22X,
> >>>  - created macro formulas to compute the ADC rate for each,
> >>>  - added a condition on presence of ADC_EN2 reg before setting/resetting
> >>>  it,
> >>>  - switched from devm_iio_device_unregister to the non-devm function
> >>>  because of the need for a remove function,
> >>>  - removed some dead code,
> >>>
> >>>  drivers/iio/adc/Kconfig      |  10 +
> >>>  drivers/iio/adc/Makefile     |   1 +
> >>>  drivers/iio/adc/axp20x_adc.c | 617 +++++++++++++++++++++++++++++++++++++++++++
> >>>  3 files changed, 628 insertions(+)
> >>>  create mode 100644 drivers/iio/adc/axp20x_adc.c
> >>>
> >>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> >>> index d777a97..d15e1bd 100644
> >>> --- a/drivers/iio/adc/Kconfig
> >>> +++ b/drivers/iio/adc/Kconfig
> >>> @@ -154,6 +154,16 @@ config AT91_SAMA5D2_ADC
> >>>  	  To compile this driver as a module, choose M here: the module will be
> >>>  	  called at91-sama5d2_adc.
> >>>  
> >>> +config AXP20X_ADC
> >>> +	tristate "X-Powers AXP20X and AXP22X ADC driver"
> >>> +	depends on MFD_AXP20X
> >>> +	help
> >>> +	  Say yes here to have support for X-Powers power management IC (PMIC)
> >>> +	  AXP20X and AXP22X ADC devices.
> >>> +
> >>> +	  To compile this driver as a module, choose M here: the module will be
> >>> +	  called axp20x_adc.
> >>> +
> >>>  config AXP288_ADC
> >>>  	tristate "X-Powers AXP288 ADC driver"
> >>>  	depends on MFD_AXP20X
> >>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> >>> index b11bb57..17899b5 100644
> >>> --- a/drivers/iio/adc/Makefile
> >>> +++ b/drivers/iio/adc/Makefile
> >>> @@ -16,6 +16,7 @@ obj-$(CONFIG_AD7887) += ad7887.o
> >>>  obj-$(CONFIG_AD799X) += ad799x.o
> >>>  obj-$(CONFIG_AT91_ADC) += at91_adc.o
> >>>  obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o
> >>> +obj-$(CONFIG_AXP20X_ADC) += axp20x_adc.o
> >>>  obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
> >>>  obj-$(CONFIG_BCM_IPROC_ADC) += bcm_iproc_adc.o
> >>>  obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
> >>> diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
> >>> new file mode 100644
> >>> index 0000000..11e1771
> >>> --- /dev/null
> >>> +++ b/drivers/iio/adc/axp20x_adc.c
> >>> @@ -0,0 +1,617 @@
> >>> +/* ADC driver for AXP20X and AXP22X PMICs
> >>> + *
> >>> + * Copyright (c) 2016 Free Electrons NextThing Co.
> >>> + *	Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> >>> + *
> >>> + * 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.
> >>> + */
> >>> +
> >>> +#include <linux/completion.h>
> >>> +#include <linux/interrupt.h>
> >>> +#include <linux/io.h>
> >>> +#include <linux/module.h>
> >>> +#include <linux/of.h>
> >>> +#include <linux/of_device.h>
> >>> +#include <linux/platform_device.h>
> >>> +#include <linux/pm_runtime.h>
> >>> +#include <linux/regmap.h>
> >>> +#include <linux/thermal.h>
> >>> +
> >>> +#include <linux/iio/iio.h>
> >>> +#include <linux/iio/driver.h>
> >>> +#include <linux/iio/machine.h>
> >>> +#include <linux/mfd/axp20x.h>
> >>> +
> >>> +#define AXP20X_ADC_EN1_MASK			GENMASK(7, 0)
> >>> +
> >>> +#define AXP20X_ADC_EN2_MASK			(GENMASK(3, 2) | BIT(7))
> >>> +#define AXP22X_ADC_EN1_MASK			(GENMASK(7, 5) | BIT(0))
> >>> +
> >>> +#define AXP20X_GPIO10_IN_RANGE_GPIO0		BIT(0)
> >>> +#define AXP20X_GPIO10_IN_RANGE_GPIO1		BIT(1)
> >>> +#define AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(x)	((x) & BIT(0))
> >>> +#define AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(x)	(((x) & BIT(0)) << 1)
> >>> +
> >>> +#define AXP20X_ADC_RATE_MASK			GENMASK(7, 6)
> >>> +#define AXP20X_ADC_RATE_HZ(x)			((ilog2((x) / 25) << 6) & AXP20X_ADC_RATE_MASK)
> >>> +#define AXP22X_ADC_RATE_HZ(x)			((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK)
> >>> +
> >>> +#define AXP20X_ADC_CHANNEL(_channel, _name, _type, _reg)	\
> >>> +	{							\
> >>> +		.type = _type,					\
> >>> +		.indexed = 1,					\
> >>> +		.channel = _channel,				\
> >>> +		.address = _reg,				\
> >>> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	\
> >>> +				      BIT(IIO_CHAN_INFO_SCALE),	\
> >>> +		.datasheet_name = _name,			\
> >>> +	}
> >>> +
> >>> +#define AXP20X_ADC_CHANNEL_OFFSET(_channel, _name, _type, _reg) \
> >>> +	{							\
> >>> +		.type = _type,					\
> >>> +		.indexed = 1,					\
> >>> +		.channel = _channel,				\
> >>> +		.address = _reg,				\
> >>> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	\
> >>> +				      BIT(IIO_CHAN_INFO_SCALE) |\
> >>> +				      BIT(IIO_CHAN_INFO_OFFSET),\
> >>> +		.datasheet_name = _name,			\
> >>> +	}
> >>> +
> >>> +struct axp_data;
> >>> +
> >>> +struct axp20x_adc_iio {
> >>> +	struct regmap		*regmap;
> >>> +	struct axp_data		*data;
> >>> +};
> >>> +
> >>> +enum axp20x_adc_channel_v {
> >>> +	AXP20X_ACIN_V = 0,
> >>> +	AXP20X_VBUS_V,
> >>> +	AXP20X_TS_IN,
> >>> +	AXP20X_GPIO0_V,
> >>> +	AXP20X_GPIO1_V,
> >>> +	AXP20X_IPSOUT_V,
> >>> +	AXP20X_BATT_V,
> >>> +};
> >>> +
> >>> +enum axp20x_adc_channel_i {
> >>> +	AXP20X_ACIN_I = 0,
> >>> +	AXP20X_VBUS_I,
> >>> +	AXP20X_BATT_CHRG_I,
> >>> +	AXP20X_BATT_DISCHRG_I,
> >>> +};
> >>> +
> >>> +enum axp22x_adc_channel_v {
> >>> +	AXP22X_TS_IN = 0,
> >>> +	AXP22X_BATT_V,
> >>> +};
> >>> +
> >>> +enum axp22x_adc_channel_i {
> >>> +	AXP22X_BATT_CHRG_I = 1,
> >>> +	AXP22X_BATT_DISCHRG_I,
> >>> +};
> >>> +
> >>> +static struct iio_map axp20x_maps[] = {
> >>> +	{
> >>> +		.consumer_dev_name = "axp20x-usb-power-supply",
> >>> +		.consumer_channel = "vbus_v",
> >>> +		.adc_channel_label = "vbus_v",
> >>> +	}, {
> >>> +		.consumer_dev_name = "axp20x-usb-power-supply",
> >>> +		.consumer_channel = "vbus_i",
> >>> +		.adc_channel_label = "vbus_i",
> >>> +	}, {
> >>> +		.consumer_dev_name = "axp20x-ac-power-supply",
> >>> +		.consumer_channel = "acin_v",
> >>> +		.adc_channel_label = "acin_v",
> >>> +	}, {
> >>> +		.consumer_dev_name = "axp20x-ac-power-supply",
> >>> +		.consumer_channel = "acin_i",
> >>> +		.adc_channel_label = "acin_i",
> >>> +	}, {
> >>> +		.consumer_dev_name = "axp20x-battery-power-supply",
> >>> +		.consumer_channel = "batt_v",
> >>> +		.adc_channel_label = "batt_v",
> >>> +	}, {
> >>> +		.consumer_dev_name = "axp20x-battery-power-supply",
> >>> +		.consumer_channel = "batt_chrg_i",
> >>> +		.adc_channel_label = "batt_chrg_i",
> >>> +	}, {
> >>> +		.consumer_dev_name = "axp20x-battery-power-supply",
> >>> +		.consumer_channel = "batt_dischrg_i",
> >>> +		.adc_channel_label = "batt_dischrg_i",
> >>> +	}, { /* sentinel */ }
> >>> +};
> >>> +
> >>> +static struct iio_map axp22x_maps[] = {
> >>> +	{
> >>> +		.consumer_dev_name = "axp20x-battery-power-supply",
> >>> +		.consumer_channel = "batt_v",
> >>> +		.adc_channel_label = "batt_v",
> >>> +	}, {
> >>> +		.consumer_dev_name = "axp20x-battery-power-supply",
> >>> +		.consumer_channel = "batt_chrg_i",
> >>> +		.adc_channel_label = "batt_chrg_i",
> >>> +	}, {
> >>> +		.consumer_dev_name = "axp20x-battery-power-supply",
> >>> +		.consumer_channel = "batt_dischrg_i",
> >>> +		.adc_channel_label = "batt_dischrg_i",
> >>> +	}, { /* sentinel */ }
> >>> +};
> >>> +
> >>> +/*
> >>> + * Channels are mapped by physical system. Their channels share the same index.
> >>> + * i.e. acin_i is in_current0_raw and acin_v is in_voltage0_raw.
> >>> + * The only exception is for the battery. batt_v will be in_voltage6_raw and
> >>> + * charge current in_current6_raw and discharge current will be in_current7_raw.
> >>> + */
> >>> +static const struct iio_chan_spec axp20x_adc_channels[] = {
> >>> +	AXP20X_ADC_CHANNEL(AXP20X_ACIN_V, "acin_v", IIO_VOLTAGE,
> >>> +			   AXP20X_ACIN_V_ADC_H),
> >>> +	AXP20X_ADC_CHANNEL(AXP20X_ACIN_I, "acin_i", IIO_CURRENT,
> >>> +			   AXP20X_ACIN_I_ADC_H),
> >>> +	AXP20X_ADC_CHANNEL(AXP20X_VBUS_V, "vbus_v", IIO_VOLTAGE,
> >>> +			   AXP20X_VBUS_V_ADC_H),
> >>> +	AXP20X_ADC_CHANNEL(AXP20X_VBUS_I, "vbus_i", IIO_CURRENT,
> >>> +			   AXP20X_VBUS_I_ADC_H),
> >>> +	{
> >>> +		.type = IIO_TEMP,
> >>> +		.address = AXP20X_TEMP_ADC_H,
> >>> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> >>> +				      BIT(IIO_CHAN_INFO_SCALE) |
> >>> +				      BIT(IIO_CHAN_INFO_OFFSET),
> >>> +		.datasheet_name = "pmic_temp",
> >>> +	},
> >>> +	AXP20X_ADC_CHANNEL_OFFSET(AXP20X_GPIO0_V, "gpio0_v", IIO_VOLTAGE,
> >>> +				  AXP20X_GPIO0_V_ADC_H),
> >>> +	AXP20X_ADC_CHANNEL_OFFSET(AXP20X_GPIO1_V, "gpio1_v", IIO_VOLTAGE,
> >>> +				  AXP20X_GPIO1_V_ADC_H),
> >>> +	AXP20X_ADC_CHANNEL(AXP20X_IPSOUT_V, "ipsout_v", IIO_VOLTAGE,
> >>> +			   AXP20X_IPSOUT_V_HIGH_H),
> >>> +	AXP20X_ADC_CHANNEL(AXP20X_BATT_V, "batt_v", IIO_VOLTAGE,
> >>> +			   AXP20X_BATT_V_H),
> >>> +	AXP20X_ADC_CHANNEL(AXP20X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
> >>> +			   AXP20X_BATT_CHRG_I_H),
> >>> +	AXP20X_ADC_CHANNEL(AXP20X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
> >>> +			   AXP20X_BATT_DISCHRG_I_H),
> >>> +};
> >>> +
> >>> +static const struct iio_chan_spec axp22x_adc_channels[] = {
> >>> +	{
> >>> +		.type = IIO_TEMP,
> >>> +		.address = AXP22X_PMIC_TEMP_H,
> >>> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> >>> +				      BIT(IIO_CHAN_INFO_SCALE) |
> >>> +				      BIT(IIO_CHAN_INFO_OFFSET),
> >>> +		.datasheet_name = "pmic_temp",
> >>> +	},
> >>> +	AXP20X_ADC_CHANNEL(AXP22X_BATT_V, "batt_v", IIO_VOLTAGE,
> >>> +			   AXP20X_BATT_V_H),
> >>> +	AXP20X_ADC_CHANNEL(AXP22X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
> >>> +			   AXP20X_BATT_CHRG_I_H),
> >>> +	AXP20X_ADC_CHANNEL(AXP22X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
> >>> +			   AXP20X_BATT_DISCHRG_I_H),
> >>> +};
> >>> +
> >>> +static int axp20x_adc_raw(struct iio_dev *indio_dev,
> >>> +			  struct iio_chan_spec const *chan, int *val)
> >>> +{
> >>> +	struct axp20x_adc_iio *info = iio_priv(indio_dev);
> >>> +	int size = 12;
> >>> +
> >>> +	/*
> >>> +	 * N.B.:  Unlike the Chinese datasheets tell, the charging current is
> >>> +	 * stored on 12 bits, not 13 bits. Only discharging current is on 13
> >>> +	 * bits.
> >>> +	 */
> >>> +	if (chan->type == IIO_CURRENT && chan->channel == AXP20X_BATT_DISCHRG_I)
> >>> +		size = 13;
> >>> +	else
> >>> +		size = 12;
> >>> +
> >>> +	*val = axp20x_read_variable_width(info->regmap, chan->address, size);
> >>> +	if (*val < 0)
> >>> +		return *val;
> >>> +
> >>> +	return IIO_VAL_INT;
> >>> +}
> >>> +
> >>> +static int axp22x_adc_raw(struct iio_dev *indio_dev,
> >>> +			  struct iio_chan_spec const *chan, int *val)
> >>> +{
> >>> +	struct axp20x_adc_iio *info = iio_priv(indio_dev);
> >>> +	int size;
> >>> +
> >>> +	/*
> >>> +	 * N.B.: Unlike the Chinese datasheets tell, the charging current is
> >>> +	 * stored on 12 bits, not 13 bits. Only discharging current is on 13
> >>> +	 * bits.
> >>> +	 */
> >>> +	if (chan->type == IIO_CURRENT && chan->channel == AXP22X_BATT_DISCHRG_I)
> >>> +		size = 13;
> >>> +	else
> >>> +		size = 12;
> >>> +
> >>> +	*val = axp20x_read_variable_width(info->regmap, chan->address, size);
> >>> +	if (*val < 0)
> >>> +		return *val;
> >>> +
> >>> +	return IIO_VAL_INT;
> >>> +}
> >>> +
> >>> +static int axp20x_adc_scale_voltage(int channel, int *val, int *val2)
> >>> +{
> >>> +	switch (channel) {
> >>> +	case AXP20X_ACIN_V:
> >>> +	case AXP20X_VBUS_V:
> >>> +		*val = 1;
> >>> +		*val2 = 700000;
> >>> +		return IIO_VAL_INT_PLUS_MICRO;
> >>> +
> >>> +	case AXP20X_GPIO0_V:
> >>> +	case AXP20X_GPIO1_V:
> >>> +		*val = 0;
> >>> +		*val2 = 500000;
> >>> +		return IIO_VAL_INT_PLUS_MICRO;
> >>> +
> >>> +	case AXP20X_BATT_V:
> >>> +		*val = 1;
> >>> +		*val2 = 100000;
> >>> +		return IIO_VAL_INT_PLUS_MICRO;
> >>> +
> >>> +	case AXP20X_IPSOUT_V:
> >>> +		*val = 1;
> >>> +		*val2 = 400000;
> >>> +		return IIO_VAL_INT_PLUS_MICRO;
> >>> +
> >>> +	default:
> >>> +		return -EINVAL;
> >>> +	}
> >>> +}
> >>> +
> >>> +static int axp20x_adc_scale_current(int channel, int *val, int *val2)
> >>> +{
> >>> +	switch (channel) {
> >>> +	case AXP20X_ACIN_I:
> >>> +		*val = 0;
> >>> +		*val2 = 625000;
> >>> +		return IIO_VAL_INT_PLUS_MICRO;
> >>> +
> >>> +	case AXP20X_VBUS_I:
> >>> +		*val = 0;
> >>> +		*val2 = 375000;
> >>> +		return IIO_VAL_INT_PLUS_MICRO;
> >>> +
> >>> +	case AXP20X_BATT_DISCHRG_I:
> >>> +	case AXP20X_BATT_CHRG_I:
> >>> +		*val = 0;
> >>> +		*val2 = 500000;
> >>> +		return IIO_VAL_INT_PLUS_MICRO;
> >>> +
> >>> +	default:
> >>> +		return -EINVAL;
> >>> +	}
> >>> +}
> >>> +
> >>> +static int axp20x_adc_scale(struct iio_chan_spec const *chan, int *val,
> >>> +			    int *val2)
> >>> +{
> >>> +	switch (chan->type) {
> >>> +	case IIO_VOLTAGE:
> >>> +		return axp20x_adc_scale_voltage(chan->channel, val, val2);
> >>> +
> >>> +	case IIO_CURRENT:
> >>> +		return axp20x_adc_scale_current(chan->channel, val, val2);
> >>> +
> >>> +	case IIO_TEMP:
> >>> +		*val = 100;
> >>> +		return IIO_VAL_INT;
> >>> +
> >>> +	default:
> >>> +		return -EINVAL;
> >>> +	}
> >>> +}
> >>> +
> >>> +static int axp22x_adc_scale(struct iio_chan_spec const *chan, int *val,
> >>> +			    int *val2)
> >>> +{
> >>> +	switch (chan->type) {
> >>> +	case IIO_VOLTAGE:
> >>> +		if (chan->channel != AXP22X_BATT_V)
> >>> +			return -EINVAL;
> >>> +
> >>> +		*val = 1;
> >>> +		*val2 = 100000;
> >>> +		return IIO_VAL_INT_PLUS_MICRO;
> >>> +
> >>> +	case IIO_CURRENT:
> >>> +		*val = 0;
> >>> +		*val2 = 500000;
> >>> +		return IIO_VAL_INT_PLUS_MICRO;
> >>> +
> >>> +	case IIO_TEMP:
> >>> +		*val = 100;
> >>> +		return IIO_VAL_INT;
> >>> +
> >>> +	default:
> >>> +		return -EINVAL;
> >>> +	}
> >>> +}
> >>> +
> >>> +static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
> >>> +				     int *val)
> >>> +{
> >>> +	struct axp20x_adc_iio *info = iio_priv(indio_dev);
> >>> +	int ret;
> >>> +
> >>> +	ret = regmap_read(info->regmap, AXP20X_GPIO10_IN_RANGE, val);
> >>> +	if (ret < 0)
> >>> +		return ret;
> >>> +
> >>> +	switch (channel) {
> >>> +	case AXP20X_GPIO0_V:
> >>> +		*val &= AXP20X_GPIO10_IN_RANGE_GPIO0;
> >>> +		break;
> >>> +
> >>> +	case AXP20X_GPIO1_V:
> >>> +		*val &= AXP20X_GPIO10_IN_RANGE_GPIO1;
> >>> +		break;
> >>> +
> >>> +	default:
> >>> +		return -EINVAL;
> >>> +	}
> >>> +
> >>> +	*val = !!(*val) * 700000;
> >>> +
> >>> +	return IIO_VAL_INT;
> >>> +}
> >>> +
> >>> +static int axp20x_adc_offset(struct iio_dev *indio_dev,
> >>> +			     struct iio_chan_spec const *chan, int *val)
> >>> +{
> >>> +	switch (chan->type) {
> >>> +	case IIO_VOLTAGE:
> >>> +		return axp20x_adc_offset_voltage(indio_dev, chan->channel, val);
> >>> +
> >>> +	case IIO_TEMP:
> >>> +		*val = -1447;
> >>> +		return IIO_VAL_INT;
> >>> +
> >>> +	default:
> >>> +		return -EINVAL;
> >>> +	}
> >>> +}
> >>> +
> >>> +static int axp20x_read_raw(struct iio_dev *indio_dev,
> >>> +			   struct iio_chan_spec const *chan, int *val,
> >>> +			   int *val2, long mask)
> >>> +{
> >>> +	switch (mask) {
> >>> +	case IIO_CHAN_INFO_OFFSET:
> >>> +		return axp20x_adc_offset(indio_dev, chan, val);
> >>> +
> >>> +	case IIO_CHAN_INFO_SCALE:
> >>> +		return axp20x_adc_scale(chan, val, val2);
> >>> +
> >>> +	case IIO_CHAN_INFO_RAW:
> >>> +		return axp20x_adc_raw(indio_dev, chan, val);
> >>> +
> >>> +	default:
> >>> +		return -EINVAL;
> >>> +	}
> >>> +}
> >>> +
> >>> +static int axp22x_read_raw(struct iio_dev *indio_dev,
> >>> +			   struct iio_chan_spec const *chan, int *val,
> >>> +			   int *val2, long mask)
> >>> +{
> >>> +	switch (mask) {
> >>> +	case IIO_CHAN_INFO_OFFSET:
> >>> +		*val = -2677;
> >>> +		return IIO_VAL_INT;
> >>> +
> >>> +	case IIO_CHAN_INFO_SCALE:
> >>> +		return axp22x_adc_scale(chan, val, val2);
> >>> +
> >>> +	case IIO_CHAN_INFO_RAW:
> >>> +		return axp22x_adc_raw(indio_dev, chan, val);
> >>> +
> >>> +	default:
> >>> +		return -EINVAL;
> >>> +	}
> >>> +}
> >>> +
> >>> +static int axp20x_write_raw(struct iio_dev *indio_dev,
> >>> +			    struct iio_chan_spec const *chan, int val, int val2,
> >>> +			    long mask)
> >>> +{
> >>> +	struct axp20x_adc_iio *info = iio_priv(indio_dev);
> >>> +	unsigned int reg, regval;
> >>> +
> >>> +	/*
> >>> +	 * The AXP20X PMIC allows the user to choose between 0V and 0.7V offsets
> >>> +	 * for (independently) GPIO0 and GPIO1 when in ADC mode.
> >>> +	 */
> >>> +	if (mask != IIO_CHAN_INFO_OFFSET)
> >>> +		return -EINVAL;
> >>> +
> >>> +	if (val != 0 && val != 700000)
> >>> +		return -EINVAL;
> >>> +
> >>> +	switch (chan->channel) {
> >>> +	case AXP20X_GPIO0_V:
> >>> +		reg = AXP20X_GPIO10_IN_RANGE_GPIO0;
> >>> +		regval = AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(!!val);
> >>> +		break;
> >>> +
> >>> +	case AXP20X_GPIO1_V:
> >>> +		reg = AXP20X_GPIO10_IN_RANGE_GPIO1;
> >>> +		regval = AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(!!val);
> >>> +		break;
> >>> +
> >>> +	default:
> >>> +		return -EINVAL;
> >>> +	}
> >>> +
> >>> +	return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE, reg,
> >>> +				  regval);
> >>> +}
> >>> +
> >>> +static const struct iio_info axp20x_adc_iio_info = {
> >>> +	.read_raw = axp20x_read_raw,
> >>> +	.write_raw = axp20x_write_raw,
> >>> +	.driver_module = THIS_MODULE,
> >>> +};
> >>> +
> >>> +static const struct iio_info axp22x_adc_iio_info = {
> >>> +	.read_raw = axp22x_read_raw,
> >>> +	.driver_module = THIS_MODULE,
> >>> +};
> >>> +
> >>> +static int axp20x_adc_rate(int rate)
> >>> +{
> >>> +	return AXP20X_ADC_RATE_HZ(rate);
> >>> +}
> >>> +
> >>> +static int axp22x_adc_rate(int rate)
> >>> +{
> >>> +	return AXP22X_ADC_RATE_HZ(rate);
> >>> +}
> >>> +
> >>> +struct axp_data {
> >>> +	const struct iio_info		*iio_info;
> >>> +	int				num_channels;
> >>> +	struct iio_chan_spec const	*channels;
> >>> +	unsigned long			adc_en1_mask;
> >>> +	int				(*adc_rate)(int rate);
> >>> +	bool				adc_en2;
> >>> +	struct iio_map			*maps;
> >>> +};
> >>> +
> >>> +static const struct axp_data axp20x_data = {
> >>> +	.iio_info = &axp20x_adc_iio_info,
> >>> +	.num_channels = ARRAY_SIZE(axp20x_adc_channels),
> >>> +	.channels = axp20x_adc_channels,
> >>> +	.adc_en1_mask = AXP20X_ADC_EN1_MASK,
> >>> +	.adc_rate = axp20x_adc_rate,
> >>> +	.adc_en2 = true,
> >>> +	.maps = axp20x_maps,
> >>> +};
> >>> +
> >>> +static const struct axp_data axp22x_data = {
> >>> +	.iio_info = &axp22x_adc_iio_info,
> >>> +	.num_channels = ARRAY_SIZE(axp22x_adc_channels),
> >>> +	.channels = axp22x_adc_channels,
> >>> +	.adc_en1_mask = AXP22X_ADC_EN1_MASK,
> >>> +	.adc_rate = axp22x_adc_rate,
> >>> +	.adc_en2 = false,
> >>> +	.maps = axp22x_maps,
> >>> +};
> >>> +
> >>> +static const struct platform_device_id axp20x_adc_id_match[] = {
> >>> +	{ .name = "axp20x-adc", .driver_data = (kernel_ulong_t)&axp20x_data, },
> >>> +	{ .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, },
> >>> +	{ /* sentinel */ },
> >>> +};
> >>> +MODULE_DEVICE_TABLE(platform, axp20x_adc_id_match);
> >>> +
> >>> +static int axp20x_probe(struct platform_device *pdev)
> >>> +{
> >>> +	struct axp20x_adc_iio *info;
> >>> +	struct iio_dev *indio_dev;
> >>> +	struct axp20x_dev *axp20x_dev;
> >>> +	int ret;
> >>> +
> >>> +	axp20x_dev = dev_get_drvdata(pdev->dev.parent);
> >>> +
> >>> +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
> >>> +	if (!indio_dev)
> >>> +		return -ENOMEM;
> >>> +
> >>> +	info = iio_priv(indio_dev);
> >>> +	platform_set_drvdata(pdev, indio_dev);
> >>> +
> >>> +	info->regmap = axp20x_dev->regmap;
> >>> +	indio_dev->dev.parent = &pdev->dev;
> >>> +	indio_dev->dev.of_node = pdev->dev.of_node;
> >>> +	indio_dev->modes = INDIO_DIRECT_MODE;
> >>> +
> >>> +	info->data = (struct axp_data *)platform_get_device_id(pdev)->driver_data;
> >>> +
> >>> +	indio_dev->name = platform_get_device_id(pdev)->name;
> >>> +	indio_dev->info = info->data->iio_info;
> >>> +	indio_dev->num_channels = info->data->num_channels;
> >>> +	indio_dev->channels = info->data->channels;
> >>> +
> >>> +	/* Enable the ADCs on IP */
> >>> +	regmap_write(info->regmap, AXP20X_ADC_EN1, info->data->adc_en1_mask);
> >>> +
> >>> +	if (info->data->adc_en2)
> >>> +		/* Enable GPIO0/1 and internal temperature ADCs */
> >>> +		regmap_update_bits(info->regmap, AXP20X_ADC_EN2,
> >>> +				   AXP20X_ADC_EN2_MASK, AXP20X_ADC_EN2_MASK);
> >>> +
> >>> +	/* Configure ADCs rate */
> >>> +	regmap_update_bits(info->regmap, AXP20X_ADC_RATE, AXP20X_ADC_RATE_MASK,
> >>> +			   info->data->adc_rate(100));
> >>> +
> >>> +	ret = iio_map_array_register(indio_dev, info->data->maps);
> >>> +	if (ret < 0) {
> >>> +		dev_err(&pdev->dev, "failed to register IIO maps: %d\n", ret);
> >>> +		goto fail_map;
> >>> +	}
> >>> +
> >>> +	ret = iio_device_register(indio_dev);
> >>> +	if (ret < 0) {
> >>> +		dev_err(&pdev->dev, "could not register the device\n");
> >>> +		goto fail_register;
> >>> +	}
> >>> +
> >>> +	return 0;
> >>> +
> >>> +fail_register:
> >>> +	iio_map_array_unregister(indio_dev);
> >>> +
> >>> +fail_map:
> >>> +	regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
> >>> +
> >>> +	if (info->data->adc_en2)
> >>> +		regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
> >>> +
> >>> +	return ret;
> >>> +}
> >>> +
> >>> +static int axp20x_remove(struct platform_device *pdev)
> >>> +{
> >>> +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> >>> +	struct axp20x_adc_iio *info = iio_priv(indio_dev);
> >>> +
> >>> +	iio_device_unregister(indio_dev);
> >>> +	iio_map_array_unregister(indio_dev);
> >>> +
> >>> +	regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
> >>> +
> >>> +	if (info->data->adc_en2)
> >>> +		regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
> >>> +
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static struct platform_driver axp20x_adc_driver = {
> >>> +	.driver = {
> >>> +		.name = "axp20x-adc",
> >>> +	},
> >>> +	.id_table = axp20x_adc_id_match,
> >>> +	.probe = axp20x_probe,
> >>> +	.remove = axp20x_remove,
> >>> +};
> >>> +
> >>> +module_platform_driver(axp20x_adc_driver);
> >>> +
> >>> +MODULE_DESCRIPTION("ADC driver for AXP20X and AXP22X PMICs");
> >>> +MODULE_AUTHOR("Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>");
> >>> +MODULE_LICENSE("GPL");
> >>>
> >>
> > 
> 

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

-- 
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.

^ permalink raw reply

* Re: [PATCH v7 00/13] mmc: Add support to Marvell Xenon SD Host Controller
From: Gregory CLEMENT @ 2017-04-11  7:59 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Adrian Hunter, linux-mmc@vger.kernel.org, Jason Cooper,
	Andrew Lunn, Sebastian Hesselbarth, Thomas Petazzoni,
	linux-arm-kernel@lists.infradead.org, Mike Turquette,
	Stephen Boyd, linux-clk, linux-kernel@vger.kernel.org,
	Rob Herring, devicetree@vger.kernel.org, Ziji Hu, Jimmy Xu,
	Jisheng Zhang, Nadav Haklai
In-Reply-To: <CAPDyKFqsU6vSmM3kMzGw4DmoB8JpUKaTJYzXUfwCz5cCbYM_3A@mail.gmail.com>

Hi Ulf,
 
 On lun., avril 10 2017, Ulf Hansson <ulf.hansson@linaro.org> wrote:

> On 30 March 2017 at 17:22, Gregory CLEMENT
> <gregory.clement@free-electrons.com> wrote:
>> Hello,
>>
>> This the seventh version of the series adding support for the SDHCI
>> Xenon controller. It can be currently found on the Armada 37xx and the
>> Armada 7K/8K but will be also used in more Marvell SoC (and not only
>> the mvebu ones actually).
>>
>> v6->v7:
>>  - Add comments on vqmmc and vmmc in examples in dt binding doc.
>>
>>  - Fix all the issues pointed out by Ulf and Adrian:
>>
>>    - Align the prefix of function and variable names.
>>    - Replace the if-else with switch statements when checking MMC_TIMING_*
>>    - Remove the spinlocks in set_ios.
>>    - Optimize the delay loop as Adrian patch does.
>>    - Add release of phy params structures
>>
>> - Add check of Vqmmc supply in Xenon signal voltage switch. If Vqmmc
>>   regulator doesn't exist, skip standard SD signal voltage regulator
>>   switch process.
>>
>> - Remove parse of child node mmc-card. Wait for a better solution.
>>
>> v5->v6:
>>
>> - Add a generic "mmc-card" parse in core layer.
>>
>> - Fix the spelling issues in Xenon dt binding doc and drivers.
>>
>> - Remove descriptions to common mmc properties from Xenon dt binding
>>   doc.
>>
>> - Split compatible string "marvell,armada-8k-sdhci" into
>>  "marvell,armada-ap806-sdhci" and "marvell,armada-cp110-sdhci".
>>
>> - Also updates the example in Xenon dt binding doc.
>>
>> - Remove unnecessary dependency on MMC_SDHCI from Xenon entry in
>>   Kconfig.
>>
>> - Move Xenon specific dt parse into a separate function.
>>
>> - Adjust warnings and condition check in Xenon PHY setting, to remove
>>  fragile hs200->hs400/hs400->hs200 sequence check function.
>>
>> - Enable PHY Slow Mode in MMC_TIMING_LEGACY timing if PHY Slow Mode is
>>  required in dts.
>>
>> - Add a patch allowing dts backwards compatible for the clock
>>
>> v4->v5:
>>
>> - Remove the patch to export sdhci_execute_tuning(). It is already
>>   exported in v4.10.
>>
>> - Introduce a patch adding a missing clock for the sdhci controller
>>   present on the CP master for A7K/A8K. There is no build dependency
>>   but obviously this patch is need to use the sdhci controller present
>>   on the CP part.
>>
>> - Adjust Xenon return setup, to avoid being overwritten by
>>    sdhci_add_host().
>>
>> - Change Xenon register definition prefix to "XENON_".
>>
>> -  Fix typos in Xenon driver and dt-binding docs.
>>
>> - Change compatible string "marvell,armada-7000-sdhci" to
>>   "marvell,armada-8k-sdhci". Actually the Armada 7K SoCs are a subset
>>   of the Armada 8K SoCs. Moreover, the use of the '000' is not
>>   consistent with all the other compatible string already used for the
>>   Armada 7K/8K family.
>>
>> - Added the Tested-by from Russell King on an Armada 8K based board.
>>
>> v3 -> v4:
>> For this version a few change have been done:
>> - fixes 2 bug  reported by kbuild-bot
>>   - remove extra of_node_put()
>>   - convert 0 in false for function returning boolean
>>
>> - add a device tree node for the sdhci controller present on the CP
>>   master for A7K/A8K. It also led to rename the sdhci0 node on AP to
>>   ap_sdhci0 to make a distinction with the one present on CP master.
>>
>> v2 -> v3
>> I think that now most (if not all) the remarks had been taking into
>> account since the second version. According to Ziji Hu, here are the
>> following changes:
>> " Changes in V3:
>>   Adjust and improve Xenon DT bindings. Move some caps setting from driver into
>>   DT. Use mmc-card sub-node to represent eMMC type.
>>   Remove PHY Sampling Fixed Delay Line scan in lower speed mode.
>>   Improve Xenon probe and ->init_card() functions.
>>   Export sdhci_enable_sdio_irq() and implement own SDIO IRQ control.
>>   Split PHY patch into two smaller patches.
>>   Temporarily remove AXI clock before its implementation is improved."
>>
>> Besides this changes I also
>> - Removed the sdhci-xenon-phy.h and moved its content in the
>> shc-xenon-phy.c file.
>> - Fixed the tuning-count usage
>> - Managed the error case for clk_prepare_enable
>>
>> For the record the change from v1 was:
>> " Changes in V2:
>>   rebase on v4.9-rc2.
>>   Re-write Xenon bindings. Ajust Xenon DT property naming.
>>   Add a new DT property to indicate eMMC card type, instead of using
>>   variable card_candidate.
>>   Clear quirks SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 in Xenon platform data
>>   Add support to HS400 retuning."
>>
>> Thanks,
>>
>> Gregory
>>
>> Gregory CLEMENT (4):
>>   clk: apn806: Turn the eMMC clock as optional for dts backwards compatible
>>   arm64: dts: marvell: add eMMC support for Armada 37xx
>>   arm64: dts: marvell: add sdhci support for Armada 7K/8K
>>   arm64: configs: enable SDHCI driver for Xenon
>>
>> Hu Ziji (8):
>>   mmc: sdhci: Export sdhci_set_ios() from sdhci.c
>>   mmc: sdhci: Export sdhci_start_signal_voltage_switch() in sdhci.c
>>   mmc: sdhci: Export sdhci_enable_sdio_irq() from sdhci.c
>>   dt: bindings: Add bindings for Marvell Xenon SD Host Controller
>>   mmc: sdhci-xenon: Add Marvell Xenon SDHC core functionality
>>   mmc: sdhci-xenon: Add support to PHYs of Marvell Xenon SDHC
>>   mmc: sdhci-xenon: Add SoC PHY PAD voltage control
>>   MAINTAINERS: add entry for Marvell Xenon MMC Host Controller drivers
>>
>> Konstantin Porotchkin (1):
>>   clk: apn806: Add eMMC clock to system controller driver
>>
>>  Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt | 170 +-
>>  MAINTAINERS                                                   |   7 +-
>>  arch/arm64/boot/dts/marvell/armada-3720-db.dts                |   9 +-
>>  arch/arm64/boot/dts/marvell/armada-37xx.dtsi                  |  11 +-
>>  arch/arm64/boot/dts/marvell/armada-7040-db.dts                |  14 +-
>>  arch/arm64/boot/dts/marvell/armada-8040-db.dts                |  12 +-
>>  arch/arm64/boot/dts/marvell/armada-ap806.dtsi                 |  14 +-
>>  arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi          |  11 +-
>>  arch/arm64/configs/defconfig                                  |   1 +-
>>  drivers/clk/mvebu/ap806-system-controller.c                   |  21 +-
>>  drivers/mmc/host/Kconfig                                      |   8 +-
>>  drivers/mmc/host/Makefile                                     |   3 +-
>>  drivers/mmc/host/sdhci-xenon-phy.c                            | 835 +++++++-
>>  drivers/mmc/host/sdhci-xenon.c                                | 548 +++++-
>>  drivers/mmc/host/sdhci-xenon.h                                | 101 +-
>>  drivers/mmc/host/sdhci.c                                      |  11 +-
>>  drivers/mmc/host/sdhci.h                                      |   4 +-
>>  17 files changed, 1774 insertions(+), 6 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
>>  create mode 100644 drivers/mmc/host/sdhci-xenon-phy.c
>>  create mode 100644 drivers/mmc/host/sdhci-xenon.c
>>  create mode 100644 drivers/mmc/host/sdhci-xenon.h
>>
>> base-commit: a645cc1df4ff41ba54a2fb839962b8ff142121d9
>> --
>> git-series 0.9.1
>
>
> Thanks, applied patch 1->10 for next! 11->13 will have to go via the
> SoC maintainer tree.

Great, thanks!

Patch 11 and 12 are now applied on mvebu/dt64 and patch 13 on
mvebu/defconfig64.

Gregory

>
> Kind regards
> Uffe

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

^ permalink raw reply

* Re: [PATCH v3 14/37] mtd: nand: denali: support "nand-ecc-strength" DT property
From: Boris Brezillon @ 2017-04-11  7:56 UTC (permalink / raw)
  To: Masahiro Yamada
  Cc: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Enrico Jorns,
	Artem Bityutskiy, Dinh Nguyen, Marek Vasut, Graham Moore,
	David Woodhouse, Masami Hiramatsu, Chuanxiao Dong, Jassi Brar,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Linux Kernel Mailing List,
	Brian Norris, Richard Weinberger, Cyrille Pitchen, Rob Herring,
	Mark Rutland
In-Reply-To: <CAK7LNARxR722uRE9SnJPuOqictrpnbFmcKBsW_g=f1OnNgvpRA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

Hi Masahiro,

On Tue, 11 Apr 2017 15:19:21 +0900
Masahiro Yamada <yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A@public.gmane.org> wrote:

> Hi Boris,
> 
> 
> 
> 2017-04-10 1:33 GMT+09:00 Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>:
> > On Mon, 3 Apr 2017 12:16:34 +0900
> > Masahiro Yamada <yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A@public.gmane.org> wrote:
> >  
> >> Hi Boris,
> >>
> >>
> >>
> >> 2017-03-31 18:46 GMT+09:00 Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>:
> >>  
> >> > You can try something like that when no explicit ecc.strength and
> >> > ecc.size has been set in the DT and when ECC_MAXIMIZE was not passed.
> >> >
> >> > static int
> >> > denali_get_closest_ecc_strength(struct denali_nand_info *denali,
> >> >                                 int strength)
> >> > {
> >> >         /*
> >> >          * Whatever you need to select a strength that is greater than
> >> >          * or equal to strength.
> >> >          */
> >> >
> >> >         return X;
> >> > }  
> >>
> >>
> >> Is here anything specific to Denali?  
> >
> > Well, only the denali driver knows what the hardware supports, though
> > having a generic function that takes a table of supported strengths
> > would work.
> >  
> >>
> >>  
> >> > static int denali_try_to_match_ecc_req(struct denali_nand_info *denali)
> >> > {
> >> >         struct nand_chip *chip = &denali->nand;
> >> >         struct mtd_info *mtd = nand_to_mtd(chip);
> >> >         int max_ecc_bytes = mtd->oobsize - denali->bbtskipbytes;
> >> >         int ecc_steps, ecc_strength, ecc_bytes;
> >> >         int ecc_size = chip->ecc_step_ds;
> >> >         int ecc_strength = chip->ecc_strength_ds;
> >> >
> >> >         /*
> >> >          * No information provided by the NAND chip, let the core
> >> >          * maximize the strength.
> >> >          */
> >> >         if (!ecc_size || !ecc_strength)
> >> >                 return -ENOTSUPP;
> >> >
> >> >         if (ecc_size > 512)
> >> >                 ecc_size = 1024;
> >> >         else
> >> >                 ecc_size = 512;
> >> >
> >> >         /* Adjust ECC step size based on hardware support. */
> >> >         if (ecc_size == 1024 &&
> >> >             !(denali->caps & DENALI_CAP_ECC_SIZE_1024))
> >> >                 ecc_size = 512;
> >> >         else if(ecc_size == 512 &&
> >> >                 !(denali->caps & DENALI_CAP_ECC_SIZE_512))
> >> >                 ecc_size = 1024;
> >> >
> >> >         if (ecc_size < chip->ecc_size_ds) {
> >> >                 /*
> >> >                  * When the selected size if smaller than the expected
> >> >                  * one we try to use the same strength but on 512 blocks
> >> >                  * so that we can still fix the same number of errors
> >> >                  * even if they are concentrated in the first 512bytes
> >> >                  * of a 1024bytes portion.
> >> >                  */
> >> >                 ecc_strength = chip->ecc_strength_ds;
> >> >                 ecc_strength = denali_get_closest_ecc_strength(denali,
> >> >                                                                ecc_strength);
> >> >         } else {
> >> >                 /* Always prefer 1024bytes ECC blocks when possible. */
> >> >                 if (ecc_size != 1024 &&
> >> >                     (denali->caps & DENALI_CAP_ECC_SIZE_1024) &&
> >> >                     mtd->writesize > 1024)
> >> >                         ecc_size = 1024;
> >> >
> >> >                 /*
> >> >                  * Adjust the strength based on the selected ECC step
> >> >                  * size.
> >> >                  */
> >> >                 ecc_strength = DIV_ROUND_UP(ecc_size,
> >> >                                             chip->ecc_step_ds) *
> >> >                                chip->ecc_strength_ds;
> >> >         }
> >> >
> >> >         ecc_bytes = denali_calc_ecc_bytes(ecc_size,
> >> >                                           ecc_strength);
> >> >         ecc_bytes *= mtd->writesize / ecc_size;
> >> >
> >> >         /*
> >> >          * If we don't have enough space, let the core maximize
> >> >          * the strength.
> >> >          */
> >> >         if (ecc_bytes > max_ecc_bytes)
> >> >                 return -ENOTSUPP;
> >> >
> >> >         chip->ecc.strength = ecc_strength;
> >> >         chip->ecc.size = ecc_size;
> >> >
> >> >         return 0;
> >> > }  
> >>
> >>
> >> As a whole, this does not seem to driver-specific.  
> >
> > It's almost controller-agnostic, except for the denali_calc_ecc_bytes()
> > function, but I guess we could ask drivers to implement a hook that is
> > passed the ECC step size and strength and returns the associated
> > number of ECC bytes.
> >  
> >>
> >>
> >> [1] A driver provides some pairs of (ecc_strength, ecc_size)
> >>     it can support.
> >>
> >> [2] The core framework knows the chip's requirement
> >>     (ecc_strength_ds, ecc_size_ds).
> >>
> >>
> >> Then, the core framework provides a function
> >> to return a most recommended (ecc_strength, ecc_size).
> >>
> >>
> >>
> >> struct nand_ecc_spec {
> >>        int ecc_strength;
> >>        int ecc_size;
> >> };
> >>
> >> /*
> >>  * This function choose the most recommented (ecc_str, ecc_size)
> >>  * "recommended" means: minimum ecc stregth that meets
> >>  * the chip's requirment.
> >>  *
> >>  *
> >>  * @chip   - nand_chip
> >>  * @controller_ecc_spec - Array of (ecc_str, ecc_size) supported by the
> >>                           controller. (terminated by NULL as sentinel)
> >>  */
> >> struct nand_ecc_spec * nand_try_to_match_ecc_req(struct nand_chip *chip,
> >>                                                  struct nand_ecc_spec
> >> *controller_ecc_spec)
> >> {
> >>       /*
> >>        * Return the pointer to the most recommended
> >>        * struct nand_ecc_spec.
> >>        * If nothing suitable found, return NULL.
> >>        */
> >> }
> >>  
> >
> > I like the idea, except I would do this slightly differently to avoid
> > declaring all combinations of stepsize and strengths
> >
> > struct nand_ecc_stepsize_info {
> >         int stepsize;
> >         int nstrengths;
> >         int *strengths;
> > };
> >
> > struct nand_ecc_engine_caps {
> >         int nstepsizes;
> >         struct nand_ecc_stepsize_info *stepsizes;
> >         int (*calc_ecc_bytes)(int stepsize, int strength);
> > };
> >
> > int nand_try_to_match_ecc_req(struct nand_chip *chip,
> >                               const struct nand_ecc_engine_caps *caps,
> >                               struct nand_ecc_spec *spec)
> > {
> >         /*
> >          * Find the most appropriate setting based on the ECC engine
> >          * caps and fill the spec object accordingly.
> >          * Returns 0 in case of success and a negative error code
> >          * otherwise.
> >          */
> > }
> >
> > Note that nand_try_to_match_ecc_req() has to be more generic than
> > denali_try_to_match_ecc_req() WRT step sizes, which will probably
> > complexify the logic.  
> 
> 
> After I fiddle with this generic approach for a while,
> I started to feel like giving up.

I don't get it. What was the problem with my initial suggestion (the
denali specific one, not the generic approach)? You proposed to make it
generic, which, I agree, is a bit more complicated.

> 
> I wonder if we really want over-implementation
> for covering _theoretically_ possible cases.

Okay, one more theoretical case I'd like to expose: you have board
design with different NAND parts which have different ECC requirements.
If you were about to describe the exact ECC strength you want for each
board you'll have to have different DTs. Maximizing the ECC strength
would still work, but what if the MTD user needs some OOB bytes (like
is the case with JFFS2) and ECC maximization reserved all of the
available bytes?

The other reason I prefer to have the drivers automatically guessing
what's appropriate is because then you don't have to care when writing
your DT.

> 
> In practice, there are not so many ECC settings possible
> on a single controller.
> 
> As for Denali IP, it would be theoretically possible to instantiate
> multiple ECC engines.  However, in practice, there is no sensible
> reason to do so.  At least, I do not know any real chip to support that.
> 
> So, I'd like to simplify the logic for Denali.
> 
>   - Support either 512 or 1024 ECC size.
>     If there is (ever) a controller that supports both,
>     1024 should be chosen.
> 
>   - ECC strength is not specified via DT, it is simply maximized.
> 
> This simplifies the logic much and I believe this is enough.
> 
> One more reason is, as we talked before,
> we need to match ECC setting between Linux and firmware (boot-loader),

If the bootloader implements the same logic it should match.

> so anyway we end up with using a fixed setting specified by DT.
> 

Really, I don't see what's the problem with the function I proposed,
but I'm willing to make a concession.
Make the nand-ecc-strength+nand-ecc-step-size or nand-ecc-maximize
mandatory so that if someone ever needs to support the 'match NAND
requirements' feature we won't have to add a vendor specific property
like this one [1].

Are you fine with that?

[1]http://lxr.free-electrons.com/source/Documentation/devicetree/bindings/mtd/gpmi-nand.txt#L20
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v4 3/9] dt-bindings: pinctrl: Add RZ/A1 bindings doc
From: Linus Walleij @ 2017-04-11  7:54 UTC (permalink / raw)
  To: Rob Herring
  Cc: Jacopo Mondi, Geert Uytterhoeven, Laurent Pinchart, Chris Brandt,
	Mark Rutland, Russell King, Linux-Renesas,
	linux-gpio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <20170410181215.e6cihbv2rfljbm3b@rob-hp-laptop>

On Mon, Apr 10, 2017 at 8:12 PM, Rob Herring <robh@kernel.org> wrote:
> On Wed, Apr 05, 2017 at 04:07:21PM +0200, Jacopo Mondi wrote:

>> +  The allowed generic formats for a pin multiplexing sub-node are the
>> +  following ones:
>> +
>> +  node-1 {
>> +      pinmux = <PIN_ID_AND_MUX>, <PIN_ID_AND_MUX>, ... ;
>> +      GENERIC_PINCONFIG;
>
> What's GENERIC_PINCONFIG? I see this in some other binding docs, but not
> used anywhere. If this is a boolean property then get rid of the all
> caps. If this is a define, then don't use complex defines that expand to
> dts source.

I guess it is a wildcard for everything under the heading in
"Generic pin configuration node content"
in Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt

I'm all for documenting it properly.

It's kind of useful, but I don't know the recent ambtions about being
formal with DT bindings. The GPIO bindings are just over the top
with BNF notation in its formalism. Dunno what is best here :/

Yours,
Linus Walleij

^ permalink raw reply

* Re: [PATCH] ARM: dts: stm32f7: add STM32f769I & stm32f746 discovery board support
From: Alexandre Torgue @ 2017-04-11  7:50 UTC (permalink / raw)
  To: Vikas Manocha, patrice.chotard-qxv4g6HH51o
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	moderated list:ARM PORT, open list, Mark Rutland, Maxime Coquelin,
	Rob Herring, Russell King
In-Reply-To: <6e07ebcf-4463-523f-ea24-5a176efb0779-qxv4g6HH51o@public.gmane.org>

Hi Vikas

On 04/10/2017 08:40 PM, Vikas Manocha wrote:
> Thanks Alex,
>
> On 04/10/2017 12:23 AM, Alexandre Torgue wrote:
>> Hi
>>
>> On 04/08/2017 03:12 AM, Vikas Manocha wrote:
>>> Stm32f769I & stm32f746 are MCUs of stm32f7 family. Here are the major
>>> spces of the two boards:
>>>
>>> stm32f769I discovery board:
>>>     - Cortex-M7 core @216MHz
>>>     - 2MB mcu internal flash
>>>     - 512KB internal sram
>>>     - 16MB sdram memory
>>>     - 64MB qspi flash memory
>>>     - 4 inch wvga LCD-TFT Display
>>>
>>> stm32f746 discovery board:
>>>     - Cortex-M7 core @216MHz
>>>     - 1MB mcu internal flash
>>>     - 320KB internal sram
>>>     - 8MB sdram memory
>>>     - 16MB qspi flash memory
>>>     - 4.3 inch 480x272 LCD-TFT display
>>>
>>> Signed-off-by: Vikas Manocha <vikas.manocha-qxv4g6HH51o@public.gmane.org>
>>> ---
>>>  arch/arm/boot/dts/Makefile            |   2 +
>>>  arch/arm/boot/dts/stm32f746-disco.dts | 101 ++++++++++++++++++++++++++++++++++
>>>  arch/arm/boot/dts/stm32f746.dtsi      |   2 +-
>>>  arch/arm/boot/dts/stm32f769-disco.dts | 101 ++++++++++++++++++++++++++++++++++
>>>  4 files changed, 205 insertions(+), 1 deletion(-)
>>>  create mode 100644 arch/arm/boot/dts/stm32f746-disco.dts
>>>  create mode 100644 arch/arm/boot/dts/stm32f769-disco.dts
>>>
>>> diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
>>> index 0118084..a119f74 100644
>>> --- a/arch/arm/boot/dts/Makefile
>>> +++ b/arch/arm/boot/dts/Makefile
>>> @@ -763,6 +763,8 @@ dtb-$(CONFIG_ARCH_STI) += \
>>>  dtb-$(CONFIG_ARCH_STM32)+= \
>>>      stm32f429-disco.dtb \
>>>      stm32f469-disco.dtb \
>>> +    stm32f746-disco.dtb \
>>> +    stm32f769-disco.dtb \
>>>      stm32429i-eval.dtb \
>>>      stm32746g-eval.dtb
>>>  dtb-$(CONFIG_MACH_SUN4I) += \
>>> diff --git a/arch/arm/boot/dts/stm32f746-disco.dts b/arch/arm/boot/dts/stm32f746-disco.dts
>>> new file mode 100644
>>> index 0000000..c0e313f
>>> --- /dev/null
>>> +++ b/arch/arm/boot/dts/stm32f746-disco.dts
>>> @@ -0,0 +1,101 @@
>>> +/*
>>> + * Copyright 2017 - Vikas MANOCHA <vikas.manocha-qxv4g6HH51o@public.gmane.org>
>>> + *
>>> + * This file is dual-licensed: you can use it either under the terms
>>> + * of the GPL or the X11 license, at your option. Note that this dual
>>> + * licensing only applies to this file, and not this project as a
>>> + * whole.
>>> + *
>>> + *  a) This file is free software; you can redistribute it and/or
>>> + *     modify it under the terms of the GNU General Public License as
>>> + *     published by the Free Software Foundation; either version 2 of the
>>> + *     License, or (at your option) any later version.
>>> + *
>>> + *     This file is distributed in the hope that it will be useful,
>>> + *     but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + *     GNU General Public License for more details.
>>> + *
>>> + * Or, alternatively,
>>> + *
>>> + *  b) Permission is hereby granted, free of charge, to any person
>>> + *     obtaining a copy of this software and associated documentation
>>> + *     files (the "Software"), to deal in the Software without
>>> + *     restriction, including without limitation the rights to use,
>>> + *     copy, modify, merge, publish, distribute, sublicense, and/or
>>> + *     sell copies of the Software, and to permit persons to whom the
>>> + *     Software is furnished to do so, subject to the following
>>> + *     conditions:
>>> + *
>>> + *     The above copyright notice and this permission notice shall be
>>> + *     included in all copies or substantial portions of the Software.
>>> + *
>>> + *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>> + *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
>>> + *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>>> + *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
>>> + *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
>>> + *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>>> + *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>>> + *     OTHER DEALINGS IN THE SOFTWARE.
>>> + */
>>> +
>>> +/dts-v1/;
>>> +#include "stm32f746.dtsi"
>>> +#include <dt-bindings/input/input.h>
>>> +
>>> +/ {
>>> +    model = "STMicroelectronics STM32F746-DISCO board";
>>> +    compatible = "st,stm32f746-disco", "st,stm32f746";
>>> +
>>> +    chosen {
>>> +        bootargs = "root=/dev/ram";
>>> +        stdout-path = "serial0:115200n8";
>>> +    };
>>> +
>>> +    memory {
>>> +        reg = <0xC0000000 0x800000>;
>>> +    };
>>> +
>>> +    aliases {
>>> +        serial0 = &usart1;
>>> +    };
>>> +
>>> +};
>>> +
>>> +&clk_hse {
>>> +    clock-frequency = <25000000>;
>>> +};
>>> +
>>> +&pinctrl {
>>
>>
>> Pin muxing is not defined in board file. Please move it into SOC dtsi file.
>
> Pin muxing used is different for different boards. e.g. usart1_rx pad is PA10 for stm32f769-disco board while it is PB7 for stm32f746-disco board.
> The other possibilities for same pad (usart1_rx) is PB15. To make situation bit more complex, it is only available in f769 device.
>
> Putting in SOC dtsi file means having lot of combinations for different pins in separate groups.
> e.g. only for one instance of one ip (usart1), following groups might be required at one point of time:
>
> usart1_pa10_pa9 {..}
> usart1_pa10_pb14 {..}
> usart1_pa10_pb6 {..}
>
> usart1_pb7_pa9 {..}
> usart1_pb7_pb14 {..}
> usart1_pb7_pb6 {..}
>
> usart1_pb15_pa9 {..}
> usart1_pb15_pb14 {..}
> usart1_pb15_pb6 {..}
>
> In case of boards based on stm32f746 device, all the above mentioned groups with pb14 & pb15 will not be available.
> One solution (to avoid using not available groups) could be to have separate dtsi (or separate pinmux.dtsi) for different devices of same family like one for stm32f746 & other for stm32f769. Still it does not resolve the need to have lot of groups combinations for each instance of every peripheral in dtsi as mentioned above.

Yes, it is what I want to have. I did the job on for STM32F4 (F429 / 
F469). You could have a look on ARM Linux patchwork: 
https://patchwork.kernel.org/patch/9669433/

To sum-up the implementation:

-Pinmuxing is defined in separate files which will be included in board 
dts file.

-We have a common pinmuxing file + a dedicated pinmuxing file per SOC.

Example for STMF469-disco:
stm32f4-pinctrl.dtsi --> stm32f469-pinctrl.dtsi --> stm32f469-disco.dts

stm32f4-pinctrl.dtsi contains common pinmuxing bindings between STM32F4
stm32f469-pinctrl.dtsi contains dedicated pinmuxing bindings for 
STM32F469 (ex: QSPI pins, gpio-ranges ...)

This implementation is under review.


> It seems cleaner solution would be pin muxing in board dts file. Please let me know if there is some drawback of this approach. One point which i can think of is : duplication of pinmux groups in different board dts files.

Pinmuxing in board file is currently not my choice. In the board file we 
only select the group to use.

Regards
Alex


>
> Cheers,
> Vikas
>
>>> +    usart1_pins: usart1@0    {
>>> +        pins1 {
>>> +            pinmux = <STM32F746_PA9_FUNC_USART1_TX>;
>>> +                bias-disable;
>>> +                drive-push-pull;
>>> +                slew-rate = <2>;
>>> +        };
>>> +        pins2 {
>>> +            pinmux = <STM32F746_PB7_FUNC_USART1_RX>;
>>> +            bias-disable;
>>> +        };
>>> +    };
>>> +
>>> +    qspi_pins: qspi@0 {
>>> +        pins {
>>> +            pinmux = <STM32F746_PB2_FUNC_QUADSPI_CLK>,
>>> +                   <STM32F746_PB6_FUNC_QUADSPI_BK1_NCS>,
>>> +                   <STM32F746_PD11_FUNC_QUADSPI_BK1_IO0>,
>>> +                   <STM32F746_PD12_FUNC_QUADSPI_BK1_IO1>,
>>> +                   <STM32F746_PD13_FUNC_QUADSPI_BK1_IO3>,
>>> +                   <STM32F746_PE2_FUNC_QUADSPI_BK1_IO2>;
>>> +            slew-rate = <2>;
>>> +        };
>>> +    };
>>> +};
>>> +
>>> +&usart1 {
>>> +    pinctrl-0 = <&usart1_pins>;
>>> +    pinctrl-names = "default";
>>> +    status = "okay";
>>> +};
>>> diff --git a/arch/arm/boot/dts/stm32f746.dtsi b/arch/arm/boot/dts/stm32f746.dtsi
>>> index f321ffe..826700f 100644
>>> --- a/arch/arm/boot/dts/stm32f746.dtsi
>>> +++ b/arch/arm/boot/dts/stm32f746.dtsi
>>> @@ -178,7 +178,7 @@
>>>              interrupts = <1>, <2>, <3>, <6>, <7>, <8>, <9>, <10>, <23>, <40>, <41>, <42>, <62>, <76>;
>>>          };
>>>
>>> -        pin-controller {
>>> +        pinctrl: pin-controller {
>>>              #address-cells = <1>;
>>>              #size-cells = <1>;
>>>              compatible = "st,stm32f746-pinctrl";
>>> diff --git a/arch/arm/boot/dts/stm32f769-disco.dts b/arch/arm/boot/dts/stm32f769-disco.dts
>>> new file mode 100644
>>> index 0000000..5f8558e
>>> --- /dev/null
>>> +++ b/arch/arm/boot/dts/stm32f769-disco.dts
>>> @@ -0,0 +1,101 @@
>>> +/*
>>> + * Copyright 2017 - Vikas MANOCHA <vikas.manocha-qxv4g6HH51o@public.gmane.org>
>>> + *
>>> + * This file is dual-licensed: you can use it either under the terms
>>> + * of the GPL or the X11 license, at your option. Note that this dual
>>> + * licensing only applies to this file, and not this project as a
>>> + * whole.
>>> + *
>>> + *  a) This file is free software; you can redistribute it and/or
>>> + *     modify it under the terms of the GNU General Public License as
>>> + *     published by the Free Software Foundation; either version 2 of the
>>> + *     License, or (at your option) any later version.
>>> + *
>>> + *     This file is distributed in the hope that it will be useful,
>>> + *     but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + *     GNU General Public License for more details.
>>> + *
>>> + * Or, alternatively,
>>> + *
>>> + *  b) Permission is hereby granted, free of charge, to any person
>>> + *     obtaining a copy of this software and associated documentation
>>> + *     files (the "Software"), to deal in the Software without
>>> + *     restriction, including without limitation the rights to use,
>>> + *     copy, modify, merge, publish, distribute, sublicense, and/or
>>> + *     sell copies of the Software, and to permit persons to whom the
>>> + *     Software is furnished to do so, subject to the following
>>> + *     conditions:
>>> + *
>>> + *     The above copyright notice and this permission notice shall be
>>> + *     included in all copies or substantial portions of the Software.
>>> + *
>>> + *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>> + *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
>>> + *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>>> + *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
>>> + *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
>>> + *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>>> + *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>>> + *     OTHER DEALINGS IN THE SOFTWARE.
>>> + */
>>> +
>>> +/dts-v1/;
>>> +#include "stm32f746.dtsi"
>>> +#include <dt-bindings/input/input.h>
>>> +
>>> +/ {
>>> +    model = "STMicroelectronics STM32F769-DISCO board";
>>> +    compatible = "st,stm32f769-disco", "st,stm32f7";
>>> +
>>> +    chosen {
>>> +        bootargs = "root=/dev/ram";
>>> +        stdout-path = "serial0:115200n8";
>>> +    };
>>> +
>>> +    memory {
>>> +        reg = <0xC0000000 0x1000000>;
>>> +    };
>>> +
>>> +    aliases {
>>> +        serial0 = &usart1;
>>> +    };
>>> +
>>> +};
>>> +
>>> +&clk_hse {
>>> +    clock-frequency = <25000000>;
>>> +};
>>> +
>>> +&pinctrl {
>>
>> same.
>>
>>> +    usart1_pins: usart1@0    {
>>> +        pins1 {
>>> +            pinmux = <STM32F746_PA9_FUNC_USART1_TX>;
>>> +                bias-disable;
>>> +                drive-push-pull;
>>> +                slew-rate = <2>;
>>> +        };
>>> +        pins2 {
>>> +            pinmux = <STM32F746_PA10_FUNC_USART1_RX>;
>>> +            bias-disable;
>>> +        };
>>> +    };
>>> +
>>> +    qspi_pins: qspi@0 {
>>> +        pins {
>>> +            pinmux = <STM32F746_PB2_FUNC_QUADSPI_CLK>,
>>> +                   <STM32F746_PB6_FUNC_QUADSPI_BK1_NCS>,
>>> +                   <STM32F746_PC9_FUNC_QUADSPI_BK1_IO0>,
>>> +                   <STM32F746_PC10_FUNC_QUADSPI_BK1_IO1>,
>>> +                   <STM32F746_PD13_FUNC_QUADSPI_BK1_IO3>,
>>> +                   <STM32F746_PE2_FUNC_QUADSPI_BK1_IO2>;
>>> +            slew-rate = <2>;
>>> +        };
>>> +    };
>>> +};
>>> +
>>> +&usart1 {
>>> +    pinctrl-0 = <&usart1_pins>;
>>> +    pinctrl-names = "default";
>>> +    status = "okay";
>>> +};
>>>
>> .
>>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH v2] mmc: core: add mmc-card hardware reset enable support
From: Richard Leitner @ 2017-04-11  7:31 UTC (permalink / raw)
  To: ulf.hansson, robh+dt, mark.rutland
  Cc: shawn.lin, adrian.hunter, jh80.chung, linus.walleij, linux-mmc,
	linux-kernel, devicetree, dev, Richard Leitner

Some eMMCs disable their hardware reset line (RST_N) by default. To enable
it the host must set the corresponding bit in ECSD. An example for such
a device is the Micron MTFCxGACAANA-4M.

This patch adds a new mmc-card devicetree property to let the host enable
this feature during card initialization.

Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
---
CHANGES v2:
	- add RST_N_FUNCTION value to dt documentation
	- set RST_N_FUNCTION only if it was not set before
---
 Documentation/devicetree/bindings/mmc/mmc-card.txt |  4 ++++
 drivers/mmc/core/mmc.c                             | 23 ++++++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/Documentation/devicetree/bindings/mmc/mmc-card.txt b/Documentation/devicetree/bindings/mmc/mmc-card.txt
index a70fcd6..bbfccce 100644
--- a/Documentation/devicetree/bindings/mmc/mmc-card.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc-card.txt
@@ -12,6 +12,10 @@ Required properties:
 Optional properties:
 -broken-hpi : Use this to indicate that the mmc-card has a broken hpi
               implementation, and that hpi should not be used
+-enable-hw-reset : some eMMC devices have disabled the hw reset functionality
+                   (RST_N_FUNCTION) by default. By adding this property the
+                   host will enable it during initialization. This will set
+                   RST_N_FUNCTION to 0x1 (permanently enabled).
 
 Example:
 
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index b502601..30066be 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1520,9 +1520,16 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	int err;
 	u32 cid[4];
 	u32 rocr;
+	struct device_node *np;
+	bool enable_rst_n = false;
 
 	WARN_ON(!host->claimed);
 
+	np = mmc_of_find_child_device(host, 0);
+	if (np && of_device_is_compatible(np, "mmc-card"))
+		enable_rst_n = of_property_read_bool(np, "enable-hw-reset");
+	of_node_put(np);
+
 	/* Set correct bus mode for MMC before attempting init */
 	if (!mmc_host_is_spi(host))
 		mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN);
@@ -1810,6 +1817,22 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		}
 	}
 
+	/*
+	 * enable RST_N if requested (and rst_n_function is not set)
+	 * This is needed because some eMMC chips disable this function by
+	 * default.
+	 */
+	if (enable_rst_n &&
+	    !(card->ext_csd.rst_n_function & EXT_CSD_RST_N_EN_MASK)) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_RST_N_FUNCTION, EXT_CSD_RST_N_ENABLED,
+				 card->ext_csd.generic_cmd6_time);
+		card->ext_csd.rst_n_function = EXT_CSD_RST_N_ENABLED;
+		if (err && err != -EBADMSG)
+			pr_warn("%s: Enabling RST_N feature failed\n",
+				mmc_hostname(card->host));
+	}
+
 	if (!oldcard)
 		host->card = card;
 
-- 
2.1.4


^ permalink raw reply related


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