Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v2] iio: max5481: Add support for Maxim digital potentiometers
From: Slawomir Stepien @ 2017-01-14 11:42 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	cristina.moraru09-Re5JQEeQqe8AvxtiuMwx3w,
	matthew.weber-lFk7bPDcGtkY5TsXZYaR1UEOCMrvLtNR,
	maury.anderson-lFk7bPDcGtkY5TsXZYaR1UEOCMrvLtNR,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Mark Rutland,
	Rob Herring
In-Reply-To: <ee973aa1-c881-6bc8-c61a-9f36b8598f5f-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

On Jan 14, 2017 10:38, Jonathan Cameron wrote:
> As this has device tree bindings it should have gone to linux-devicetree,
> Rob and Mark (maintainers of bindings).

I will add them to CC on the new version.

> Spi buffers for spi_write need to be cacheline aligned.  See below
> for roughly why.

I can recall that from my previous submissions... I made the same mistake.
Thank you once again for explaining that. I hope this will imprint in my mind
from now on.

Thank you!

> Jonathan
> > ---
> > +static int max5481_write_cmd(struct spi_device *spi, u8 cmd, u16 val)
> > +{
> > +	/* SPI Format from MAX5481-MAX5484 (19-3708; Rev 5; 4/10) pg 15 */
> > +	u8 msg[3];
> It's clearly one of those days - same issue in two drivers in a row. :(
> Still I can refine me response ;)
> 
> There are requirements for buffers passed directly to spi_read / spi_write.
> They get passed to spi_sync which calls into the spi master drivers.
> SPI master drivers are explicitly allowed to directly use this buffer
> in dma. On most modern platforms it is fine to do DMA from any location...
> 
> However, cacheline corruption comes in here. There is no guarantee that
> the SPI controller won't write back to this address, as it it will be
> bypassing the processor whilst doing this, that can result in a difference
> in other parts of the cacheline between what is in the cache and what is
> in main memory.  At the end of the dma transfer any changes elsewhere in
> the cacheline can be wiped out as result. (or something like that ;)
> 
> Anyhow, two solutions.  Either allocate the memory in it's own cacheline
> which will naturally happen if you allocate on the heap using kmalloc
> or use the fact we carefully align the iio_priv memory to be cacheline
> aligned. This means that if you stick a __cacheline_aligned buffer at the
> end of your iio_priv structure it was also be in it's own cacheline.
> 
> Not doing this is the source of really hard to track down bugs!
> > +
> > +	msg[0] = cmd;
> > +
> > +	switch (cmd) {
> > +	case MAX5481_WRITE_WIPER:
> > +		msg[1] = val >> 2;
> > +		msg[2] = (val & 0x3) << 6;
> > +		return spi_write(spi, msg, ARRAY_SIZE(msg));
> > +
> > +	case MAX5481_COPY_AB_TO_NV:
> > +	case MAX5481_COPY_NV_TO_AB:
> > +		return spi_write(spi, msg, sizeof(u8));
> > +
> > +	default:
> > +		return -EIO;
> > +	}
> > +}

-- 
Slawomir Stepien

^ permalink raw reply

* Re: [PATCH v2 2/2] iio: distance: srf08: add IIO driver for us ranger
From: Jonathan Cameron @ 2017-01-14 12:17 UTC (permalink / raw)
  To: Andreas Klinger, knaack.h-Mmb7MZpHnFY,
	lars-Qo5EllUWu/uELgA04lAiVw, pmeerw-jW+XmwGofnusTnJN9+BGXg,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, ktsai-GubuWUlQtMwciDkP5Hr2oA,
	wsa-z923LK4zBo2bacvFa/9K2g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ, trivial-DgEjT+Ai2ygdnm+yROfE0A,
	mranostay-Re5JQEeQqe8AvxtiuMwx3w,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170110184815.GA15532@andreas>

On 10/01/17 18:48, Andreas Klinger wrote:
> This is the IIO driver for devantech srf08 ultrasonic ranger which can be
> used to measure the distances to an object.
> 
> The sensor supports I2C with some registers.
> 
> Supported Features include:
> - read the distance in ranging mode in centimeters
> - output of the driver is directly the read value
> - together with the scale the driver delivers the distance in meters
> - only the first echo of the nearest object is delivered
> - set max gain register; userspace enters analogue value
> - set range registers; userspace enters range in millimeters in 43 mm steps
> 
> Features not supported by this driver:
> - ranging mode in inches or in microseconds
> - ANN mode
> - change I2C address through this driver
> - light sensor
> 
> The driver was added in the directory "proximity" of the iio subsystem
> in absence of another directory named "distance".
> There is also a new submenu "distance"
Hi Andreas,

Sorry it took me a while to get to this!

I'd not bother with the new submenu.  Perhaps we should rename the
proximity menu to proximity/distance.

We already the lightening detector in there which is definitely not
measuring proximity in the convetional sense!

Anyhow, the actual code is fine, but we need to think about how the
userspace ABI fits within the wider IIO ABI.  Naming and approaches
that make sense in a single class of drivers can end up meaining
very different things for other drivers.  Various suggestions inline.

Jonathan
> 
> Signed-off-by: Andreas Klinger <ak-n176/SwNRljddJNmlsFzeA@public.gmane.org>
> ---
>  drivers/iio/proximity/Kconfig  |  15 ++
>  drivers/iio/proximity/Makefile |   1 +
>  drivers/iio/proximity/srf08.c  | 362 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 378 insertions(+)
>  create mode 100644 drivers/iio/proximity/srf08.c
> 
> diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig
> index ef4c73db5b53..7b10a137702b 100644
> --- a/drivers/iio/proximity/Kconfig
> +++ b/drivers/iio/proximity/Kconfig
> @@ -46,3 +46,18 @@ config SX9500
>  	  module will be called sx9500.
>  
>  endmenu
> +
> +menu "Distance sensors"
> +
> +config SRF08
> +	tristate "Devantech SRF08 ultrasonic ranger sensor"
> +	depends on I2C
> +	help
> +	  Say Y here to build a driver for Devantech SRF08 ultrasonic
> +	  ranger sensor. This driver can be used to measure the distance
> +	  of objects.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called srf08.
> +
> +endmenu
> diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
> index 9aadd9a8ee99..e914c2a5dd49 100644
> --- a/drivers/iio/proximity/Makefile
> +++ b/drivers/iio/proximity/Makefile
> @@ -5,4 +5,5 @@
>  # When adding new entries keep the list in alphabetical order
>  obj-$(CONFIG_AS3935)		+= as3935.o
>  obj-$(CONFIG_LIDAR_LITE_V2)	+= pulsedlight-lidar-lite-v2.o
> +obj-$(CONFIG_SRF08)		+= srf08.o
>  obj-$(CONFIG_SX9500)		+= sx9500.o
> diff --git a/drivers/iio/proximity/srf08.c b/drivers/iio/proximity/srf08.c
> new file mode 100644
> index 000000000000..f38c74ed0933
> --- /dev/null
> +++ b/drivers/iio/proximity/srf08.c
> @@ -0,0 +1,362 @@
> +/*
> + * srf08.c - Support for Devantech SRF08 ultrasonic ranger
> + *
> + * Copyright (c) 2016 Andreas Klinger <ak-n176/SwNRljddJNmlsFzeA@public.gmane.org>
> + *
> + * This file is subject to the terms and conditions of version 2 of
> + * the GNU General Public License.  See the file COPYING in the main
> + * directory of this archive for more details.
> + *
> + * For details about the device see:
> + * http://www.robot-electronics.co.uk/htm/srf08tech.html
> + */
> +
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/delay.h>
> +#include <linux/module.h>
> +#include <linux/bitops.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +
> +/* registers of SRF08 device */
> +#define SRF08_WRITE_COMMAND	0x00	/* Command Register */
> +#define SRF08_WRITE_MAX_GAIN	0x01	/* Max Gain Register: 0 .. 31 */
> +#define SRF08_WRITE_RANGE	0x02	/* Range Register: 0 .. 255 */
> +#define SRF08_READ_SW_REVISION	0x00	/* Software Revision */
> +#define SRF08_READ_LIGHT	0x01	/* Light Sensor during last echo */
> +#define SRF08_READ_ECHO_1_HIGH	0x02	/* Range of first echo received */
> +#define SRF08_READ_ECHO_1_LOW	0x03	/* Range of first echo received */
> +
> +#define SRF08_CMD_RANGING_CM	0x51	/* Ranging Mode - Result in cm */
> +
> +#define SRF08_DEFAULT_GAIN	1025	/* max. analogue value of Gain */
> +#define SRF08_DEFAULT_RANGE	11008	/* max. value of Range in mm */
> +
> +struct srf08_data {
> +	struct i2c_client	*client;
> +	int			gain;			/* Max Gain */
> +	int			range_mm;		/* Range in mm */
> +	struct mutex		lock;
> +};
> +
> +static const int srf08_gain[] = {
> +	 94,  97, 100, 103, 107, 110, 114, 118,
> +	123, 128, 133, 139, 145, 152, 159, 168,
> +	177, 187, 199, 212, 227, 245, 265, 288,
> +	317, 352, 395, 450, 524, 626, 777, 1025 };
> +
> +static int srf08_read_ranging(struct srf08_data *data)
> +{
> +	struct i2c_client *client = data->client;
> +	int ret, i;
> +
> +	mutex_lock(&data->lock);
> +
> +	ret = i2c_smbus_write_byte_data(data->client,
> +			SRF08_WRITE_COMMAND, SRF08_CMD_RANGING_CM);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "write command - err: %d\n", ret);
> +		mutex_unlock(&data->lock);
> +		return ret;
> +	}
> +
> +	/*
> +	 * normally after 65 ms the device should have the read value
> +	 * we round it up to 100 ms
I'd suggest this should be adapted so that it takes advantage of knowing
roughly how long it is going to take as the 'range' maximum is changed.
So perhaps in the basic case, sleep for 65 msecs, then poll at 5msec
intervals.  If we know it's going to be a lot faster, then poll it from
an earlier time.
> +	 *
> +	 * we read here until a correct version number shows up as
> +	 * suggested by the documentation
> +	 */
> +	for (i = 0; i < 5; i++) {
> +		ret = i2c_smbus_read_byte_data(data->client,
> +						SRF08_READ_SW_REVISION);
> +
> +		/* check if a valid version number is read */
> +		if (ret < 255 && ret > 0)
> +			break;
> +		msleep(20);
> +	}
> +
> +	if (ret >= 255 || ret <= 0) {
> +		dev_err(&client->dev, "device not ready\n");
> +		mutex_unlock(&data->lock);
> +		return -EIO;
> +	}
> +
> +	ret = i2c_smbus_read_word_swapped(data->client,
> +						SRF08_READ_ECHO_1_HIGH);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "cannot read distance: ret=%d\n", ret);
> +		mutex_unlock(&data->lock);
> +		return ret;
> +	}
> +
> +	mutex_unlock(&data->lock);
> +
> +	return ret;
> +}
> +
> +static int srf08_read_raw(struct iio_dev *indio_dev,
> +			    struct iio_chan_spec const *channel, int *val,
> +			    int *val2, long mask)
> +{
> +	struct srf08_data *data = iio_priv(indio_dev);
> +	int ret;
> +
> +	if (channel->type != IIO_DISTANCE)
> +		return -EINVAL;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		ret = srf08_read_ranging(data);
> +		if (ret < 0)
> +			return ret;
> +		*val = ret;
> +		return IIO_VAL_INT;
> +	case IIO_CHAN_INFO_SCALE:
> +		/* 1 LSB is 1 cm */
> +		*val = 0;
> +		*val2 = 10000;
> +		return IIO_VAL_INT_PLUS_MICRO;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static ssize_t srf08_show_range_mm_available(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	int i, len = 0;
> +
> +	for (i = 0; i < 256; i++)
> +		len += scnprintf(buf + len, PAGE_SIZE - len,
> +							"%d ", (i + 1) * 43);
> +
> +	buf[len - 1] = '\n';
> +
> +	return len;
> +}
> +
> +static IIO_DEVICE_ATTR(range_mm_available, S_IRUGO,
> +				srf08_show_range_mm_available, NULL, 0);
> +
> +static ssize_t srf08_show_range_mm(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct srf08_data *data = iio_priv(indio_dev);
> +
> +	return sprintf(buf, "%d\n", data->range_mm);
> +}
> +
> +/*
> + * set the range of the sensor to an even multiple of 43 mm
> + * which corresponds to 1 LSB in the register
> + *
> + * register value    corresponding range
> + *         0x00             43 mm
> + *         0x01             86 mm
> + *         0x02            129 mm
> + *         ...
> + *         0xFF          11008 mm
> + */
> +static ssize_t srf08_write_range_mm(struct device *dev,
> +					struct device_attribute *attr,
> +					const char *buf, size_t len)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct srf08_data *data = iio_priv(indio_dev);
> +	struct i2c_client *client = data->client;
> +	int ret;
> +	unsigned int val, mod;
> +	u8 regval;
> +
> +	ret = kstrtouint(buf, 10, &val);
> +	if (ret)
> +		return ret;
> +
> +	ret = val / 43 - 1;
> +	mod = val % 43;
> +
> +	if (mod || (ret < 0) || (ret > 255))
> +		return -EINVAL;
> +
> +	regval = ret;
> +
> +	mutex_lock(&data->lock);
> +
> +	ret = i2c_smbus_write_byte_data(data->client,
> +						SRF08_WRITE_RANGE, regval);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "write_range - err: %d\n", ret);
> +		mutex_unlock(&data->lock);
> +		return ret;
> +	}
> +
> +	data->range_mm = val;
> +
> +	mutex_unlock(&data->lock);
> +
> +	return len;
> +}
> +
> +static IIO_DEVICE_ATTR(range_mm, S_IRUGO | S_IWUSR,
> +			srf08_show_range_mm, srf08_write_range_mm, 0);
> +
> +static ssize_t srf08_show_gain_available(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	int i, len = 0;
> +
> +	for (i = 0; i < ARRAY_SIZE(srf08_gain); i++)
> +		len += sprintf(buf + len, "%d ", srf08_gain[i]);
> +
> +	len += sprintf(buf + len, "\n");
> +
> +	return len;
> +}
> +
> +static IIO_DEVICE_ATTR(gain_available, S_IRUGO,
> +				srf08_show_gain_available, NULL, 0);
> +
> +static ssize_t srf08_show_gain(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct srf08_data *data = iio_priv(indio_dev);
> +	int len;
> +
> +	len = sprintf(buf, "%d\n", data->gain);
> +
> +	return len;
> +}
> +
> +static ssize_t srf08_write_gain(struct device *dev,
> +						struct device_attribute *attr,
> +						const char *buf, size_t len)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct srf08_data *data = iio_priv(indio_dev);
> +	struct i2c_client *client = data->client;
> +	int ret, i;
> +	unsigned int val;
> +	u8 regval;
> +
> +	ret = kstrtouint(buf, 10, &val);
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < ARRAY_SIZE(srf08_gain); i++)
> +		if (val == srf08_gain[i]) {
> +			regval = i;
> +			break;
> +		}
> +
> +	if (i >= ARRAY_SIZE(srf08_gain))
> +		return -EINVAL;
> +
> +	mutex_lock(&data->lock);
> +
> +	ret = i2c_smbus_write_byte_data(data->client,
> +						SRF08_WRITE_MAX_GAIN, regval);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "write_gain - err: %d\n", ret);
> +		mutex_unlock(&data->lock);
> +		return ret;
> +	}
> +
> +	data->gain = val;
> +
> +	mutex_unlock(&data->lock);
> +
> +	return len;
> +}
> +
> +static IIO_DEVICE_ATTR(gain, S_IRUGO | S_IWUSR,
> +					srf08_show_gain, srf08_write_gain, 0);
> +
> +static struct attribute *srf08_attributes[] = {
> +	&iio_dev_attr_range_mm.dev_attr.attr,
> +	&iio_dev_attr_range_mm_available.dev_attr.attr,
> +	&iio_dev_attr_gain.dev_attr.attr,
> +	&iio_dev_attr_gain_available.dev_attr.attr,
Hmm. Custom attributes always give us issues. The primary point of IIO
is to enforce (more or less) standard interfaces.

If you do need to add something new then that is fine (and I do think
you need to here!).

They need to be formally proposed as an addition to the ABI with
docs in /Documentation/ABI/testing/sysfs-bus-iio*

Once we take one driver using it it becomes part of our ABI that
userspace will need to handle, hence we consider these very
carefully.

My gut feeling would be that gain needs to be more specific as it's
a term that can mean very different things.. Here we are talking
about an amplifier on a signal that we are then looking at the timing
of.   It might otherwise be interpretted as another term for what
we term 'scale' in IIO.

So what to call it... Perhaps afegain for Analog front end gain?
We might want to add this to the core supported attrs, but lets
not do so until we see if we have this on a number of devices.

The description would need to make it explicit that this gain is
for cases where we aren't measuring the magnitude of what is
being amplified.

For the range, it's an interesting one.  Again the term range could
mean too many things within the wider ABI. We need to make it more
specific.

Actually reading the datasheet, I think this is fundamentally about the
maximum sampling frequency rather than directly about the range.
The only reason you'd reduce the range is to speed that up. It doesn't
improve the resolution, the device simply answers quicker.

So I'd support this as sampling_frequency.  You could then use
the the iio_info_mask_*_available and relevant callback to provide
info on what it then restricts the possible output values to
(rather than controlling it directly).

> +	NULL,
> +};
> +
> +static const struct attribute_group srf08_attribute_group = {
> +	.attrs = srf08_attributes,
> +};
> +
> +static const struct iio_chan_spec srf08_channels[] = {
> +	{
> +		.type = IIO_DISTANCE,
> +		.info_mask_separate =
> +				BIT(IIO_CHAN_INFO_RAW) |
> +				BIT(IIO_CHAN_INFO_SCALE),
> +	},
> +};
> +
> +static const struct iio_info srf08_info = {
> +	.read_raw = srf08_read_raw,
> +	.attrs = &srf08_attribute_group,
> +	.driver_module = THIS_MODULE,
> +};
> +
> +static int srf08_probe(struct i2c_client *client,
> +					 const struct i2c_device_id *id)
> +{
> +	struct iio_dev *indio_dev;
> +	struct srf08_data *data;
> +
> +	if (!i2c_check_functionality(client->adapter,
> +					I2C_FUNC_SMBUS_READ_BYTE_DATA |
> +					I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
> +					I2C_FUNC_SMBUS_READ_WORD_DATA))
> +		return -ENODEV;
> +
> +	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	data = iio_priv(indio_dev);
> +	i2c_set_clientdata(client, indio_dev);
> +	data->client = client;
> +
> +	/*
> +	 * set default values of device here
> +	 * these values are already set on the hardware after power on
> +	 */
> +	data->gain = SRF08_DEFAULT_GAIN;
> +	data->range_mm = SRF08_DEFAULT_RANGE;
We should be a little careful with assumptions about the device having
just been powered on.  The driver might simply have been removed and
reprobed.  So I'd sugest rewriting them whatever to be sure we have
what we expect.  Either that or if they can be read back, then just
always retrieve them from the device.
> +
> +	indio_dev->name = dev_name(&client->dev);
> +	indio_dev->dev.parent = &client->dev;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->info = &srf08_info;
> +	indio_dev->channels = srf08_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(srf08_channels);
> +
> +	mutex_init(&data->lock);
> +
> +	return devm_iio_device_register(&client->dev, indio_dev);
> +}
> +
> +static const struct i2c_device_id srf08_id[] = {
> +	{ "srf08", 0 },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, srf08_id);
> +
> +static struct i2c_driver srf08_driver = {
> +	.driver = {
> +		.name	= "srf08",
> +	},
> +	.probe = srf08_probe,
> +	.id_table = srf08_id,
> +};
> +module_i2c_driver(srf08_driver);
> +
> +MODULE_AUTHOR("Andreas Klinger <ak-n176/SwNRljddJNmlsFzeA@public.gmane.org>");
> +MODULE_DESCRIPTION("Devantech SRF08 ultrasonic ranger driver");
> +MODULE_LICENSE("GPL");
> 

--
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 0/4] Drop drivers for Exynos4415
From: Krzysztof Kozlowski @ 2017-01-14 12:36 UTC (permalink / raw)
  To: Sylwester Nawrocki, Tomasz Figa, Chanwoo Choi, Michael Turquette,
	Stephen Boyd, Rob Herring, Mark Rutland, Kukjin Kim,
	Krzysztof Kozlowski, Javier Martinez Canillas, Inki Dae,
	Joonyoung Shim, Seung-Woo Kim, Kyungmin Park, Linus Walleij,
	linux-samsung-soc, linux-clk, devicetree, linux-arm-kernel,
	linux-kernel, dri-deve

Hi,

Support for Exynos4415 is being removed because:
1. There are no upstream users,
2. There are no known downstream users,
3. Except compile testing, you cannot build working kernel
   for Exynos4415 anymore.

Patches are rebased on current next and are independent.
Please pick up as you wish.

Best regards,
Krzysztof

Krzysztof Kozlowski (4):
  ARM: EXYNOS: Remove Exynos4415 driver (SoC not supported anymore)
  clk: samsung: Remove Exynos4415 driver (SoC not supported anymore)
  pinctrl: samsung: Remove support for Exynos4415 (SoC not supported
    anymore)
  drm: exynos: Remove support for Exynos4415 (SoC not supported anymore)

 .../devicetree/bindings/clock/exynos4415-clock.txt |   38 -
 .../bindings/display/exynos/exynos_dsim.txt        |    1 -
 .../bindings/display/exynos/samsung-fimd.txt       |    1 -
 arch/arm/mach-exynos/Kconfig                       |    5 -
 arch/arm/mach-exynos/exynos.c                      |    1 -
 arch/arm/mach-exynos/suspend.c                     |    1 -
 drivers/clk/samsung/Makefile                       |    1 -
 drivers/clk/samsung/clk-exynos4415.c               | 1022 --------------------
 drivers/gpu/drm/exynos/exynos_drm_dsi.c            |   15 +-
 drivers/gpu/drm/exynos/exynos_drm_fimd.c           |   18 +-
 drivers/pinctrl/samsung/pinctrl-exynos.c           |   75 --
 drivers/pinctrl/samsung/pinctrl-samsung.c          |    2 -
 drivers/pinctrl/samsung/pinctrl-samsung.h          |    1 -
 include/dt-bindings/clock/exynos4415.h             |  360 -------
 14 files changed, 3 insertions(+), 1538 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/clock/exynos4415-clock.txt
 delete mode 100644 drivers/clk/samsung/clk-exynos4415.c
 delete mode 100644 include/dt-bindings/clock/exynos4415.h

-- 
2.9.3


^ permalink raw reply

* [PATCH 1/4] ARM: EXYNOS: Remove Exynos4415 driver (SoC not supported anymore)
From: Krzysztof Kozlowski @ 2017-01-14 12:36 UTC (permalink / raw)
  To: Sylwester Nawrocki, Tomasz Figa, Chanwoo Choi, Michael Turquette,
	Stephen Boyd, Rob Herring, Mark Rutland, Kukjin Kim,
	Krzysztof Kozlowski, Javier Martinez Canillas, Inki Dae,
	Joonyoung Shim, Seung-Woo Kim, Kyungmin Park, Linus Walleij,
	linux-samsung-soc, linux-clk, devicetree, linux-arm-kernel,
	linux-kernel, dri-deve
In-Reply-To: <20170114123642.15581-1-krzk@kernel.org>

Support for Exynos4415 is going away because there are no internal nor
external users.

Since commit 46dcf0ff0de3 ("ARM: dts: exynos: Remove exynos4415.dtsi"),
the platform cannot be instantiated so remove also the mach code.

Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
---
 arch/arm/mach-exynos/Kconfig   | 5 -----
 arch/arm/mach-exynos/exynos.c  | 1 -
 arch/arm/mach-exynos/suspend.c | 1 -
 3 files changed, 7 deletions(-)

diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 0bb63b8d21e7..0a99140b6ba2 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -95,11 +95,6 @@ config SOC_EXYNOS4412
 	default y
 	depends on ARCH_EXYNOS4
 
-config SOC_EXYNOS4415
-	bool "SAMSUNG EXYNOS4415"
-	default y
-	depends on ARCH_EXYNOS4
-
 config SOC_EXYNOS5250
 	bool "SAMSUNG EXYNOS5250"
 	default y
diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c
index 35b832f4bc7e..c404c15ad07f 100644
--- a/arch/arm/mach-exynos/exynos.c
+++ b/arch/arm/mach-exynos/exynos.c
@@ -210,7 +210,6 @@ static char const *const exynos_dt_compat[] __initconst = {
 	"samsung,exynos4210",
 	"samsung,exynos4212",
 	"samsung,exynos4412",
-	"samsung,exynos4415",
 	"samsung,exynos5",
 	"samsung,exynos5250",
 	"samsung,exynos5260",
diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c
index 518420241062..25e7c5326259 100644
--- a/arch/arm/mach-exynos/suspend.c
+++ b/arch/arm/mach-exynos/suspend.c
@@ -270,7 +270,6 @@ EXYNOS_PMU_IRQ(exynos3250_pmu_irq, "samsung,exynos3250-pmu");
 EXYNOS_PMU_IRQ(exynos4210_pmu_irq, "samsung,exynos4210-pmu");
 EXYNOS_PMU_IRQ(exynos4212_pmu_irq, "samsung,exynos4212-pmu");
 EXYNOS_PMU_IRQ(exynos4412_pmu_irq, "samsung,exynos4412-pmu");
-EXYNOS_PMU_IRQ(exynos4415_pmu_irq, "samsung,exynos4415-pmu");
 EXYNOS_PMU_IRQ(exynos5250_pmu_irq, "samsung,exynos5250-pmu");
 EXYNOS_PMU_IRQ(exynos5420_pmu_irq, "samsung,exynos5420-pmu");
 
-- 
2.9.3

^ permalink raw reply related

* [PATCH 2/4] clk: samsung: Remove Exynos4415 driver (SoC not supported anymore)
From: Krzysztof Kozlowski @ 2017-01-14 12:36 UTC (permalink / raw)
  To: Sylwester Nawrocki, Tomasz Figa, Chanwoo Choi, Michael Turquette,
	Stephen Boyd, Rob Herring, Mark Rutland, Kukjin Kim,
	Krzysztof Kozlowski, Javier Martinez Canillas, Inki Dae,
	Joonyoung Shim, Seung-Woo Kim, Kyungmin Park, Linus Walleij,
	linux-samsung-soc, linux-clk, devicetree, linux-arm-kernel,
	linux-kernel, dri-deve
In-Reply-To: <20170114123642.15581-1-krzk@kernel.org>

Support for Exynos4415 is going away because there are no internal nor
external users.

Since commit 46dcf0ff0de3 ("ARM: dts: exynos: Remove exynos4415.dtsi"),
the platform cannot be instantiated so remove also the drivers.

Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
---
 .../devicetree/bindings/clock/exynos4415-clock.txt |   38 -
 drivers/clk/samsung/Makefile                       |    1 -
 drivers/clk/samsung/clk-exynos4415.c               | 1022 --------------------
 include/dt-bindings/clock/exynos4415.h             |  360 -------
 4 files changed, 1421 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/clock/exynos4415-clock.txt
 delete mode 100644 drivers/clk/samsung/clk-exynos4415.c
 delete mode 100644 include/dt-bindings/clock/exynos4415.h

diff --git a/Documentation/devicetree/bindings/clock/exynos4415-clock.txt b/Documentation/devicetree/bindings/clock/exynos4415-clock.txt
deleted file mode 100644
index 847d98bae8cf..000000000000
--- a/Documentation/devicetree/bindings/clock/exynos4415-clock.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-* Samsung Exynos4415 Clock Controller
-
-The Exynos4415 clock controller generates and supplies clock to various
-consumer devices within the Exynos4415 SoC.
-
-Required properties:
-
-- compatible: should be one of the following:
-  - "samsung,exynos4415-cmu" - for the main system clocks controller
-    (CMU_LEFTBUS, CMU_RIGHTBUS, CMU_TOP, CMU_CPU clock domains).
-  - "samsung,exynos4415-cmu-dmc" - for the Exynos4415 SoC DRAM Memory
-    Controller (DMC) domain clock controller.
-
-- reg: physical base address of the controller and length of memory mapped
-  region.
-
-- #clock-cells: should be 1.
-
-Each clock is assigned an identifier and client nodes can use this identifier
-to specify the clock which they consume.
-
-All available clocks are defined as preprocessor macros in
-dt-bindings/clock/exynos4415.h header and can be used in device
-tree sources.
-
-Example 1: An example of a clock controller node is listed below.
-
-	cmu: clock-controller@10030000 {
-		compatible = "samsung,exynos4415-cmu";
-		reg = <0x10030000 0x18000>;
-		#clock-cells = <1>;
-	};
-
-	cmu-dmc: clock-controller@105C0000 {
-		compatible = "samsung,exynos4415-cmu-dmc";
-		reg = <0x105C0000 0x3000>;
-		#clock-cells = <1>;
-	};
diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile
index 57f4dc6dc447..7afc21dc374e 100644
--- a/drivers/clk/samsung/Makefile
+++ b/drivers/clk/samsung/Makefile
@@ -5,7 +5,6 @@
 obj-$(CONFIG_COMMON_CLK)	+= clk.o clk-pll.o clk-cpu.o
 obj-$(CONFIG_SOC_EXYNOS3250)	+= clk-exynos3250.o
 obj-$(CONFIG_ARCH_EXYNOS4)	+= clk-exynos4.o
-obj-$(CONFIG_SOC_EXYNOS4415)	+= clk-exynos4415.o
 obj-$(CONFIG_SOC_EXYNOS5250)	+= clk-exynos5250.o
 obj-$(CONFIG_SOC_EXYNOS5260)	+= clk-exynos5260.o
 obj-$(CONFIG_SOC_EXYNOS5410)	+= clk-exynos5410.o
diff --git a/drivers/clk/samsung/clk-exynos4415.c b/drivers/clk/samsung/clk-exynos4415.c
deleted file mode 100644
index 6c9063159717..000000000000
--- a/drivers/clk/samsung/clk-exynos4415.c
+++ /dev/null
@@ -1,1022 +0,0 @@
-/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- * Author: Chanwoo Choi <cw00.choi@samsung.com>
- *
- * 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.
- *
- * Common Clock Framework support for Exynos4415 SoC.
- */
-
-#include <linux/clk-provider.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/platform_device.h>
-#include <linux/syscore_ops.h>
-
-#include <dt-bindings/clock/exynos4415.h>
-
-#include "clk.h"
-#include "clk-pll.h"
-
-#define SRC_LEFTBUS		0x4200
-#define DIV_LEFTBUS		0x4500
-#define GATE_IP_LEFTBUS		0x4800
-#define GATE_IP_IMAGE		0x4930
-#define SRC_RIGHTBUS		0x8200
-#define DIV_RIGHTBUS		0x8500
-#define GATE_IP_RIGHTBUS	0x8800
-#define GATE_IP_PERIR		0x8960
-#define EPLL_LOCK		0xc010
-#define G3D_PLL_LOCK		0xc020
-#define DISP_PLL_LOCK		0xc030
-#define ISP_PLL_LOCK		0xc040
-#define EPLL_CON0		0xc110
-#define EPLL_CON1		0xc114
-#define EPLL_CON2		0xc118
-#define G3D_PLL_CON0		0xc120
-#define G3D_PLL_CON1		0xc124
-#define G3D_PLL_CON2		0xc128
-#define ISP_PLL_CON0		0xc130
-#define ISP_PLL_CON1		0xc134
-#define ISP_PLL_CON2		0xc138
-#define DISP_PLL_CON0		0xc140
-#define DISP_PLL_CON1		0xc144
-#define DISP_PLL_CON2		0xc148
-#define SRC_TOP0		0xc210
-#define SRC_TOP1		0xc214
-#define SRC_CAM			0xc220
-#define SRC_TV			0xc224
-#define SRC_MFC			0xc228
-#define SRC_G3D			0xc22c
-#define SRC_LCD			0xc234
-#define SRC_ISP			0xc238
-#define SRC_MAUDIO		0xc23c
-#define SRC_FSYS		0xc240
-#define SRC_PERIL0		0xc250
-#define SRC_PERIL1		0xc254
-#define SRC_CAM1		0xc258
-#define SRC_TOP_ISP0		0xc25c
-#define SRC_TOP_ISP1		0xc260
-#define SRC_MASK_TOP		0xc310
-#define SRC_MASK_CAM		0xc320
-#define SRC_MASK_TV		0xc324
-#define SRC_MASK_LCD		0xc334
-#define SRC_MASK_ISP		0xc338
-#define SRC_MASK_MAUDIO		0xc33c
-#define SRC_MASK_FSYS		0xc340
-#define SRC_MASK_PERIL0		0xc350
-#define SRC_MASK_PERIL1		0xc354
-#define DIV_TOP			0xc510
-#define DIV_CAM			0xc520
-#define DIV_TV			0xc524
-#define DIV_MFC			0xc528
-#define DIV_G3D			0xc52c
-#define DIV_LCD			0xc534
-#define DIV_ISP			0xc538
-#define DIV_MAUDIO		0xc53c
-#define DIV_FSYS0		0xc540
-#define DIV_FSYS1		0xc544
-#define DIV_FSYS2		0xc548
-#define DIV_PERIL0		0xc550
-#define DIV_PERIL1		0xc554
-#define DIV_PERIL2		0xc558
-#define DIV_PERIL3		0xc55c
-#define DIV_PERIL4		0xc560
-#define DIV_PERIL5		0xc564
-#define DIV_CAM1		0xc568
-#define DIV_TOP_ISP1		0xc56c
-#define DIV_TOP_ISP0		0xc570
-#define CLKDIV2_RATIO		0xc580
-#define GATE_SCLK_CAM		0xc820
-#define GATE_SCLK_TV		0xc824
-#define GATE_SCLK_MFC		0xc828
-#define GATE_SCLK_G3D		0xc82c
-#define GATE_SCLK_LCD		0xc834
-#define GATE_SCLK_MAUDIO	0xc83c
-#define GATE_SCLK_FSYS		0xc840
-#define GATE_SCLK_PERIL		0xc850
-#define GATE_IP_CAM		0xc920
-#define GATE_IP_TV		0xc924
-#define GATE_IP_MFC		0xc928
-#define GATE_IP_G3D		0xc92c
-#define GATE_IP_LCD		0xc934
-#define GATE_IP_FSYS		0xc940
-#define GATE_IP_PERIL		0xc950
-#define GATE_BLOCK		0xc970
-#define APLL_LOCK		0x14000
-#define APLL_CON0		0x14100
-#define SRC_CPU			0x14200
-#define DIV_CPU0		0x14500
-#define DIV_CPU1		0x14504
-
-static const unsigned long exynos4415_cmu_clk_regs[] __initconst = {
-	SRC_LEFTBUS,
-	DIV_LEFTBUS,
-	GATE_IP_LEFTBUS,
-	GATE_IP_IMAGE,
-	SRC_RIGHTBUS,
-	DIV_RIGHTBUS,
-	GATE_IP_RIGHTBUS,
-	GATE_IP_PERIR,
-	EPLL_LOCK,
-	G3D_PLL_LOCK,
-	DISP_PLL_LOCK,
-	ISP_PLL_LOCK,
-	EPLL_CON0,
-	EPLL_CON1,
-	EPLL_CON2,
-	G3D_PLL_CON0,
-	G3D_PLL_CON1,
-	G3D_PLL_CON2,
-	ISP_PLL_CON0,
-	ISP_PLL_CON1,
-	ISP_PLL_CON2,
-	DISP_PLL_CON0,
-	DISP_PLL_CON1,
-	DISP_PLL_CON2,
-	SRC_TOP0,
-	SRC_TOP1,
-	SRC_CAM,
-	SRC_TV,
-	SRC_MFC,
-	SRC_G3D,
-	SRC_LCD,
-	SRC_ISP,
-	SRC_MAUDIO,
-	SRC_FSYS,
-	SRC_PERIL0,
-	SRC_PERIL1,
-	SRC_CAM1,
-	SRC_TOP_ISP0,
-	SRC_TOP_ISP1,
-	SRC_MASK_TOP,
-	SRC_MASK_CAM,
-	SRC_MASK_TV,
-	SRC_MASK_LCD,
-	SRC_MASK_ISP,
-	SRC_MASK_MAUDIO,
-	SRC_MASK_FSYS,
-	SRC_MASK_PERIL0,
-	SRC_MASK_PERIL1,
-	DIV_TOP,
-	DIV_CAM,
-	DIV_TV,
-	DIV_MFC,
-	DIV_G3D,
-	DIV_LCD,
-	DIV_ISP,
-	DIV_MAUDIO,
-	DIV_FSYS0,
-	DIV_FSYS1,
-	DIV_FSYS2,
-	DIV_PERIL0,
-	DIV_PERIL1,
-	DIV_PERIL2,
-	DIV_PERIL3,
-	DIV_PERIL4,
-	DIV_PERIL5,
-	DIV_CAM1,
-	DIV_TOP_ISP1,
-	DIV_TOP_ISP0,
-	CLKDIV2_RATIO,
-	GATE_SCLK_CAM,
-	GATE_SCLK_TV,
-	GATE_SCLK_MFC,
-	GATE_SCLK_G3D,
-	GATE_SCLK_LCD,
-	GATE_SCLK_MAUDIO,
-	GATE_SCLK_FSYS,
-	GATE_SCLK_PERIL,
-	GATE_IP_CAM,
-	GATE_IP_TV,
-	GATE_IP_MFC,
-	GATE_IP_G3D,
-	GATE_IP_LCD,
-	GATE_IP_FSYS,
-	GATE_IP_PERIL,
-	GATE_BLOCK,
-	APLL_LOCK,
-	APLL_CON0,
-	SRC_CPU,
-	DIV_CPU0,
-	DIV_CPU1,
-};
-
-/* list of all parent clock list */
-PNAME(mout_g3d_pllsrc_p)	= { "fin_pll", };
-
-PNAME(mout_apll_p)		= { "fin_pll", "fout_apll", };
-PNAME(mout_g3d_pll_p)		= { "fin_pll", "fout_g3d_pll", };
-PNAME(mout_isp_pll_p)		= { "fin_pll", "fout_isp_pll", };
-PNAME(mout_disp_pll_p)		= { "fin_pll", "fout_disp_pll", };
-
-PNAME(mout_mpll_user_p)		= { "fin_pll", "div_mpll_pre", };
-PNAME(mout_epll_p)		= { "fin_pll", "fout_epll", };
-PNAME(mout_core_p)		= { "mout_apll", "mout_mpll_user_c", };
-PNAME(mout_hpm_p)		= { "mout_apll", "mout_mpll_user_c", };
-
-PNAME(mout_ebi_p)		= { "div_aclk_200", "div_aclk_160", };
-PNAME(mout_ebi_1_p)		= { "mout_ebi", "mout_g3d_pll", };
-
-PNAME(mout_gdl_p)		= { "mout_mpll_user_l", };
-PNAME(mout_gdr_p)		= { "mout_mpll_user_r", };
-
-PNAME(mout_aclk_266_p)		= { "mout_mpll_user_t", "mout_g3d_pll", };
-
-PNAME(group_epll_g3dpll_p)	= { "mout_epll", "mout_g3d_pll" };
-PNAME(group_sclk_p)		= { "xxti", "xusbxti",
-				    "none", "mout_isp_pll",
-				    "none", "none", "div_mpll_pre",
-				    "mout_epll", "mout_g3d_pll", };
-PNAME(group_spdif_p)		= { "mout_audio0", "mout_audio1",
-				    "mout_audio2", "spdif_extclk", };
-PNAME(group_sclk_audio2_p)	= { "audiocdclk2", "none",
-				    "none", "mout_isp_pll",
-				    "mout_disp_pll", "xusbxti",
-				    "div_mpll_pre", "mout_epll",
-				    "mout_g3d_pll", };
-PNAME(group_sclk_audio1_p)	= { "audiocdclk1", "none",
-				    "none", "mout_isp_pll",
-				    "mout_disp_pll", "xusbxti",
-				    "div_mpll_pre", "mout_epll",
-				    "mout_g3d_pll", };
-PNAME(group_sclk_audio0_p)	= { "audiocdclk0", "none",
-				    "none", "mout_isp_pll",
-				    "mout_disp_pll", "xusbxti",
-				    "div_mpll_pre", "mout_epll",
-				    "mout_g3d_pll", };
-PNAME(group_fimc_lclk_p)	= { "xxti", "xusbxti",
-				    "none", "mout_isp_pll",
-				    "none", "mout_disp_pll",
-				    "mout_mpll_user_t", "mout_epll",
-				    "mout_g3d_pll", };
-PNAME(group_sclk_fimd0_p)	= { "xxti", "xusbxti",
-				    "m_bitclkhsdiv4_4l", "mout_isp_pll",
-				    "mout_disp_pll", "sclk_hdmiphy",
-				    "div_mpll_pre", "mout_epll",
-				    "mout_g3d_pll", };
-PNAME(mout_hdmi_p)		= { "sclk_pixel", "sclk_hdmiphy" };
-PNAME(mout_mfc_p)		= { "mout_mfc_0", "mout_mfc_1" };
-PNAME(mout_g3d_p)		= { "mout_g3d_0", "mout_g3d_1" };
-PNAME(mout_jpeg_p)		= { "mout_jpeg_0", "mout_jpeg_1" };
-PNAME(mout_jpeg1_p)		= { "mout_epll", "mout_g3d_pll" };
-PNAME(group_aclk_isp0_300_p)	= { "mout_isp_pll", "div_mpll_pre" };
-PNAME(group_aclk_isp0_400_user_p) = { "fin_pll", "div_aclk_400_mcuisp" };
-PNAME(group_aclk_isp0_300_user_p) = { "fin_pll", "mout_aclk_isp0_300" };
-PNAME(group_aclk_isp1_300_user_p) = { "fin_pll", "mout_aclk_isp1_300" };
-PNAME(group_mout_mpll_user_t_p)	= { "mout_mpll_user_t" };
-
-static const struct samsung_fixed_factor_clock exynos4415_fixed_factor_clks[] __initconst = {
-	/* HACK: fin_pll hardcoded to xusbxti until detection is implemented. */
-	FFACTOR(CLK_FIN_PLL, "fin_pll", "xusbxti", 1, 1, 0),
-};
-
-static const struct samsung_fixed_rate_clock exynos4415_fixed_rate_clks[] __initconst = {
-	FRATE(CLK_SCLK_HDMIPHY, "sclk_hdmiphy", NULL, 0, 27000000),
-};
-
-static const struct samsung_mux_clock exynos4415_mux_clks[] __initconst = {
-	/*
-	 * NOTE: Following table is sorted by register address in ascending
-	 * order and then bitfield shift in descending order, as it is done
-	 * in the User's Manual. When adding new entries, please make sure
-	 * that the order is preserved, to avoid merge conflicts and make
-	 * further work with defined data easier.
-	 */
-
-	/* SRC_LEFTBUS */
-	MUX(CLK_MOUT_MPLL_USER_L, "mout_mpll_user_l", mout_mpll_user_p,
-		SRC_LEFTBUS, 4, 1),
-	MUX(CLK_MOUT_GDL, "mout_gdl", mout_gdl_p, SRC_LEFTBUS, 0, 1),
-
-	/* SRC_RIGHTBUS */
-	MUX(CLK_MOUT_MPLL_USER_R, "mout_mpll_user_r", mout_mpll_user_p,
-		SRC_RIGHTBUS, 4, 1),
-	MUX(CLK_MOUT_GDR, "mout_gdr", mout_gdr_p, SRC_RIGHTBUS, 0, 1),
-
-	/* SRC_TOP0 */
-	MUX(CLK_MOUT_EBI, "mout_ebi", mout_ebi_p, SRC_TOP0, 28, 1),
-	MUX(CLK_MOUT_ACLK_200, "mout_aclk_200", group_mout_mpll_user_t_p,
-		SRC_TOP0, 24, 1),
-	MUX(CLK_MOUT_ACLK_160, "mout_aclk_160", group_mout_mpll_user_t_p,
-		SRC_TOP0, 20, 1),
-	MUX(CLK_MOUT_ACLK_100, "mout_aclk_100", group_mout_mpll_user_t_p,
-		SRC_TOP0, 16, 1),
-	MUX(CLK_MOUT_ACLK_266, "mout_aclk_266", mout_aclk_266_p,
-		SRC_TOP0, 12, 1),
-	MUX(CLK_MOUT_G3D_PLL, "mout_g3d_pll", mout_g3d_pll_p,
-		SRC_TOP0, 8, 1),
-	MUX(CLK_MOUT_EPLL, "mout_epll", mout_epll_p, SRC_TOP0, 4, 1),
-	MUX(CLK_MOUT_EBI_1, "mout_ebi_1", mout_ebi_1_p, SRC_TOP0, 0, 1),
-
-	/* SRC_TOP1 */
-	MUX(CLK_MOUT_ISP_PLL, "mout_isp_pll", mout_isp_pll_p,
-		SRC_TOP1, 28, 1),
-	MUX(CLK_MOUT_DISP_PLL, "mout_disp_pll", mout_disp_pll_p,
-		SRC_TOP1, 16, 1),
-	MUX(CLK_MOUT_MPLL_USER_T, "mout_mpll_user_t", mout_mpll_user_p,
-		SRC_TOP1, 12, 1),
-	MUX(CLK_MOUT_ACLK_400_MCUISP, "mout_aclk_400_mcuisp",
-		group_mout_mpll_user_t_p, SRC_TOP1, 8, 1),
-	MUX(CLK_MOUT_G3D_PLLSRC, "mout_g3d_pllsrc", mout_g3d_pllsrc_p,
-		SRC_TOP1, 0, 1),
-
-	/* SRC_CAM */
-	MUX(CLK_MOUT_CSIS1, "mout_csis1", group_fimc_lclk_p, SRC_CAM, 28, 4),
-	MUX(CLK_MOUT_CSIS0, "mout_csis0", group_fimc_lclk_p, SRC_CAM, 24, 4),
-	MUX(CLK_MOUT_CAM1, "mout_cam1", group_fimc_lclk_p, SRC_CAM, 20, 4),
-	MUX(CLK_MOUT_FIMC3_LCLK, "mout_fimc3_lclk", group_fimc_lclk_p, SRC_CAM,
-		12, 4),
-	MUX(CLK_MOUT_FIMC2_LCLK, "mout_fimc2_lclk", group_fimc_lclk_p, SRC_CAM,
-		8, 4),
-	MUX(CLK_MOUT_FIMC1_LCLK, "mout_fimc1_lclk", group_fimc_lclk_p, SRC_CAM,
-		4, 4),
-	MUX(CLK_MOUT_FIMC0_LCLK, "mout_fimc0_lclk", group_fimc_lclk_p, SRC_CAM,
-		0, 4),
-
-	/* SRC_TV */
-	MUX(CLK_MOUT_HDMI, "mout_hdmi", mout_hdmi_p, SRC_TV, 0, 1),
-
-	/* SRC_MFC */
-	MUX(CLK_MOUT_MFC, "mout_mfc", mout_mfc_p, SRC_MFC, 8, 1),
-	MUX(CLK_MOUT_MFC_1, "mout_mfc_1", group_epll_g3dpll_p, SRC_MFC, 4, 1),
-	MUX(CLK_MOUT_MFC_0, "mout_mfc_0", group_mout_mpll_user_t_p, SRC_MFC, 0,
-		1),
-
-	/* SRC_G3D */
-	MUX(CLK_MOUT_G3D, "mout_g3d", mout_g3d_p, SRC_G3D, 8, 1),
-	MUX(CLK_MOUT_G3D_1, "mout_g3d_1", group_epll_g3dpll_p, SRC_G3D, 4, 1),
-	MUX(CLK_MOUT_G3D_0, "mout_g3d_0", group_mout_mpll_user_t_p, SRC_G3D, 0,
-		1),
-
-	/* SRC_LCD */
-	MUX(CLK_MOUT_MIPI0, "mout_mipi0", group_fimc_lclk_p, SRC_LCD, 12, 4),
-	MUX(CLK_MOUT_FIMD0, "mout_fimd0", group_sclk_fimd0_p, SRC_LCD, 0, 4),
-
-	/* SRC_ISP */
-	MUX(CLK_MOUT_TSADC_ISP, "mout_tsadc_isp", group_fimc_lclk_p, SRC_ISP,
-		16, 4),
-	MUX(CLK_MOUT_UART_ISP, "mout_uart_isp", group_fimc_lclk_p, SRC_ISP,
-		12, 4),
-	MUX(CLK_MOUT_SPI1_ISP, "mout_spi1_isp", group_fimc_lclk_p, SRC_ISP,
-		8, 4),
-	MUX(CLK_MOUT_SPI0_ISP, "mout_spi0_isp", group_fimc_lclk_p, SRC_ISP,
-		4, 4),
-	MUX(CLK_MOUT_PWM_ISP, "mout_pwm_isp", group_fimc_lclk_p, SRC_ISP,
-		0, 4),
-
-	/* SRC_MAUDIO */
-	MUX(CLK_MOUT_AUDIO0, "mout_audio0", group_sclk_audio0_p, SRC_MAUDIO,
-		0, 4),
-
-	/* SRC_FSYS */
-	MUX(CLK_MOUT_TSADC, "mout_tsadc", group_sclk_p, SRC_FSYS, 28, 4),
-	MUX(CLK_MOUT_MMC2, "mout_mmc2", group_sclk_p, SRC_FSYS, 8, 4),
-	MUX(CLK_MOUT_MMC1, "mout_mmc1", group_sclk_p, SRC_FSYS, 4, 4),
-	MUX(CLK_MOUT_MMC0, "mout_mmc0", group_sclk_p, SRC_FSYS, 0, 4),
-
-	/* SRC_PERIL0 */
-	MUX(CLK_MOUT_UART3, "mout_uart3", group_sclk_p, SRC_PERIL0, 12, 4),
-	MUX(CLK_MOUT_UART2, "mout_uart2", group_sclk_p, SRC_PERIL0, 8, 4),
-	MUX(CLK_MOUT_UART1, "mout_uart1", group_sclk_p, SRC_PERIL0, 4, 4),
-	MUX(CLK_MOUT_UART0, "mout_uart0", group_sclk_p, SRC_PERIL0, 0, 4),
-
-	/* SRC_PERIL1 */
-	MUX(CLK_MOUT_SPI2, "mout_spi2", group_sclk_p, SRC_PERIL1, 24, 4),
-	MUX(CLK_MOUT_SPI1, "mout_spi1", group_sclk_p, SRC_PERIL1, 20, 4),
-	MUX(CLK_MOUT_SPI0, "mout_spi0", group_sclk_p, SRC_PERIL1, 16, 4),
-	MUX(CLK_MOUT_SPDIF, "mout_spdif", group_spdif_p, SRC_PERIL1, 8, 4),
-	MUX(CLK_MOUT_AUDIO2, "mout_audio2", group_sclk_audio2_p, SRC_PERIL1,
-		4, 4),
-	MUX(CLK_MOUT_AUDIO1, "mout_audio1", group_sclk_audio1_p, SRC_PERIL1,
-		0, 4),
-
-	/* SRC_CPU */
-	MUX(CLK_MOUT_MPLL_USER_C, "mout_mpll_user_c", mout_mpll_user_p,
-		SRC_CPU, 24, 1),
-	MUX(CLK_MOUT_HPM, "mout_hpm", mout_hpm_p, SRC_CPU, 20, 1),
-	MUX_F(CLK_MOUT_CORE, "mout_core", mout_core_p, SRC_CPU, 16, 1, 0,
-		CLK_MUX_READ_ONLY),
-	MUX_F(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1,
-		CLK_SET_RATE_PARENT, 0),
-
-	/* SRC_CAM1 */
-	MUX(CLK_MOUT_PXLASYNC_CSIS1_FIMC, "mout_pxlasync_csis1",
-		group_fimc_lclk_p, SRC_CAM1, 20, 1),
-	MUX(CLK_MOUT_PXLASYNC_CSIS0_FIMC, "mout_pxlasync_csis0",
-		group_fimc_lclk_p, SRC_CAM1, 16, 1),
-	MUX(CLK_MOUT_JPEG, "mout_jpeg", mout_jpeg_p, SRC_CAM1, 8, 1),
-	MUX(CLK_MOUT_JPEG1, "mout_jpeg_1", mout_jpeg1_p, SRC_CAM1, 4, 1),
-	MUX(CLK_MOUT_JPEG0, "mout_jpeg_0", group_mout_mpll_user_t_p, SRC_CAM1,
-		0, 1),
-
-	/* SRC_TOP_ISP0 */
-	MUX(CLK_MOUT_ACLK_ISP0_300, "mout_aclk_isp0_300",
-		group_aclk_isp0_300_p, SRC_TOP_ISP0, 8, 1),
-	MUX(CLK_MOUT_ACLK_ISP0_400, "mout_aclk_isp0_400_user",
-		group_aclk_isp0_400_user_p, SRC_TOP_ISP0, 4, 1),
-	MUX(CLK_MOUT_ACLK_ISP0_300_USER, "mout_aclk_isp0_300_user",
-		group_aclk_isp0_300_user_p, SRC_TOP_ISP0, 0, 1),
-
-	/* SRC_TOP_ISP1 */
-	MUX(CLK_MOUT_ACLK_ISP1_300, "mout_aclk_isp1_300",
-		group_aclk_isp0_300_p, SRC_TOP_ISP1, 4, 1),
-	MUX(CLK_MOUT_ACLK_ISP1_300_USER, "mout_aclk_isp1_300_user",
-		group_aclk_isp1_300_user_p, SRC_TOP_ISP1, 0, 1),
-};
-
-static const struct samsung_div_clock exynos4415_div_clks[] __initconst = {
-	/*
-	 * NOTE: Following table is sorted by register address in ascending
-	 * order and then bitfield shift in descending order, as it is done
-	 * in the User's Manual. When adding new entries, please make sure
-	 * that the order is preserved, to avoid merge conflicts and make
-	 * further work with defined data easier.
-	 */
-
-	/* DIV_LEFTBUS */
-	DIV(CLK_DIV_GPL, "div_gpl", "div_gdl", DIV_LEFTBUS, 4, 3),
-	DIV(CLK_DIV_GDL, "div_gdl", "mout_gdl", DIV_LEFTBUS, 0, 4),
-
-	/* DIV_RIGHTBUS */
-	DIV(CLK_DIV_GPR, "div_gpr", "div_gdr", DIV_RIGHTBUS, 4, 3),
-	DIV(CLK_DIV_GDR, "div_gdr", "mout_gdr", DIV_RIGHTBUS, 0, 4),
-
-	/* DIV_TOP */
-	DIV(CLK_DIV_ACLK_400_MCUISP, "div_aclk_400_mcuisp",
-		"mout_aclk_400_mcuisp", DIV_TOP, 24, 3),
-	DIV(CLK_DIV_EBI, "div_ebi", "mout_ebi_1", DIV_TOP, 16, 3),
-	DIV(CLK_DIV_ACLK_200, "div_aclk_200", "mout_aclk_200", DIV_TOP, 12, 3),
-	DIV(CLK_DIV_ACLK_160, "div_aclk_160", "mout_aclk_160", DIV_TOP, 8, 3),
-	DIV(CLK_DIV_ACLK_100, "div_aclk_100", "mout_aclk_100", DIV_TOP, 4, 4),
-	DIV(CLK_DIV_ACLK_266, "div_aclk_266", "mout_aclk_266", DIV_TOP, 0, 3),
-
-	/* DIV_CAM */
-	DIV(CLK_DIV_CSIS1, "div_csis1", "mout_csis1", DIV_CAM, 28, 4),
-	DIV(CLK_DIV_CSIS0, "div_csis0", "mout_csis0", DIV_CAM, 24, 4),
-	DIV(CLK_DIV_CAM1, "div_cam1", "mout_cam1", DIV_CAM, 20, 4),
-	DIV(CLK_DIV_FIMC3_LCLK, "div_fimc3_lclk", "mout_fimc3_lclk", DIV_CAM,
-		12, 4),
-	DIV(CLK_DIV_FIMC2_LCLK, "div_fimc2_lclk", "mout_fimc2_lclk", DIV_CAM,
-		8, 4),
-	DIV(CLK_DIV_FIMC1_LCLK, "div_fimc1_lclk", "mout_fimc1_lclk", DIV_CAM,
-		4, 4),
-	DIV(CLK_DIV_FIMC0_LCLK, "div_fimc0_lclk", "mout_fimc0_lclk", DIV_CAM,
-		0, 4),
-
-	/* DIV_TV */
-	DIV(CLK_DIV_TV_BLK, "div_tv_blk", "mout_g3d_pll", DIV_TV, 0, 4),
-
-	/* DIV_MFC */
-	DIV(CLK_DIV_MFC, "div_mfc", "mout_mfc", DIV_MFC, 0, 4),
-
-	/* DIV_G3D */
-	DIV(CLK_DIV_G3D, "div_g3d", "mout_g3d", DIV_G3D, 0, 4),
-
-	/* DIV_LCD */
-	DIV_F(CLK_DIV_MIPI0_PRE, "div_mipi0_pre", "div_mipi0", DIV_LCD, 20, 4,
-		CLK_SET_RATE_PARENT, 0),
-	DIV(CLK_DIV_MIPI0, "div_mipi0", "mout_mipi0", DIV_LCD, 16, 4),
-	DIV(CLK_DIV_FIMD0, "div_fimd0", "mout_fimd0", DIV_LCD, 0, 4),
-
-	/* DIV_ISP */
-	DIV(CLK_DIV_UART_ISP, "div_uart_isp", "mout_uart_isp", DIV_ISP, 28, 4),
-	DIV_F(CLK_DIV_SPI1_ISP_PRE, "div_spi1_isp_pre", "div_spi1_isp",
-		DIV_ISP, 20, 8, CLK_SET_RATE_PARENT, 0),
-	DIV(CLK_DIV_SPI1_ISP, "div_spi1_isp", "mout_spi1_isp", DIV_ISP, 16, 4),
-	DIV_F(CLK_DIV_SPI0_ISP_PRE, "div_spi0_isp_pre", "div_spi0_isp",
-		DIV_ISP, 8, 8, CLK_SET_RATE_PARENT, 0),
-	DIV(CLK_DIV_SPI0_ISP, "div_spi0_isp", "mout_spi0_isp", DIV_ISP, 4, 4),
-	DIV(CLK_DIV_PWM_ISP, "div_pwm_isp", "mout_pwm_isp", DIV_ISP, 0, 4),
-
-	/* DIV_MAUDIO */
-	DIV(CLK_DIV_PCM0, "div_pcm0", "div_audio0", DIV_MAUDIO, 4, 8),
-	DIV(CLK_DIV_AUDIO0, "div_audio0", "mout_audio0", DIV_MAUDIO, 0, 4),
-
-	/* DIV_FSYS0 */
-	DIV_F(CLK_DIV_TSADC_PRE, "div_tsadc_pre", "div_tsadc", DIV_FSYS0, 8, 8,
-		CLK_SET_RATE_PARENT, 0),
-	DIV(CLK_DIV_TSADC, "div_tsadc", "mout_tsadc", DIV_FSYS0, 0, 4),
-
-	/* DIV_FSYS1 */
-	DIV_F(CLK_DIV_MMC1_PRE, "div_mmc1_pre", "div_mmc1", DIV_FSYS1, 24, 8,
-		CLK_SET_RATE_PARENT, 0),
-	DIV(CLK_DIV_MMC1, "div_mmc1", "mout_mmc1", DIV_FSYS1, 16, 4),
-	DIV_F(CLK_DIV_MMC0_PRE, "div_mmc0_pre", "div_mmc0", DIV_FSYS1, 8, 8,
-		CLK_SET_RATE_PARENT, 0),
-	DIV(CLK_DIV_MMC0, "div_mmc0", "mout_mmc0", DIV_FSYS1, 0, 4),
-
-	/* DIV_FSYS2 */
-	DIV_F(CLK_DIV_MMC2_PRE, "div_mmc2_pre", "div_mmc2", DIV_FSYS2, 8, 8,
-		CLK_SET_RATE_PARENT, 0),
-	DIV_F(CLK_DIV_MMC2_PRE, "div_mmc2", "mout_mmc2", DIV_FSYS2, 0, 4,
-		CLK_SET_RATE_PARENT, 0),
-
-	/* DIV_PERIL0 */
-	DIV(CLK_DIV_UART3, "div_uart3", "mout_uart3", DIV_PERIL0, 12, 4),
-	DIV(CLK_DIV_UART2, "div_uart2", "mout_uart2", DIV_PERIL0, 8, 4),
-	DIV(CLK_DIV_UART1, "div_uart1", "mout_uart1", DIV_PERIL0, 4, 4),
-	DIV(CLK_DIV_UART0, "div_uart0", "mout_uart0", DIV_PERIL0, 0, 4),
-
-	/* DIV_PERIL1 */
-	DIV_F(CLK_DIV_SPI1_PRE, "div_spi1_pre", "div_spi1", DIV_PERIL1, 24, 8,
-		CLK_SET_RATE_PARENT, 0),
-	DIV(CLK_DIV_SPI1, "div_spi1", "mout_spi1", DIV_PERIL1, 16, 4),
-	DIV_F(CLK_DIV_SPI0_PRE, "div_spi0_pre", "div_spi0", DIV_PERIL1, 8, 8,
-		CLK_SET_RATE_PARENT, 0),
-	DIV(CLK_DIV_SPI0, "div_spi0", "mout_spi0", DIV_PERIL1, 0, 4),
-
-	/* DIV_PERIL2 */
-	DIV_F(CLK_DIV_SPI2_PRE, "div_spi2_pre", "div_spi2", DIV_PERIL2, 8, 8,
-		CLK_SET_RATE_PARENT, 0),
-	DIV(CLK_DIV_SPI2, "div_spi2", "mout_spi2", DIV_PERIL2, 0, 4),
-
-	/* DIV_PERIL4 */
-	DIV(CLK_DIV_PCM2, "div_pcm2", "div_audio2", DIV_PERIL4, 20, 8),
-	DIV(CLK_DIV_AUDIO2, "div_audio2", "mout_audio2", DIV_PERIL4, 16, 4),
-	DIV(CLK_DIV_PCM1, "div_pcm1", "div_audio1", DIV_PERIL4, 20, 8),
-	DIV(CLK_DIV_AUDIO1, "div_audio1", "mout_audio1", DIV_PERIL4, 0, 4),
-
-	/* DIV_PERIL5 */
-	DIV(CLK_DIV_I2S1, "div_i2s1", "div_audio1", DIV_PERIL5, 0, 6),
-
-	/* DIV_CAM1 */
-	DIV(CLK_DIV_PXLASYNC_CSIS1_FIMC, "div_pxlasync_csis1_fimc",
-		"mout_pxlasync_csis1", DIV_CAM1, 24, 4),
-	DIV(CLK_DIV_PXLASYNC_CSIS0_FIMC, "div_pxlasync_csis0_fimc",
-		"mout_pxlasync_csis0", DIV_CAM1, 20, 4),
-	DIV(CLK_DIV_JPEG, "div_jpeg", "mout_jpeg", DIV_CAM1, 0, 4),
-
-	/* DIV_CPU0 */
-	DIV(CLK_DIV_CORE2, "div_core2", "div_core", DIV_CPU0, 28, 3),
-	DIV_F(CLK_DIV_APLL, "div_apll", "mout_apll", DIV_CPU0, 24, 3,
-			CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY),
-	DIV(CLK_DIV_PCLK_DBG, "div_pclk_dbg", "div_core2", DIV_CPU0, 20, 3),
-	DIV(CLK_DIV_ATB, "div_atb", "div_core2", DIV_CPU0, 16, 3),
-	DIV(CLK_DIV_PERIPH, "div_periph", "div_core2", DIV_CPU0, 12, 3),
-	DIV(CLK_DIV_COREM1, "div_corem1", "div_core2", DIV_CPU0, 8, 3),
-	DIV(CLK_DIV_COREM0, "div_corem0", "div_core2", DIV_CPU0, 4, 3),
-	DIV_F(CLK_DIV_CORE, "div_core", "mout_core", DIV_CPU0, 0, 3,
-		CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY),
-
-	/* DIV_CPU1 */
-	DIV(CLK_DIV_HPM, "div_hpm", "div_copy", DIV_CPU1, 4, 3),
-	DIV(CLK_DIV_COPY, "div_copy", "mout_hpm", DIV_CPU1, 0, 3),
-};
-
-static const struct samsung_gate_clock exynos4415_gate_clks[] __initconst = {
-	/*
-	 * NOTE: Following table is sorted by register address in ascending
-	 * order and then bitfield shift in descending order, as it is done
-	 * in the User's Manual. When adding new entries, please make sure
-	 * that the order is preserved, to avoid merge conflicts and make
-	 * further work with defined data easier.
-	 */
-
-	/* GATE_IP_LEFTBUS */
-	GATE(CLK_ASYNC_G3D, "async_g3d", "div_aclk_100", GATE_IP_LEFTBUS, 6,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_ASYNC_MFCL, "async_mfcl", "div_aclk_100", GATE_IP_LEFTBUS, 4,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_ASYNC_TVX, "async_tvx", "div_aclk_100", GATE_IP_LEFTBUS, 3,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_PPMULEFT, "ppmuleft", "div_aclk_100", GATE_IP_LEFTBUS, 1,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_GPIO_LEFT, "gpio_left", "div_aclk_100", GATE_IP_LEFTBUS, 0,
-		CLK_IGNORE_UNUSED, 0),
-
-	/* GATE_IP_IMAGE */
-	GATE(CLK_PPMUIMAGE, "ppmuimage", "div_aclk_100", GATE_IP_IMAGE,
-		9, 0, 0),
-	GATE(CLK_QEMDMA2, "qe_mdma2", "div_aclk_100", GATE_IP_IMAGE,
-		8, 0, 0),
-	GATE(CLK_QEROTATOR, "qe_rotator", "div_aclk_100", GATE_IP_IMAGE,
-		7, 0, 0),
-	GATE(CLK_SMMUMDMA2, "smmu_mdam2", "div_aclk_100", GATE_IP_IMAGE,
-		5, 0, 0),
-	GATE(CLK_SMMUROTATOR, "smmu_rotator", "div_aclk_100", GATE_IP_IMAGE,
-		4, 0, 0),
-	GATE(CLK_MDMA2, "mdma2", "div_aclk_100", GATE_IP_IMAGE, 2, 0, 0),
-	GATE(CLK_ROTATOR, "rotator", "div_aclk_100", GATE_IP_IMAGE, 1, 0, 0),
-
-	/* GATE_IP_RIGHTBUS */
-	GATE(CLK_ASYNC_ISPMX, "async_ispmx", "div_aclk_100",
-		GATE_IP_RIGHTBUS, 9, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_ASYNC_MAUDIOX, "async_maudiox", "div_aclk_100",
-		GATE_IP_RIGHTBUS, 7, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_ASYNC_MFCR, "async_mfcr", "div_aclk_100",
-		GATE_IP_RIGHTBUS, 6, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_ASYNC_FSYSD, "async_fsysd", "div_aclk_100",
-		GATE_IP_RIGHTBUS, 5, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_ASYNC_LCD0X, "async_lcd0x", "div_aclk_100",
-		GATE_IP_RIGHTBUS, 3, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_ASYNC_CAMX, "async_camx", "div_aclk_100",
-		GATE_IP_RIGHTBUS, 2, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_PPMURIGHT, "ppmuright", "div_aclk_100",
-		GATE_IP_RIGHTBUS, 1, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_GPIO_RIGHT, "gpio_right", "div_aclk_100",
-		GATE_IP_RIGHTBUS, 0, CLK_IGNORE_UNUSED, 0),
-
-	/* GATE_IP_PERIR */
-	GATE(CLK_ANTIRBK_APBIF, "antirbk_apbif", "div_aclk_100",
-		GATE_IP_PERIR, 24, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_EFUSE_WRITER_APBIF, "efuse_writer_apbif", "div_aclk_100",
-		GATE_IP_PERIR, 23, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_MONOCNT, "monocnt", "div_aclk_100", GATE_IP_PERIR, 22,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_TZPC6, "tzpc6", "div_aclk_100", GATE_IP_PERIR, 21,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_PROVISIONKEY1, "provisionkey1", "div_aclk_100",
-		GATE_IP_PERIR, 20, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_PROVISIONKEY0, "provisionkey0", "div_aclk_100",
-		GATE_IP_PERIR, 19, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_CMU_ISPPART, "cmu_isppart", "div_aclk_100", GATE_IP_PERIR, 18,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_TMU_APBIF, "tmu_apbif", "div_aclk_100",
-		GATE_IP_PERIR, 17, 0, 0),
-	GATE(CLK_KEYIF, "keyif", "div_aclk_100", GATE_IP_PERIR, 16, 0, 0),
-	GATE(CLK_RTC, "rtc", "div_aclk_100", GATE_IP_PERIR, 15, 0, 0),
-	GATE(CLK_WDT, "wdt", "div_aclk_100", GATE_IP_PERIR, 14, 0, 0),
-	GATE(CLK_MCT, "mct", "div_aclk_100", GATE_IP_PERIR, 13, 0, 0),
-	GATE(CLK_SECKEY, "seckey", "div_aclk_100", GATE_IP_PERIR, 12,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_HDMI_CEC, "hdmi_cec", "div_aclk_100", GATE_IP_PERIR, 11,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_TZPC5, "tzpc5", "div_aclk_100", GATE_IP_PERIR, 10,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_TZPC4, "tzpc4", "div_aclk_100", GATE_IP_PERIR, 9,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_TZPC3, "tzpc3", "div_aclk_100", GATE_IP_PERIR, 8,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_TZPC2, "tzpc2", "div_aclk_100", GATE_IP_PERIR, 7,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_TZPC1, "tzpc1", "div_aclk_100", GATE_IP_PERIR, 6,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_TZPC0, "tzpc0", "div_aclk_100", GATE_IP_PERIR, 5,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_CMU_COREPART, "cmu_corepart", "div_aclk_100", GATE_IP_PERIR, 4,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_CMU_TOPPART, "cmu_toppart", "div_aclk_100", GATE_IP_PERIR, 3,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_PMU_APBIF, "pmu_apbif", "div_aclk_100", GATE_IP_PERIR, 2,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_SYSREG, "sysreg", "div_aclk_100", GATE_IP_PERIR, 1,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_CHIP_ID, "chip_id", "div_aclk_100", GATE_IP_PERIR, 0,
-		CLK_IGNORE_UNUSED, 0),
-
-	/* GATE_SCLK_CAM - non-completed */
-	GATE(CLK_SCLK_PXLAYSNC_CSIS1_FIMC, "sclk_pxlasync_csis1_fimc",
-		"div_pxlasync_csis1_fimc", GATE_SCLK_CAM, 11,
-		CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_PXLAYSNC_CSIS0_FIMC, "sclk_pxlasync_csis0_fimc",
-		"div_pxlasync_csis0_fimc", GATE_SCLK_CAM,
-		10, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_JPEG, "sclk_jpeg", "div_jpeg",
-		GATE_SCLK_CAM, 8, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_CSIS1, "sclk_csis1", "div_csis1",
-		GATE_SCLK_CAM, 7, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_CSIS0, "sclk_csis0", "div_csis0",
-		GATE_SCLK_CAM, 6, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_CAM1, "sclk_cam1", "div_cam1",
-		GATE_SCLK_CAM, 5, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_FIMC3_LCLK, "sclk_fimc3_lclk", "div_fimc3_lclk",
-		GATE_SCLK_CAM, 3, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_FIMC2_LCLK, "sclk_fimc2_lclk", "div_fimc2_lclk",
-		GATE_SCLK_CAM, 2, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_FIMC1_LCLK, "sclk_fimc1_lclk", "div_fimc1_lclk",
-		GATE_SCLK_CAM, 1, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_FIMC0_LCLK, "sclk_fimc0_lclk", "div_fimc0_lclk",
-		GATE_SCLK_CAM, 0, CLK_SET_RATE_PARENT, 0),
-
-	/* GATE_SCLK_TV */
-	GATE(CLK_SCLK_PIXEL, "sclk_pixel", "div_tv_blk",
-		GATE_SCLK_TV, 3, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_HDMI, "sclk_hdmi", "mout_hdmi",
-		GATE_SCLK_TV, 2, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_MIXER, "sclk_mixer", "div_tv_blk",
-		GATE_SCLK_TV, 0, CLK_SET_RATE_PARENT, 0),
-
-	/* GATE_SCLK_MFC */
-	GATE(CLK_SCLK_MFC, "sclk_mfc", "div_mfc",
-		GATE_SCLK_MFC, 0, CLK_SET_RATE_PARENT, 0),
-
-	/* GATE_SCLK_G3D */
-	GATE(CLK_SCLK_G3D, "sclk_g3d", "div_g3d",
-		GATE_SCLK_G3D, 0, CLK_SET_RATE_PARENT, 0),
-
-	/* GATE_SCLK_LCD */
-	GATE(CLK_SCLK_MIPIDPHY4L, "sclk_mipidphy4l", "div_mipi0",
-		GATE_SCLK_LCD, 4, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_MIPI0, "sclk_mipi0", "div_mipi0_pre",
-		GATE_SCLK_LCD, 3, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_MDNIE0, "sclk_mdnie0", "div_fimd0",
-		GATE_SCLK_LCD, 1, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_FIMD0, "sclk_fimd0", "div_fimd0",
-		GATE_SCLK_LCD, 0, CLK_SET_RATE_PARENT, 0),
-
-	/* GATE_SCLK_MAUDIO */
-	GATE(CLK_SCLK_PCM0, "sclk_pcm0", "div_pcm0",
-		GATE_SCLK_MAUDIO, 1, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_AUDIO0, "sclk_audio0", "div_audio0",
-		GATE_SCLK_MAUDIO, 0, CLK_SET_RATE_PARENT, 0),
-
-	/* GATE_SCLK_FSYS */
-	GATE(CLK_SCLK_TSADC, "sclk_tsadc", "div_tsadc_pre",
-		GATE_SCLK_FSYS, 9, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_EBI, "sclk_ebi", "div_ebi",
-		GATE_SCLK_FSYS, 6, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_MMC2, "sclk_mmc2", "div_mmc2_pre",
-		GATE_SCLK_FSYS, 2, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_MMC1, "sclk_mmc1", "div_mmc1_pre",
-		GATE_SCLK_FSYS, 1, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_MMC0, "sclk_mmc0", "div_mmc0_pre",
-		GATE_SCLK_FSYS, 0, CLK_SET_RATE_PARENT, 0),
-
-	/* GATE_SCLK_PERIL */
-	GATE(CLK_SCLK_I2S, "sclk_i2s1", "div_i2s1",
-		GATE_SCLK_PERIL, 18, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_PCM2, "sclk_pcm2", "div_pcm2",
-		GATE_SCLK_PERIL, 16, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_PCM1, "sclk_pcm1", "div_pcm1",
-		GATE_SCLK_PERIL, 15, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_AUDIO2, "sclk_audio2", "div_audio2",
-		GATE_SCLK_PERIL, 14, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_AUDIO1, "sclk_audio1", "div_audio1",
-		GATE_SCLK_PERIL, 13, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_SPDIF, "sclk_spdif", "mout_spdif",
-		GATE_SCLK_PERIL, 10, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_SPI2, "sclk_spi2", "div_spi2_pre",
-		GATE_SCLK_PERIL, 8, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_SPI1, "sclk_spi1", "div_spi1_pre",
-		GATE_SCLK_PERIL, 7, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_SPI0, "sclk_spi0", "div_spi0_pre",
-		GATE_SCLK_PERIL, 6, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_UART3, "sclk_uart3", "div_uart3",
-		GATE_SCLK_PERIL, 3, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_UART2, "sclk_uart2", "div_uart2",
-		GATE_SCLK_PERIL, 2, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_UART1, "sclk_uart1", "div_uart1",
-		GATE_SCLK_PERIL, 1, CLK_SET_RATE_PARENT, 0),
-	GATE(CLK_SCLK_UART0, "sclk_uart0", "div_uart0",
-		GATE_SCLK_PERIL, 0, CLK_SET_RATE_PARENT, 0),
-
-	/* GATE_IP_CAM */
-	GATE(CLK_SMMUFIMC_LITE2, "smmufimc_lite2", "div_aclk_160", GATE_IP_CAM,
-		22, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_FIMC_LITE2, "fimc_lite2", "div_aclk_160", GATE_IP_CAM,
-		20, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_PIXELASYNCM1, "pixelasyncm1", "div_aclk_160", GATE_IP_CAM,
-		18, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_PIXELASYNCM0, "pixelasyncm0", "div_aclk_160", GATE_IP_CAM,
-		17, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_PPMUCAMIF, "ppmucamif", "div_aclk_160", GATE_IP_CAM,
-		16, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_SMMUJPEG, "smmujpeg", "div_aclk_160", GATE_IP_CAM, 11, 0, 0),
-	GATE(CLK_SMMUFIMC3, "smmufimc3", "div_aclk_160", GATE_IP_CAM, 10, 0, 0),
-	GATE(CLK_SMMUFIMC2, "smmufimc2", "div_aclk_160", GATE_IP_CAM, 9, 0, 0),
-	GATE(CLK_SMMUFIMC1, "smmufimc1", "div_aclk_160", GATE_IP_CAM, 8, 0, 0),
-	GATE(CLK_SMMUFIMC0, "smmufimc0", "div_aclk_160", GATE_IP_CAM, 7, 0, 0),
-	GATE(CLK_JPEG, "jpeg", "div_aclk_160", GATE_IP_CAM, 6, 0, 0),
-	GATE(CLK_CSIS1, "csis1", "div_aclk_160", GATE_IP_CAM, 5, 0, 0),
-	GATE(CLK_CSIS0, "csis0", "div_aclk_160", GATE_IP_CAM, 4, 0, 0),
-	GATE(CLK_FIMC3, "fimc3", "div_aclk_160", GATE_IP_CAM, 3, 0, 0),
-	GATE(CLK_FIMC2, "fimc2", "div_aclk_160", GATE_IP_CAM, 2, 0, 0),
-	GATE(CLK_FIMC1, "fimc1", "div_aclk_160", GATE_IP_CAM, 1, 0, 0),
-	GATE(CLK_FIMC0, "fimc0", "div_aclk_160", GATE_IP_CAM, 0, 0, 0),
-
-	/* GATE_IP_TV */
-	GATE(CLK_PPMUTV, "ppmutv", "div_aclk_100", GATE_IP_TV, 5, 0, 0),
-	GATE(CLK_SMMUTV, "smmutv", "div_aclk_100", GATE_IP_TV, 4, 0, 0),
-	GATE(CLK_HDMI, "hdmi", "div_aclk_100", GATE_IP_TV, 3, 0, 0),
-	GATE(CLK_MIXER, "mixer", "div_aclk_100", GATE_IP_TV, 1, 0, 0),
-	GATE(CLK_VP, "vp", "div_aclk_100", GATE_IP_TV, 0, 0, 0),
-
-	/* GATE_IP_MFC */
-	GATE(CLK_PPMUMFC_R, "ppmumfc_r", "div_aclk_200", GATE_IP_MFC, 4,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_PPMUMFC_L, "ppmumfc_l", "div_aclk_200", GATE_IP_MFC, 3,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_SMMUMFC_R, "smmumfc_r", "div_aclk_200", GATE_IP_MFC, 2, 0, 0),
-	GATE(CLK_SMMUMFC_L, "smmumfc_l", "div_aclk_200", GATE_IP_MFC, 1, 0, 0),
-	GATE(CLK_MFC, "mfc", "div_aclk_200", GATE_IP_MFC, 0, 0, 0),
-
-	/* GATE_IP_G3D */
-	GATE(CLK_PPMUG3D, "ppmug3d", "div_aclk_200", GATE_IP_G3D, 1,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_G3D, "g3d", "div_aclk_200", GATE_IP_G3D, 0, 0, 0),
-
-	/* GATE_IP_LCD */
-	GATE(CLK_PPMULCD0, "ppmulcd0", "div_aclk_160", GATE_IP_LCD, 5,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_SMMUFIMD0, "smmufimd0", "div_aclk_160", GATE_IP_LCD, 4, 0, 0),
-	GATE(CLK_DSIM0, "dsim0", "div_aclk_160", GATE_IP_LCD, 3, 0, 0),
-	GATE(CLK_SMIES, "smies", "div_aclk_160", GATE_IP_LCD, 2, 0, 0),
-	GATE(CLK_MIE0, "mie0", "div_aclk_160", GATE_IP_LCD, 1, 0, 0),
-	GATE(CLK_FIMD0, "fimd0", "div_aclk_160", GATE_IP_LCD, 0, 0, 0),
-
-	/* GATE_IP_FSYS */
-	GATE(CLK_TSADC, "tsadc", "div_aclk_200", GATE_IP_FSYS, 20, 0, 0),
-	GATE(CLK_PPMUFILE, "ppmufile", "div_aclk_200", GATE_IP_FSYS, 17,
-		CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_NFCON, "nfcon", "div_aclk_200", GATE_IP_FSYS, 16, 0, 0),
-	GATE(CLK_USBDEVICE, "usbdevice", "div_aclk_200", GATE_IP_FSYS, 13,
-		0, 0),
-	GATE(CLK_USBHOST, "usbhost", "div_aclk_200", GATE_IP_FSYS, 12, 0, 0),
-	GATE(CLK_SROMC, "sromc", "div_aclk_200", GATE_IP_FSYS, 11, 0, 0),
-	GATE(CLK_SDMMC2, "sdmmc2", "div_aclk_200", GATE_IP_FSYS, 7, 0, 0),
-	GATE(CLK_SDMMC1, "sdmmc1", "div_aclk_200", GATE_IP_FSYS, 6, 0, 0),
-	GATE(CLK_SDMMC0, "sdmmc0", "div_aclk_200", GATE_IP_FSYS, 5, 0, 0),
-	GATE(CLK_PDMA1, "pdma1", "div_aclk_200", GATE_IP_FSYS, 1, 0, 0),
-	GATE(CLK_PDMA0, "pdma0", "div_aclk_200", GATE_IP_FSYS, 0, 0, 0),
-
-	/* GATE_IP_PERIL */
-	GATE(CLK_SPDIF, "spdif", "div_aclk_100", GATE_IP_PERIL, 26, 0, 0),
-	GATE(CLK_PWM, "pwm", "div_aclk_100", GATE_IP_PERIL, 24, 0, 0),
-	GATE(CLK_PCM2, "pcm2", "div_aclk_100", GATE_IP_PERIL, 23, 0, 0),
-	GATE(CLK_PCM1, "pcm1", "div_aclk_100", GATE_IP_PERIL, 22, 0, 0),
-	GATE(CLK_I2S1, "i2s1", "div_aclk_100", GATE_IP_PERIL, 20, 0, 0),
-	GATE(CLK_SPI2, "spi2", "div_aclk_100", GATE_IP_PERIL, 18, 0, 0),
-	GATE(CLK_SPI1, "spi1", "div_aclk_100", GATE_IP_PERIL, 17, 0, 0),
-	GATE(CLK_SPI0, "spi0", "div_aclk_100", GATE_IP_PERIL, 16, 0, 0),
-	GATE(CLK_I2CHDMI, "i2chdmi", "div_aclk_100", GATE_IP_PERIL, 14, 0, 0),
-	GATE(CLK_I2C7, "i2c7", "div_aclk_100", GATE_IP_PERIL, 13, 0, 0),
-	GATE(CLK_I2C6, "i2c6", "div_aclk_100", GATE_IP_PERIL, 12, 0, 0),
-	GATE(CLK_I2C5, "i2c5", "div_aclk_100", GATE_IP_PERIL, 11, 0, 0),
-	GATE(CLK_I2C4, "i2c4", "div_aclk_100", GATE_IP_PERIL, 10, 0, 0),
-	GATE(CLK_I2C3, "i2c3", "div_aclk_100", GATE_IP_PERIL, 9, 0, 0),
-	GATE(CLK_I2C2, "i2c2", "div_aclk_100", GATE_IP_PERIL, 8, 0, 0),
-	GATE(CLK_I2C1, "i2c1", "div_aclk_100", GATE_IP_PERIL, 7, 0, 0),
-	GATE(CLK_I2C0, "i2c0", "div_aclk_100", GATE_IP_PERIL, 6, 0, 0),
-	GATE(CLK_UART3, "uart3", "div_aclk_100", GATE_IP_PERIL, 3, 0, 0),
-	GATE(CLK_UART2, "uart2", "div_aclk_100", GATE_IP_PERIL, 2, 0, 0),
-	GATE(CLK_UART1, "uart1", "div_aclk_100", GATE_IP_PERIL, 1, 0, 0),
-	GATE(CLK_UART0, "uart0", "div_aclk_100", GATE_IP_PERIL, 0, 0, 0),
-};
-
-/*
- * APLL & MPLL & BPLL & ISP_PLL & DISP_PLL & G3D_PLL
- */
-static const struct samsung_pll_rate_table exynos4415_pll_rates[] __initconst = {
-	PLL_35XX_RATE(1600000000, 400, 3,  1),
-	PLL_35XX_RATE(1500000000, 250, 2,  1),
-	PLL_35XX_RATE(1400000000, 175, 3,  0),
-	PLL_35XX_RATE(1300000000, 325, 3,  1),
-	PLL_35XX_RATE(1200000000, 400, 4,  1),
-	PLL_35XX_RATE(1100000000, 275, 3,  1),
-	PLL_35XX_RATE(1066000000, 533, 6,  1),
-	PLL_35XX_RATE(1000000000, 250, 3,  1),
-	PLL_35XX_RATE(960000000,  320, 4,  1),
-	PLL_35XX_RATE(900000000,  300, 4,  1),
-	PLL_35XX_RATE(850000000,  425, 6,  1),
-	PLL_35XX_RATE(800000000,  200, 3,  1),
-	PLL_35XX_RATE(700000000,  175, 3,  1),
-	PLL_35XX_RATE(667000000,  667, 12, 1),
-	PLL_35XX_RATE(600000000,  400, 4,  2),
-	PLL_35XX_RATE(550000000,  275, 3,  2),
-	PLL_35XX_RATE(533000000,  533, 6,  2),
-	PLL_35XX_RATE(520000000,  260, 3,  2),
-	PLL_35XX_RATE(500000000,  250, 3,  2),
-	PLL_35XX_RATE(440000000,  220, 3,  2),
-	PLL_35XX_RATE(400000000,  200, 3,  2),
-	PLL_35XX_RATE(350000000,  175, 3,  2),
-	PLL_35XX_RATE(300000000,  300, 3,  3),
-	PLL_35XX_RATE(266000000,  266, 3,  3),
-	PLL_35XX_RATE(200000000,  200, 3,  3),
-	PLL_35XX_RATE(160000000,  160, 3,  3),
-	PLL_35XX_RATE(100000000,  200, 3,  4),
-	{ /* sentinel */ }
-};
-
-/* EPLL */
-static const struct samsung_pll_rate_table exynos4415_epll_rates[] __initconst = {
-	PLL_36XX_RATE(800000000, 200, 3, 1,     0),
-	PLL_36XX_RATE(288000000,  96, 2, 2,     0),
-	PLL_36XX_RATE(192000000, 128, 2, 3,     0),
-	PLL_36XX_RATE(144000000,  96, 2, 3,     0),
-	PLL_36XX_RATE(96000000,  128, 2, 4,     0),
-	PLL_36XX_RATE(84000000,  112, 2, 4,     0),
-	PLL_36XX_RATE(80750011,  107, 2, 4, 43691),
-	PLL_36XX_RATE(73728004,   98, 2, 4, 19923),
-	PLL_36XX_RATE(67987602,  271, 3, 5, 62285),
-	PLL_36XX_RATE(65911004,  175, 2, 5, 49982),
-	PLL_36XX_RATE(50000000,  200, 3, 5,     0),
-	PLL_36XX_RATE(49152003,  131, 2, 5,  4719),
-	PLL_36XX_RATE(48000000,  128, 2, 5,     0),
-	PLL_36XX_RATE(45250000,  181, 3, 5,     0),
-	{ /* sentinel */ }
-};
-
-static const struct samsung_pll_clock exynos4415_plls[] __initconst = {
-	PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
-		APLL_LOCK, APLL_CON0, exynos4415_pll_rates),
-	PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
-		EPLL_LOCK, EPLL_CON0, exynos4415_epll_rates),
-	PLL(pll_35xx, CLK_FOUT_G3D_PLL, "fout_g3d_pll", "mout_g3d_pllsrc",
-		G3D_PLL_LOCK, G3D_PLL_CON0, exynos4415_pll_rates),
-	PLL(pll_35xx, CLK_FOUT_ISP_PLL, "fout_isp_pll", "fin_pll",
-		ISP_PLL_LOCK, ISP_PLL_CON0, exynos4415_pll_rates),
-	PLL(pll_35xx, CLK_FOUT_DISP_PLL, "fout_disp_pll",
-		"fin_pll", DISP_PLL_LOCK, DISP_PLL_CON0, exynos4415_pll_rates),
-};
-
-static const struct samsung_cmu_info cmu_info __initconst = {
-	.pll_clks		= exynos4415_plls,
-	.nr_pll_clks		= ARRAY_SIZE(exynos4415_plls),
-	.mux_clks		= exynos4415_mux_clks,
-	.nr_mux_clks		= ARRAY_SIZE(exynos4415_mux_clks),
-	.div_clks		= exynos4415_div_clks,
-	.nr_div_clks		= ARRAY_SIZE(exynos4415_div_clks),
-	.gate_clks		= exynos4415_gate_clks,
-	.nr_gate_clks		= ARRAY_SIZE(exynos4415_gate_clks),
-	.fixed_clks		= exynos4415_fixed_rate_clks,
-	.nr_fixed_clks		= ARRAY_SIZE(exynos4415_fixed_rate_clks),
-	.fixed_factor_clks	= exynos4415_fixed_factor_clks,
-	.nr_fixed_factor_clks	= ARRAY_SIZE(exynos4415_fixed_factor_clks),
-	.nr_clk_ids		= CLK_NR_CLKS,
-	.clk_regs		= exynos4415_cmu_clk_regs,
-	.nr_clk_regs		= ARRAY_SIZE(exynos4415_cmu_clk_regs),
-};
-
-static void __init exynos4415_cmu_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &cmu_info);
-}
-CLK_OF_DECLARE(exynos4415_cmu, "samsung,exynos4415-cmu", exynos4415_cmu_init);
-
-/*
- * CMU DMC
- */
-
-#define MPLL_LOCK		0x008
-#define MPLL_CON0		0x108
-#define MPLL_CON1		0x10c
-#define MPLL_CON2		0x110
-#define BPLL_LOCK		0x118
-#define BPLL_CON0		0x218
-#define BPLL_CON1		0x21c
-#define BPLL_CON2		0x220
-#define SRC_DMC			0x300
-#define DIV_DMC1		0x504
-
-static const unsigned long exynos4415_cmu_dmc_clk_regs[] __initconst = {
-	MPLL_LOCK,
-	MPLL_CON0,
-	MPLL_CON1,
-	MPLL_CON2,
-	BPLL_LOCK,
-	BPLL_CON0,
-	BPLL_CON1,
-	BPLL_CON2,
-	SRC_DMC,
-	DIV_DMC1,
-};
-
-PNAME(mout_mpll_p)		= { "fin_pll", "fout_mpll", };
-PNAME(mout_bpll_p)		= { "fin_pll", "fout_bpll", };
-PNAME(mbpll_p)			= { "mout_mpll", "mout_bpll", };
-
-static const struct samsung_mux_clock exynos4415_dmc_mux_clks[] __initconst = {
-	MUX(CLK_DMC_MOUT_MPLL, "mout_mpll", mout_mpll_p, SRC_DMC, 12, 1),
-	MUX(CLK_DMC_MOUT_BPLL, "mout_bpll", mout_bpll_p, SRC_DMC, 10, 1),
-	MUX(CLK_DMC_MOUT_DPHY, "mout_dphy", mbpll_p, SRC_DMC, 8, 1),
-	MUX(CLK_DMC_MOUT_DMC_BUS, "mout_dmc_bus", mbpll_p, SRC_DMC, 4, 1),
-};
-
-static const struct samsung_div_clock exynos4415_dmc_div_clks[] __initconst = {
-	DIV(CLK_DMC_DIV_DMC, "div_dmc", "div_dmc_pre", DIV_DMC1, 27, 3),
-	DIV(CLK_DMC_DIV_DPHY, "div_dphy", "mout_dphy", DIV_DMC1, 23, 3),
-	DIV(CLK_DMC_DIV_DMC_PRE, "div_dmc_pre", "mout_dmc_bus",
-		DIV_DMC1, 19, 2),
-	DIV(CLK_DMC_DIV_DMCP, "div_dmcp", "div_dmcd", DIV_DMC1, 15, 3),
-	DIV(CLK_DMC_DIV_DMCD, "div_dmcd", "div_dmc", DIV_DMC1, 11, 3),
-	DIV(CLK_DMC_DIV_MPLL_PRE, "div_mpll_pre", "mout_mpll", DIV_DMC1, 8, 2),
-};
-
-static const struct samsung_pll_clock exynos4415_dmc_plls[] __initconst = {
-	PLL(pll_35xx, CLK_DMC_FOUT_MPLL, "fout_mpll", "fin_pll",
-		MPLL_LOCK, MPLL_CON0, exynos4415_pll_rates),
-	PLL(pll_35xx, CLK_DMC_FOUT_BPLL, "fout_bpll", "fin_pll",
-		BPLL_LOCK, BPLL_CON0, exynos4415_pll_rates),
-};
-
-static const struct samsung_cmu_info cmu_dmc_info __initconst = {
-	.pll_clks		= exynos4415_dmc_plls,
-	.nr_pll_clks		= ARRAY_SIZE(exynos4415_dmc_plls),
-	.mux_clks		= exynos4415_dmc_mux_clks,
-	.nr_mux_clks		= ARRAY_SIZE(exynos4415_dmc_mux_clks),
-	.div_clks		= exynos4415_dmc_div_clks,
-	.nr_div_clks		= ARRAY_SIZE(exynos4415_dmc_div_clks),
-	.nr_clk_ids		= NR_CLKS_DMC,
-	.clk_regs		= exynos4415_cmu_dmc_clk_regs,
-	.nr_clk_regs		= ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs),
-};
-
-static void __init exynos4415_cmu_dmc_init(struct device_node *np)
-{
-	samsung_cmu_register_one(np, &cmu_dmc_info);
-}
-CLK_OF_DECLARE(exynos4415_cmu_dmc, "samsung,exynos4415-cmu-dmc",
-		exynos4415_cmu_dmc_init);
diff --git a/include/dt-bindings/clock/exynos4415.h b/include/dt-bindings/clock/exynos4415.h
deleted file mode 100644
index 7eed55100721..000000000000
--- a/include/dt-bindings/clock/exynos4415.h
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- * Author: Chanwoo Choi <cw00.choi@samsung.com>
- *
- * 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.
- *
- * Device Tree binding constants for Samsung Exynos4415 clock controllers.
- */
-
-#ifndef _DT_BINDINGS_CLOCK_SAMSUNG_EXYNOS4415_CLOCK_H
-#define _DT_BINDINGS_CLOCK_SAMSUNG_EXYNOS4415_CLOCK_H
-
-/*
- * Let each exported clock get a unique index, which is used on DT-enabled
- * platforms to lookup the clock from a clock specifier. These indices are
- * therefore considered an ABI and so must not be changed. This implies
- * that new clocks should be added either in free spaces between clock groups
- * or at the end.
- */
-
-/*
- * Main CMU
- */
-
-#define CLK_OSCSEL			1
-#define CLK_FIN_PLL			2
-#define CLK_FOUT_APLL			3
-#define CLK_FOUT_MPLL			4
-#define CLK_FOUT_EPLL			5
-#define CLK_FOUT_G3D_PLL		6
-#define CLK_FOUT_ISP_PLL		7
-#define CLK_FOUT_DISP_PLL		8
-
-/* Muxes */
-#define CLK_MOUT_MPLL_USER_L		16
-#define CLK_MOUT_GDL			17
-#define CLK_MOUT_MPLL_USER_R		18
-#define CLK_MOUT_GDR			19
-#define CLK_MOUT_EBI			20
-#define CLK_MOUT_ACLK_200		21
-#define CLK_MOUT_ACLK_160		22
-#define CLK_MOUT_ACLK_100		23
-#define CLK_MOUT_ACLK_266		24
-#define CLK_MOUT_G3D_PLL		25
-#define CLK_MOUT_EPLL			26
-#define CLK_MOUT_EBI_1			27
-#define CLK_MOUT_ISP_PLL		28
-#define CLK_MOUT_DISP_PLL		29
-#define CLK_MOUT_MPLL_USER_T		30
-#define CLK_MOUT_ACLK_400_MCUISP	31
-#define CLK_MOUT_G3D_PLLSRC		32
-#define CLK_MOUT_CSIS1			33
-#define CLK_MOUT_CSIS0			34
-#define CLK_MOUT_CAM1			35
-#define CLK_MOUT_FIMC3_LCLK		36
-#define CLK_MOUT_FIMC2_LCLK		37
-#define CLK_MOUT_FIMC1_LCLK		38
-#define CLK_MOUT_FIMC0_LCLK		39
-#define CLK_MOUT_MFC			40
-#define CLK_MOUT_MFC_1			41
-#define CLK_MOUT_MFC_0			42
-#define CLK_MOUT_G3D			43
-#define CLK_MOUT_G3D_1			44
-#define CLK_MOUT_G3D_0			45
-#define CLK_MOUT_MIPI0			46
-#define CLK_MOUT_FIMD0			47
-#define CLK_MOUT_TSADC_ISP		48
-#define CLK_MOUT_UART_ISP		49
-#define CLK_MOUT_SPI1_ISP		50
-#define CLK_MOUT_SPI0_ISP		51
-#define CLK_MOUT_PWM_ISP		52
-#define CLK_MOUT_AUDIO0			53
-#define CLK_MOUT_TSADC			54
-#define CLK_MOUT_MMC2			55
-#define CLK_MOUT_MMC1			56
-#define CLK_MOUT_MMC0			57
-#define CLK_MOUT_UART3			58
-#define CLK_MOUT_UART2			59
-#define CLK_MOUT_UART1			60
-#define CLK_MOUT_UART0			61
-#define CLK_MOUT_SPI2			62
-#define CLK_MOUT_SPI1			63
-#define CLK_MOUT_SPI0			64
-#define CLK_MOUT_SPDIF			65
-#define CLK_MOUT_AUDIO2			66
-#define CLK_MOUT_AUDIO1			67
-#define CLK_MOUT_MPLL_USER_C		68
-#define CLK_MOUT_HPM			69
-#define CLK_MOUT_CORE			70
-#define CLK_MOUT_APLL			71
-#define CLK_MOUT_PXLASYNC_CSIS1_FIMC	72
-#define CLK_MOUT_PXLASYNC_CSIS0_FIMC	73
-#define CLK_MOUT_JPEG			74
-#define CLK_MOUT_JPEG1			75
-#define CLK_MOUT_JPEG0			76
-#define CLK_MOUT_ACLK_ISP0_300		77
-#define CLK_MOUT_ACLK_ISP0_400		78
-#define CLK_MOUT_ACLK_ISP0_300_USER	79
-#define CLK_MOUT_ACLK_ISP1_300		80
-#define CLK_MOUT_ACLK_ISP1_300_USER	81
-#define CLK_MOUT_HDMI			82
-
-/* Dividers */
-#define CLK_DIV_GPL			90
-#define CLK_DIV_GDL			91
-#define CLK_DIV_GPR			92
-#define CLK_DIV_GDR			93
-#define CLK_DIV_ACLK_400_MCUISP		94
-#define CLK_DIV_EBI			95
-#define CLK_DIV_ACLK_200		96
-#define CLK_DIV_ACLK_160		97
-#define CLK_DIV_ACLK_100		98
-#define CLK_DIV_ACLK_266		99
-#define CLK_DIV_CSIS1			100
-#define CLK_DIV_CSIS0			101
-#define CLK_DIV_CAM1			102
-#define CLK_DIV_FIMC3_LCLK		103
-#define CLK_DIV_FIMC2_LCLK		104
-#define CLK_DIV_FIMC1_LCLK		105
-#define CLK_DIV_FIMC0_LCLK		106
-#define CLK_DIV_TV_BLK			107
-#define CLK_DIV_MFC			108
-#define CLK_DIV_G3D			109
-#define CLK_DIV_MIPI0_PRE		110
-#define CLK_DIV_MIPI0			111
-#define CLK_DIV_FIMD0			112
-#define CLK_DIV_UART_ISP		113
-#define CLK_DIV_SPI1_ISP_PRE		114
-#define CLK_DIV_SPI1_ISP		115
-#define CLK_DIV_SPI0_ISP_PRE		116
-#define CLK_DIV_SPI0_ISP		117
-#define CLK_DIV_PWM_ISP			118
-#define CLK_DIV_PCM0			119
-#define CLK_DIV_AUDIO0			120
-#define CLK_DIV_TSADC_PRE		121
-#define CLK_DIV_TSADC			122
-#define CLK_DIV_MMC1_PRE		123
-#define CLK_DIV_MMC1			124
-#define CLK_DIV_MMC0_PRE		125
-#define CLK_DIV_MMC0			126
-#define CLK_DIV_MMC2_PRE		127
-#define CLK_DIV_MMC2			128
-#define CLK_DIV_UART3			129
-#define CLK_DIV_UART2			130
-#define CLK_DIV_UART1			131
-#define CLK_DIV_UART0			132
-#define CLK_DIV_SPI1_PRE		133
-#define CLK_DIV_SPI1			134
-#define CLK_DIV_SPI0_PRE		135
-#define CLK_DIV_SPI0			136
-#define CLK_DIV_SPI2_PRE		137
-#define CLK_DIV_SPI2			138
-#define CLK_DIV_PCM2			139
-#define CLK_DIV_AUDIO2			140
-#define CLK_DIV_PCM1			141
-#define CLK_DIV_AUDIO1			142
-#define CLK_DIV_I2S1			143
-#define CLK_DIV_PXLASYNC_CSIS1_FIMC	144
-#define CLK_DIV_PXLASYNC_CSIS0_FIMC	145
-#define CLK_DIV_JPEG			146
-#define CLK_DIV_CORE2			147
-#define CLK_DIV_APLL			148
-#define CLK_DIV_PCLK_DBG		149
-#define CLK_DIV_ATB			150
-#define CLK_DIV_PERIPH			151
-#define CLK_DIV_COREM1			152
-#define CLK_DIV_COREM0			153
-#define CLK_DIV_CORE			154
-#define CLK_DIV_HPM			155
-#define CLK_DIV_COPY			156
-
-/* Gates */
-#define CLK_ASYNC_G3D			180
-#define CLK_ASYNC_MFCL			181
-#define CLK_ASYNC_TVX			182
-#define CLK_PPMULEFT			183
-#define CLK_GPIO_LEFT			184
-#define CLK_PPMUIMAGE			185
-#define CLK_QEMDMA2			186
-#define CLK_QEROTATOR			187
-#define CLK_SMMUMDMA2			188
-#define CLK_SMMUROTATOR			189
-#define CLK_MDMA2			190
-#define CLK_ROTATOR			191
-#define CLK_ASYNC_ISPMX			192
-#define CLK_ASYNC_MAUDIOX		193
-#define CLK_ASYNC_MFCR			194
-#define CLK_ASYNC_FSYSD			195
-#define CLK_ASYNC_LCD0X			196
-#define CLK_ASYNC_CAMX			197
-#define CLK_PPMURIGHT			198
-#define CLK_GPIO_RIGHT			199
-#define CLK_ANTIRBK_APBIF		200
-#define CLK_EFUSE_WRITER_APBIF		201
-#define CLK_MONOCNT			202
-#define CLK_TZPC6			203
-#define CLK_PROVISIONKEY1		204
-#define CLK_PROVISIONKEY0		205
-#define CLK_CMU_ISPPART			206
-#define CLK_TMU_APBIF			207
-#define CLK_KEYIF			208
-#define CLK_RTC				209
-#define CLK_WDT				210
-#define CLK_MCT				211
-#define CLK_SECKEY			212
-#define CLK_HDMI_CEC			213
-#define CLK_TZPC5			214
-#define CLK_TZPC4			215
-#define CLK_TZPC3			216
-#define CLK_TZPC2			217
-#define CLK_TZPC1			218
-#define CLK_TZPC0			219
-#define CLK_CMU_COREPART		220
-#define CLK_CMU_TOPPART			221
-#define CLK_PMU_APBIF			222
-#define CLK_SYSREG			223
-#define CLK_CHIP_ID			224
-#define CLK_SMMUFIMC_LITE2		225
-#define CLK_FIMC_LITE2			226
-#define CLK_PIXELASYNCM1		227
-#define CLK_PIXELASYNCM0		228
-#define CLK_PPMUCAMIF			229
-#define CLK_SMMUJPEG			230
-#define CLK_SMMUFIMC3			231
-#define CLK_SMMUFIMC2			232
-#define CLK_SMMUFIMC1			233
-#define CLK_SMMUFIMC0			234
-#define CLK_JPEG			235
-#define CLK_CSIS1			236
-#define CLK_CSIS0			237
-#define CLK_FIMC3			238
-#define CLK_FIMC2			239
-#define CLK_FIMC1			240
-#define CLK_FIMC0			241
-#define CLK_PPMUTV			242
-#define CLK_SMMUTV			243
-#define CLK_HDMI			244
-#define CLK_MIXER			245
-#define CLK_VP				246
-#define CLK_PPMUMFC_R			247
-#define CLK_PPMUMFC_L			248
-#define CLK_SMMUMFC_R			249
-#define CLK_SMMUMFC_L			250
-#define CLK_MFC				251
-#define CLK_PPMUG3D			252
-#define CLK_G3D				253
-#define CLK_PPMULCD0			254
-#define CLK_SMMUFIMD0			255
-#define CLK_DSIM0			256
-#define CLK_SMIES			257
-#define CLK_MIE0			258
-#define CLK_FIMD0			259
-#define CLK_TSADC			260
-#define CLK_PPMUFILE			261
-#define CLK_NFCON			262
-#define CLK_USBDEVICE			263
-#define CLK_USBHOST			264
-#define CLK_SROMC			265
-#define CLK_SDMMC2			266
-#define CLK_SDMMC1			267
-#define CLK_SDMMC0			268
-#define CLK_PDMA1			269
-#define CLK_PDMA0			270
-#define CLK_SPDIF			271
-#define CLK_PWM				272
-#define CLK_PCM2			273
-#define CLK_PCM1			274
-#define CLK_I2S1			275
-#define CLK_SPI2			276
-#define CLK_SPI1			277
-#define CLK_SPI0			278
-#define CLK_I2CHDMI			279
-#define CLK_I2C7			280
-#define CLK_I2C6			281
-#define CLK_I2C5			282
-#define CLK_I2C4			283
-#define CLK_I2C3			284
-#define CLK_I2C2			285
-#define CLK_I2C1			286
-#define CLK_I2C0			287
-#define CLK_UART3			288
-#define CLK_UART2			289
-#define CLK_UART1			290
-#define CLK_UART0			291
-
-/* Special clocks */
-#define CLK_SCLK_PXLAYSNC_CSIS1_FIMC	330
-#define CLK_SCLK_PXLAYSNC_CSIS0_FIMC	331
-#define CLK_SCLK_JPEG			332
-#define CLK_SCLK_CSIS1			333
-#define CLK_SCLK_CSIS0			334
-#define CLK_SCLK_CAM1			335
-#define CLK_SCLK_FIMC3_LCLK		336
-#define CLK_SCLK_FIMC2_LCLK		337
-#define CLK_SCLK_FIMC1_LCLK		338
-#define CLK_SCLK_FIMC0_LCLK		339
-#define CLK_SCLK_PIXEL			340
-#define CLK_SCLK_HDMI			341
-#define CLK_SCLK_MIXER			342
-#define CLK_SCLK_MFC			343
-#define CLK_SCLK_G3D			344
-#define CLK_SCLK_MIPIDPHY4L		345
-#define CLK_SCLK_MIPI0			346
-#define CLK_SCLK_MDNIE0			347
-#define CLK_SCLK_FIMD0			348
-#define CLK_SCLK_PCM0			349
-#define CLK_SCLK_AUDIO0			350
-#define CLK_SCLK_TSADC			351
-#define CLK_SCLK_EBI			352
-#define CLK_SCLK_MMC2			353
-#define CLK_SCLK_MMC1			354
-#define CLK_SCLK_MMC0			355
-#define CLK_SCLK_I2S			356
-#define CLK_SCLK_PCM2			357
-#define CLK_SCLK_PCM1			358
-#define CLK_SCLK_AUDIO2			359
-#define CLK_SCLK_AUDIO1			360
-#define CLK_SCLK_SPDIF			361
-#define CLK_SCLK_SPI2			362
-#define CLK_SCLK_SPI1			363
-#define CLK_SCLK_SPI0			364
-#define CLK_SCLK_UART3			365
-#define CLK_SCLK_UART2			366
-#define CLK_SCLK_UART1			367
-#define CLK_SCLK_UART0			368
-#define CLK_SCLK_HDMIPHY		369
-
-/*
- * Total number of clocks of main CMU.
- * NOTE: Must be equal to last clock ID increased by one.
- */
-#define CLK_NR_CLKS			370
-
-/*
- * CMU DMC
- */
-#define CLK_DMC_FOUT_MPLL		1
-#define CLK_DMC_FOUT_BPLL		2
-
-#define CLK_DMC_MOUT_MPLL		3
-#define CLK_DMC_MOUT_BPLL		4
-#define CLK_DMC_MOUT_DPHY		5
-#define CLK_DMC_MOUT_DMC_BUS		6
-
-#define CLK_DMC_DIV_DMC			7
-#define CLK_DMC_DIV_DPHY		8
-#define CLK_DMC_DIV_DMC_PRE		9
-#define CLK_DMC_DIV_DMCP		10
-#define CLK_DMC_DIV_DMCD		11
-#define CLK_DMC_DIV_MPLL_PRE		12
-
-/*
- * Total number of clocks of CMU_DMC.
- * NOTE: Must be equal to highest clock ID increased by one.
- */
-#define NR_CLKS_DMC			13
-
-#endif /* _DT_BINDINGS_CLOCK_SAMSUNG_EXYNOS4415_CLOCK_H */
-- 
2.9.3


^ permalink raw reply related

* [PATCH 3/4] pinctrl: samsung: Remove support for Exynos4415 (SoC not supported anymore)
From: Krzysztof Kozlowski @ 2017-01-14 12:36 UTC (permalink / raw)
  To: Sylwester Nawrocki, Tomasz Figa, Chanwoo Choi, Michael Turquette,
	Stephen Boyd, Rob Herring, Mark Rutland, Kukjin Kim,
	Krzysztof Kozlowski, Javier Martinez Canillas, Inki Dae,
	Joonyoung Shim, Seung-Woo Kim, Kyungmin Park, Linus Walleij,
	linux-samsung-soc, linux-clk, devicetree, linux-arm-kernel,
	linux-kernel, dri-deve
In-Reply-To: <20170114123642.15581-1-krzk@kernel.org>

Support for Exynos4415 is going away because there are no internal nor
external users.

Since commit 46dcf0ff0de3 ("ARM: dts: exynos: Remove exynos4415.dtsi"),
the platform cannot be instantiated so remove also the drivers.

Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
---
 drivers/pinctrl/samsung/pinctrl-exynos.c  | 75 -------------------------------
 drivers/pinctrl/samsung/pinctrl-samsung.c |  2 -
 drivers/pinctrl/samsung/pinctrl-samsung.h |  1 -
 3 files changed, 78 deletions(-)

diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c
index 07409fde02b2..24814db251a7 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.c
@@ -919,81 +919,6 @@ const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = {
 	},
 };
 
-/* pin banks of exynos4415 pin-controller 0 */
-static const struct samsung_pin_bank_data exynos4415_pin_banks0[] = {
-	EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
-	EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
-	EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08),
-	EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0", 0x0c),
-	EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1", 0x10),
-	EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpd0", 0x14),
-	EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpd1", 0x18),
-	EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf0", 0x30),
-	EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpf1", 0x34),
-	EXYNOS_PIN_BANK_EINTG(1, 0x1C0, "gpf2", 0x38),
-};
-
-/* pin banks of exynos4415 pin-controller 1 */
-static const struct samsung_pin_bank_data exynos4415_pin_banks1[] = {
-	EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpk0", 0x08),
-	EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1", 0x0c),
-	EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2", 0x10),
-	EXYNOS_PIN_BANK_EINTG(7, 0x0A0, "gpk3", 0x14),
-	EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpl0", 0x18),
-	EXYNOS_PIN_BANK_EINTN(6, 0x120, "mp00"),
-	EXYNOS_PIN_BANK_EINTN(4, 0x140, "mp01"),
-	EXYNOS_PIN_BANK_EINTN(6, 0x160, "mp02"),
-	EXYNOS_PIN_BANK_EINTN(8, 0x180, "mp03"),
-	EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "mp04"),
-	EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "mp05"),
-	EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "mp06"),
-	EXYNOS_PIN_BANK_EINTG(8, 0x260, "gpm0", 0x24),
-	EXYNOS_PIN_BANK_EINTG(7, 0x280, "gpm1", 0x28),
-	EXYNOS_PIN_BANK_EINTG(5, 0x2A0, "gpm2", 0x2c),
-	EXYNOS_PIN_BANK_EINTG(8, 0x2C0, "gpm3", 0x30),
-	EXYNOS_PIN_BANK_EINTG(8, 0x2E0, "gpm4", 0x34),
-	EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00),
-	EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04),
-	EXYNOS_PIN_BANK_EINTW(8, 0xC40, "gpx2", 0x08),
-	EXYNOS_PIN_BANK_EINTW(8, 0xC60, "gpx3", 0x0c),
-};
-
-/* pin banks of exynos4415 pin-controller 2 */
-static const struct samsung_pin_bank_data exynos4415_pin_banks2[] = {
-	EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
-	EXYNOS_PIN_BANK_EINTN(2, 0x000, "etc1"),
-};
-
-/*
- * Samsung pinctrl driver data for Exynos4415 SoC. Exynos4415 SoC includes
- * three gpio/pin-mux/pinconfig controllers.
- */
-const struct samsung_pin_ctrl exynos4415_pin_ctrl[] = {
-	{
-		/* pin-controller instance 0 data */
-		.pin_banks	= exynos4415_pin_banks0,
-		.nr_banks	= ARRAY_SIZE(exynos4415_pin_banks0),
-		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
-	}, {
-		/* pin-controller instance 1 data */
-		.pin_banks	= exynos4415_pin_banks1,
-		.nr_banks	= ARRAY_SIZE(exynos4415_pin_banks1),
-		.eint_gpio_init = exynos_eint_gpio_init,
-		.eint_wkup_init = exynos_eint_wkup_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
-	}, {
-		/* pin-controller instance 2 data */
-		.pin_banks	= exynos4415_pin_banks2,
-		.nr_banks	= ARRAY_SIZE(exynos4415_pin_banks2),
-		.eint_gpio_init = exynos_eint_gpio_init,
-		.suspend	= exynos_pinctrl_suspend,
-		.resume		= exynos_pinctrl_resume,
-	},
-};
-
 /* pin banks of exynos5250 pin-controller 0 */
 static const struct samsung_pin_bank_data exynos5250_pin_banks0[] __initconst = {
 	EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c
index 41e62391c33c..3bc925f61b71 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.c
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.c
@@ -1238,8 +1238,6 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = {
 		.data = (void *)exynos4210_pin_ctrl },
 	{ .compatible = "samsung,exynos4x12-pinctrl",
 		.data = (void *)exynos4x12_pin_ctrl },
-	{ .compatible = "samsung,exynos4415-pinctrl",
-		.data = (void *)exynos4415_pin_ctrl },
 	{ .compatible = "samsung,exynos5250-pinctrl",
 		.data = (void *)exynos5250_pin_ctrl },
 	{ .compatible = "samsung,exynos5260-pinctrl",
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h
index 043cb6c11180..6f7ce7539a00 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.h
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.h
@@ -273,7 +273,6 @@ struct samsung_pmx_func {
 extern const struct samsung_pin_ctrl exynos3250_pin_ctrl[];
 extern const struct samsung_pin_ctrl exynos4210_pin_ctrl[];
 extern const struct samsung_pin_ctrl exynos4x12_pin_ctrl[];
-extern const struct samsung_pin_ctrl exynos4415_pin_ctrl[];
 extern const struct samsung_pin_ctrl exynos5250_pin_ctrl[];
 extern const struct samsung_pin_ctrl exynos5260_pin_ctrl[];
 extern const struct samsung_pin_ctrl exynos5410_pin_ctrl[];
-- 
2.9.3

^ permalink raw reply related

* [PATCH 4/4] drm: exynos: Remove support for Exynos4415 (SoC not supported anymore)
From: Krzysztof Kozlowski @ 2017-01-14 12:36 UTC (permalink / raw)
  To: Sylwester Nawrocki, Tomasz Figa, Chanwoo Choi, Michael Turquette,
	Stephen Boyd, Rob Herring, Mark Rutland, Kukjin Kim,
	Krzysztof Kozlowski, Javier Martinez Canillas, Inki Dae,
	Joonyoung Shim, Seung-Woo Kim, Kyungmin Park, Linus Walleij,
	linux-samsung-soc, linux-clk, devicetree, linux-arm-kernel,
	linux-kernel, dri-deve
In-Reply-To: <20170114123642.15581-1-krzk@kernel.org>

Support for Exynos4415 is going away because there are no internal nor
external users.

Since commit 46dcf0ff0de3 ("ARM: dts: exynos: Remove exynos4415.dtsi"),
the platform cannot be instantiated so remove also the drivers.

Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
---
 .../devicetree/bindings/display/exynos/exynos_dsim.txt |  1 -
 .../bindings/display/exynos/samsung-fimd.txt           |  1 -
 drivers/gpu/drm/exynos/exynos_drm_dsi.c                | 15 +--------------
 drivers/gpu/drm/exynos/exynos_drm_fimd.c               | 18 ++----------------
 4 files changed, 3 insertions(+), 32 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/exynos/exynos_dsim.txt b/Documentation/devicetree/bindings/display/exynos/exynos_dsim.txt
index a78265993665..ca5204b3bc21 100644
--- a/Documentation/devicetree/bindings/display/exynos/exynos_dsim.txt
+++ b/Documentation/devicetree/bindings/display/exynos/exynos_dsim.txt
@@ -4,7 +4,6 @@ Required properties:
   - compatible: value should be one of the following
 		"samsung,exynos3250-mipi-dsi" /* for Exynos3250/3472 SoCs */
 		"samsung,exynos4210-mipi-dsi" /* for Exynos4 SoCs */
-		"samsung,exynos4415-mipi-dsi" /* for Exynos4415 SoC */
 		"samsung,exynos5410-mipi-dsi" /* for Exynos5410/5420/5440 SoCs */
 		"samsung,exynos5422-mipi-dsi" /* for Exynos5422/5800 SoCs */
 		"samsung,exynos5433-mipi-dsi" /* for Exynos5433 SoCs */
diff --git a/Documentation/devicetree/bindings/display/exynos/samsung-fimd.txt b/Documentation/devicetree/bindings/display/exynos/samsung-fimd.txt
index c7c6b9af87ac..c7ffe614ab2d 100644
--- a/Documentation/devicetree/bindings/display/exynos/samsung-fimd.txt
+++ b/Documentation/devicetree/bindings/display/exynos/samsung-fimd.txt
@@ -11,7 +11,6 @@ Required properties:
 		"samsung,s5pv210-fimd"; /* for S5PV210 SoC */
 		"samsung,exynos3250-fimd"; /* for Exynos3250/3472 SoCs */
 		"samsung,exynos4210-fimd"; /* for Exynos4 SoCs */
-		"samsung,exynos4415-fimd"; /* for Exynos4415 SoC */
 		"samsung,exynos5250-fimd"; /* for Exynos5250 SoCs */
 		"samsung,exynos5420-fimd"; /* for Exynos5420/5422/5800 SoCs */
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 812e2ec0761d..ef6f9c6de098 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -86,7 +86,7 @@
 #define DSIM_SYNC_INFORM		(1 << 27)
 #define DSIM_EOT_DISABLE		(1 << 28)
 #define DSIM_MFLUSH_VS			(1 << 29)
-/* This flag is valid only for exynos3250/3472/4415/5260/5430 */
+/* This flag is valid only for exynos3250/3472/5260/5430 */
 #define DSIM_CLKLANE_STOP		(1 << 30)
 
 /* DSIM_ESCMODE */
@@ -473,17 +473,6 @@ static const struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
 	.reg_values = reg_values,
 };
 
-static const struct exynos_dsi_driver_data exynos4415_dsi_driver_data = {
-	.reg_ofs = exynos_reg_ofs,
-	.plltmr_reg = 0x58,
-	.has_clklane_stop = 1,
-	.num_clks = 2,
-	.max_freq = 1000,
-	.wait_for_reset = 1,
-	.num_bits_resol = 11,
-	.reg_values = reg_values,
-};
-
 static const struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
 	.reg_ofs = exynos_reg_ofs,
 	.plltmr_reg = 0x58,
@@ -521,8 +510,6 @@ static const struct of_device_id exynos_dsi_of_match[] = {
 	  .data = &exynos3_dsi_driver_data },
 	{ .compatible = "samsung,exynos4210-mipi-dsi",
 	  .data = &exynos4_dsi_driver_data },
-	{ .compatible = "samsung,exynos4415-mipi-dsi",
-	  .data = &exynos4415_dsi_driver_data },
 	{ .compatible = "samsung,exynos5410-mipi-dsi",
 	  .data = &exynos5_dsi_driver_data },
 	{ .compatible = "samsung,exynos5422-mipi-dsi",
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 745cfbdf6b39..7ba50549283e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -71,10 +71,10 @@
 #define TRIGCON				0x1A4
 #define TRGMODE_ENABLE			(1 << 0)
 #define SWTRGCMD_ENABLE			(1 << 1)
-/* Exynos3250, 3472, 4415, 5260 5410, 5420 and 5422 only supported. */
+/* Exynos3250, 3472, 5260 5410, 5420 and 5422 only supported. */
 #define HWTRGEN_ENABLE			(1 << 3)
 #define HWTRGMASK_ENABLE		(1 << 4)
-/* Exynos3250, 3472, 4415, 5260, 5420 and 5422 only supported. */
+/* Exynos3250, 3472, 5260, 5420 and 5422 only supported. */
 #define HWTRIGEN_PER_ENABLE		(1 << 31)
 
 /* display mode change control register except exynos4 */
@@ -140,18 +140,6 @@ static struct fimd_driver_data exynos4_fimd_driver_data = {
 	.has_vtsel = 1,
 };
 
-static struct fimd_driver_data exynos4415_fimd_driver_data = {
-	.timing_base = 0x20000,
-	.lcdblk_offset = 0x210,
-	.lcdblk_vt_shift = 10,
-	.lcdblk_bypass_shift = 1,
-	.trg_type = I80_HW_TRG,
-	.has_shadowcon = 1,
-	.has_vidoutcon = 1,
-	.has_vtsel = 1,
-	.has_trigger_per_te = 1,
-};
-
 static struct fimd_driver_data exynos5_fimd_driver_data = {
 	.timing_base = 0x20000,
 	.lcdblk_offset = 0x214,
@@ -212,8 +200,6 @@ static const struct of_device_id fimd_driver_dt_match[] = {
 	  .data = &exynos3_fimd_driver_data },
 	{ .compatible = "samsung,exynos4210-fimd",
 	  .data = &exynos4_fimd_driver_data },
-	{ .compatible = "samsung,exynos4415-fimd",
-	  .data = &exynos4415_fimd_driver_data },
 	{ .compatible = "samsung,exynos5250-fimd",
 	  .data = &exynos5_fimd_driver_data },
 	{ .compatible = "samsung,exynos5420-fimd",
-- 
2.9.3

^ permalink raw reply related

* Re: [PATCH v4 1/2] iio: imu: add support to lsm6dsx driver
From: Jonathan Cameron @ 2017-01-14 12:41 UTC (permalink / raw)
  To: Lorenzo Bianconi
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, lorenzo.bianconi-qxv4g6HH51o
In-Reply-To: <20170110215519.960-2-lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>

On 10/01/17 21:55, Lorenzo Bianconi wrote:
> Add support to STM LSM6DS3-LSM6DSM 6-axis (acc + gyro) Mems sensor
> 
> http://www.st.com/resource/en/datasheet/lsm6ds3.pdf
> http://www.st.com/resource/en/datasheet/lsm6dsm.pdf
> 
> - continuous mode support
> - i2c support
> - spi support
> - sw fifo mode support
> - supported devices: lsm6ds3, lsm6dsm
> 
> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>
A nice driver, for a complex device. Good work!

Applied to the togreg branch of iio.git - pushed out as testing for the
autobuilders to play with it.

Please watch out for double newlines at the end of files though.
I've fixed up when applying.

Thanks,

Jonathan
> ---
>  drivers/iio/imu/Kconfig                        |   1 +
>  drivers/iio/imu/Makefile                       |   2 +
>  drivers/iio/imu/st_lsm6dsx/Kconfig             |  23 +
>  drivers/iio/imu/st_lsm6dsx/Makefile            |   5 +
>  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h        | 142 ++++++
>  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 455 +++++++++++++++++
>  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c   | 673 +++++++++++++++++++++++++
>  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c    | 101 ++++
>  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c    | 118 +++++
>  9 files changed, 1520 insertions(+)
>  create mode 100644 drivers/iio/imu/st_lsm6dsx/Kconfig
>  create mode 100644 drivers/iio/imu/st_lsm6dsx/Makefile
>  create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
>  create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
>  create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
>  create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
>  create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
> 
> diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
> index 1f1ad41..156630a 100644
> --- a/drivers/iio/imu/Kconfig
> +++ b/drivers/iio/imu/Kconfig
> @@ -39,6 +39,7 @@ config KMX61
>  	  be called kmx61.
>  
>  source "drivers/iio/imu/inv_mpu6050/Kconfig"
> +source "drivers/iio/imu/st_lsm6dsx/Kconfig"
>  
>  endmenu
>  
> diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
> index c71bcd3..8b563c3 100644
> --- a/drivers/iio/imu/Makefile
> +++ b/drivers/iio/imu/Makefile
> @@ -17,3 +17,5 @@ obj-y += bmi160/
>  obj-y += inv_mpu6050/
>  
>  obj-$(CONFIG_KMX61) += kmx61.o
> +
> +obj-y += st_lsm6dsx/
> diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig
> new file mode 100644
> index 0000000..2ebcb74
> --- /dev/null
> +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig
> @@ -0,0 +1,23 @@
> +
> +config IIO_ST_LSM6DSX
> +	tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors"
> +	depends on (I2C || SPI)
> +	select IIO_BUFFER
> +	select IIO_KFIFO_BUF
> +	select IIO_ST_LSM6DSX_I2C if (I2C)
> +	select IIO_ST_LSM6DSX_SPI if (SPI_MASTER)
> +	help
> +	  Say yes here to build support for STMicroelectronics LSM6DSx imu
> +	  sensor. Supported devices: lsm6ds3, lsm6dsm
> +
> +	  To compile this driver as a module, choose M here: the module
> +	  will be called st_lsm6dsx.
> +
> +config IIO_ST_LSM6DSX_I2C
> +	tristate
> +	depends on IIO_ST_LSM6DSX
> +
> +config IIO_ST_LSM6DSX_SPI
> +	tristate
> +	depends on IIO_ST_LSM6DSX
> +
> diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile b/drivers/iio/imu/st_lsm6dsx/Makefile
> new file mode 100644
> index 0000000..35919fe
> --- /dev/null
> +++ b/drivers/iio/imu/st_lsm6dsx/Makefile
> @@ -0,0 +1,5 @@
> +st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o
> +
> +obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o
> +obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o
> +obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o
> diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
> new file mode 100644
> index 0000000..16189ff
> --- /dev/null
> +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
> @@ -0,0 +1,142 @@
> +/*
> + * STMicroelectronics st_lsm6dsx sensor driver
> + *
> + * Copyright 2016 STMicroelectronics Inc.
> + *
> + * Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>
> + * Denis Ciocca <denis.ciocca-qxv4g6HH51o@public.gmane.org>
> + *
> + * Licensed under the GPL-2.
> + */
> +
> +#ifndef ST_LSM6DSX_H
> +#define ST_LSM6DSX_H
> +
> +#include <linux/device.h>
> +
> +#define ST_LSM6DS3_DEV_NAME	"lsm6ds3"
> +#define ST_LSM6DSM_DEV_NAME	"lsm6dsm"
> +
> +enum st_lsm6dsx_hw_id {
> +	ST_LSM6DS3_ID,
> +	ST_LSM6DSM_ID,
> +};
> +
> +#define ST_LSM6DSX_CHAN_SIZE		2
> +#define ST_LSM6DSX_SAMPLE_SIZE		6
> +#define ST_LSM6DSX_SAMPLE_DEPTH		(ST_LSM6DSX_SAMPLE_SIZE / \
> +					 ST_LSM6DSX_CHAN_SIZE)
> +
> +#if defined(CONFIG_SPI_MASTER)
> +#define ST_LSM6DSX_RX_MAX_LENGTH	256
> +#define ST_LSM6DSX_TX_MAX_LENGTH	8
> +
> +struct st_lsm6dsx_transfer_buffer {
> +	u8 rx_buf[ST_LSM6DSX_RX_MAX_LENGTH];
> +	u8 tx_buf[ST_LSM6DSX_TX_MAX_LENGTH] ____cacheline_aligned;
> +};
> +#endif /* CONFIG_SPI_MASTER */
> +
> +struct st_lsm6dsx_transfer_function {
> +	int (*read)(struct device *dev, u8 addr, int len, u8 *data);
> +	int (*write)(struct device *dev, u8 addr, int len, u8 *data);
> +};
> +
> +struct st_lsm6dsx_reg {
> +	u8 addr;
> +	u8 mask;
> +};
> +
> +struct st_lsm6dsx_settings {
> +	u8 wai;
> +	u16 max_fifo_size;
> +	enum st_lsm6dsx_hw_id id;
> +};
> +
> +enum st_lsm6dsx_sensor_id {
> +	ST_LSM6DSX_ID_ACC,
> +	ST_LSM6DSX_ID_GYRO,
> +	ST_LSM6DSX_ID_MAX,
> +};
> +
> +enum st_lsm6dsx_fifo_mode {
> +	ST_LSM6DSX_FIFO_BYPASS = 0x0,
> +	ST_LSM6DSX_FIFO_CONT = 0x6,
> +};
> +
> +/**
> + * struct st_lsm6dsx_sensor - ST IMU sensor instance
> + * @id: Sensor identifier.
> + * @hw: Pointer to instance of struct st_lsm6dsx_hw.
> + * @gain: Configured sensor sensitivity.
> + * @odr: Output data rate of the sensor [Hz].
> + * @watermark: Sensor watermark level.
> + * @sip: Number of samples in a given pattern.
> + * @decimator: FIFO decimation factor.
> + * @decimator_mask: Sensor mask for decimation register.
> + * @delta_ts: Delta time between two consecutive interrupts.
> + * @ts: Latest timestamp from the interrupt handler.
> + */
> +struct st_lsm6dsx_sensor {
> +	enum st_lsm6dsx_sensor_id id;
> +	struct st_lsm6dsx_hw *hw;
> +
> +	u32 gain;
> +	u16 odr;
> +
> +	u16 watermark;
> +	u8 sip;
> +	u8 decimator;
> +	u8 decimator_mask;
> +
> +	s64 delta_ts;
> +	s64 ts;
> +};
> +
> +/**
> + * struct st_lsm6dsx_hw - ST IMU MEMS hw instance
> + * @dev: Pointer to instance of struct device (I2C or SPI).
> + * @irq: Device interrupt line (I2C or SPI).
> + * @lock: Mutex to protect read and write operations.
> + * @fifo_lock: Mutex to prevent concurrent access to the hw FIFO.
> + * @fifo_mode: FIFO operating mode supported by the device.
> + * @enable_mask: Enabled sensor bitmask.
> + * @sip: Total number of samples (acc/gyro) in a given pattern.
> + * @iio_devs: Pointers to acc/gyro iio_dev instances.
> + * @settings: Pointer to the specific sensor settings in use.
> + * @tf: Transfer function structure used by I/O operations.
> + * @tb: Transfer buffers used by SPI I/O operations.
> + */
> +struct st_lsm6dsx_hw {
> +	struct device *dev;
> +	int irq;
> +
> +	struct mutex lock;
> +	struct mutex fifo_lock;
> +
> +	enum st_lsm6dsx_fifo_mode fifo_mode;
> +	u8 enable_mask;
> +	u8 sip;
> +
> +	struct iio_dev *iio_devs[ST_LSM6DSX_ID_MAX];
> +
> +	const struct st_lsm6dsx_settings *settings;
> +
> +	const struct st_lsm6dsx_transfer_function *tf;
> +#if defined(CONFIG_SPI_MASTER)
> +	struct st_lsm6dsx_transfer_buffer tb;
> +#endif /* CONFIG_SPI_MASTER */
> +};
> +
> +int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
> +		     const struct st_lsm6dsx_transfer_function *tf_ops);
> +int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor);
> +int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor);
> +int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw);
> +int st_lsm6dsx_write_with_mask(struct st_lsm6dsx_hw *hw, u8 addr, u8 mask,
> +			       u8 val);
> +int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor,
> +				u16 watermark);
> +
> +#endif /* ST_LSM6DSX_H */
> +
> diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
> new file mode 100644
> index 0000000..a16d7c9
> --- /dev/null
> +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
> @@ -0,0 +1,455 @@
> +/*
> + * STMicroelectronics st_lsm6dsx FIFO buffer library driver
> + *
> + * LSM6DS3/LSM6DSM: The FIFO buffer can be configured to store data
> + * from gyroscope and accelerometer. Samples are queued without any tag
> + * according to a specific pattern based on 'FIFO data sets' (6 bytes each):
> + *  - 1st data set is reserved for gyroscope data
> + *  - 2nd data set is reserved for accelerometer data
> + * The FIFO pattern changes depending on the ODRs and decimation factors
> + * assigned to the FIFO data sets. The first sequence of data stored in FIFO
> + * buffer contains the data of all the enabled FIFO data sets
> + * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the
> + * value of the decimation factor and ODR set for each FIFO data set.
> + * FIFO supported modes:
> + *  - BYPASS: FIFO disabled
> + *  - CONTINUOUS: FIFO enabled. When the buffer is full, the FIFO index
> + *    restarts from the beginning and the oldest sample is overwritten
> + *
> + * Copyright 2016 STMicroelectronics Inc.
> + *
> + * Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>
> + * Denis Ciocca <denis.ciocca-qxv4g6HH51o@public.gmane.org>
> + *
> + * Licensed under the GPL-2.
> + */
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/iio/kfifo_buf.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/buffer.h>
> +
> +#include "st_lsm6dsx.h"
> +
> +#define ST_LSM6DSX_REG_FIFO_THL_ADDR		0x06
> +#define ST_LSM6DSX_REG_FIFO_THH_ADDR		0x07
> +#define ST_LSM6DSX_FIFO_TH_MASK			GENMASK(11, 0)
> +#define ST_LSM6DSX_REG_FIFO_DEC_GXL_ADDR	0x08
> +#define ST_LSM6DSX_REG_FIFO_MODE_ADDR		0x0a
> +#define ST_LSM6DSX_FIFO_MODE_MASK		GENMASK(2, 0)
> +#define ST_LSM6DSX_FIFO_ODR_MASK		GENMASK(6, 3)
> +#define ST_LSM6DSX_REG_FIFO_DIFFL_ADDR		0x3a
> +#define ST_LSM6DSX_FIFO_DIFF_MASK		GENMASK(11, 0)
> +#define ST_LSM6DSX_FIFO_EMPTY_MASK		BIT(12)
> +#define ST_LSM6DSX_REG_FIFO_OUTL_ADDR		0x3e
> +
> +#define ST_LSM6DSX_MAX_FIFO_ODR_VAL		0x08
> +
> +struct st_lsm6dsx_decimator_entry {
> +	u8 decimator;
> +	u8 val;
> +};
> +
> +static const
> +struct st_lsm6dsx_decimator_entry st_lsm6dsx_decimator_table[] = {
> +	{  0, 0x0 },
> +	{  1, 0x1 },
> +	{  2, 0x2 },
> +	{  3, 0x3 },
> +	{  4, 0x4 },
> +	{  8, 0x5 },
> +	{ 16, 0x6 },
> +	{ 32, 0x7 },
> +};
> +
> +static int st_lsm6dsx_get_decimator_val(u8 val)
> +{
> +	const int max_size = ARRAY_SIZE(st_lsm6dsx_decimator_table);
> +	int i;
> +
> +	for (i = 0; i < max_size; i++)
> +		if (st_lsm6dsx_decimator_table[i].decimator == val)
> +			break;
> +
> +	return i == max_size ? 0 : st_lsm6dsx_decimator_table[i].val;
> +}
> +
> +static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw,
> +				       u16 *max_odr, u16 *min_odr)
> +{
> +	struct st_lsm6dsx_sensor *sensor;
> +	int i;
> +
> +	*max_odr = 0, *min_odr = ~0;
> +	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
> +		sensor = iio_priv(hw->iio_devs[i]);
> +
> +		if (!(hw->enable_mask & BIT(sensor->id)))
> +			continue;
> +
> +		*max_odr = max_t(u16, *max_odr, sensor->odr);
> +		*min_odr = min_t(u16, *min_odr, sensor->odr);
> +	}
> +}
> +
> +static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
> +{
> +	struct st_lsm6dsx_sensor *sensor;
> +	u16 max_odr, min_odr, sip = 0;
> +	int err, i;
> +	u8 data;
> +
> +	st_lsm6dsx_get_max_min_odr(hw, &max_odr, &min_odr);
> +
> +	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
> +		sensor = iio_priv(hw->iio_devs[i]);
> +
> +		/* update fifo decimators and sample in pattern */
> +		if (hw->enable_mask & BIT(sensor->id)) {
> +			sensor->sip = sensor->odr / min_odr;
> +			sensor->decimator = max_odr / sensor->odr;
> +			data = st_lsm6dsx_get_decimator_val(sensor->decimator);
> +		} else {
> +			sensor->sip = 0;
> +			sensor->decimator = 0;
> +			data = 0;
> +		}
> +
> +		err = st_lsm6dsx_write_with_mask(hw,
> +					ST_LSM6DSX_REG_FIFO_DEC_GXL_ADDR,
> +					sensor->decimator_mask, data);
> +		if (err < 0)
> +			return err;
> +
> +		sip += sensor->sip;
> +	}
> +	hw->sip = sip;
> +
> +	return 0;
> +}
> +
> +static int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
> +				    enum st_lsm6dsx_fifo_mode fifo_mode)
> +{
> +	u8 data;
> +	int err;
> +
> +	switch (fifo_mode) {
> +	case ST_LSM6DSX_FIFO_BYPASS:
> +		data = fifo_mode;
> +		break;
> +	case ST_LSM6DSX_FIFO_CONT:
> +		data = (ST_LSM6DSX_MAX_FIFO_ODR_VAL <<
> +			__ffs(ST_LSM6DSX_FIFO_ODR_MASK)) | fifo_mode;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	err = hw->tf->write(hw->dev, ST_LSM6DSX_REG_FIFO_MODE_ADDR,
> +			    sizeof(data), &data);
> +	if (err < 0)
> +		return err;
> +
> +	hw->fifo_mode = fifo_mode;
> +
> +	return 0;
> +}
> +
> +int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
> +{
> +	u16 fifo_watermark = ~0, cur_watermark, sip = 0;
> +	struct st_lsm6dsx_hw *hw = sensor->hw;
> +	struct st_lsm6dsx_sensor *cur_sensor;
> +	__le16 wdata;
> +	int i, err;
> +	u8 data;
> +
> +	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
> +		cur_sensor = iio_priv(hw->iio_devs[i]);
> +
> +		if (!(hw->enable_mask & BIT(cur_sensor->id)))
> +			continue;
> +
> +		cur_watermark = (cur_sensor == sensor) ? watermark
> +						       : cur_sensor->watermark;
> +
> +		fifo_watermark = min_t(u16, fifo_watermark, cur_watermark);
> +		sip += cur_sensor->sip;
> +	}
> +
> +	if (!sip)
> +		return 0;
> +
> +	fifo_watermark = max_t(u16, fifo_watermark, sip);
> +	fifo_watermark = (fifo_watermark / sip) * sip;
> +	fifo_watermark = fifo_watermark * ST_LSM6DSX_SAMPLE_DEPTH;
> +
> +	mutex_lock(&hw->lock);
> +
> +	err = hw->tf->read(hw->dev, ST_LSM6DSX_REG_FIFO_THH_ADDR,
> +			   sizeof(data), &data);
> +	if (err < 0)
> +		goto out;
> +
> +	fifo_watermark = ((data & ~ST_LSM6DSX_FIFO_TH_MASK) << 8) |
> +			  (fifo_watermark & ST_LSM6DSX_FIFO_TH_MASK);
> +
> +	wdata = cpu_to_le16(fifo_watermark);
> +	err = hw->tf->write(hw->dev, ST_LSM6DSX_REG_FIFO_THL_ADDR,
> +			    sizeof(wdata), (u8 *)&wdata);
> +out:
> +	mutex_unlock(&hw->lock);
> +
> +	return err < 0 ? err : 0;
> +}
> +
> +/**
> + * st_lsm6dsx_read_fifo() - LSM6DS3-LSM6DSM read FIFO routine
> + * @hw: Pointer to instance of struct st_lsm6dsx_hw.
> + *
> + * Read samples from the hw FIFO and push them to IIO buffers.
> + *
> + * Return: Number of bytes read from the FIFO
> + */
> +static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
> +{
> +	u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE;
> +	int err, acc_sip, gyro_sip, read_len, samples, offset;
> +	struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor;
> +	s64 acc_ts, acc_delta_ts, gyro_ts, gyro_delta_ts;
> +	u8 iio_buff[ALIGN(ST_LSM6DSX_SAMPLE_SIZE, sizeof(s64)) + sizeof(s64)];
> +	u8 buff[pattern_len];
> +	__le16 fifo_status;
> +
> +	err = hw->tf->read(hw->dev, ST_LSM6DSX_REG_FIFO_DIFFL_ADDR,
> +			   sizeof(fifo_status), (u8 *)&fifo_status);
> +	if (err < 0)
> +		return err;
> +
> +	if (fifo_status & cpu_to_le16(ST_LSM6DSX_FIFO_EMPTY_MASK))
> +		return 0;
> +
> +	fifo_len = (le16_to_cpu(fifo_status) & ST_LSM6DSX_FIFO_DIFF_MASK) *
> +		   ST_LSM6DSX_CHAN_SIZE;
> +	samples = fifo_len / ST_LSM6DSX_SAMPLE_SIZE;
> +	fifo_len = (fifo_len / pattern_len) * pattern_len;
> +
> +	/*
> +	 * compute delta timestamp between two consecutive samples
> +	 * in order to estimate queueing time of data generated
> +	 * by the sensor
> +	 */
> +	acc_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
> +	acc_ts = acc_sensor->ts - acc_sensor->delta_ts;
> +	acc_delta_ts = div_s64(acc_sensor->delta_ts * acc_sensor->decimator,
> +			       samples);
> +
> +	gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]);
> +	gyro_ts = gyro_sensor->ts - gyro_sensor->delta_ts;
> +	gyro_delta_ts = div_s64(gyro_sensor->delta_ts * gyro_sensor->decimator,
> +				samples);
> +
> +	for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
> +		err = hw->tf->read(hw->dev, ST_LSM6DSX_REG_FIFO_OUTL_ADDR,
> +				   sizeof(buff), buff);
> +		if (err < 0)
> +			return err;
> +
> +		/*
> +		 * Data are written to the FIFO with a specific pattern
> +		 * depending on the configured ODRs. The first sequence of data
> +		 * stored in FIFO contains the data of all enabled sensors
> +		 * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated
> +		 * depending on the value of the decimation factor set for each
> +		 * sensor.
> +		 *
> +		 * Supposing the FIFO is storing data from gyroscope and
> +		 * accelerometer at different ODRs:
> +		 *   - gyroscope ODR = 208Hz, accelerometer ODR = 104Hz
> +		 * Since the gyroscope ODR is twice the accelerometer one, the
> +		 * following pattern is repeated every 9 samples:
> +		 *   - Gx, Gy, Gz, Ax, Ay, Az, Gx, Gy, Gz
> +		 */
> +		gyro_sip = gyro_sensor->sip;
> +		acc_sip = acc_sensor->sip;
> +		offset = 0;
> +
> +		while (acc_sip > 0 || gyro_sip > 0) {
> +			if (gyro_sip-- > 0) {
> +				memcpy(iio_buff, &buff[offset],
> +				       ST_LSM6DSX_SAMPLE_SIZE);
> +				iio_push_to_buffers_with_timestamp(
> +					hw->iio_devs[ST_LSM6DSX_ID_GYRO],
> +					iio_buff, gyro_ts);
> +				offset += ST_LSM6DSX_SAMPLE_SIZE;
> +				gyro_ts += gyro_delta_ts;
> +			}
> +
> +			if (acc_sip-- > 0) {
> +				memcpy(iio_buff, &buff[offset],
> +				       ST_LSM6DSX_SAMPLE_SIZE);
> +				iio_push_to_buffers_with_timestamp(
> +					hw->iio_devs[ST_LSM6DSX_ID_ACC],
> +					iio_buff, acc_ts);
> +				offset += ST_LSM6DSX_SAMPLE_SIZE;
> +				acc_ts += acc_delta_ts;
> +			}
> +		}
> +	}
> +
> +	return read_len;
> +}
> +
> +static int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw)
> +{
> +	int err;
> +
> +	mutex_lock(&hw->fifo_lock);
> +
> +	st_lsm6dsx_read_fifo(hw);
> +	err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_BYPASS);
> +
> +	mutex_unlock(&hw->fifo_lock);
> +
> +	return err;
> +}
> +
> +static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable)
> +{
> +	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> +	struct st_lsm6dsx_hw *hw = sensor->hw;
> +	int err;
> +
> +	if (hw->fifo_mode != ST_LSM6DSX_FIFO_BYPASS) {
> +		err = st_lsm6dsx_flush_fifo(hw);
> +		if (err < 0)
> +			return err;
> +	}
> +
> +	if (enable) {
> +		err = st_lsm6dsx_sensor_enable(sensor);
> +		if (err < 0)
> +			return err;
> +	} else {
> +		err = st_lsm6dsx_sensor_disable(sensor);
> +		if (err < 0)
> +			return err;
> +	}
> +
> +	err = st_lsm6dsx_update_decimators(hw);
> +	if (err < 0)
> +		return err;
> +
> +	err = st_lsm6dsx_update_watermark(sensor, sensor->watermark);
> +	if (err < 0)
> +		return err;
> +
> +	if (hw->enable_mask) {
> +		err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT);
> +		if (err < 0)
> +			return err;
> +
> +		/*
> +		 * store enable buffer timestamp as reference to compute
> +		 * first delta timestamp
> +		 */
> +		sensor->ts = iio_get_time_ns(iio_dev);
> +	}
> +
> +	return 0;
> +}
> +
> +static irqreturn_t st_lsm6dsx_handler_irq(int irq, void *private)
> +{
> +	struct st_lsm6dsx_hw *hw = (struct st_lsm6dsx_hw *)private;
> +	struct st_lsm6dsx_sensor *sensor;
> +	int i;
> +
> +	if (!hw->sip)
> +		return IRQ_NONE;
> +
> +	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
> +		sensor = iio_priv(hw->iio_devs[i]);
> +
> +		if (sensor->sip > 0) {
> +			s64 timestamp;
> +
> +			timestamp = iio_get_time_ns(hw->iio_devs[i]);
> +			sensor->delta_ts = timestamp - sensor->ts;
> +			sensor->ts = timestamp;
> +		}
> +	}
> +
> +	return IRQ_WAKE_THREAD;
> +}
> +
> +static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
> +{
> +	struct st_lsm6dsx_hw *hw = (struct st_lsm6dsx_hw *)private;
> +	int count;
> +
> +	mutex_lock(&hw->fifo_lock);
> +	count = st_lsm6dsx_read_fifo(hw);
> +	mutex_unlock(&hw->fifo_lock);
> +
> +	return !count ? IRQ_NONE : IRQ_HANDLED;
> +}
> +
> +static int st_lsm6dsx_buffer_preenable(struct iio_dev *iio_dev)
> +{
> +	return st_lsm6dsx_update_fifo(iio_dev, true);
> +}
> +
> +static int st_lsm6dsx_buffer_postdisable(struct iio_dev *iio_dev)
> +{
> +	return st_lsm6dsx_update_fifo(iio_dev, false);
> +}
> +
> +static const struct iio_buffer_setup_ops st_lsm6dsx_buffer_ops = {
> +	.preenable = st_lsm6dsx_buffer_preenable,
> +	.postdisable = st_lsm6dsx_buffer_postdisable,
> +};
> +
> +int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw)
> +{
> +	struct iio_buffer *buffer;
> +	unsigned long irq_type;
> +	int i, err;
> +
> +	irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq));
> +
> +	switch (irq_type) {
> +	case IRQF_TRIGGER_HIGH:
> +	case IRQF_TRIGGER_RISING:
> +		break;
> +	default:
> +		dev_info(hw->dev, "mode %lx unsupported\n", irq_type);
> +		return -EINVAL;
> +	}
> +
> +	err = devm_request_threaded_irq(hw->dev, hw->irq,
> +					st_lsm6dsx_handler_irq,
> +					st_lsm6dsx_handler_thread,
> +					irq_type | IRQF_ONESHOT,
> +					"lsm6dsx", hw);
> +	if (err) {
> +		dev_err(hw->dev, "failed to request trigger irq %d\n",
> +			hw->irq);
> +		return err;
> +	}
> +
> +	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
> +		buffer = devm_iio_kfifo_allocate(hw->dev);
> +		if (!buffer)
> +			return -ENOMEM;
> +
> +		iio_device_attach_buffer(hw->iio_devs[i], buffer);
> +		hw->iio_devs[i]->modes |= INDIO_BUFFER_SOFTWARE;
> +		hw->iio_devs[i]->setup_ops = &st_lsm6dsx_buffer_ops;
> +	}
> +
> +	return 0;
> +}
> +
> diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
> new file mode 100644
> index 0000000..01e002c
> --- /dev/null
> +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
> @@ -0,0 +1,673 @@
> +/*
> + * STMicroelectronics st_lsm6dsx sensor driver
> + *
> + * The ST LSM6DSx IMU MEMS series consists of 3D digital accelerometer
> + * and 3D digital gyroscope system-in-package with a digital I2C/SPI serial
> + * interface standard output.
> + * LSM6DSx IMU MEMS series has a dynamic user-selectable full-scale
> + * acceleration range of +-2/+-4/+-8/+-16 g and an angular rate range of
> + * +-125/+-245/+-500/+-1000/+-2000 dps
> + * LSM6DSx series has an integrated First-In-First-Out (FIFO) buffer
> + * allowing dynamic batching of sensor data.
> + *
> + * Supported sensors:
> + * - LSM6DS3:
> + *   - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
> + *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
> + *   - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
> + *   - FIFO size: 8KB
> + *
> + * - LSM6DSM:
> + *   - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
> + *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
> + *   - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
> + *   - FIFO size: 4KB
> + *
> + * Copyright 2016 STMicroelectronics Inc.
> + *
> + * Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>
> + * Denis Ciocca <denis.ciocca-qxv4g6HH51o@public.gmane.org>
> + *
> + * Licensed under the GPL-2.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +
> +#include "st_lsm6dsx.h"
> +
> +#define ST_LSM6DSX_REG_ACC_DEC_MASK		GENMASK(2, 0)
> +#define ST_LSM6DSX_REG_GYRO_DEC_MASK		GENMASK(5, 3)
> +#define ST_LSM6DSX_REG_INT1_ADDR		0x0d
> +#define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK	BIT(3)
> +#define ST_LSM6DSX_REG_WHOAMI_ADDR		0x0f
> +#define ST_LSM6DSX_REG_RESET_ADDR		0x12
> +#define ST_LSM6DSX_REG_RESET_MASK		BIT(0)
> +#define ST_LSM6DSX_REG_BDU_ADDR			0x12
> +#define ST_LSM6DSX_REG_BDU_MASK			BIT(6)
> +#define ST_LSM6DSX_REG_INT2_ON_INT1_ADDR	0x13
> +#define ST_LSM6DSX_REG_INT2_ON_INT1_MASK	BIT(5)
> +#define ST_LSM6DSX_REG_ROUNDING_ADDR		0x16
> +#define ST_LSM6DSX_REG_ROUNDING_MASK		BIT(2)
> +#define ST_LSM6DSX_REG_LIR_ADDR			0x58
> +#define ST_LSM6DSX_REG_LIR_MASK			BIT(0)
> +
> +#define ST_LSM6DSX_REG_ACC_ODR_ADDR		0x10
> +#define ST_LSM6DSX_REG_ACC_ODR_MASK		GENMASK(7, 4)
> +#define ST_LSM6DSX_REG_ACC_FS_ADDR		0x10
> +#define ST_LSM6DSX_REG_ACC_FS_MASK		GENMASK(3, 2)
> +#define ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR		0x28
> +#define ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR		0x2a
> +#define ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR		0x2c
> +
> +#define ST_LSM6DSX_REG_GYRO_ODR_ADDR		0x11
> +#define ST_LSM6DSX_REG_GYRO_ODR_MASK		GENMASK(7, 4)
> +#define ST_LSM6DSX_REG_GYRO_FS_ADDR		0x11
> +#define ST_LSM6DSX_REG_GYRO_FS_MASK		GENMASK(3, 2)
> +#define ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR	0x22
> +#define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR	0x24
> +#define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR	0x26
> +
> +#define ST_LSM6DS3_WHOAMI			0x69
> +#define ST_LSM6DSM_WHOAMI			0x6a
> +
> +#define ST_LSM6DS3_MAX_FIFO_SIZE		8192
> +#define ST_LSM6DSM_MAX_FIFO_SIZE		4096
> +
> +#define ST_LSM6DSX_ACC_FS_2G_GAIN		IIO_G_TO_M_S_2(61)
> +#define ST_LSM6DSX_ACC_FS_4G_GAIN		IIO_G_TO_M_S_2(122)
> +#define ST_LSM6DSX_ACC_FS_8G_GAIN		IIO_G_TO_M_S_2(244)
> +#define ST_LSM6DSX_ACC_FS_16G_GAIN		IIO_G_TO_M_S_2(488)
> +
> +#define ST_LSM6DSX_GYRO_FS_245_GAIN		IIO_DEGREE_TO_RAD(4375)
> +#define ST_LSM6DSX_GYRO_FS_500_GAIN		IIO_DEGREE_TO_RAD(8750)
> +#define ST_LSM6DSX_GYRO_FS_1000_GAIN		IIO_DEGREE_TO_RAD(17500)
> +#define ST_LSM6DSX_GYRO_FS_2000_GAIN		IIO_DEGREE_TO_RAD(70000)
> +
> +struct st_lsm6dsx_odr {
> +	u16 hz;
> +	u8 val;
> +};
> +
> +#define ST_LSM6DSX_ODR_LIST_SIZE	6
> +struct st_lsm6dsx_odr_table_entry {
> +	struct st_lsm6dsx_reg reg;
> +	struct st_lsm6dsx_odr odr_avl[ST_LSM6DSX_ODR_LIST_SIZE];
> +};
> +
> +static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = {
> +	[ST_LSM6DSX_ID_ACC] = {
> +		.reg = {
> +			.addr = ST_LSM6DSX_REG_ACC_ODR_ADDR,
> +			.mask = ST_LSM6DSX_REG_ACC_ODR_MASK,
> +		},
> +		.odr_avl[0] = {  13, 0x01 },
> +		.odr_avl[1] = {  26, 0x02 },
> +		.odr_avl[2] = {  52, 0x03 },
> +		.odr_avl[3] = { 104, 0x04 },
> +		.odr_avl[4] = { 208, 0x05 },
> +		.odr_avl[5] = { 416, 0x06 },
> +	},
> +	[ST_LSM6DSX_ID_GYRO] = {
> +		.reg = {
> +			.addr = ST_LSM6DSX_REG_GYRO_ODR_ADDR,
> +			.mask = ST_LSM6DSX_REG_GYRO_ODR_MASK,
> +		},
> +		.odr_avl[0] = {  13, 0x01 },
> +		.odr_avl[1] = {  26, 0x02 },
> +		.odr_avl[2] = {  52, 0x03 },
> +		.odr_avl[3] = { 104, 0x04 },
> +		.odr_avl[4] = { 208, 0x05 },
> +		.odr_avl[5] = { 416, 0x06 },
> +	}
> +};
> +
> +struct st_lsm6dsx_fs {
> +	u32 gain;
> +	u8 val;
> +};
> +
> +#define ST_LSM6DSX_FS_LIST_SIZE		4
> +struct st_lsm6dsx_fs_table_entry {
> +	struct st_lsm6dsx_reg reg;
> +	struct st_lsm6dsx_fs fs_avl[ST_LSM6DSX_FS_LIST_SIZE];
> +};
> +
> +static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = {
> +	[ST_LSM6DSX_ID_ACC] = {
> +		.reg = {
> +			.addr = ST_LSM6DSX_REG_ACC_FS_ADDR,
> +			.mask = ST_LSM6DSX_REG_ACC_FS_MASK,
> +		},
> +		.fs_avl[0] = {  ST_LSM6DSX_ACC_FS_2G_GAIN, 0x0 },
> +		.fs_avl[1] = {  ST_LSM6DSX_ACC_FS_4G_GAIN, 0x2 },
> +		.fs_avl[2] = {  ST_LSM6DSX_ACC_FS_8G_GAIN, 0x3 },
> +		.fs_avl[3] = { ST_LSM6DSX_ACC_FS_16G_GAIN, 0x1 },
> +	},
> +	[ST_LSM6DSX_ID_GYRO] = {
> +		.reg = {
> +			.addr = ST_LSM6DSX_REG_GYRO_FS_ADDR,
> +			.mask = ST_LSM6DSX_REG_GYRO_FS_MASK,
> +		},
> +		.fs_avl[0] = {  ST_LSM6DSX_GYRO_FS_245_GAIN, 0x0 },
> +		.fs_avl[1] = {  ST_LSM6DSX_GYRO_FS_500_GAIN, 0x1 },
> +		.fs_avl[2] = { ST_LSM6DSX_GYRO_FS_1000_GAIN, 0x2 },
> +		.fs_avl[3] = { ST_LSM6DSX_GYRO_FS_2000_GAIN, 0x3 },
> +	}
> +};
> +
> +static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
> +	{
> +		.wai = ST_LSM6DS3_WHOAMI,
> +		.max_fifo_size = ST_LSM6DS3_MAX_FIFO_SIZE,
> +		.id = ST_LSM6DS3_ID,
> +	},
> +	{
> +		.wai = ST_LSM6DSM_WHOAMI,
> +		.max_fifo_size = ST_LSM6DSM_MAX_FIFO_SIZE,
> +		.id = ST_LSM6DSM_ID,
> +	},
> +};
> +
> +#define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx)		\
> +{									\
> +	.type = chan_type,						\
> +	.address = addr,						\
> +	.modified = 1,							\
> +	.channel2 = mod,						\
> +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
> +			      BIT(IIO_CHAN_INFO_SCALE),			\
> +	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
> +	.scan_index = scan_idx,						\
> +	.scan_type = {							\
> +		.sign = 's',						\
> +		.realbits = 16,						\
> +		.storagebits = 16,					\
> +		.endianness = IIO_LE,					\
> +	},								\
> +}
> +
> +static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = {
> +	ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR,
> +			   IIO_MOD_X, 0),
> +	ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR,
> +			   IIO_MOD_Y, 1),
> +	ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR,
> +			   IIO_MOD_Z, 2),
> +	IIO_CHAN_SOFT_TIMESTAMP(3),
> +};
> +
> +static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = {
> +	ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR,
> +			   IIO_MOD_X, 0),
> +	ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR,
> +			   IIO_MOD_Y, 1),
> +	ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR,
> +			   IIO_MOD_Z, 2),
> +	IIO_CHAN_SOFT_TIMESTAMP(3),
> +};
> +
> +int st_lsm6dsx_write_with_mask(struct st_lsm6dsx_hw *hw, u8 addr, u8 mask,
> +			       u8 val)
> +{
> +	u8 data;
> +	int err;
> +
> +	mutex_lock(&hw->lock);
> +
> +	err = hw->tf->read(hw->dev, addr, sizeof(data), &data);
> +	if (err < 0) {
> +		dev_err(hw->dev, "failed to read %02x register\n", addr);
> +		goto out;
> +	}
> +
> +	data = (data & ~mask) | ((val << __ffs(mask)) & mask);
> +
> +	err = hw->tf->write(hw->dev, addr, sizeof(data), &data);
> +	if (err < 0)
> +		dev_err(hw->dev, "failed to write %02x register\n", addr);
> +
> +out:
> +	mutex_unlock(&hw->lock);
> +
> +	return err;
> +}
> +
> +static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id)
> +{
> +	int err, i;
> +	u8 data;
> +
> +	for (i = 0; i < ARRAY_SIZE(st_lsm6dsx_sensor_settings); i++) {
> +		if (id == st_lsm6dsx_sensor_settings[i].id)
> +			break;
> +	}
> +
> +	if (i == ARRAY_SIZE(st_lsm6dsx_sensor_settings)) {
> +		dev_err(hw->dev, "unsupported hw id [%02x]\n", id);
> +		return -ENODEV;
> +	}
> +
> +	err = hw->tf->read(hw->dev, ST_LSM6DSX_REG_WHOAMI_ADDR, sizeof(data),
> +			   &data);
> +	if (err < 0) {
> +		dev_err(hw->dev, "failed to read whoami register\n");
> +		return err;
> +	}
> +
> +	if (data != st_lsm6dsx_sensor_settings[i].wai) {
> +		dev_err(hw->dev, "unsupported whoami [%02x]\n", data);
> +		return -ENODEV;
> +	}
> +
> +	hw->settings = &st_lsm6dsx_sensor_settings[i];
> +
> +	return 0;
> +}
> +
> +static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
> +				     u32 gain)
> +{
> +	enum st_lsm6dsx_sensor_id id = sensor->id;
> +	int i, err;
> +	u8 val;
> +
> +	for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
> +		if (st_lsm6dsx_fs_table[id].fs_avl[i].gain == gain)
> +			break;
> +
> +	if (i == ST_LSM6DSX_FS_LIST_SIZE)
> +		return -EINVAL;
> +
> +	val = st_lsm6dsx_fs_table[id].fs_avl[i].val;
> +	err = st_lsm6dsx_write_with_mask(sensor->hw,
> +					 st_lsm6dsx_fs_table[id].reg.addr,
> +					 st_lsm6dsx_fs_table[id].reg.mask,
> +					 val);
> +	if (err < 0)
> +		return err;
> +
> +	sensor->gain = gain;
> +
> +	return 0;
> +}
> +
> +static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr)
> +{
> +	enum st_lsm6dsx_sensor_id id = sensor->id;
> +	int i, err;
> +	u8 val;
> +
> +	for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
> +		if (st_lsm6dsx_odr_table[id].odr_avl[i].hz == odr)
> +			break;
> +
> +	if (i == ST_LSM6DSX_ODR_LIST_SIZE)
> +		return -EINVAL;
> +
> +	val = st_lsm6dsx_odr_table[id].odr_avl[i].val;
> +	err = st_lsm6dsx_write_with_mask(sensor->hw,
> +					 st_lsm6dsx_odr_table[id].reg.addr,
> +					 st_lsm6dsx_odr_table[id].reg.mask,
> +					 val);
> +	if (err < 0)
> +		return err;
> +
> +	sensor->odr = odr;
> +
> +	return 0;
> +}
> +
> +int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor)
> +{
> +	int err;
> +
> +	err = st_lsm6dsx_set_odr(sensor, sensor->odr);
> +	if (err < 0)
> +		return err;
> +
> +	sensor->hw->enable_mask |= BIT(sensor->id);
> +
> +	return 0;
> +}
> +
> +int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor)
> +{
> +	enum st_lsm6dsx_sensor_id id = sensor->id;
> +	int err;
> +
> +	err = st_lsm6dsx_write_with_mask(sensor->hw,
> +					 st_lsm6dsx_odr_table[id].reg.addr,
> +					 st_lsm6dsx_odr_table[id].reg.mask, 0);
> +	if (err < 0)
> +		return err;
> +
> +	sensor->hw->enable_mask &= ~BIT(id);
> +
> +	return 0;
> +}
> +
> +static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor,
> +				   u8 addr, int *val)
> +{
> +	int err, delay;
> +	__le16 data;
> +
> +	err = st_lsm6dsx_sensor_enable(sensor);
> +	if (err < 0)
> +		return err;
> +
> +	delay = 1000000 / sensor->odr;
> +	usleep_range(delay, 2 * delay);
> +
> +	err = sensor->hw->tf->read(sensor->hw->dev, addr, sizeof(data),
> +				   (u8 *)&data);
> +	if (err < 0)
> +		return err;
> +
> +	st_lsm6dsx_sensor_disable(sensor);
> +
> +	*val = (s16)data;
> +
> +	return IIO_VAL_INT;
> +}
> +
> +static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev,
> +			       struct iio_chan_spec const *ch,
> +			       int *val, int *val2, long mask)
> +{
> +	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> +	int ret;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		ret = iio_device_claim_direct_mode(iio_dev);
> +		if (ret)
> +			break;
> +
> +		ret = st_lsm6dsx_read_oneshot(sensor, ch->address, val);
> +		iio_device_release_direct_mode(iio_dev);
> +		break;
> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		*val = sensor->odr;
> +		ret = IIO_VAL_INT;
> +		break;
> +	case IIO_CHAN_INFO_SCALE:
> +		*val = 0;
> +		*val2 = sensor->gain;
> +		ret = IIO_VAL_INT_PLUS_MICRO;
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
> +				struct iio_chan_spec const *chan,
> +				int val, int val2, long mask)
> +{
> +	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> +	int err;
> +
> +	err = iio_device_claim_direct_mode(iio_dev);
> +	if (err)
> +		return err;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_SCALE:
> +		err = st_lsm6dsx_set_full_scale(sensor, val2);
> +		break;
> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		err = st_lsm6dsx_set_odr(sensor, val);
> +		break;
> +	default:
> +		err = -EINVAL;
> +		break;
> +	}
> +
> +	iio_device_release_direct_mode(iio_dev);
> +
> +	return err;
> +}
> +
> +static int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val)
> +{
> +	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> +	struct st_lsm6dsx_hw *hw = sensor->hw;
> +	int err, max_fifo_len;
> +
> +	max_fifo_len = hw->settings->max_fifo_size / ST_LSM6DSX_SAMPLE_SIZE;
> +	if (val < 1 || val > max_fifo_len)
> +		return -EINVAL;
> +
> +	err = st_lsm6dsx_update_watermark(sensor, val);
> +	if (err < 0)
> +		return err;
> +
> +	sensor->watermark = val;
> +
> +	return 0;
> +}
> +
> +static ssize_t
> +st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev,
> +					  struct device_attribute *attr,
> +					  char *buf)
> +{
> +	struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
> +	enum st_lsm6dsx_sensor_id id = sensor->id;
> +	int i, len = 0;
> +
> +	for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
> +		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
> +				 st_lsm6dsx_odr_table[id].odr_avl[i].hz);
> +	buf[len - 1] = '\n';
> +
> +	return len;
> +}
> +
> +static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev,
> +					    struct device_attribute *attr,
> +					    char *buf)
> +{
> +	struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
> +	enum st_lsm6dsx_sensor_id id = sensor->id;
> +	int i, len = 0;
> +
> +	for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
> +		len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
> +				 st_lsm6dsx_fs_table[id].fs_avl[i].gain);
> +	buf[len - 1] = '\n';
> +
> +	return len;
> +}
> +
> +static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_sysfs_sampling_frequency_avail);
> +static IIO_DEVICE_ATTR(in_accel_scale_available, 0444,
> +		       st_lsm6dsx_sysfs_scale_avail, NULL, 0);
> +static IIO_DEVICE_ATTR(in_anglvel_scale_available, 0444,
> +		       st_lsm6dsx_sysfs_scale_avail, NULL, 0);
> +
> +static struct attribute *st_lsm6dsx_acc_attributes[] = {
> +	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
> +	&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group st_lsm6dsx_acc_attribute_group = {
> +	.attrs = st_lsm6dsx_acc_attributes,
> +};
> +
> +static const struct iio_info st_lsm6dsx_acc_info = {
> +	.driver_module = THIS_MODULE,
> +	.attrs = &st_lsm6dsx_acc_attribute_group,
> +	.read_raw = st_lsm6dsx_read_raw,
> +	.write_raw = st_lsm6dsx_write_raw,
> +	.hwfifo_set_watermark = st_lsm6dsx_set_watermark,
> +};
> +
> +static struct attribute *st_lsm6dsx_gyro_attributes[] = {
> +	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
> +	&iio_dev_attr_in_anglvel_scale_available.dev_attr.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group st_lsm6dsx_gyro_attribute_group = {
> +	.attrs = st_lsm6dsx_gyro_attributes,
> +};
> +
> +static const struct iio_info st_lsm6dsx_gyro_info = {
> +	.driver_module = THIS_MODULE,
> +	.attrs = &st_lsm6dsx_gyro_attribute_group,
> +	.read_raw = st_lsm6dsx_read_raw,
> +	.write_raw = st_lsm6dsx_write_raw,
> +	.hwfifo_set_watermark = st_lsm6dsx_set_watermark,
> +};
> +
> +static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0};
> +
> +static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
> +{
> +	int err;
> +	u8 data;
> +
> +	data = ST_LSM6DSX_REG_RESET_MASK;
> +	err = hw->tf->write(hw->dev, ST_LSM6DSX_REG_RESET_ADDR, sizeof(data),
> +			    &data);
> +	if (err < 0)
> +		return err;
> +
> +	msleep(200);
> +
> +	/* latch interrupts */
> +	err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_LIR_ADDR,
> +					 ST_LSM6DSX_REG_LIR_MASK, 1);
> +	if (err < 0)
> +		return err;
> +
> +	/* enable Block Data Update */
> +	err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_BDU_ADDR,
> +					 ST_LSM6DSX_REG_BDU_MASK, 1);
> +	if (err < 0)
> +		return err;
> +
> +	err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_ROUNDING_ADDR,
> +					 ST_LSM6DSX_REG_ROUNDING_MASK, 1);
> +	if (err < 0)
> +		return err;
> +
> +	/* enable FIFO watermak interrupt */
> +	err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_INT1_ADDR,
> +					 ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, 1);
> +	if (err < 0)
> +		return err;
> +
> +	/* redirect INT2 on INT1 */
> +	return st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_INT2_ON_INT1_ADDR,
> +					  ST_LSM6DSX_REG_INT2_ON_INT1_MASK, 1);
> +}
> +
> +static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
> +					       enum st_lsm6dsx_sensor_id id)
> +{
> +	struct st_lsm6dsx_sensor *sensor;
> +	struct iio_dev *iio_dev;
> +
> +	iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor));
> +	if (!iio_dev)
> +		return NULL;
> +
> +	iio_dev->modes = INDIO_DIRECT_MODE;
> +	iio_dev->dev.parent = hw->dev;
> +	iio_dev->available_scan_masks = st_lsm6dsx_available_scan_masks;
> +
> +	sensor = iio_priv(iio_dev);
> +	sensor->id = id;
> +	sensor->hw = hw;
> +	sensor->odr = st_lsm6dsx_odr_table[id].odr_avl[0].hz;
> +	sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain;
> +	sensor->watermark = 1;
> +
> +	switch (id) {
> +	case ST_LSM6DSX_ID_ACC:
> +		iio_dev->channels = st_lsm6dsx_acc_channels;
> +		iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels);
> +		iio_dev->name = "lsm6dsx_accel";
> +		iio_dev->info = &st_lsm6dsx_acc_info;
> +
> +		sensor->decimator_mask = ST_LSM6DSX_REG_ACC_DEC_MASK;
> +		break;
> +	case ST_LSM6DSX_ID_GYRO:
> +		iio_dev->channels = st_lsm6dsx_gyro_channels;
> +		iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels);
> +		iio_dev->name = "lsm6dsx_gyro";
> +		iio_dev->info = &st_lsm6dsx_gyro_info;
> +
> +		sensor->decimator_mask = ST_LSM6DSX_REG_GYRO_DEC_MASK;
> +		break;
> +	default:
> +		return NULL;
> +	}
> +
> +	return iio_dev;
> +}
> +
> +int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
> +		     const struct st_lsm6dsx_transfer_function *tf_ops)
> +{
> +	struct st_lsm6dsx_hw *hw;
> +	int i, err;
> +
> +	hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
> +	if (!hw)
> +		return -ENOMEM;
> +
> +	dev_set_drvdata(dev, (void *)hw);
> +
> +	mutex_init(&hw->lock);
> +	mutex_init(&hw->fifo_lock);
> +
> +	hw->dev = dev;
> +	hw->irq = irq;
> +	hw->tf = tf_ops;
> +
> +	err = st_lsm6dsx_check_whoami(hw, hw_id);
> +	if (err < 0)
> +		return err;
> +
> +	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
> +		hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i);
> +		if (!hw->iio_devs[i])
> +			return -ENOMEM;
> +	}
> +
> +	err = st_lsm6dsx_init_device(hw);
> +	if (err < 0)
> +		return err;
> +
> +	if (hw->irq > 0) {
> +		err = st_lsm6dsx_fifo_setup(hw);
> +		if (err < 0)
> +			return err;
> +	}
> +
> +	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
> +		err = devm_iio_device_register(hw->dev, hw->iio_devs[i]);
> +		if (err)
> +			return err;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(st_lsm6dsx_probe);
> +
> +MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>");
> +MODULE_AUTHOR("Denis Ciocca <denis.ciocca-qxv4g6HH51o@public.gmane.org>");
> +MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
> new file mode 100644
> index 0000000..ea30411
> --- /dev/null
> +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
> @@ -0,0 +1,101 @@
> +/*
> + * STMicroelectronics st_lsm6dsx i2c driver
> + *
> + * Copyright 2016 STMicroelectronics Inc.
> + *
> + * Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>
> + * Denis Ciocca <denis.ciocca-qxv4g6HH51o@public.gmane.org>
> + *
> + * Licensed under the GPL-2.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/i2c.h>
> +#include <linux/slab.h>
> +#include <linux/of.h>
> +
> +#include "st_lsm6dsx.h"
> +
> +static int st_lsm6dsx_i2c_read(struct device *dev, u8 addr, int len, u8 *data)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct i2c_msg msg[2];
> +
> +	msg[0].addr = client->addr;
> +	msg[0].flags = client->flags;
> +	msg[0].len = 1;
> +	msg[0].buf = &addr;
> +
> +	msg[1].addr = client->addr;
> +	msg[1].flags = client->flags | I2C_M_RD;
> +	msg[1].len = len;
> +	msg[1].buf = data;
> +
> +	return i2c_transfer(client->adapter, msg, 2);
> +}
> +
> +static int st_lsm6dsx_i2c_write(struct device *dev, u8 addr, int len, u8 *data)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct i2c_msg msg;
> +	u8 send[len + 1];
> +
> +	send[0] = addr;
> +	memcpy(&send[1], data, len * sizeof(u8));
> +
> +	msg.addr = client->addr;
> +	msg.flags = client->flags;
> +	msg.len = len + 1;
> +	msg.buf = send;
> +
> +	return i2c_transfer(client->adapter, &msg, 1);
> +}
> +
> +static const struct st_lsm6dsx_transfer_function st_lsm6dsx_transfer_fn = {
> +	.read = st_lsm6dsx_i2c_read,
> +	.write = st_lsm6dsx_i2c_write,
> +};
> +
> +static int st_lsm6dsx_i2c_probe(struct i2c_client *client,
> +				const struct i2c_device_id *id)
> +{
> +	return st_lsm6dsx_probe(&client->dev, client->irq,
> +				(int)id->driver_data,
> +				&st_lsm6dsx_transfer_fn);
> +}
> +
> +static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
> +	{
> +		.compatible = "st,lsm6ds3",
> +		.data = (void *)ST_LSM6DS3_ID,
> +	},
> +	{
> +		.compatible = "st,lsm6dsm",
> +		.data = (void *)ST_LSM6DSM_ID,
> +	},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
> +
> +static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
> +	{ ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID },
> +	{ ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
> +
> +static struct i2c_driver st_lsm6dsx_driver = {
> +	.driver = {
> +		.name = "st_lsm6dsx_i2c",
> +		.of_match_table = of_match_ptr(st_lsm6dsx_i2c_of_match),
> +	},
> +	.probe = st_lsm6dsx_i2c_probe,
> +	.id_table = st_lsm6dsx_i2c_id_table,
> +};
> +module_i2c_driver(st_lsm6dsx_driver);
> +
> +MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>");
> +MODULE_AUTHOR("Denis Ciocca <denis.ciocca-qxv4g6HH51o@public.gmane.org>");
> +MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i2c driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
> new file mode 100644
> index 0000000..fbe7247
> --- /dev/null
> +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
> @@ -0,0 +1,118 @@
> +/*
> + * STMicroelectronics st_lsm6dsx spi driver
> + *
> + * Copyright 2016 STMicroelectronics Inc.
> + *
> + * Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>
> + * Denis Ciocca <denis.ciocca-qxv4g6HH51o@public.gmane.org>
> + *
> + * Licensed under the GPL-2.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/spi/spi.h>
> +#include <linux/slab.h>
> +#include <linux/of.h>
> +
> +#include "st_lsm6dsx.h"
> +
> +#define SENSORS_SPI_READ	BIT(7)
> +
> +static int st_lsm6dsx_spi_read(struct device *dev, u8 addr, int len,
> +			       u8 *data)
> +{
> +	struct spi_device *spi = to_spi_device(dev);
> +	struct st_lsm6dsx_hw *hw = spi_get_drvdata(spi);
> +	int err;
> +
> +	struct spi_transfer xfers[] = {
> +		{
> +			.tx_buf = hw->tb.tx_buf,
> +			.bits_per_word = 8,
> +			.len = 1,
> +		},
> +		{
> +			.rx_buf = hw->tb.rx_buf,
> +			.bits_per_word = 8,
> +			.len = len,
> +		}
> +	};
> +
> +	hw->tb.tx_buf[0] = addr | SENSORS_SPI_READ;
> +
> +	err = spi_sync_transfer(spi, xfers,  ARRAY_SIZE(xfers));
> +	if (err < 0)
> +		return err;
> +
> +	memcpy(data, hw->tb.rx_buf, len * sizeof(u8));
> +
> +	return len;
> +}
> +
> +static int st_lsm6dsx_spi_write(struct device *dev, u8 addr, int len,
> +				u8 *data)
> +{
> +	struct st_lsm6dsx_hw *hw;
> +	struct spi_device *spi;
> +
> +	if (len >= ST_LSM6DSX_TX_MAX_LENGTH)
> +		return -ENOMEM;
> +
> +	spi = to_spi_device(dev);
> +	hw = spi_get_drvdata(spi);
> +
> +	hw->tb.tx_buf[0] = addr;
> +	memcpy(&hw->tb.tx_buf[1], data, len);
> +
> +	return spi_write(spi, hw->tb.tx_buf, len + 1);
> +}
> +
> +static const struct st_lsm6dsx_transfer_function st_lsm6dsx_transfer_fn = {
> +	.read = st_lsm6dsx_spi_read,
> +	.write = st_lsm6dsx_spi_write,
> +};
> +
> +static int st_lsm6dsx_spi_probe(struct spi_device *spi)
> +{
> +	const struct spi_device_id *id = spi_get_device_id(spi);
> +
> +	return st_lsm6dsx_probe(&spi->dev, spi->irq,
> +				(int)id->driver_data,
> +				&st_lsm6dsx_transfer_fn);
> +}
> +
> +static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
> +	{
> +		.compatible = "st,lsm6ds3",
> +		.data = (void *)ST_LSM6DS3_ID,
> +	},
> +	{
> +		.compatible = "st,lsm6dsm",
> +		.data = (void *)ST_LSM6DSM_ID,
> +	},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
> +
> +static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
> +	{ ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID },
> +	{ ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
> +
> +static struct spi_driver st_lsm6dsx_driver = {
> +	.driver = {
> +		.name = "st_lsm6dsx_spi",
> +		.of_match_table = of_match_ptr(st_lsm6dsx_spi_of_match),
> +	},
> +	.probe = st_lsm6dsx_spi_probe,
> +	.id_table = st_lsm6dsx_spi_id_table,
> +};
> +module_spi_driver(st_lsm6dsx_driver);
> +
> +MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>");
> +MODULE_AUTHOR("Denis Ciocca <denis.ciocca-qxv4g6HH51o@public.gmane.org>");
> +MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx spi driver");
> +MODULE_LICENSE("GPL v2");
> 

^ permalink raw reply

* Re: [PATCH v4 2/2] Documentation: dt: iio: add st_lsm6dsx sensor device binding
From: Jonathan Cameron @ 2017-01-14 12:42 UTC (permalink / raw)
  To: Lorenzo Bianconi
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, lorenzo.bianconi-qxv4g6HH51o
In-Reply-To: <20170110215519.960-3-lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>

On 10/01/17 21:55, Lorenzo Bianconi wrote:
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>
Applied.

Thanks,

Jonathan
> ---
>  .../devicetree/bindings/iio/imu/st_lsm6dsx.txt     | 24 ++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
> 
> diff --git a/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
> new file mode 100644
> index 0000000..ed3cdac
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
> @@ -0,0 +1,24 @@
> +* ST_LSM6DSx driver for STM 6-axis (acc + gyro) imu Mems sensors
> +
> +Required properties:
> +- compatible: must be one of:
> +  "st,lsm6ds3"
> +  "st,lsm6dsm"
> +- reg: i2c address of the sensor / spi cs line
> +
> +Optional properties:
> +- interrupt-parent: should be the phandle for the interrupt controller
> +- interrupts: interrupt mapping for IRQ. It should be configured with
> +  flags IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_EDGE_RISING.
> +
> +  Refer to interrupt-controller/interrupts.txt for generic interrupt
> +  client node bindings.
> +
> +Example:
> +
> +lsm6dsm@6b {
> +	compatible = "st,lsm6dsm";
> +	reg = <0x6b>;
> +	interrupt-parent = <&gpio0>;
> +	interrupts = <0 IRQ_TYPE_EDGE_RISING>;
> +};
> 

^ permalink raw reply

* Re: [PATCH 2/3] iio: adc: ti-ads7950: Drop "ti-" prefix from module name
From: Jonathan Cameron @ 2017-01-14 12:49 UTC (permalink / raw)
  To: David Lechner, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA
  Cc: Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Rob Herring, Mark Rutland, linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1484157171-15571-3-git-send-email-david-nq/r/kbU++upp/zk7JDF2g@public.gmane.org>

On 11/01/17 17:52, David Lechner wrote:
> This drops the "ti-" prefix from the module name. It makes the module name
> consistent with other iio ti-ads* drivers and it makes the driver work
> with device tree (the spi subsystem drops the "ti," prefix when matching
> compatible strings from device tree).
> 
> Tested working on LEGO MINDSTORMS EV3 with the following device tree node:
> 
> 	adc@3 {
> 		compatible = "ti,ads7957";
> 		reg = <3>;
> 		#io-channel-cells = <1>;
> 		spi-max-frequency = <10000000>;
> 		vref-supply = <&adc_ref>;
> 	};
> 
> Signed-off-by: David Lechner <david-nq/r/kbU++upp/zk7JDF2g@public.gmane.org>
What worries me here is that we might break existing setups.  I agree
we should have gotten this 'right' in the first place, but can we fix
it now.  Not so sure. We'd be better off perhaps adding an of_device_id
table with the write entries for device tree.
> ---
>  drivers/iio/adc/ti-ads7950.c | 26 +++++++++++++-------------
>  1 file changed, 13 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c
> index 0330361..b587fa6 100644
> --- a/drivers/iio/adc/ti-ads7950.c
> +++ b/drivers/iio/adc/ti-ads7950.c
> @@ -459,25 +459,25 @@ static int ti_ads7950_remove(struct spi_device *spi)
>  }
>  
>  static const struct spi_device_id ti_ads7950_id[] = {
> -	{"ti-ads7950", TI_ADS7950},
> -	{"ti-ads7951", TI_ADS7951},
> -	{"ti-ads7952", TI_ADS7952},
> -	{"ti-ads7953", TI_ADS7953},
> -	{"ti-ads7954", TI_ADS7954},
> -	{"ti-ads7955", TI_ADS7955},
> -	{"ti-ads7956", TI_ADS7956},
> -	{"ti-ads7957", TI_ADS7957},
> -	{"ti-ads7958", TI_ADS7958},
> -	{"ti-ads7959", TI_ADS7959},
> -	{"ti-ads7960", TI_ADS7960},
> -	{"ti-ads7961", TI_ADS7961},
> +	{ "ads7950", TI_ADS7950 },
> +	{ "ads7951", TI_ADS7951 },
> +	{ "ads7952", TI_ADS7952 },
> +	{ "ads7953", TI_ADS7953 },
> +	{ "ads7954", TI_ADS7954 },
> +	{ "ads7955", TI_ADS7955 },
> +	{ "ads7956", TI_ADS7956 },
> +	{ "ads7957", TI_ADS7957 },
> +	{ "ads7958", TI_ADS7958 },
> +	{ "ads7959", TI_ADS7959 },
> +	{ "ads7960", TI_ADS7960 },
> +	{ "ads7961", TI_ADS7961 },
>  	{ }
>  };
>  MODULE_DEVICE_TABLE(spi, ti_ads7950_id);
>  
>  static struct spi_driver ti_ads7950_driver = {
>  	.driver = {
> -		.name	= "ti-ads7950",
> +		.name	= "ads7950",
>  	},
>  	.probe		= ti_ads7950_probe,
>  	.remove		= ti_ads7950_remove,
> 

--
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 3/3] iio: adc: ti-ads7950: Change regulator matching string to "vref"
From: Jonathan Cameron @ 2017-01-14 12:52 UTC (permalink / raw)
  To: David Lechner, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA
  Cc: Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Rob Herring, Mark Rutland, linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1484157171-15571-4-git-send-email-david-nq/r/kbU++upp/zk7JDF2g@public.gmane.org>

On 11/01/17 17:52, David Lechner wrote:
> This changes the reference voltage regulator matching string from "refin"
> to "vref". This is to be consistent with other A/DC chips that also use
> "vref-supply" in their device tree bindings.
> 
> Signed-off-by: David Lechner <david-nq/r/kbU++upp/zk7JDF2g@public.gmane.org>
> ---
>  drivers/iio/adc/ti-ads7950.c | 6 +++---
Again, we missed this before and it would have been nice to have
had it as vref (which is matches the datasheet).  The question
becomes how do we handle this going forward with no risk of breaking
existing device trees.  We may have to do an optional get on one
name and then a non optional on the second. It's ugly, but
would fix this up in a 'safe' way.

Jonathan
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c
> index b587fa6..16a0663 100644
> --- a/drivers/iio/adc/ti-ads7950.c
> +++ b/drivers/iio/adc/ti-ads7950.c
> @@ -411,15 +411,15 @@ static int ti_ads7950_probe(struct spi_device *spi)
>  	spi_message_init_with_transfers(&st->scan_single_msg,
>  					st->scan_single_xfer, 3);
>  
> -	st->reg = devm_regulator_get(&spi->dev, "refin");
> +	st->reg = devm_regulator_get(&spi->dev, "vref");
>  	if (IS_ERR(st->reg)) {
> -		dev_err(&spi->dev, "Failed get get regulator \"refin\"\n");
> +		dev_err(&spi->dev, "Failed get get regulator \"vref\"\n");
>  		return PTR_ERR(st->reg);
>  	}
>  
>  	ret = regulator_enable(st->reg);
>  	if (ret) {
> -		dev_err(&spi->dev, "Failed to enable regulator \"refin\"\n");
> +		dev_err(&spi->dev, "Failed to enable regulator \"vref\"\n");
>  		return ret;
>  	}
>  
> 

^ permalink raw reply

* Re: [PATCH 1/3] DT/bindings: Add bindings for TI ADS7950 A/DC chips
From: Jonathan Cameron @ 2017-01-14 12:53 UTC (permalink / raw)
  To: David Lechner, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA
  Cc: Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Rob Herring, Mark Rutland, linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1484157171-15571-2-git-send-email-david-nq/r/kbU++upp/zk7JDF2g@public.gmane.org>

On 11/01/17 17:52, David Lechner wrote:
> This adds device tree bindings for the TI ADS7950 family of A/DC chips.
> 
> Signed-off-by: David Lechner <david-nq/r/kbU++upp/zk7JDF2g@public.gmane.org>
This is in of itself good, but we may need to have some deprecated
elements to continue supporting what was implicitly happening with
the missnaming so as to avoid accidentally breaking someone's device
tree.

Jonathan
> ---
>  .../devicetree/bindings/iio/adc/ti-ads7950.txt     | 23 ++++++++++++++++++++++
>  1 file changed, 23 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/adc/ti-ads7950.txt
> 
> diff --git a/Documentation/devicetree/bindings/iio/adc/ti-ads7950.txt b/Documentation/devicetree/bindings/iio/adc/ti-ads7950.txt
> new file mode 100644
> index 0000000..e77a6f7
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/adc/ti-ads7950.txt
> @@ -0,0 +1,23 @@
> +* Texas Instruments ADS7950 family of A/DC chips
> +
> +Required properties:
> + - compatible: Must be one of "ti,ads7950", "ti,ads7951", "ti,ads7952",
> +   "ti,ads7953", "ti,ads7954", "ti,ads7955", "ti,ads7956", "ti,ads7957",
> +   "ti,ads7958", "ti,ads7959", "ti,ads7960", or "ti,ads7961"
> + - reg: SPI chip select number for the device
> + - #io-channel-cells: Must be 1 as per ../iio-bindings.txt
> + - vref-supply: phandle to a regulator node that supplies the 2.5V or 5V
> +   reference voltage
> +
> +Recommended properties:
> + - spi-max-frequency: Definition as per
> +		Documentation/devicetree/bindings/spi/spi-bus.txt
> +
> +Example:
> +adc@0 {
> +	compatible = "ti,ads7957";
> +	reg = <0>;
> +	#io-channel-cells = <1>;
> +	vref-supply = <&refin_supply>;
> +	spi-max-frequency = <10000000>;
> +};
> 

^ permalink raw reply

* Re: [PATCH 3/4] iio: adc: add a driver for the SAR ADC found in Amlogic Meson SoCs
From: Jonathan Cameron @ 2017-01-14 14:46 UTC (permalink / raw)
  To: Martin Blumenstingl, knaack.h, lars, pmeerw, robh+dt,
	mark.rutland, khilman, linux-iio, devicetree, linux-amlogic,
	linux-clk
  Cc: carlo, catalin.marinas, will.deacon, mturquette, sboyd,
	narmstrong, linux-arm-kernel, Russell King
In-Reply-To: <20170111174334.24343-4-martin.blumenstingl@googlemail.com>

On 11/01/17 17:43, Martin Blumenstingl wrote:
> This adds support for the SAR (Successive Approximation Register) ADC
> on the Amlogic Meson SoCs.
> 
> The code is based on the public S805 (Meson8b) and S905 (GXBB)
> datasheets, as well as by reading (various versions of) the vendor
> driver and by inspecting the registers on the vendor kernels of my
> testing-hardware.
> 
> Currently the GXBB, GXL and GXM SoCs are supported. GXBB hardware has
> 10-bit ADC resolution, while GXL and GXM have 12-bit ADC resolution.
> The code was written to support older SoCs (Meson8 and Meson8b) as well,
> but due to lack of actual testing-hardware no of_device_id was added for
> these.
> 
> Two "features" from the vendor driver are currently missing:
> - the vendor driver uses channel #7 for calibration (this improves the
>   accuracy of the results - in my tests the results were less than 3%
>   off without calibration compared to the vendor driver). Adding support
>   for this should be easy, but is not required for most applications.
> - channel #6 is connected to the SoCs internal temperature sensor.
>   Adding support for this is probably not so easy since (based on the
>   u-boot sources) most SoC versions are using different registers and
>   algorithms for the conversion from "ADC value" to temperature.
> 
> Supported by the hardware but currently not supported by the driver:
> - reading multiple channels at the same time (the hardware has a FIFO
>   buffer which stores multiple results)
> - continuous sampling (this would require a way to enable this
>   individually because otherwise the ADC would be drawing power
>   constantly)
> - interrupt support (similar to the vendor driver this new driver is
>   polling the results. It is unclear if the IRQ-mode is supported on
>   older (Meson6 or Meson8) hardware as well or if there are any errata)
>
Russell Cc'd for a quick question on the clk api.

Ideally include a source for datasheets if available. Saves time googling and
perhaps getting the wrong thing!

A few other minor comments inline. Pretty good V1.

Jonathan
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> ---
>  drivers/iio/adc/Kconfig        |  12 +
>  drivers/iio/adc/Makefile       |   1 +
>  drivers/iio/adc/meson_saradc.c | 860 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 873 insertions(+)
>  create mode 100644 drivers/iio/adc/meson_saradc.c
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 9c8b558ba19e..86059b9b91bf 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -371,6 +371,18 @@ config MEN_Z188_ADC
>  	  This driver can also be built as a module. If so, the module will be
>  	  called men_z188_adc.
>  
> +config MESON_SARADC
> +	tristate "Amlogic Meson SAR ADC driver"
> +	default ARCH_MESON
> +	depends on OF && COMMON_CLK && (ARCH_MESON || COMPILE_TEST)
> +	select REGMAP_MMIO
> +	help
> +	  Say yes here to build support for the SAR ADC found in Amlogic Meson
> +	  SoCs.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called meson_saradc.
> +
>  config MXS_LRADC
>          tristate "Freescale i.MX23/i.MX28 LRADC"
>          depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index d36c4be8d1fc..de05b9e75f8f 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -36,6 +36,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
>  obj-$(CONFIG_MCP3422) += mcp3422.o
>  obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
>  obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
> +obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
>  obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
>  obj-$(CONFIG_NAU7802) += nau7802.o
>  obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
> diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
> new file mode 100644
> index 000000000000..06e8ac620385
> --- /dev/null
> +++ b/drivers/iio/adc/meson_saradc.c
> @@ -0,0 +1,860 @@
> +/*
> + * Amlogic Meson Successive Approximation Register (SAR) A/D Converter
> + *
> + * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> + *
> + * 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.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/clk-provider.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/iio/iio.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/clk.h>
> +#include <linux/completion.h>
> +#include <linux/delay.h>
> +#include <linux/reset.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +
> +#define SAR_ADC_REG0						0x00
> +	#define SAR_ADC_REG0_PANEL_DETECT			BIT(31)
> +	#define SAR_ADC_REG0_BUSY_MASK				GENMASK(30, 28)
> +	#define SAR_ADC_REG0_DELTA_BUSY				BIT(30)
> +	#define SAR_ADC_REG0_AVG_BUSY				BIT(29)
> +	#define SAR_ADC_REG0_SAMPLE_BUSY			BIT(28)
> +	#define SAR_ADC_REG0_FIFO_FULL				BIT(27)
> +	#define SAR_ADC_REG0_FIFO_EMPTY				BIT(26)
> +	#define SAR_ADC_REG0_FIFO_COUNT_MASK			GENMASK(25, 21)
> +	#define SAR_ADC_REG0_ADC_BIAS_CTRL_MASK			GENMASK(20, 19)
> +	#define SAR_ADC_REG0_CURR_CHAN_ID_MASK			GENMASK(18, 16)
> +	#define SAR_ADC_REG0_ADC_TEMP_SEN_SEL			BIT(15)
> +	#define SAR_ADC_REG0_SAMPLING_STOP			BIT(14)
> +	#define SAR_ADC_REG0_CHAN_DELTA_EN_MASK			GENMASK(13, 12)
> +	#define SAR_ADC_REG0_DETECT_IRQ_POL			BIT(10)
> +	#define SAR_ADC_REG0_DETECT_IRQ_EN			BIT(9)
> +	#define SAR_ADC_REG0_FIFO_CNT_IRQ_MASK			GENMASK(8, 4)
> +	#define SAR_ADC_REG0_FIFO_IRQ_EN			BIT(3)
> +	#define SAR_ADC_REG0_SAMPLING_START			BIT(2)
> +	#define SAR_ADC_REG0_CONTINUOUS_EN			BIT(1)
> +	#define SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE		BIT(0)
> +
> +#define SAR_ADC_CHAN_LIST					0x04
> +	#define SAR_ADC_CHAN_LIST_MAX_INDEX_MASK		GENMASK(26, 24)
> +	#define SAR_ADC_CHAN_CHAN_ENTRY_MASK(_chan)		\
> +					(GENMASK(2, 0) << (_chan * 3))
> +
> +#define SAR_ADC_AVG_CNTL					0x08
> +	#define SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(_chan)		\
> +					(16 + (_chan * 2))
> +	#define SAR_ADC_AVG_CNTL_AVG_MODE_MASK(_chan)		\
> +					(GENMASK(17, 16) << (_chan * 2))
> +	#define SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(_chan)	\
> +					(0 + (_chan * 2))
> +	#define SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(_chan)	\
> +					(GENMASK(1, 0) << (_chan * 2))
> +
> +#define SAR_ADC_REG3						0x0c
> +	#define SAR_ADC_REG3_CNTL_USE_SC_DLY			BIT(31)
> +	#define SAR_ADC_REG3_CLK_EN				BIT(30)
> +	#define SAR_ADC_REG3_BL30_INITIALIZED			BIT(28)
> +	#define SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN		BIT(27)
> +	#define SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE		BIT(26)
> +	#define SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK		GENMASK(25, 23)
> +	#define SAR_ADC_REG3_DETECT_EN				BIT(22)
> +	#define SAR_ADC_REG3_ADC_EN				BIT(21)
> +	#define SAR_ADC_REG3_PANEL_DETECT_COUNT_MASK		GENMASK(20, 18)
> +	#define SAR_ADC_REG3_PANEL_DETECT_FILTER_TB_MASK	GENMASK(17, 16)
> +	#define SAR_ADC_REG3_ADC_CLK_DIV_SHIFT			10
> +	#define SAR_ADC_REG3_ADC_CLK_DIV_WIDTH			5
> +	#define SAR_ADC_REG3_ADC_CLK_DIV_MASK			GENMASK(15, 10)
> +	#define SAR_ADC_REG3_BLOCK_DLY_SEL_MASK			GENMASK(9, 8)
> +	#define SAR_ADC_REG3_BLOCK_DLY_MASK			GENMASK(7, 0)
> +
> +#define SAR_ADC_DELAY						0x10
> +	#define SAR_ADC_DELAY_INPUT_DLY_SEL_MASK		GENMASK(25, 24)
> +	#define SAR_ADC_DELAY_BL30_BUSY				BIT(15)
> +	#define SAR_ADC_DELAY_KERNEL_BUSY			BIT(14)
> +	#define SAR_ADC_DELAY_INPUT_DLY_CNT_MASK		GENMASK(23, 16)
> +	#define SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK		GENMASK(9, 8)
> +	#define SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK		GENMASK(7, 0)
> +
> +#define SAR_ADC_LAST_RD						0x14
> +	#define SAR_ADC_LAST_RD_LAST_CHANNEL1_MASK		GENMASK(23, 16)
> +	#define SAR_ADC_LAST_RD_LAST_CHANNEL0_MASK		GENMASK(9, 0)
> +
> +#define SAR_ADC_FIFO_RD						0x18
> +	#define SAR_ADC_FIFO_RD_CHAN_ID_MASK			GENMASK(14, 12)
> +	#define SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK		GENMASK(11, 0)
> +
> +#define SAR_ADC_AUX_SW						0x1c
> +	#define SAR_ADC_AUX_SW_MUX_SEL_CHAN_MASK(_chan)		\
> +					(GENMASK(10, 8) << ((_chan - 2) * 2))
> +	#define SAR_ADC_AUX_SW_VREF_P_MUX			BIT(6)
> +	#define SAR_ADC_AUX_SW_VREF_N_MUX			BIT(5)
> +	#define SAR_ADC_AUX_SW_MODE_SEL				BIT(4)
> +	#define SAR_ADC_AUX_SW_YP_DRIVE_SW			BIT(3)
> +	#define SAR_ADC_AUX_SW_XP_DRIVE_SW			BIT(2)
> +	#define SAR_ADC_AUX_SW_YM_DRIVE_SW			BIT(1)
> +	#define SAR_ADC_AUX_SW_XM_DRIVE_SW			BIT(0)
> +
> +#define SAR_ADC_CHAN_10_SW					0x20
> +	#define SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK		GENMASK(25, 23)
> +	#define SAR_ADC_CHAN_10_SW_CHAN1_VREF_P_MUX		BIT(22)
> +	#define SAR_ADC_CHAN_10_SW_CHAN1_VREF_N_MUX		BIT(21)
> +	#define SAR_ADC_CHAN_10_SW_CHAN1_MODE_SEL		BIT(20)
> +	#define SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW		BIT(19)
> +	#define SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW		BIT(18)
> +	#define SAR_ADC_CHAN_10_SW_CHAN1_YM_DRIVE_SW		BIT(17)
> +	#define SAR_ADC_CHAN_10_SW_CHAN1_XM_DRIVE_SW		BIT(16)
> +	#define SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK		GENMASK(9, 7)
> +	#define SAR_ADC_CHAN_10_SW_CHAN0_VREF_P_MUX		BIT(6)
> +	#define SAR_ADC_CHAN_10_SW_CHAN0_VREF_N_MUX		BIT(5)
> +	#define SAR_ADC_CHAN_10_SW_CHAN0_MODE_SEL		BIT(4)
> +	#define SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW		BIT(3)
> +	#define SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW		BIT(2)
> +	#define SAR_ADC_CHAN_10_SW_CHAN0_YM_DRIVE_SW		BIT(1)
> +	#define SAR_ADC_CHAN_10_SW_CHAN0_XM_DRIVE_SW		BIT(0)
> +
> +#define SAR_ADC_DETECT_IDLE_SW					0x24
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_SW_EN		BIT(26)
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_MUX_MASK	GENMASK(25, 23)
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_VREF_P_MUX	BIT(22)
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_VREF_N_MUX	BIT(21)
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_SEL		BIT(20)
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_YP_DRIVE_SW	BIT(19)
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_XP_DRIVE_SW	BIT(18)
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_YM_DRIVE_SW	BIT(17)
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_XM_DRIVE_SW	BIT(16)
> +	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_MUX_SEL_MASK	GENMASK(9, 7)
> +	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_VREF_P_MUX	BIT(6)
> +	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_VREF_N_MUX	BIT(5)
> +	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_SEL		BIT(4)
> +	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_YP_DRIVE_SW	BIT(3)
> +	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_XP_DRIVE_SW	BIT(2)
> +	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_YM_DRIVE_SW	BIT(1)
> +	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_XM_DRIVE_SW	BIT(0)
> +
> +#define SAR_ADC_DELTA_10					0x28
> +	#define SAR_ADC_DELTA_10_TEMP_SEL			BIT(27)
> +	#define SAR_ADC_DELTA_10_TS_REVE1			BIT(26)
> +	#define SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_SHIFT	16
> +	#define SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_MASK		GENMASK(25, 16)
> +	#define SAR_ADC_DELTA_10_TS_REVE0			BIT(15)
> +	#define SAR_ADC_DELTA_10_TS_C_SHIFT			11
> +	#define SAR_ADC_DELTA_10_TS_C_MASK			GENMASK(14, 11)
> +	#define SAR_ADC_DELTA_10_TS_VBG_EN			BIT(10)
> +	#define SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_SHIFT	0
> +	#define SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_MASK		GENMASK(9, 0)
> +
> +/* NOTE: registers from here are undocumented (the vendor Linux kernel driver
> + * and u-boot source served as reference). These only seem to be relevant on
> + * GXBB and newer.
> + */
> +#define SAR_ADC_REG11						0x2c
> +	#define SAR_ADC_REG11_BANDGAP_EN			BIT(13)
> +
> +#define SAR_ADC_REG13						0x34
> +	#define SAR_ADC_REG13_12BIT_CALIBRATION_MASK		GENMASK(13, 8)
> +
> +#define SAR_ADC_MAX_FIFO_SIZE		32
> +#define SAR_ADC_NUM_CHANNELS		ARRAY_SIZE(meson_saradc_iio_channels)
> +#define SAR_ADC_VALUE_MASK(_priv)	(BIT(_priv->resolution) - 1)
> +
> +#define MESON_SAR_ADC_CHAN(_chan, _type) {				\
> +	.type = _type,							\
> +	.indexed = true,						\
> +	.channel = _chan,						\
> +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
> +				BIT(IIO_CHAN_INFO_AVERAGE_RAW),		\
> +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),		\
> +	.datasheet_name = "SAR_ADC_CH"#_chan,				\
> +}
> +
> +/* TODO: the hardware supports IIO_TEMP for channel 6 as well which is
Multline comment syntax.
> + * currently not supported by this driver.
> + */
> +static const struct iio_chan_spec meson_saradc_iio_channels[] = {
> +	MESON_SAR_ADC_CHAN(0, IIO_VOLTAGE),
> +	MESON_SAR_ADC_CHAN(1, IIO_VOLTAGE),
> +	MESON_SAR_ADC_CHAN(2, IIO_VOLTAGE),
> +	MESON_SAR_ADC_CHAN(3, IIO_VOLTAGE),
> +	MESON_SAR_ADC_CHAN(4, IIO_VOLTAGE),
> +	MESON_SAR_ADC_CHAN(5, IIO_VOLTAGE),
> +	MESON_SAR_ADC_CHAN(6, IIO_VOLTAGE),
> +	MESON_SAR_ADC_CHAN(7, IIO_VOLTAGE),
> +	IIO_CHAN_SOFT_TIMESTAMP(8),
> +};
> +
> +enum meson_saradc_avg_mode {
> +	NO_AVERAGING = 0x0,
> +	MEAN_AVERAGING = 0x1,
> +	MEDIAN_AVERAGING = 0x2,
> +};
> +
> +enum meson_saradc_num_samples {
> +	ONE_SAMPLE = 0x0,
> +	TWO_SAMPLES = 0x1,
> +	FOUR_SAMPLES = 0x2,
> +	EIGHT_SAMPLES = 0x3,
> +};
> +
> +enum meson_saradc_chan7_mux_sel {
> +	CHAN7_MUX_VSS = 0x0,
> +	CHAN7_MUX_VDD_DIV4 = 0x1,
> +	CHAN7_MUX_VDD_DIV2 = 0x2,
> +	CHAN7_MUX_VDD_MUL3_DIV4 = 0x3,
> +	CHAN7_MUX_VDD = 0x4,
> +	CHAN7_MUX_CH7_INPUT = 0x7,
> +};
> +
> +struct meson_saradc_priv {
> +	struct regmap			*regmap;
> +	struct clk			*clkin;
> +	struct clk			*core_clk;
> +	struct clk			*sana_clk;
> +	struct clk			*adc_sel_clk;
> +	struct clk			*adc_clk;
> +	struct clk_gate			clk_gate;
> +	struct clk			*adc_div_clk;
> +	struct clk_divider		clk_div;
> +	struct regulator		*vref;
> +	struct completion		completion;
> +	u8				resolution;
> +};
> +
> +static const struct regmap_config meson_saradc_regmap_config = {
> +	.reg_bits = 8,
> +	.val_bits = 32,
> +	.reg_stride = 4,
> +	.max_register = SAR_ADC_REG13,
> +};
> +
> +static unsigned int meson_saradc_get_fifo_count(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	u32 regval;
> +
> +	regmap_read(priv->regmap, SAR_ADC_REG0, &regval);
> +
> +	return FIELD_GET(SAR_ADC_REG0_FIFO_COUNT_MASK, regval);
> +}
> +
> +static int meson_saradc_wait_busy_clear(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	int regval, timeout = 10000;
> +
> +	do {
> +		udelay(1);
> +		regmap_read(priv->regmap, SAR_ADC_REG0, &regval);
> +	} while (FIELD_GET(SAR_ADC_REG0_BUSY_MASK, regval) && timeout--);
> +
> +	if (timeout < 0)
> +		return -ETIMEDOUT;
> +
> +	return 0;
> +}
> +
> +static int meson_saradc_read_raw_sample(struct iio_dev *indio_dev,
> +					const struct iio_chan_spec *chan,
> +					int *val)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	int ret, regval, fifo_chan, fifo_val, sum = 0, count = 0;
> +
> +	ret = meson_saradc_wait_busy_clear(indio_dev);
> +	if (ret)
> +		return ret;
> +
> +	regmap_read(priv->regmap, SAR_ADC_REG0, &regval);
> +
> +	while (meson_saradc_get_fifo_count(indio_dev) > 0 &&
> +	       count < SAR_ADC_MAX_FIFO_SIZE) {
> +		regmap_read(priv->regmap, SAR_ADC_FIFO_RD, &regval);
> +
> +		fifo_chan = FIELD_GET(SAR_ADC_FIFO_RD_CHAN_ID_MASK, regval);
> +		if (fifo_chan == chan->channel) {
> +			fifo_val = FIELD_GET(SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK,
> +					     regval) & SAR_ADC_VALUE_MASK(priv);
> +			sum += fifo_val;
> +			count++;
> +		}
> +	}
> +
> +	if (!count)
> +		return -ENOENT;
> +
> +	*val = sum / count;
> +
> +	return 0;
> +}
> +
> +static void meson_saradc_set_averaging(struct iio_dev *indio_dev,
> +				       const struct iio_chan_spec *chan,
> +				       enum meson_saradc_avg_mode mode,
> +				       enum meson_saradc_num_samples samples)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	u32 val;
> +
> +	val = samples << SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(chan->channel);
> +	regmap_update_bits(priv->regmap, SAR_ADC_AVG_CNTL,
> +			   SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(chan->channel),
> +			   val);
> +
> +	val = mode << SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(chan->channel);
> +	regmap_update_bits(priv->regmap, SAR_ADC_AVG_CNTL,
> +			   SAR_ADC_AVG_CNTL_AVG_MODE_MASK(chan->channel), val);
> +}
> +
> +static void meson_saradc_enable_channel(struct iio_dev *indio_dev,
> +					const struct iio_chan_spec *chan)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	u32 regval;
> +
> +	/* the SAR ADC engine allows sampling multiple channels at the same
> +	 * time. to keep it simple we're only working with one *internal*
> +	 * channel, which starts counting at index 0 (which means: count = 1).
> +	 */
> +	regval = FIELD_PREP(SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, 0);
> +	regmap_update_bits(priv->regmap, SAR_ADC_CHAN_LIST,
> +			   SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, regval);
> +
> +	/* map channel index 0 to the channel which we want to read */
> +	regval = FIELD_PREP(SAR_ADC_CHAN_CHAN_ENTRY_MASK(0), chan->channel);
> +	regmap_update_bits(priv->regmap, SAR_ADC_CHAN_LIST,
> +			   SAR_ADC_CHAN_CHAN_ENTRY_MASK(0), regval);
> +
> +	regval = FIELD_PREP(SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_MUX_MASK,
> +			    chan->channel);
> +	regmap_update_bits(priv->regmap, SAR_ADC_DETECT_IDLE_SW,
> +			   SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_MUX_MASK,
> +			   regval);
> +
> +	regval = FIELD_PREP(SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_MUX_SEL_MASK,
> +			    chan->channel);
> +	regmap_update_bits(priv->regmap, SAR_ADC_DETECT_IDLE_SW,
> +			   SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_MUX_SEL_MASK,
> +			   regval);
> +
> +	if (chan->channel == 6)
> +		regmap_update_bits(priv->regmap, SAR_ADC_DELTA_10,
> +				   SAR_ADC_DELTA_10_TEMP_SEL, 0);
> +}
> +
> +static void meson_saradc_set_channel7_mux(struct iio_dev *indio_dev,
> +					  enum meson_saradc_chan7_mux_sel sel)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	u32 regval;
> +
> +	regval = FIELD_PREP(SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, sel);
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG3,
> +			   SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, regval);
> +
> +	usleep_range(10, 20);
> +}
> +
> +static void meson_saradc_start_sample_engine(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG0,
> +			   SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE,
> +			   SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
> +
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG0,
> +			   SAR_ADC_REG0_SAMPLING_START,
> +			   SAR_ADC_REG0_SAMPLING_START);
> +}
> +
> +static void meson_saradc_stop_sample_engine(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG0,
> +			   SAR_ADC_REG0_SAMPLING_STOP,
> +			   SAR_ADC_REG0_SAMPLING_STOP);
> +
> +	/* wait until all modules are stopped */
> +	meson_saradc_wait_busy_clear(indio_dev);
> +
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG0,
> +			   SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0);
> +}
> +
> +static void meson_saradc_lock(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	int val;
> +
> +	mutex_lock(&indio_dev->mlock);
> +
> +	/* prevent BL30 from using the SAR ADC while we are using it */
> +	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
> +			   SAR_ADC_DELAY_KERNEL_BUSY,
> +			   SAR_ADC_DELAY_KERNEL_BUSY);
> +
> +	/* wait until BL30 releases it's lock (so we can use the SAR ADC) */
> +	do {
> +		udelay(1);
> +		regmap_read(priv->regmap, SAR_ADC_DELAY, &val);
> +	} while (val & SAR_ADC_DELAY_BL30_BUSY);
> +}
> +
> +static void meson_saradc_unlock(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +
> +	/* allow BL30 to use the SAR ADC again */
> +	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
> +			   SAR_ADC_DELAY_KERNEL_BUSY, 0);
> +
> +	mutex_unlock(&indio_dev->mlock);
> +}
> +
> +static int meson_saradc_get_sample(struct iio_dev *indio_dev,
> +				   const struct iio_chan_spec *chan,
> +				   enum meson_saradc_avg_mode avg_mode,
> +				   enum meson_saradc_num_samples avg_samples,
> +				   int *val)
> +{
> +	int ret, tmp;
> +
> +	meson_saradc_lock(indio_dev);
> +
> +	/* clear old values from the FIFO buffer, ignoring errors */
> +	meson_saradc_read_raw_sample(indio_dev, chan, &tmp);
> +
> +	meson_saradc_set_averaging(indio_dev, chan, avg_mode, avg_samples);
> +
> +	meson_saradc_enable_channel(indio_dev, chan);
> +
> +	meson_saradc_start_sample_engine(indio_dev);
> +	ret = meson_saradc_read_raw_sample(indio_dev, chan, val);
> +	meson_saradc_stop_sample_engine(indio_dev);
> +
> +	meson_saradc_unlock(indio_dev);
> +
> +	if (ret) {
> +		dev_warn(&indio_dev->dev,
> +			 "failed to read sample for channel %d: %d\n",
> +			 chan->channel, ret);
> +		return ret;
> +	}
> +
> +	return IIO_VAL_INT;
> +}
> +
> +static int meson_saradc_iio_info_read_raw(struct iio_dev *indio_dev,
> +					  const struct iio_chan_spec *chan,
> +					  int *val, int *val2, long mask)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	int ret;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		return meson_saradc_get_sample(indio_dev, chan, NO_AVERAGING,
> +					       ONE_SAMPLE, val);
> +		break;
> +
> +	case IIO_CHAN_INFO_AVERAGE_RAW:
> +		return meson_saradc_get_sample(indio_dev, chan, MEAN_AVERAGING,
> +					       EIGHT_SAMPLES, val);
> +		break;
> +
> +	case IIO_CHAN_INFO_SCALE:
> +		ret = regulator_get_voltage(priv->vref);
> +		if (ret < 0) {
> +			dev_err(&indio_dev->dev,
> +				"failed to get vref voltage: %d\n", ret);
> +			return ret;
> +		}
> +
> +		*val = ret / 1000;
> +		*val2 = priv->resolution;
> +		return IIO_VAL_FRACTIONAL_LOG2;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int meson_saradc_clk_init(struct iio_dev *indio_dev, void __iomem *base)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	struct clk_init_data init;
> +	char clk_name[32];
> +	const char *clk_parents[1];
> +
> +	snprintf(clk_name, sizeof(clk_name), "%s#adc_div",
> +		 of_node_full_name(indio_dev->dev.of_node));
> +	init.name = devm_kstrdup(&indio_dev->dev, clk_name, GFP_KERNEL);
> +	init.flags = 0;
> +	init.ops = &clk_divider_ops;
> +	clk_parents[0] = __clk_get_name(priv->clkin);
> +	init.parent_names = clk_parents;
> +	init.num_parents = 1;
> +
> +	priv->clk_div.reg = base + SAR_ADC_REG3;
> +	priv->clk_div.shift = SAR_ADC_REG3_ADC_CLK_DIV_SHIFT;
> +	priv->clk_div.width = SAR_ADC_REG3_ADC_CLK_DIV_WIDTH;
> +	priv->clk_div.hw.init = &init;
> +	priv->clk_div.flags = 0;
> +
> +	priv->adc_div_clk = devm_clk_register(&indio_dev->dev,
> +					      &priv->clk_div.hw);
> +	if (WARN_ON(IS_ERR(priv->adc_div_clk)))
> +		return PTR_ERR(priv->adc_div_clk);
> +
> +	snprintf(clk_name, sizeof(clk_name), "%s#adc_en",
> +		 of_node_full_name(indio_dev->dev.of_node));
> +	init.name = devm_kstrdup(&indio_dev->dev, clk_name, GFP_KERNEL);
> +	init.flags = CLK_SET_RATE_PARENT;
> +	init.ops = &clk_gate_ops;
> +	clk_parents[0] = __clk_get_name(priv->adc_div_clk);
> +	init.parent_names = clk_parents;
> +	init.num_parents = 1;
> +
> +	priv->clk_gate.reg = base + SAR_ADC_REG3;
> +	priv->clk_gate.bit_idx = fls(SAR_ADC_REG3_CLK_EN);
> +	priv->clk_gate.hw.init = &init;
> +
> +	priv->adc_clk = devm_clk_register(&indio_dev->dev, &priv->clk_gate.hw);
> +	if (WARN_ON(IS_ERR(priv->adc_clk)))
> +		return PTR_ERR(priv->adc_clk);
> +
> +	return 0;
> +}
> +
> +static int meson_saradc_init(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	int regval, ret;
> +
> +	/* make sure we start at CH7 input */
why?  Seems like a little more detail would be good here ;)
> +	meson_saradc_set_channel7_mux(indio_dev, CHAN7_MUX_CH7_INPUT);
> +
> +	regmap_read(priv->regmap, SAR_ADC_REG3, &regval);
> +	if (regval & SAR_ADC_REG3_BL30_INITIALIZED) {
> +		dev_info(&indio_dev->dev, "already initialized by BL30\n");
> +		return 0;
> +	}
> +
> +	dev_info(&indio_dev->dev, "initializing SAR ADC\n");
I'd argue this provides no useful info so should be dropped.
Useful for debugging no doubt, but just noise going forward.
> +
> +	meson_saradc_stop_sample_engine(indio_dev);
> +
> +	/* update the channel 6 MUX to select the temperature sensor */
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG0,
> +			SAR_ADC_REG0_ADC_TEMP_SEN_SEL,
> +			SAR_ADC_REG0_ADC_TEMP_SEN_SEL);
> +
> +	/* disable all channels by default */
> +	regmap_write(priv->regmap, SAR_ADC_CHAN_LIST, 0x0);
> +
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG3,
> +			   SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE, 0);
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG3,
> +			   SAR_ADC_REG3_CNTL_USE_SC_DLY,
> +			   SAR_ADC_REG3_CNTL_USE_SC_DLY);
> +
> +	/* delay between two samples = (10+1) * 1uS */
> +	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
> +			   SAR_ADC_DELAY_INPUT_DLY_CNT_MASK,
> +			   FIELD_PREP(SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK, 10));
> +	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
> +			   SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK,
> +			   FIELD_PREP(SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK, 0));
> +
> +	/* delay between two samples = (10+1) * 1uS */
> +	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
> +			   SAR_ADC_DELAY_INPUT_DLY_CNT_MASK,
> +			   FIELD_PREP(SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, 10));
> +	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
> +			   SAR_ADC_DELAY_INPUT_DLY_SEL_MASK,
> +			   FIELD_PREP(SAR_ADC_DELAY_INPUT_DLY_SEL_MASK, 1));
> +
Cool. I hadn't come across FIELD_PREP before. Neater and tidier than having
a shift and a mask for at least some usecases.

> +	ret = clk_set_parent(priv->adc_sel_clk, priv->clkin);
> +	if (ret) {
> +		dev_err(&indio_dev->dev,
> +			"failed to set adc parent to clkin\n");
> +		return ret;
> +	}
> +
> +	ret = clk_set_rate(priv->adc_clk, 1200000);
> +	if (ret) {
> +		dev_err(&indio_dev->dev, "failed to set adc clock rate\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int meson_saradc_hw_enable(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	int ret;
> +
> +	meson_saradc_lock(indio_dev);
> +
> +	ret = regulator_enable(priv->vref);
> +	if (ret < 0) {
> +		dev_err(&indio_dev->dev, "failed to enable vref regulator\n");
> +		goto err_vref;
> +	}
> +
> +	ret = clk_prepare_enable(priv->core_clk);
> +	if (ret) {
> +		dev_err(&indio_dev->dev, "failed to enable core clk\n");
> +		goto err_core_clk;
> +	}
> +
> +	ret = clk_prepare_enable(priv->sana_clk);
> +	if (ret) {
> +		dev_err(&indio_dev->dev, "failed to enable sana clk\n");
> +		goto err_sana_clk;
> +	}
> +
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG11,
> +			   SAR_ADC_REG11_BANDGAP_EN, SAR_ADC_REG11_BANDGAP_EN);
Is this controlling an offset for a bandgap or some actual electronics?
Not sure if it should be disabled on error and the datasheets I've found are
far from great!  You disable it in the disable, so I'd expect it to be
unwound on error in here too.
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG3, SAR_ADC_REG3_ADC_EN,
> +			   SAR_ADC_REG3_ADC_EN);
The fact you turn this of in the disable suggests to me that on error
you should be doing it in here too.
> +
> +	udelay(5);
> +
> +	ret = clk_prepare_enable(priv->adc_clk);
> +	if (ret) {
> +		dev_err(&indio_dev->dev, "failed to enable adc_en clk\n");
> +		goto err_adc_clk;
> +	}
> +
> +	meson_saradc_unlock(indio_dev);
> +
> +	return 0;
> +
> +err_adc_clk:
> +	clk_disable_unprepare(priv->sana_clk);
> +err_sana_clk:
> +	clk_disable_unprepare(priv->core_clk);
> +err_core_clk:
> +	regulator_disable(priv->vref);
> +err_vref:
> +	meson_saradc_unlock(indio_dev);
> +	return ret;
> +}
> +
> +static void meson_saradc_hw_disable(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +
> +	meson_saradc_lock(indio_dev);
> +
> +	clk_disable_unprepare(priv->adc_clk);
> +
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG3, SAR_ADC_REG3_ADC_EN, 0);
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG11,
> +			   SAR_ADC_REG11_BANDGAP_EN, 0);
> +
> +	clk_disable_unprepare(priv->sana_clk);
> +	clk_disable_unprepare(priv->core_clk);
> +
> +	regulator_disable(priv->vref);
> +
> +	meson_saradc_unlock(indio_dev);
> +}
> +
> +static const struct iio_info meson_saradc_iio_info = {
> +	.read_raw = meson_saradc_iio_info_read_raw,
> +	.driver_module = THIS_MODULE,
> +};
> +
> +static const struct of_device_id meson_saradc_of_match[] = {
> +	{
> +		.compatible = "amlogic,meson-gxbb-saradc",
> +		.data = (void *)10,
Might have been worth having a structure array indexed from an enum.
For now it is overkill, but seems likely there are a few other differences
that aren't supported yet?
> +	}, {
> +		.compatible = "amlogic,meson-gxl-saradc",
> +		.data = (void *)12,
> +	},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, meson_saradc_of_match);
> +
> +static int meson_saradc_probe(struct platform_device *pdev)
> +{
> +	struct meson_saradc_priv *priv;
> +	struct iio_dev *indio_dev;
> +	struct resource *res;
> +	void __iomem *base;
> +	const struct of_device_id *match;
> +	int ret;
> +
> +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
> +	if (!indio_dev) {
> +		dev_err(&pdev->dev, "failed allocating iio device\n");
> +		return -ENOMEM;
> +	}
> +
> +	priv = iio_priv(indio_dev);
> +
> +	match = of_match_device(meson_saradc_of_match, &pdev->dev);
> +	priv->resolution = (unsigned long)match->data;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(base))
> +		return PTR_ERR(base);
> +
> +	priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
> +					     &meson_saradc_regmap_config);
> +	if (IS_ERR(priv->regmap))
> +		return PTR_ERR(priv->regmap);
> +
> +	init_completion(&priv->completion);
> +
> +	priv->clkin = devm_clk_get(&pdev->dev, "clkin");
> +	if (IS_ERR(priv->clkin)) {
> +		dev_err(&pdev->dev, "failed to get clkin\n");
> +		return PTR_ERR(priv->clkin);
> +	}
> +
> +	priv->core_clk = devm_clk_get(&pdev->dev, "core");
> +	if (IS_ERR(priv->core_clk)) {
> +		dev_err(&pdev->dev, "failed to get core clk\n");
> +		return PTR_ERR(priv->core_clk);
> +	}
> +
> +	priv->sana_clk = devm_clk_get(&pdev->dev, "sana");
Oh for a devm_clk_get_optional to handle this boiler plate neatly.
It's been suggested before, but nothing seems to have come of it.

Some array clk get functions might also clean this up a touch.

> +	if (IS_ERR(priv->sana_clk)) {
> +		if (PTR_ERR(priv->sana_clk) == -ENOENT) {
> +			priv->sana_clk = NULL;
> +		} else {
> +			dev_err(&pdev->dev, "failed to get sana clk\n");
> +			return PTR_ERR(priv->sana_clk);
> +		}
> +	}
> +
> +	priv->adc_clk = devm_clk_get(&pdev->dev, "adc_clk");
> +	if (IS_ERR(priv->adc_clk)) {
> +		if (PTR_ERR(priv->adc_clk) == -ENOENT) {
> +			priv->adc_clk = NULL;
> +		} else {
> +			dev_err(&pdev->dev, "failed to get adc clk\n");
> +			return PTR_ERR(priv->adc_clk);
> +		}
> +	}
> +
> +	priv->adc_sel_clk = devm_clk_get(&pdev->dev, "adc_sel");
> +	if (IS_ERR(priv->adc_sel_clk)) {
> +		if (PTR_ERR(priv->adc_sel_clk) == -ENOENT) {
> +			priv->adc_sel_clk = NULL;
> +		} else {
> +			dev_err(&pdev->dev, "failed to get adc_sel clk\n");
> +			return PTR_ERR(priv->adc_sel_clk);
> +		}
> +	}
> +
> +	/* on pre-GXBB SoCs the SAR ADC itself provides the ADC clock: */
> +	if (!priv->adc_clk) {
> +		ret = meson_saradc_clk_init(indio_dev, base);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	priv->vref = devm_regulator_get(&pdev->dev, "vref");
> +	if (IS_ERR(priv->vref)) {
> +		dev_err(&pdev->dev, "failed to get vref regulator\n");
> +		return PTR_ERR(priv->vref);
> +	}
> +
> +	ret = meson_saradc_init(indio_dev);
> +	if (ret)
> +		goto err;
> +
> +	ret = meson_saradc_hw_enable(indio_dev);
> +	if (ret)
> +		goto err;
> +
> +	platform_set_drvdata(pdev, indio_dev);
> +
> +	indio_dev->name = dev_name(&pdev->dev);
> +	indio_dev->dev.parent = &pdev->dev;
> +	indio_dev->dev.of_node = pdev->dev.of_node;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->info = &meson_saradc_iio_info;
> +
> +	indio_dev->channels = meson_saradc_iio_channels;
> +	indio_dev->num_channels = SAR_ADC_NUM_CHANNELS;
> +
> +	ret = iio_device_register(indio_dev);
> +	if (ret)
> +		goto err_hw;
> +
> +	return 0;
> +
> +err_hw:
> +	meson_saradc_hw_disable(indio_dev);
> +err:
> +	return ret;
> +}
> +
> +static int meson_saradc_remove(struct platform_device *pdev)
> +{
> +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> +
> +	meson_saradc_hw_disable(indio_dev);
> +	iio_device_unregister(indio_dev);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int meson_saradc_suspend(struct device *dev)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +
> +	meson_saradc_hw_disable(indio_dev);
> +
> +	return 0;
> +}
> +
> +static int meson_saradc_resume(struct device *dev)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +
> +	return meson_saradc_hw_enable(indio_dev);
> +}
> +#endif /* CONFIG_PM_SLEEP */
> +
> +static SIMPLE_DEV_PM_OPS(meson_saradc_pm_ops,
> +			 meson_saradc_suspend, meson_saradc_resume);
> +
> +static struct platform_driver meson_saradc_driver = {
> +	.probe		= meson_saradc_probe,
> +	.remove		= meson_saradc_remove,
> +	.driver		= {
> +		.name	= "meson-saradc",
> +		.of_match_table = meson_saradc_of_match,
> +		.pm = &meson_saradc_pm_ops,
> +	},
> +};
> +
> +module_platform_driver(meson_saradc_driver);
> +
> +MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
> +MODULE_DESCRIPTION("Amlogic Meson SAR ADC driver");
> +MODULE_LICENSE("GPL v2");
> 


^ permalink raw reply

* Re: [PATCH v2 5/6] arm: dts: mt2701: Add ethernet device node.
From: Sean Wang @ 2017-01-14 16:10 UTC (permalink / raw)
  To: John Crispin
  Cc: Erin Lo, Matthias Brugger, devicetree, srv_heupstream,
	linux-kernel, linux-mediatek, linux-arm-kernel
In-Reply-To: <f9f5616f-a327-be4d-3d1d-4555e67d123a@phrozen.org>

Hi John,

the watchdog driver should just be the driver that includes
reset functions called from driver and then send reset signal
to abnormal hw.. 

however luckily ETHDMA_RST provided from watchdog is not required
and even actually the latest driver didn't refer to the property
no longer. So i will remove it from dtsi in the next version 

  Sean


On Sat, 2017-01-14 at 11:32 +0100, John Crispin wrote:
> Hi Erin,
> 
> small comment inline
> 
> On 13/01/2017 09:42, Erin Lo wrote:
> > From: Sean Wang <sean.wang@mediatek.com>
> > 
> > Add ethernet device node for MT2701.
> > 
> > Signed-off-by: Sean Wang <sean.wang@mediatek.com>
> > Signed-off-by: Erin Lo <erin.lo@mediatek.com>
> > ---
> >  arch/arm/boot/dts/mt2701-evb.dts | 40 ++++++++++++++++++++++++++++++++++++++++
> >  arch/arm/boot/dts/mt2701.dtsi    | 22 ++++++++++++++++++++++
> >  2 files changed, 62 insertions(+)
> > 
> > diff --git a/arch/arm/boot/dts/mt2701-evb.dts b/arch/arm/boot/dts/mt2701-evb.dts
> > index a483798..40abd3b 100644
> > --- a/arch/arm/boot/dts/mt2701-evb.dts
> > +++ b/arch/arm/boot/dts/mt2701-evb.dts
> > @@ -28,7 +28,47 @@
> >  	status = "okay";
> >  };
> >  
> > +&eth {
> > +	mac-address = [00 00 00 00 00 00];
> > +	status = "okay";
> > +	pinctrl-names = "default";
> > +	pinctrl-0 = <&gmac1_pins>;
> > +	gmac1: mac@1 {
> > +		compatible = "mediatek,eth-mac";
> > +		reg = <1>;
> > +		phy-handle = <&phy5>;
> > +	};
> > +
> > +	mdio-bus {
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +		phy5: ethernet-phy@5 {
> > +			reg = <5>;
> > +			phy-mode = "rgmii-rxid";
> > +		};
> > +	};
> > +};
> > +
> >  &pio {
> > +	gmac1_pins: eth@0 {
> > +		pins_eth {
> > +			pinmux = <MT2701_PIN_275_MDC__FUNC_MDC>,
> > +				 <MT2701_PIN_276_MDIO__FUNC_MDIO>,
> > +				 <MT2701_PIN_262_G2_TXEN__FUNC_G2_TXEN>,
> > +				 <MT2701_PIN_263_G2_TXD3__FUNC_G2_TXD3>,
> > +				 <MT2701_PIN_264_G2_TXD2__FUNC_G2_TXD2>,
> > +				 <MT2701_PIN_265_G2_TXD1__FUNC_G2_TXD1>,
> > +				 <MT2701_PIN_266_G2_TXD0__FUNC_G2_TXD0>,
> > +				 <MT2701_PIN_267_G2_TXC__FUNC_G2_TXC>,
> > +				 <MT2701_PIN_268_G2_RXC__FUNC_G2_RXC>,
> > +				 <MT2701_PIN_269_G2_RXD0__FUNC_G2_RXD0>,
> > +				 <MT2701_PIN_270_G2_RXD1__FUNC_G2_RXD1>,
> > +				 <MT2701_PIN_271_G2_RXD2__FUNC_G2_RXD2>,
> > +				 <MT2701_PIN_272_G2_RXD3__FUNC_G2_RXD3>,
> > +				 <MT2701_PIN_274_G2_RXDV__FUNC_G2_RXDV>;
> > +		};
> > +	};
> > +
> >  	spi_pins_a: spi0@0 {
> >  		pins_spi {
> >  			pinmux = <MT2701_PIN_53_SPI0_CSN__FUNC_SPI0_CS>,
> > diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
> > index 4f52019..3847f70 100644
> > --- a/arch/arm/boot/dts/mt2701.dtsi
> > +++ b/arch/arm/boot/dts/mt2701.dtsi
> > @@ -381,6 +381,28 @@
> >  		#clock-cells = <1>;
> >  	};
> >  
> > +	eth: ethernet@1b100000 {
> > +		compatible = "mediatek,mt7623-eth";
> > +		reg = <0 0x1b100000 0 0x20000>;
> > +		interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_LOW>,
> > +			     <GIC_SPI 199 IRQ_TYPE_LEVEL_LOW>,
> > +			     <GIC_SPI 198 IRQ_TYPE_LEVEL_LOW>;
> > +		clocks = <&topckgen CLK_TOP_ETHIF_SEL>,
> > +			 <&apmixedsys CLK_APMIXED_TRGPLL>,
> > +			 <&ethsys CLK_ETHSYS_ESW>,
> > +			 <&ethsys CLK_ETHSYS_GP2>,
> > +			 <&ethsys CLK_ETHSYS_GP1>;
> > +		clock-names = "ethif", "trgpll", "esw", "gp2", "gp1";
> > +		power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>;
> > +		resets = <&watchdog MT2701_TOPRGU_ETHDMA_RST>;
> 
> are you sure this is correct ? on mt7623 we point the reset at ethsys
> and not the watchdog.
> 
> 	John
> 
> > +		reset-names = "eth";
> > +		mediatek,ethsys = <&ethsys>;
> > +		mediatek,pctl = <&syscfg_pctl_a>;
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +		status = "disabled";
> > +	};
> > +
> >  	bdpsys: syscon@1c000000 {
> >  		compatible = "mediatek,mt2701-bdpsys", "syscon";
> >  		reg = <0 0x1c000000 0 0x1000>;
> > 

^ permalink raw reply

* Re: [PATCH 3/4] iio: adc: add a driver for the SAR ADC found in Amlogic Meson SoCs
From: Martin Blumenstingl @ 2017-01-14 17:44 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: knaack.h-Mmb7MZpHnFY, lars-Qo5EllUWu/uELgA04lAiVw,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, khilman-rdvid1DuHRBWk0Htik3J/w,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-clk-u79uwXL29TY76Z2rM5mHXA, carlo-KA+7E9HrN00dnm+yROfE0A,
	catalin.marinas-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
	mturquette-rdvid1DuHRBWk0Htik3J/w, sboyd-sgV2jX0FEOL9JmXXK+q4OQ,
	narmstrong-rdvid1DuHRBWk0Htik3J/w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Russell King
In-Reply-To: <870f8899-b3a1-153a-5953-88ac23ff6942-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

Hi Jonathan,

thank you for the review!
(further comments from me inline)
I think I'll send an updated version on Monday.

On Sat, Jan 14, 2017 at 3:46 PM, Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> On 11/01/17 17:43, Martin Blumenstingl wrote:
>> This adds support for the SAR (Successive Approximation Register) ADC
>> on the Amlogic Meson SoCs.
>>
>> The code is based on the public S805 (Meson8b) and S905 (GXBB)
>> datasheets, as well as by reading (various versions of) the vendor
>> driver and by inspecting the registers on the vendor kernels of my
>> testing-hardware.
>>
>> Currently the GXBB, GXL and GXM SoCs are supported. GXBB hardware has
>> 10-bit ADC resolution, while GXL and GXM have 12-bit ADC resolution.
>> The code was written to support older SoCs (Meson8 and Meson8b) as well,
>> but due to lack of actual testing-hardware no of_device_id was added for
>> these.
>>
>> Two "features" from the vendor driver are currently missing:
>> - the vendor driver uses channel #7 for calibration (this improves the
>>   accuracy of the results - in my tests the results were less than 3%
>>   off without calibration compared to the vendor driver). Adding support
>>   for this should be easy, but is not required for most applications.
>> - channel #6 is connected to the SoCs internal temperature sensor.
>>   Adding support for this is probably not so easy since (based on the
>>   u-boot sources) most SoC versions are using different registers and
>>   algorithms for the conversion from "ADC value" to temperature.
>>
>> Supported by the hardware but currently not supported by the driver:
>> - reading multiple channels at the same time (the hardware has a FIFO
>>   buffer which stores multiple results)
>> - continuous sampling (this would require a way to enable this
>>   individually because otherwise the ADC would be drawing power
>>   constantly)
>> - interrupt support (similar to the vendor driver this new driver is
>>   polling the results. It is unclear if the IRQ-mode is supported on
>>   older (Meson6 or Meson8) hardware as well or if there are any errata)
>>
> Russell Cc'd for a quick question on the clk api.
a quick side-note the clk API: my driver is a clock consumer and
provider at the same time. This seems to be a recurring pattern in
Amlogic hardware designs (as the MMC and DWMAC glue drivers are doing
this also), see [0]

> Ideally include a source for datasheets if available. Saves time googling and
> perhaps getting the wrong thing!
OK, will do this in v2

> A few other minor comments inline. Pretty good V1.
thanks :-)

> Jonathan
>> Signed-off-by: Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
>> ---
>>  drivers/iio/adc/Kconfig        |  12 +
>>  drivers/iio/adc/Makefile       |   1 +
>>  drivers/iio/adc/meson_saradc.c | 860 +++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 873 insertions(+)
>>  create mode 100644 drivers/iio/adc/meson_saradc.c
>>
>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> index 9c8b558ba19e..86059b9b91bf 100644
>> --- a/drivers/iio/adc/Kconfig
>> +++ b/drivers/iio/adc/Kconfig
>> @@ -371,6 +371,18 @@ config MEN_Z188_ADC
>>         This driver can also be built as a module. If so, the module will be
>>         called men_z188_adc.
>>
>> +config MESON_SARADC
>> +     tristate "Amlogic Meson SAR ADC driver"
>> +     default ARCH_MESON
>> +     depends on OF && COMMON_CLK && (ARCH_MESON || COMPILE_TEST)
>> +     select REGMAP_MMIO
>> +     help
>> +       Say yes here to build support for the SAR ADC found in Amlogic Meson
>> +       SoCs.
>> +
>> +       To compile this driver as a module, choose M here: the
>> +       module will be called meson_saradc.
>> +
>>  config MXS_LRADC
>>          tristate "Freescale i.MX23/i.MX28 LRADC"
>>          depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM
>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>> index d36c4be8d1fc..de05b9e75f8f 100644
>> --- a/drivers/iio/adc/Makefile
>> +++ b/drivers/iio/adc/Makefile
>> @@ -36,6 +36,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
>>  obj-$(CONFIG_MCP3422) += mcp3422.o
>>  obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
>>  obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
>> +obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
>>  obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
>>  obj-$(CONFIG_NAU7802) += nau7802.o
>>  obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
>> diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
>> new file mode 100644
>> index 000000000000..06e8ac620385
>> --- /dev/null
>> +++ b/drivers/iio/adc/meson_saradc.c
>> @@ -0,0 +1,860 @@
>> +/*
>> + * Amlogic Meson Successive Approximation Register (SAR) A/D Converter
>> + *
>> + * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@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.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/bitfield.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/io.h>
>> +#include <linux/iio/iio.h>
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/clk.h>
>> +#include <linux/completion.h>
>> +#include <linux/delay.h>
>> +#include <linux/reset.h>
>> +#include <linux/regmap.h>
>> +#include <linux/regulator/consumer.h>
>> +
>> +#define SAR_ADC_REG0                                         0x00
>> +     #define SAR_ADC_REG0_PANEL_DETECT                       BIT(31)
>> +     #define SAR_ADC_REG0_BUSY_MASK                          GENMASK(30, 28)
>> +     #define SAR_ADC_REG0_DELTA_BUSY                         BIT(30)
>> +     #define SAR_ADC_REG0_AVG_BUSY                           BIT(29)
>> +     #define SAR_ADC_REG0_SAMPLE_BUSY                        BIT(28)
>> +     #define SAR_ADC_REG0_FIFO_FULL                          BIT(27)
>> +     #define SAR_ADC_REG0_FIFO_EMPTY                         BIT(26)
>> +     #define SAR_ADC_REG0_FIFO_COUNT_MASK                    GENMASK(25, 21)
>> +     #define SAR_ADC_REG0_ADC_BIAS_CTRL_MASK                 GENMASK(20, 19)
>> +     #define SAR_ADC_REG0_CURR_CHAN_ID_MASK                  GENMASK(18, 16)
>> +     #define SAR_ADC_REG0_ADC_TEMP_SEN_SEL                   BIT(15)
>> +     #define SAR_ADC_REG0_SAMPLING_STOP                      BIT(14)
>> +     #define SAR_ADC_REG0_CHAN_DELTA_EN_MASK                 GENMASK(13, 12)
>> +     #define SAR_ADC_REG0_DETECT_IRQ_POL                     BIT(10)
>> +     #define SAR_ADC_REG0_DETECT_IRQ_EN                      BIT(9)
>> +     #define SAR_ADC_REG0_FIFO_CNT_IRQ_MASK                  GENMASK(8, 4)
>> +     #define SAR_ADC_REG0_FIFO_IRQ_EN                        BIT(3)
>> +     #define SAR_ADC_REG0_SAMPLING_START                     BIT(2)
>> +     #define SAR_ADC_REG0_CONTINUOUS_EN                      BIT(1)
>> +     #define SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE               BIT(0)
>> +
>> +#define SAR_ADC_CHAN_LIST                                    0x04
>> +     #define SAR_ADC_CHAN_LIST_MAX_INDEX_MASK                GENMASK(26, 24)
>> +     #define SAR_ADC_CHAN_CHAN_ENTRY_MASK(_chan)             \
>> +                                     (GENMASK(2, 0) << (_chan * 3))
>> +
>> +#define SAR_ADC_AVG_CNTL                                     0x08
>> +     #define SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(_chan)          \
>> +                                     (16 + (_chan * 2))
>> +     #define SAR_ADC_AVG_CNTL_AVG_MODE_MASK(_chan)           \
>> +                                     (GENMASK(17, 16) << (_chan * 2))
>> +     #define SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(_chan)       \
>> +                                     (0 + (_chan * 2))
>> +     #define SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(_chan)        \
>> +                                     (GENMASK(1, 0) << (_chan * 2))
>> +
>> +#define SAR_ADC_REG3                                         0x0c
>> +     #define SAR_ADC_REG3_CNTL_USE_SC_DLY                    BIT(31)
>> +     #define SAR_ADC_REG3_CLK_EN                             BIT(30)
>> +     #define SAR_ADC_REG3_BL30_INITIALIZED                   BIT(28)
>> +     #define SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN          BIT(27)
>> +     #define SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE          BIT(26)
>> +     #define SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK            GENMASK(25, 23)
>> +     #define SAR_ADC_REG3_DETECT_EN                          BIT(22)
>> +     #define SAR_ADC_REG3_ADC_EN                             BIT(21)
>> +     #define SAR_ADC_REG3_PANEL_DETECT_COUNT_MASK            GENMASK(20, 18)
>> +     #define SAR_ADC_REG3_PANEL_DETECT_FILTER_TB_MASK        GENMASK(17, 16)
>> +     #define SAR_ADC_REG3_ADC_CLK_DIV_SHIFT                  10
>> +     #define SAR_ADC_REG3_ADC_CLK_DIV_WIDTH                  5
>> +     #define SAR_ADC_REG3_ADC_CLK_DIV_MASK                   GENMASK(15, 10)
>> +     #define SAR_ADC_REG3_BLOCK_DLY_SEL_MASK                 GENMASK(9, 8)
>> +     #define SAR_ADC_REG3_BLOCK_DLY_MASK                     GENMASK(7, 0)
>> +
>> +#define SAR_ADC_DELAY                                                0x10
>> +     #define SAR_ADC_DELAY_INPUT_DLY_SEL_MASK                GENMASK(25, 24)
>> +     #define SAR_ADC_DELAY_BL30_BUSY                         BIT(15)
>> +     #define SAR_ADC_DELAY_KERNEL_BUSY                       BIT(14)
>> +     #define SAR_ADC_DELAY_INPUT_DLY_CNT_MASK                GENMASK(23, 16)
>> +     #define SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK               GENMASK(9, 8)
>> +     #define SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK               GENMASK(7, 0)
>> +
>> +#define SAR_ADC_LAST_RD                                              0x14
>> +     #define SAR_ADC_LAST_RD_LAST_CHANNEL1_MASK              GENMASK(23, 16)
>> +     #define SAR_ADC_LAST_RD_LAST_CHANNEL0_MASK              GENMASK(9, 0)
>> +
>> +#define SAR_ADC_FIFO_RD                                              0x18
>> +     #define SAR_ADC_FIFO_RD_CHAN_ID_MASK                    GENMASK(14, 12)
>> +     #define SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK               GENMASK(11, 0)
>> +
>> +#define SAR_ADC_AUX_SW                                               0x1c
>> +     #define SAR_ADC_AUX_SW_MUX_SEL_CHAN_MASK(_chan)         \
>> +                                     (GENMASK(10, 8) << ((_chan - 2) * 2))
>> +     #define SAR_ADC_AUX_SW_VREF_P_MUX                       BIT(6)
>> +     #define SAR_ADC_AUX_SW_VREF_N_MUX                       BIT(5)
>> +     #define SAR_ADC_AUX_SW_MODE_SEL                         BIT(4)
>> +     #define SAR_ADC_AUX_SW_YP_DRIVE_SW                      BIT(3)
>> +     #define SAR_ADC_AUX_SW_XP_DRIVE_SW                      BIT(2)
>> +     #define SAR_ADC_AUX_SW_YM_DRIVE_SW                      BIT(1)
>> +     #define SAR_ADC_AUX_SW_XM_DRIVE_SW                      BIT(0)
>> +
>> +#define SAR_ADC_CHAN_10_SW                                   0x20
>> +     #define SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK           GENMASK(25, 23)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN1_VREF_P_MUX             BIT(22)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN1_VREF_N_MUX             BIT(21)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN1_MODE_SEL               BIT(20)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW            BIT(19)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW            BIT(18)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN1_YM_DRIVE_SW            BIT(17)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN1_XM_DRIVE_SW            BIT(16)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK           GENMASK(9, 7)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN0_VREF_P_MUX             BIT(6)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN0_VREF_N_MUX             BIT(5)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN0_MODE_SEL               BIT(4)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW            BIT(3)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW            BIT(2)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN0_YM_DRIVE_SW            BIT(1)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN0_XM_DRIVE_SW            BIT(0)
>> +
>> +#define SAR_ADC_DETECT_IDLE_SW                                       0x24
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_SW_EN             BIT(26)
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_MUX_MASK     GENMASK(25, 23)
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_VREF_P_MUX   BIT(22)
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_VREF_N_MUX   BIT(21)
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_SEL          BIT(20)
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_YP_DRIVE_SW  BIT(19)
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_XP_DRIVE_SW  BIT(18)
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_YM_DRIVE_SW  BIT(17)
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_XM_DRIVE_SW  BIT(16)
>> +     #define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_MUX_SEL_MASK   GENMASK(9, 7)
>> +     #define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_VREF_P_MUX     BIT(6)
>> +     #define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_VREF_N_MUX     BIT(5)
>> +     #define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_SEL            BIT(4)
>> +     #define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_YP_DRIVE_SW    BIT(3)
>> +     #define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_XP_DRIVE_SW    BIT(2)
>> +     #define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_YM_DRIVE_SW    BIT(1)
>> +     #define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_XM_DRIVE_SW    BIT(0)
>> +
>> +#define SAR_ADC_DELTA_10                                     0x28
>> +     #define SAR_ADC_DELTA_10_TEMP_SEL                       BIT(27)
>> +     #define SAR_ADC_DELTA_10_TS_REVE1                       BIT(26)
>> +     #define SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_SHIFT        16
>> +     #define SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_MASK         GENMASK(25, 16)
>> +     #define SAR_ADC_DELTA_10_TS_REVE0                       BIT(15)
>> +     #define SAR_ADC_DELTA_10_TS_C_SHIFT                     11
>> +     #define SAR_ADC_DELTA_10_TS_C_MASK                      GENMASK(14, 11)
>> +     #define SAR_ADC_DELTA_10_TS_VBG_EN                      BIT(10)
>> +     #define SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_SHIFT        0
>> +     #define SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_MASK         GENMASK(9, 0)
>> +
>> +/* NOTE: registers from here are undocumented (the vendor Linux kernel driver
>> + * and u-boot source served as reference). These only seem to be relevant on
>> + * GXBB and newer.
>> + */
>> +#define SAR_ADC_REG11                                                0x2c
>> +     #define SAR_ADC_REG11_BANDGAP_EN                        BIT(13)
>> +
>> +#define SAR_ADC_REG13                                                0x34
>> +     #define SAR_ADC_REG13_12BIT_CALIBRATION_MASK            GENMASK(13, 8)
>> +
>> +#define SAR_ADC_MAX_FIFO_SIZE                32
>> +#define SAR_ADC_NUM_CHANNELS         ARRAY_SIZE(meson_saradc_iio_channels)
>> +#define SAR_ADC_VALUE_MASK(_priv)    (BIT(_priv->resolution) - 1)
>> +
>> +#define MESON_SAR_ADC_CHAN(_chan, _type) {                           \
>> +     .type = _type,                                                  \
>> +     .indexed = true,                                                \
>> +     .channel = _chan,                                               \
>> +     .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |                  \
>> +                             BIT(IIO_CHAN_INFO_AVERAGE_RAW),         \
>> +     .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),           \
>> +     .datasheet_name = "SAR_ADC_CH"#_chan,                           \
>> +}
>> +
>> +/* TODO: the hardware supports IIO_TEMP for channel 6 as well which is
> Multline comment syntax.
I got this wrong in 2 other places as well. will be fixed in v2, thanks!

>> + * currently not supported by this driver.
>> + */
>> +static const struct iio_chan_spec meson_saradc_iio_channels[] = {
>> +     MESON_SAR_ADC_CHAN(0, IIO_VOLTAGE),
>> +     MESON_SAR_ADC_CHAN(1, IIO_VOLTAGE),
>> +     MESON_SAR_ADC_CHAN(2, IIO_VOLTAGE),
>> +     MESON_SAR_ADC_CHAN(3, IIO_VOLTAGE),
>> +     MESON_SAR_ADC_CHAN(4, IIO_VOLTAGE),
>> +     MESON_SAR_ADC_CHAN(5, IIO_VOLTAGE),
>> +     MESON_SAR_ADC_CHAN(6, IIO_VOLTAGE),
>> +     MESON_SAR_ADC_CHAN(7, IIO_VOLTAGE),
>> +     IIO_CHAN_SOFT_TIMESTAMP(8),
>> +};
>> +
>> +enum meson_saradc_avg_mode {
>> +     NO_AVERAGING = 0x0,
>> +     MEAN_AVERAGING = 0x1,
>> +     MEDIAN_AVERAGING = 0x2,
>> +};
>> +
>> +enum meson_saradc_num_samples {
>> +     ONE_SAMPLE = 0x0,
>> +     TWO_SAMPLES = 0x1,
>> +     FOUR_SAMPLES = 0x2,
>> +     EIGHT_SAMPLES = 0x3,
>> +};
>> +
>> +enum meson_saradc_chan7_mux_sel {
>> +     CHAN7_MUX_VSS = 0x0,
>> +     CHAN7_MUX_VDD_DIV4 = 0x1,
>> +     CHAN7_MUX_VDD_DIV2 = 0x2,
>> +     CHAN7_MUX_VDD_MUL3_DIV4 = 0x3,
>> +     CHAN7_MUX_VDD = 0x4,
>> +     CHAN7_MUX_CH7_INPUT = 0x7,
>> +};
>> +
>> +struct meson_saradc_priv {
>> +     struct regmap                   *regmap;
>> +     struct clk                      *clkin;
>> +     struct clk                      *core_clk;
>> +     struct clk                      *sana_clk;
>> +     struct clk                      *adc_sel_clk;
>> +     struct clk                      *adc_clk;
>> +     struct clk_gate                 clk_gate;
>> +     struct clk                      *adc_div_clk;
>> +     struct clk_divider              clk_div;
>> +     struct regulator                *vref;
>> +     struct completion               completion;
>> +     u8                              resolution;
>> +};
>> +
>> +static const struct regmap_config meson_saradc_regmap_config = {
>> +     .reg_bits = 8,
>> +     .val_bits = 32,
>> +     .reg_stride = 4,
>> +     .max_register = SAR_ADC_REG13,
>> +};
>> +
>> +static unsigned int meson_saradc_get_fifo_count(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     u32 regval;
>> +
>> +     regmap_read(priv->regmap, SAR_ADC_REG0, &regval);
>> +
>> +     return FIELD_GET(SAR_ADC_REG0_FIFO_COUNT_MASK, regval);
>> +}
>> +
>> +static int meson_saradc_wait_busy_clear(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     int regval, timeout = 10000;
>> +
>> +     do {
>> +             udelay(1);
>> +             regmap_read(priv->regmap, SAR_ADC_REG0, &regval);
>> +     } while (FIELD_GET(SAR_ADC_REG0_BUSY_MASK, regval) && timeout--);
>> +
>> +     if (timeout < 0)
>> +             return -ETIMEDOUT;
>> +
>> +     return 0;
>> +}
>> +
>> +static int meson_saradc_read_raw_sample(struct iio_dev *indio_dev,
>> +                                     const struct iio_chan_spec *chan,
>> +                                     int *val)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     int ret, regval, fifo_chan, fifo_val, sum = 0, count = 0;
>> +
>> +     ret = meson_saradc_wait_busy_clear(indio_dev);
>> +     if (ret)
>> +             return ret;
>> +
>> +     regmap_read(priv->regmap, SAR_ADC_REG0, &regval);
>> +
>> +     while (meson_saradc_get_fifo_count(indio_dev) > 0 &&
>> +            count < SAR_ADC_MAX_FIFO_SIZE) {
>> +             regmap_read(priv->regmap, SAR_ADC_FIFO_RD, &regval);
>> +
>> +             fifo_chan = FIELD_GET(SAR_ADC_FIFO_RD_CHAN_ID_MASK, regval);
>> +             if (fifo_chan == chan->channel) {
>> +                     fifo_val = FIELD_GET(SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK,
>> +                                          regval) & SAR_ADC_VALUE_MASK(priv);
>> +                     sum += fifo_val;
>> +                     count++;
>> +             }
>> +     }
>> +
>> +     if (!count)
>> +             return -ENOENT;
>> +
>> +     *val = sum / count;
>> +
>> +     return 0;
>> +}
>> +
>> +static void meson_saradc_set_averaging(struct iio_dev *indio_dev,
>> +                                    const struct iio_chan_spec *chan,
>> +                                    enum meson_saradc_avg_mode mode,
>> +                                    enum meson_saradc_num_samples samples)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     u32 val;
>> +
>> +     val = samples << SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(chan->channel);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_AVG_CNTL,
>> +                        SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(chan->channel),
>> +                        val);
>> +
>> +     val = mode << SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(chan->channel);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_AVG_CNTL,
>> +                        SAR_ADC_AVG_CNTL_AVG_MODE_MASK(chan->channel), val);
>> +}
>> +
>> +static void meson_saradc_enable_channel(struct iio_dev *indio_dev,
>> +                                     const struct iio_chan_spec *chan)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     u32 regval;
>> +
>> +     /* the SAR ADC engine allows sampling multiple channels at the same
>> +      * time. to keep it simple we're only working with one *internal*
>> +      * channel, which starts counting at index 0 (which means: count = 1).
>> +      */
>> +     regval = FIELD_PREP(SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, 0);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_CHAN_LIST,
>> +                        SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, regval);
>> +
>> +     /* map channel index 0 to the channel which we want to read */
>> +     regval = FIELD_PREP(SAR_ADC_CHAN_CHAN_ENTRY_MASK(0), chan->channel);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_CHAN_LIST,
>> +                        SAR_ADC_CHAN_CHAN_ENTRY_MASK(0), regval);
>> +
>> +     regval = FIELD_PREP(SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_MUX_MASK,
>> +                         chan->channel);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_DETECT_IDLE_SW,
>> +                        SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_MUX_MASK,
>> +                        regval);
>> +
>> +     regval = FIELD_PREP(SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_MUX_SEL_MASK,
>> +                         chan->channel);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_DETECT_IDLE_SW,
>> +                        SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_MUX_SEL_MASK,
>> +                        regval);
>> +
>> +     if (chan->channel == 6)
>> +             regmap_update_bits(priv->regmap, SAR_ADC_DELTA_10,
>> +                                SAR_ADC_DELTA_10_TEMP_SEL, 0);
>> +}
>> +
>> +static void meson_saradc_set_channel7_mux(struct iio_dev *indio_dev,
>> +                                       enum meson_saradc_chan7_mux_sel sel)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     u32 regval;
>> +
>> +     regval = FIELD_PREP(SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, sel);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG3,
>> +                        SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, regval);
>> +
>> +     usleep_range(10, 20);
>> +}
>> +
>> +static void meson_saradc_start_sample_engine(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG0,
>> +                        SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE,
>> +                        SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
>> +
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG0,
>> +                        SAR_ADC_REG0_SAMPLING_START,
>> +                        SAR_ADC_REG0_SAMPLING_START);
>> +}
>> +
>> +static void meson_saradc_stop_sample_engine(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG0,
>> +                        SAR_ADC_REG0_SAMPLING_STOP,
>> +                        SAR_ADC_REG0_SAMPLING_STOP);
>> +
>> +     /* wait until all modules are stopped */
>> +     meson_saradc_wait_busy_clear(indio_dev);
>> +
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG0,
>> +                        SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0);
>> +}
>> +
>> +static void meson_saradc_lock(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     int val;
>> +
>> +     mutex_lock(&indio_dev->mlock);
>> +
>> +     /* prevent BL30 from using the SAR ADC while we are using it */
>> +     regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
>> +                        SAR_ADC_DELAY_KERNEL_BUSY,
>> +                        SAR_ADC_DELAY_KERNEL_BUSY);
>> +
>> +     /* wait until BL30 releases it's lock (so we can use the SAR ADC) */
>> +     do {
>> +             udelay(1);
>> +             regmap_read(priv->regmap, SAR_ADC_DELAY, &val);
>> +     } while (val & SAR_ADC_DELAY_BL30_BUSY);
>> +}
>> +
>> +static void meson_saradc_unlock(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +
>> +     /* allow BL30 to use the SAR ADC again */
>> +     regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
>> +                        SAR_ADC_DELAY_KERNEL_BUSY, 0);
>> +
>> +     mutex_unlock(&indio_dev->mlock);
>> +}
>> +
>> +static int meson_saradc_get_sample(struct iio_dev *indio_dev,
>> +                                const struct iio_chan_spec *chan,
>> +                                enum meson_saradc_avg_mode avg_mode,
>> +                                enum meson_saradc_num_samples avg_samples,
>> +                                int *val)
>> +{
>> +     int ret, tmp;
>> +
>> +     meson_saradc_lock(indio_dev);
>> +
>> +     /* clear old values from the FIFO buffer, ignoring errors */
>> +     meson_saradc_read_raw_sample(indio_dev, chan, &tmp);
>> +
>> +     meson_saradc_set_averaging(indio_dev, chan, avg_mode, avg_samples);
>> +
>> +     meson_saradc_enable_channel(indio_dev, chan);
>> +
>> +     meson_saradc_start_sample_engine(indio_dev);
>> +     ret = meson_saradc_read_raw_sample(indio_dev, chan, val);
>> +     meson_saradc_stop_sample_engine(indio_dev);
>> +
>> +     meson_saradc_unlock(indio_dev);
>> +
>> +     if (ret) {
>> +             dev_warn(&indio_dev->dev,
>> +                      "failed to read sample for channel %d: %d\n",
>> +                      chan->channel, ret);
>> +             return ret;
>> +     }
>> +
>> +     return IIO_VAL_INT;
>> +}
>> +
>> +static int meson_saradc_iio_info_read_raw(struct iio_dev *indio_dev,
>> +                                       const struct iio_chan_spec *chan,
>> +                                       int *val, int *val2, long mask)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     int ret;
>> +
>> +     switch (mask) {
>> +     case IIO_CHAN_INFO_RAW:
>> +             return meson_saradc_get_sample(indio_dev, chan, NO_AVERAGING,
>> +                                            ONE_SAMPLE, val);
>> +             break;
>> +
>> +     case IIO_CHAN_INFO_AVERAGE_RAW:
>> +             return meson_saradc_get_sample(indio_dev, chan, MEAN_AVERAGING,
>> +                                            EIGHT_SAMPLES, val);
>> +             break;
>> +
>> +     case IIO_CHAN_INFO_SCALE:
>> +             ret = regulator_get_voltage(priv->vref);
>> +             if (ret < 0) {
>> +                     dev_err(&indio_dev->dev,
>> +                             "failed to get vref voltage: %d\n", ret);
>> +                     return ret;
>> +             }
>> +
>> +             *val = ret / 1000;
>> +             *val2 = priv->resolution;
>> +             return IIO_VAL_FRACTIONAL_LOG2;
>> +
>> +     default:
>> +             return -EINVAL;
>> +     }
>> +}
>> +
>> +static int meson_saradc_clk_init(struct iio_dev *indio_dev, void __iomem *base)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     struct clk_init_data init;
>> +     char clk_name[32];
>> +     const char *clk_parents[1];
>> +
>> +     snprintf(clk_name, sizeof(clk_name), "%s#adc_div",
>> +              of_node_full_name(indio_dev->dev.of_node));
>> +     init.name = devm_kstrdup(&indio_dev->dev, clk_name, GFP_KERNEL);
>> +     init.flags = 0;
>> +     init.ops = &clk_divider_ops;
>> +     clk_parents[0] = __clk_get_name(priv->clkin);
>> +     init.parent_names = clk_parents;
>> +     init.num_parents = 1;
>> +
>> +     priv->clk_div.reg = base + SAR_ADC_REG3;
>> +     priv->clk_div.shift = SAR_ADC_REG3_ADC_CLK_DIV_SHIFT;
>> +     priv->clk_div.width = SAR_ADC_REG3_ADC_CLK_DIV_WIDTH;
>> +     priv->clk_div.hw.init = &init;
>> +     priv->clk_div.flags = 0;
>> +
>> +     priv->adc_div_clk = devm_clk_register(&indio_dev->dev,
>> +                                           &priv->clk_div.hw);
>> +     if (WARN_ON(IS_ERR(priv->adc_div_clk)))
>> +             return PTR_ERR(priv->adc_div_clk);
>> +
>> +     snprintf(clk_name, sizeof(clk_name), "%s#adc_en",
>> +              of_node_full_name(indio_dev->dev.of_node));
>> +     init.name = devm_kstrdup(&indio_dev->dev, clk_name, GFP_KERNEL);
>> +     init.flags = CLK_SET_RATE_PARENT;
>> +     init.ops = &clk_gate_ops;
>> +     clk_parents[0] = __clk_get_name(priv->adc_div_clk);
>> +     init.parent_names = clk_parents;
>> +     init.num_parents = 1;
>> +
>> +     priv->clk_gate.reg = base + SAR_ADC_REG3;
>> +     priv->clk_gate.bit_idx = fls(SAR_ADC_REG3_CLK_EN);
>> +     priv->clk_gate.hw.init = &init;
>> +
>> +     priv->adc_clk = devm_clk_register(&indio_dev->dev, &priv->clk_gate.hw);
>> +     if (WARN_ON(IS_ERR(priv->adc_clk)))
>> +             return PTR_ERR(priv->adc_clk);
>> +
>> +     return 0;
>> +}
>> +
>> +static int meson_saradc_init(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     int regval, ret;
>> +
>> +     /* make sure we start at CH7 input */
> why?  Seems like a little more detail would be good here ;)
I'll change this to "make sure we start at CH7 input since the other
muxes are only used for internal calibration." in v2

>> +     meson_saradc_set_channel7_mux(indio_dev, CHAN7_MUX_CH7_INPUT);
>> +
>> +     regmap_read(priv->regmap, SAR_ADC_REG3, &regval);
>> +     if (regval & SAR_ADC_REG3_BL30_INITIALIZED) {
>> +             dev_info(&indio_dev->dev, "already initialized by BL30\n");
>> +             return 0;
>> +     }
>> +
>> +     dev_info(&indio_dev->dev, "initializing SAR ADC\n");
> I'd argue this provides no useful info so should be dropped.
> Useful for debugging no doubt, but just noise going forward.
do you want me to remove them or should I turn them into dev_dbg() (so
they can be enabled for debugging purposes)?

>> +
>> +     meson_saradc_stop_sample_engine(indio_dev);
>> +
>> +     /* update the channel 6 MUX to select the temperature sensor */
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG0,
>> +                     SAR_ADC_REG0_ADC_TEMP_SEN_SEL,
>> +                     SAR_ADC_REG0_ADC_TEMP_SEN_SEL);
>> +
>> +     /* disable all channels by default */
>> +     regmap_write(priv->regmap, SAR_ADC_CHAN_LIST, 0x0);
>> +
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG3,
>> +                        SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE, 0);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG3,
>> +                        SAR_ADC_REG3_CNTL_USE_SC_DLY,
>> +                        SAR_ADC_REG3_CNTL_USE_SC_DLY);
>> +
>> +     /* delay between two samples = (10+1) * 1uS */
>> +     regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
>> +                        SAR_ADC_DELAY_INPUT_DLY_CNT_MASK,
>> +                        FIELD_PREP(SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK, 10));
>> +     regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
>> +                        SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK,
>> +                        FIELD_PREP(SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK, 0));
>> +
>> +     /* delay between two samples = (10+1) * 1uS */
>> +     regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
>> +                        SAR_ADC_DELAY_INPUT_DLY_CNT_MASK,
>> +                        FIELD_PREP(SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, 10));
>> +     regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
>> +                        SAR_ADC_DELAY_INPUT_DLY_SEL_MASK,
>> +                        FIELD_PREP(SAR_ADC_DELAY_INPUT_DLY_SEL_MASK, 1));
>> +
> Cool. I hadn't come across FIELD_PREP before. Neater and tidier than having
> a shift and a mask for at least some usecases.
I think these were introduced with v4.9. I like them because I tend
use GENMASK() incorrectly and with those macros I get an error at
compile-time (without having to debug my code at all)

>> +     ret = clk_set_parent(priv->adc_sel_clk, priv->clkin);
>> +     if (ret) {
>> +             dev_err(&indio_dev->dev,
>> +                     "failed to set adc parent to clkin\n");
>> +             return ret;
>> +     }
>> +
>> +     ret = clk_set_rate(priv->adc_clk, 1200000);
>> +     if (ret) {
>> +             dev_err(&indio_dev->dev, "failed to set adc clock rate\n");
>> +             return ret;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int meson_saradc_hw_enable(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     int ret;
>> +
>> +     meson_saradc_lock(indio_dev);
>> +
>> +     ret = regulator_enable(priv->vref);
>> +     if (ret < 0) {
>> +             dev_err(&indio_dev->dev, "failed to enable vref regulator\n");
>> +             goto err_vref;
>> +     }
>> +
>> +     ret = clk_prepare_enable(priv->core_clk);
>> +     if (ret) {
>> +             dev_err(&indio_dev->dev, "failed to enable core clk\n");
>> +             goto err_core_clk;
>> +     }
>> +
>> +     ret = clk_prepare_enable(priv->sana_clk);
>> +     if (ret) {
>> +             dev_err(&indio_dev->dev, "failed to enable sana clk\n");
>> +             goto err_sana_clk;
>> +     }
>> +
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG11,
>> +                        SAR_ADC_REG11_BANDGAP_EN, SAR_ADC_REG11_BANDGAP_EN);
> Is this controlling an offset for a bandgap or some actual electronics?
> Not sure if it should be disabled on error and the datasheets I've found are
> far from great!  You disable it in the disable, so I'd expect it to be
> unwound on error in here too.
actually the bandgap is not documented at all :(

>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG3, SAR_ADC_REG3_ADC_EN,
>> +                        SAR_ADC_REG3_ADC_EN);
> The fact you turn this of in the disable suggests to me that on error
> you should be doing it in here too.
I will disable this along with SAR_ADC_REG11_BANDGAP_EN in the
err_adc_clk label, thanks for spotting this.

>> +
>> +     udelay(5);
>> +
>> +     ret = clk_prepare_enable(priv->adc_clk);
>> +     if (ret) {
>> +             dev_err(&indio_dev->dev, "failed to enable adc_en clk\n");
>> +             goto err_adc_clk;
>> +     }
>> +
>> +     meson_saradc_unlock(indio_dev);
>> +
>> +     return 0;
>> +
>> +err_adc_clk:
>> +     clk_disable_unprepare(priv->sana_clk);
>> +err_sana_clk:
>> +     clk_disable_unprepare(priv->core_clk);
>> +err_core_clk:
>> +     regulator_disable(priv->vref);
>> +err_vref:
>> +     meson_saradc_unlock(indio_dev);
>> +     return ret;
>> +}
>> +
>> +static void meson_saradc_hw_disable(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +
>> +     meson_saradc_lock(indio_dev);
>> +
>> +     clk_disable_unprepare(priv->adc_clk);
>> +
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG3, SAR_ADC_REG3_ADC_EN, 0);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG11,
>> +                        SAR_ADC_REG11_BANDGAP_EN, 0);
>> +
>> +     clk_disable_unprepare(priv->sana_clk);
>> +     clk_disable_unprepare(priv->core_clk);
>> +
>> +     regulator_disable(priv->vref);
>> +
>> +     meson_saradc_unlock(indio_dev);
>> +}
>> +
>> +static const struct iio_info meson_saradc_iio_info = {
>> +     .read_raw = meson_saradc_iio_info_read_raw,
>> +     .driver_module = THIS_MODULE,
>> +};
>> +
>> +static const struct of_device_id meson_saradc_of_match[] = {
>> +     {
>> +             .compatible = "amlogic,meson-gxbb-saradc",
>> +             .data = (void *)10,
> Might have been worth having a structure array indexed from an enum.
> For now it is overkill, but seems likely there are a few other differences
> that aren't supported yet?
what do you mean with "structure array indexed from an enum"? I can
introduce some match-specific struct if you want (just like it's done
in rockchip_saradc.c with "struct rockchip_saradc_data").

>> +     }, {
>> +             .compatible = "amlogic,meson-gxl-saradc",
>> +             .data = (void *)12,
>> +     },
>> +     {},
>> +};
>> +MODULE_DEVICE_TABLE(of, meson_saradc_of_match);
>> +
>> +static int meson_saradc_probe(struct platform_device *pdev)
>> +{
>> +     struct meson_saradc_priv *priv;
>> +     struct iio_dev *indio_dev;
>> +     struct resource *res;
>> +     void __iomem *base;
>> +     const struct of_device_id *match;
>> +     int ret;
>> +
>> +     indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
>> +     if (!indio_dev) {
>> +             dev_err(&pdev->dev, "failed allocating iio device\n");
>> +             return -ENOMEM;
>> +     }
>> +
>> +     priv = iio_priv(indio_dev);
>> +
>> +     match = of_match_device(meson_saradc_of_match, &pdev->dev);
>> +     priv->resolution = (unsigned long)match->data;
>> +
>> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +     base = devm_ioremap_resource(&pdev->dev, res);
>> +     if (IS_ERR(base))
>> +             return PTR_ERR(base);
>> +
>> +     priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
>> +                                          &meson_saradc_regmap_config);
>> +     if (IS_ERR(priv->regmap))
>> +             return PTR_ERR(priv->regmap);
>> +
>> +     init_completion(&priv->completion);
>> +
>> +     priv->clkin = devm_clk_get(&pdev->dev, "clkin");
>> +     if (IS_ERR(priv->clkin)) {
>> +             dev_err(&pdev->dev, "failed to get clkin\n");
>> +             return PTR_ERR(priv->clkin);
>> +     }
>> +
>> +     priv->core_clk = devm_clk_get(&pdev->dev, "core");
>> +     if (IS_ERR(priv->core_clk)) {
>> +             dev_err(&pdev->dev, "failed to get core clk\n");
>> +             return PTR_ERR(priv->core_clk);
>> +     }
>> +
>> +     priv->sana_clk = devm_clk_get(&pdev->dev, "sana");
> Oh for a devm_clk_get_optional to handle this boiler plate neatly.
> It's been suggested before, but nothing seems to have come of it.
I guess quite a few drivers would benefit from that. maybe we should
take this to the linux-clk list again?

> Some array clk get functions might also clean this up a touch.
yes, unfortunately in this case it's not that easy as it would have to
allow a mix of mandatory and optional clocks. Additionally I cannot
bulk-enable them unconditionally since some of these are simple gates,
others need to be reparented and for some the rate has to be set.

>> +     if (IS_ERR(priv->sana_clk)) {
>> +             if (PTR_ERR(priv->sana_clk) == -ENOENT) {
>> +                     priv->sana_clk = NULL;
>> +             } else {
>> +                     dev_err(&pdev->dev, "failed to get sana clk\n");
>> +                     return PTR_ERR(priv->sana_clk);
>> +             }
>> +     }
>> +
>> +     priv->adc_clk = devm_clk_get(&pdev->dev, "adc_clk");
>> +     if (IS_ERR(priv->adc_clk)) {
>> +             if (PTR_ERR(priv->adc_clk) == -ENOENT) {
>> +                     priv->adc_clk = NULL;
>> +             } else {
>> +                     dev_err(&pdev->dev, "failed to get adc clk\n");
>> +                     return PTR_ERR(priv->adc_clk);
>> +             }
>> +     }
>> +
>> +     priv->adc_sel_clk = devm_clk_get(&pdev->dev, "adc_sel");
>> +     if (IS_ERR(priv->adc_sel_clk)) {
>> +             if (PTR_ERR(priv->adc_sel_clk) == -ENOENT) {
>> +                     priv->adc_sel_clk = NULL;
>> +             } else {
>> +                     dev_err(&pdev->dev, "failed to get adc_sel clk\n");
>> +                     return PTR_ERR(priv->adc_sel_clk);
>> +             }
>> +     }
>> +
>> +     /* on pre-GXBB SoCs the SAR ADC itself provides the ADC clock: */
>> +     if (!priv->adc_clk) {
>> +             ret = meson_saradc_clk_init(indio_dev, base);
>> +             if (ret)
>> +                     return ret;
>> +     }
>> +
>> +     priv->vref = devm_regulator_get(&pdev->dev, "vref");
>> +     if (IS_ERR(priv->vref)) {
>> +             dev_err(&pdev->dev, "failed to get vref regulator\n");
>> +             return PTR_ERR(priv->vref);
>> +     }
>> +
>> +     ret = meson_saradc_init(indio_dev);
>> +     if (ret)
>> +             goto err;
>> +
>> +     ret = meson_saradc_hw_enable(indio_dev);
>> +     if (ret)
>> +             goto err;
>> +
>> +     platform_set_drvdata(pdev, indio_dev);
>> +
>> +     indio_dev->name = dev_name(&pdev->dev);
>> +     indio_dev->dev.parent = &pdev->dev;
>> +     indio_dev->dev.of_node = pdev->dev.of_node;
>> +     indio_dev->modes = INDIO_DIRECT_MODE;
>> +     indio_dev->info = &meson_saradc_iio_info;
>> +
>> +     indio_dev->channels = meson_saradc_iio_channels;
>> +     indio_dev->num_channels = SAR_ADC_NUM_CHANNELS;
>> +
>> +     ret = iio_device_register(indio_dev);
>> +     if (ret)
>> +             goto err_hw;
>> +
>> +     return 0;
>> +
>> +err_hw:
>> +     meson_saradc_hw_disable(indio_dev);
>> +err:
>> +     return ret;
>> +}
>> +
>> +static int meson_saradc_remove(struct platform_device *pdev)
>> +{
>> +     struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>> +
>> +     meson_saradc_hw_disable(indio_dev);
>> +     iio_device_unregister(indio_dev);
>> +
>> +     return 0;
>> +}
>> +
>> +#ifdef CONFIG_PM_SLEEP
>> +static int meson_saradc_suspend(struct device *dev)
>> +{
>> +     struct iio_dev *indio_dev = dev_get_drvdata(dev);
>> +
>> +     meson_saradc_hw_disable(indio_dev);
>> +
>> +     return 0;
>> +}
>> +
>> +static int meson_saradc_resume(struct device *dev)
>> +{
>> +     struct iio_dev *indio_dev = dev_get_drvdata(dev);
>> +
>> +     return meson_saradc_hw_enable(indio_dev);
>> +}
>> +#endif /* CONFIG_PM_SLEEP */
>> +
>> +static SIMPLE_DEV_PM_OPS(meson_saradc_pm_ops,
>> +                      meson_saradc_suspend, meson_saradc_resume);
>> +
>> +static struct platform_driver meson_saradc_driver = {
>> +     .probe          = meson_saradc_probe,
>> +     .remove         = meson_saradc_remove,
>> +     .driver         = {
>> +             .name   = "meson-saradc",
>> +             .of_match_table = meson_saradc_of_match,
>> +             .pm = &meson_saradc_pm_ops,
>> +     },
>> +};
>> +
>> +module_platform_driver(meson_saradc_driver);
>> +
>> +MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>");
>> +MODULE_DESCRIPTION("Amlogic Meson SAR ADC driver");
>> +MODULE_LICENSE("GPL v2");
>>
>


Regards,
Martin

[0] http://lists.infradead.org/pipermail/linux-amlogic/2016-August/000986.html
--
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 v2 2/2] iio: distance: srf08: add IIO driver for us ranger
From: Andreas Klinger @ 2017-01-14 17:48 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: knaack.h-Mmb7MZpHnFY, lars-Qo5EllUWu/uELgA04lAiVw,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, ktsai-GubuWUlQtMwciDkP5Hr2oA,
	wsa-z923LK4zBo2bacvFa/9K2g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ, trivial-DgEjT+Ai2ygdnm+yROfE0A,
	mranostay-Re5JQEeQqe8AvxtiuMwx3w,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <4099feac-959c-2b5b-a21a-3b111098af39-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

Hi Jonathan,

see comments below.

Andreas


Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> schrieb am Sat, 14. Jan 12:17:
> On 10/01/17 18:48, Andreas Klinger wrote:
> > This is the IIO driver for devantech srf08 ultrasonic ranger which can be
> > used to measure the distances to an object.
> > 
> > The sensor supports I2C with some registers.
> > 
> > Supported Features include:
> > - read the distance in ranging mode in centimeters
> > - output of the driver is directly the read value
> > - together with the scale the driver delivers the distance in meters
> > - only the first echo of the nearest object is delivered
> > - set max gain register; userspace enters analogue value
> > - set range registers; userspace enters range in millimeters in 43 mm steps
> > 
> > Features not supported by this driver:
> > - ranging mode in inches or in microseconds
> > - ANN mode
> > - change I2C address through this driver
> > - light sensor
> > 
> > The driver was added in the directory "proximity" of the iio subsystem
> > in absence of another directory named "distance".
> > There is also a new submenu "distance"
> Hi Andreas,
> 
> Sorry it took me a while to get to this!
> 
> I'd not bother with the new submenu.  Perhaps we should rename the
> proximity menu to proximity/distance.
> 
> We already the lightening detector in there which is definitely not
> measuring proximity in the convetional sense!
> 
> Anyhow, the actual code is fine, but we need to think about how the
> userspace ABI fits within the wider IIO ABI.  Naming and approaches
> that make sense in a single class of drivers can end up meaining
> very different things for other drivers.  Various suggestions inline.
> 
> Jonathan
> > 
> > Signed-off-by: Andreas Klinger <ak-n176/SwNRljddJNmlsFzeA@public.gmane.org>
> > ---
> >  drivers/iio/proximity/Kconfig  |  15 ++
> >  drivers/iio/proximity/Makefile |   1 +
> >  drivers/iio/proximity/srf08.c  | 362 +++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 378 insertions(+)
> >  create mode 100644 drivers/iio/proximity/srf08.c
> > 
> > diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig
> > index ef4c73db5b53..7b10a137702b 100644
> > --- a/drivers/iio/proximity/Kconfig
> > +++ b/drivers/iio/proximity/Kconfig
> > @@ -46,3 +46,18 @@ config SX9500
> >  	  module will be called sx9500.
> >  
> >  endmenu
> > +
> > +menu "Distance sensors"
> > +
> > +config SRF08
> > +	tristate "Devantech SRF08 ultrasonic ranger sensor"
> > +	depends on I2C
> > +	help
> > +	  Say Y here to build a driver for Devantech SRF08 ultrasonic
> > +	  ranger sensor. This driver can be used to measure the distance
> > +	  of objects.
> > +
> > +	  To compile this driver as a module, choose M here: the
> > +	  module will be called srf08.
> > +
> > +endmenu
> > diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
> > index 9aadd9a8ee99..e914c2a5dd49 100644
> > --- a/drivers/iio/proximity/Makefile
> > +++ b/drivers/iio/proximity/Makefile
> > @@ -5,4 +5,5 @@
> >  # When adding new entries keep the list in alphabetical order
> >  obj-$(CONFIG_AS3935)		+= as3935.o
> >  obj-$(CONFIG_LIDAR_LITE_V2)	+= pulsedlight-lidar-lite-v2.o
> > +obj-$(CONFIG_SRF08)		+= srf08.o
> >  obj-$(CONFIG_SX9500)		+= sx9500.o
> > diff --git a/drivers/iio/proximity/srf08.c b/drivers/iio/proximity/srf08.c
> > new file mode 100644
> > index 000000000000..f38c74ed0933
> > --- /dev/null
> > +++ b/drivers/iio/proximity/srf08.c
> > @@ -0,0 +1,362 @@
> > +/*
> > + * srf08.c - Support for Devantech SRF08 ultrasonic ranger
> > + *
> > + * Copyright (c) 2016 Andreas Klinger <ak-n176/SwNRljddJNmlsFzeA@public.gmane.org>
> > + *
> > + * This file is subject to the terms and conditions of version 2 of
> > + * the GNU General Public License.  See the file COPYING in the main
> > + * directory of this archive for more details.
> > + *
> > + * For details about the device see:
> > + * http://www.robot-electronics.co.uk/htm/srf08tech.html
> > + */
> > +
> > +#include <linux/err.h>
> > +#include <linux/i2c.h>
> > +#include <linux/delay.h>
> > +#include <linux/module.h>
> > +#include <linux/bitops.h>
> > +#include <linux/iio/iio.h>
> > +#include <linux/iio/sysfs.h>
> > +
> > +/* registers of SRF08 device */
> > +#define SRF08_WRITE_COMMAND	0x00	/* Command Register */
> > +#define SRF08_WRITE_MAX_GAIN	0x01	/* Max Gain Register: 0 .. 31 */
> > +#define SRF08_WRITE_RANGE	0x02	/* Range Register: 0 .. 255 */
> > +#define SRF08_READ_SW_REVISION	0x00	/* Software Revision */
> > +#define SRF08_READ_LIGHT	0x01	/* Light Sensor during last echo */
> > +#define SRF08_READ_ECHO_1_HIGH	0x02	/* Range of first echo received */
> > +#define SRF08_READ_ECHO_1_LOW	0x03	/* Range of first echo received */
> > +
> > +#define SRF08_CMD_RANGING_CM	0x51	/* Ranging Mode - Result in cm */
> > +
> > +#define SRF08_DEFAULT_GAIN	1025	/* max. analogue value of Gain */
> > +#define SRF08_DEFAULT_RANGE	11008	/* max. value of Range in mm */
> > +
> > +struct srf08_data {
> > +	struct i2c_client	*client;
> > +	int			gain;			/* Max Gain */
> > +	int			range_mm;		/* Range in mm */
> > +	struct mutex		lock;
> > +};
> > +
> > +static const int srf08_gain[] = {
> > +	 94,  97, 100, 103, 107, 110, 114, 118,
> > +	123, 128, 133, 139, 145, 152, 159, 168,
> > +	177, 187, 199, 212, 227, 245, 265, 288,
> > +	317, 352, 395, 450, 524, 626, 777, 1025 };
> > +
> > +static int srf08_read_ranging(struct srf08_data *data)
> > +{
> > +	struct i2c_client *client = data->client;
> > +	int ret, i;
> > +
> > +	mutex_lock(&data->lock);
> > +
> > +	ret = i2c_smbus_write_byte_data(data->client,
> > +			SRF08_WRITE_COMMAND, SRF08_CMD_RANGING_CM);
> > +	if (ret < 0) {
> > +		dev_err(&client->dev, "write command - err: %d\n", ret);
> > +		mutex_unlock(&data->lock);
> > +		return ret;
> > +	}
> > +
> > +	/*
> > +	 * normally after 65 ms the device should have the read value
> > +	 * we round it up to 100 ms
> I'd suggest this should be adapted so that it takes advantage of knowing
> roughly how long it is going to take as the 'range' maximum is changed.
> So perhaps in the basic case, sleep for 65 msecs, then poll at 5msec
> intervals.  If we know it's going to be a lot faster, then poll it from
> an earlier time.
> > +	 *
> > +	 * we read here until a correct version number shows up as
> > +	 * suggested by the documentation
> > +	 */
> > +	for (i = 0; i < 5; i++) {
> > +		ret = i2c_smbus_read_byte_data(data->client,
> > +						SRF08_READ_SW_REVISION);
> > +
> > +		/* check if a valid version number is read */
> > +		if (ret < 255 && ret > 0)
> > +			break;
> > +		msleep(20);
> > +	}
> > +
> > +	if (ret >= 255 || ret <= 0) {
> > +		dev_err(&client->dev, "device not ready\n");
> > +		mutex_unlock(&data->lock);
> > +		return -EIO;
> > +	}
> > +
> > +	ret = i2c_smbus_read_word_swapped(data->client,
> > +						SRF08_READ_ECHO_1_HIGH);
> > +	if (ret < 0) {
> > +		dev_err(&client->dev, "cannot read distance: ret=%d\n", ret);
> > +		mutex_unlock(&data->lock);
> > +		return ret;
> > +	}
> > +
> > +	mutex_unlock(&data->lock);
> > +
> > +	return ret;
> > +}
> > +
> > +static int srf08_read_raw(struct iio_dev *indio_dev,
> > +			    struct iio_chan_spec const *channel, int *val,
> > +			    int *val2, long mask)
> > +{
> > +	struct srf08_data *data = iio_priv(indio_dev);
> > +	int ret;
> > +
> > +	if (channel->type != IIO_DISTANCE)
> > +		return -EINVAL;
> > +
> > +	switch (mask) {
> > +	case IIO_CHAN_INFO_RAW:
> > +		ret = srf08_read_ranging(data);
> > +		if (ret < 0)
> > +			return ret;
> > +		*val = ret;
> > +		return IIO_VAL_INT;
> > +	case IIO_CHAN_INFO_SCALE:
> > +		/* 1 LSB is 1 cm */
> > +		*val = 0;
> > +		*val2 = 10000;
> > +		return IIO_VAL_INT_PLUS_MICRO;
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +static ssize_t srf08_show_range_mm_available(struct device *dev,
> > +				struct device_attribute *attr, char *buf)
> > +{
> > +	int i, len = 0;
> > +
> > +	for (i = 0; i < 256; i++)
> > +		len += scnprintf(buf + len, PAGE_SIZE - len,
> > +							"%d ", (i + 1) * 43);
> > +
> > +	buf[len - 1] = '\n';
> > +
> > +	return len;
> > +}
> > +
> > +static IIO_DEVICE_ATTR(range_mm_available, S_IRUGO,
> > +				srf08_show_range_mm_available, NULL, 0);
> > +
> > +static ssize_t srf08_show_range_mm(struct device *dev,
> > +				struct device_attribute *attr, char *buf)
> > +{
> > +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > +	struct srf08_data *data = iio_priv(indio_dev);
> > +
> > +	return sprintf(buf, "%d\n", data->range_mm);
> > +}
> > +
> > +/*
> > + * set the range of the sensor to an even multiple of 43 mm
> > + * which corresponds to 1 LSB in the register
> > + *
> > + * register value    corresponding range
> > + *         0x00             43 mm
> > + *         0x01             86 mm
> > + *         0x02            129 mm
> > + *         ...
> > + *         0xFF          11008 mm
> > + */
> > +static ssize_t srf08_write_range_mm(struct device *dev,
> > +					struct device_attribute *attr,
> > +					const char *buf, size_t len)
> > +{
> > +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > +	struct srf08_data *data = iio_priv(indio_dev);
> > +	struct i2c_client *client = data->client;
> > +	int ret;
> > +	unsigned int val, mod;
> > +	u8 regval;
> > +
> > +	ret = kstrtouint(buf, 10, &val);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = val / 43 - 1;
> > +	mod = val % 43;
> > +
> > +	if (mod || (ret < 0) || (ret > 255))
> > +		return -EINVAL;
> > +
> > +	regval = ret;
> > +
> > +	mutex_lock(&data->lock);
> > +
> > +	ret = i2c_smbus_write_byte_data(data->client,
> > +						SRF08_WRITE_RANGE, regval);
> > +	if (ret < 0) {
> > +		dev_err(&client->dev, "write_range - err: %d\n", ret);
> > +		mutex_unlock(&data->lock);
> > +		return ret;
> > +	}
> > +
> > +	data->range_mm = val;
> > +
> > +	mutex_unlock(&data->lock);
> > +
> > +	return len;
> > +}
> > +
> > +static IIO_DEVICE_ATTR(range_mm, S_IRUGO | S_IWUSR,
> > +			srf08_show_range_mm, srf08_write_range_mm, 0);
> > +
> > +static ssize_t srf08_show_gain_available(struct device *dev,
> > +				struct device_attribute *attr, char *buf)
> > +{
> > +	int i, len = 0;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(srf08_gain); i++)
> > +		len += sprintf(buf + len, "%d ", srf08_gain[i]);
> > +
> > +	len += sprintf(buf + len, "\n");
> > +
> > +	return len;
> > +}
> > +
> > +static IIO_DEVICE_ATTR(gain_available, S_IRUGO,
> > +				srf08_show_gain_available, NULL, 0);
> > +
> > +static ssize_t srf08_show_gain(struct device *dev,
> > +				struct device_attribute *attr, char *buf)
> > +{
> > +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > +	struct srf08_data *data = iio_priv(indio_dev);
> > +	int len;
> > +
> > +	len = sprintf(buf, "%d\n", data->gain);
> > +
> > +	return len;
> > +}
> > +
> > +static ssize_t srf08_write_gain(struct device *dev,
> > +						struct device_attribute *attr,
> > +						const char *buf, size_t len)
> > +{
> > +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > +	struct srf08_data *data = iio_priv(indio_dev);
> > +	struct i2c_client *client = data->client;
> > +	int ret, i;
> > +	unsigned int val;
> > +	u8 regval;
> > +
> > +	ret = kstrtouint(buf, 10, &val);
> > +	if (ret)
> > +		return ret;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(srf08_gain); i++)
> > +		if (val == srf08_gain[i]) {
> > +			regval = i;
> > +			break;
> > +		}
> > +
> > +	if (i >= ARRAY_SIZE(srf08_gain))
> > +		return -EINVAL;
> > +
> > +	mutex_lock(&data->lock);
> > +
> > +	ret = i2c_smbus_write_byte_data(data->client,
> > +						SRF08_WRITE_MAX_GAIN, regval);
> > +	if (ret < 0) {
> > +		dev_err(&client->dev, "write_gain - err: %d\n", ret);
> > +		mutex_unlock(&data->lock);
> > +		return ret;
> > +	}
> > +
> > +	data->gain = val;
> > +
> > +	mutex_unlock(&data->lock);
> > +
> > +	return len;
> > +}
> > +
> > +static IIO_DEVICE_ATTR(gain, S_IRUGO | S_IWUSR,
> > +					srf08_show_gain, srf08_write_gain, 0);
> > +
> > +static struct attribute *srf08_attributes[] = {
> > +	&iio_dev_attr_range_mm.dev_attr.attr,
> > +	&iio_dev_attr_range_mm_available.dev_attr.attr,
> > +	&iio_dev_attr_gain.dev_attr.attr,
> > +	&iio_dev_attr_gain_available.dev_attr.attr,
> Hmm. Custom attributes always give us issues. The primary point of IIO
> is to enforce (more or less) standard interfaces.
> 
> If you do need to add something new then that is fine (and I do think
> you need to here!).
> 
> They need to be formally proposed as an addition to the ABI with
> docs in /Documentation/ABI/testing/sysfs-bus-iio*
> 
> Once we take one driver using it it becomes part of our ABI that
> userspace will need to handle, hence we consider these very
> carefully.
> 
> My gut feeling would be that gain needs to be more specific as it's
> a term that can mean very different things.. Here we are talking
> about an amplifier on a signal that we are then looking at the timing
> of.   It might otherwise be interpretted as another term for what
> we term 'scale' in IIO.
> 
> So what to call it... Perhaps afegain for Analog front end gain?
> We might want to add this to the core supported attrs, but lets
> not do so until we see if we have this on a number of devices.
> 

In /Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 there is also a
gain used in a similar situation and it's called there "sensor_sensitivity"

What it we also use this name here?

> The description would need to make it explicit that this gain is
> for cases where we aren't measuring the magnitude of what is
> being amplified.
> 
> For the range, it's an interesting one.  Again the term range could
> mean too many things within the wider ABI. We need to make it more
> specific.
> 
> Actually reading the datasheet, I think this is fundamentally about the
> maximum sampling frequency rather than directly about the range.
> The only reason you'd reduce the range is to speed that up. It doesn't
> improve the resolution, the device simply answers quicker.
> 
> So I'd support this as sampling_frequency.  You could then use
> the the iio_info_mask_*_available and relevant callback to provide
> info on what it then restricts the possible output values to
> (rather than controlling it directly).
> 

By changing the range one cannot influence the sampling frequency directly. I
have seen on the oszilloscope that the telegrams arrive almost at the same time
with different settings of range and the same gain.

Only if the gain is also adjusted the sensor works faster and a higher frequency
can be used. But the gain is also used to adjust the sensitivity of the sensor. 

What about calling it "sensor_domain" or "sensor_max_range"?


> > +	NULL,
> > +};
> > +
> > +static const struct attribute_group srf08_attribute_group = {
> > +	.attrs = srf08_attributes,
> > +};
> > +
> > +static const struct iio_chan_spec srf08_channels[] = {
> > +	{
> > +		.type = IIO_DISTANCE,
> > +		.info_mask_separate =
> > +				BIT(IIO_CHAN_INFO_RAW) |
> > +				BIT(IIO_CHAN_INFO_SCALE),
> > +	},
> > +};
> > +
> > +static const struct iio_info srf08_info = {
> > +	.read_raw = srf08_read_raw,
> > +	.attrs = &srf08_attribute_group,
> > +	.driver_module = THIS_MODULE,
> > +};
> > +
> > +static int srf08_probe(struct i2c_client *client,
> > +					 const struct i2c_device_id *id)
> > +{
> > +	struct iio_dev *indio_dev;
> > +	struct srf08_data *data;
> > +
> > +	if (!i2c_check_functionality(client->adapter,
> > +					I2C_FUNC_SMBUS_READ_BYTE_DATA |
> > +					I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
> > +					I2C_FUNC_SMBUS_READ_WORD_DATA))
> > +		return -ENODEV;
> > +
> > +	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> > +	if (!indio_dev)
> > +		return -ENOMEM;
> > +
> > +	data = iio_priv(indio_dev);
> > +	i2c_set_clientdata(client, indio_dev);
> > +	data->client = client;
> > +
> > +	/*
> > +	 * set default values of device here
> > +	 * these values are already set on the hardware after power on
> > +	 */
> > +	data->gain = SRF08_DEFAULT_GAIN;
> > +	data->range_mm = SRF08_DEFAULT_RANGE;
> We should be a little careful with assumptions about the device having
> just been powered on.  The driver might simply have been removed and
> reprobed.  So I'd sugest rewriting them whatever to be sure we have
> what we expect.  Either that or if they can be read back, then just
> always retrieve them from the device.

You are right. 
Then i'll set the default value at the sensor, because it cannot be read.

> > +
> > +	indio_dev->name = dev_name(&client->dev);
> > +	indio_dev->dev.parent = &client->dev;
> > +	indio_dev->modes = INDIO_DIRECT_MODE;
> > +	indio_dev->info = &srf08_info;
> > +	indio_dev->channels = srf08_channels;
> > +	indio_dev->num_channels = ARRAY_SIZE(srf08_channels);
> > +
> > +	mutex_init(&data->lock);
> > +
> > +	return devm_iio_device_register(&client->dev, indio_dev);
> > +}
> > +
> > +static const struct i2c_device_id srf08_id[] = {
> > +	{ "srf08", 0 },
> > +	{ }
> > +};
> > +MODULE_DEVICE_TABLE(i2c, srf08_id);
> > +
> > +static struct i2c_driver srf08_driver = {
> > +	.driver = {
> > +		.name	= "srf08",
> > +	},
> > +	.probe = srf08_probe,
> > +	.id_table = srf08_id,
> > +};
> > +module_i2c_driver(srf08_driver);
> > +
> > +MODULE_AUTHOR("Andreas Klinger <ak-n176/SwNRljddJNmlsFzeA@public.gmane.org>");
> > +MODULE_DESCRIPTION("Devantech SRF08 ultrasonic ranger driver");
> > +MODULE_LICENSE("GPL");
> > 
> 

-- 

--
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 1/3] DT/bindings: Add bindings for TI ADS7950 A/DC chips
From: David Lechner @ 2017-01-14 18:00 UTC (permalink / raw)
  To: Jonathan Cameron, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA
  Cc: Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Rob Herring, Mark Rutland, linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <f1e845c4-7db0-c6fe-fbd2-420902110be9-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

On 01/14/2017 06:53 AM, Jonathan Cameron wrote:
> On 11/01/17 17:52, David Lechner wrote:
>> This adds device tree bindings for the TI ADS7950 family of A/DC chips.
>>
>> Signed-off-by: David Lechner <david-nq/r/kbU++upp/zk7JDF2g@public.gmane.org>
> This is in of itself good, but we may need to have some deprecated
> elements to continue supporting what was implicitly happening with
> the missnaming so as to avoid accidentally breaking someone's device
> tree.
>

As I mentioned in my cover letter, this driver, as far as I can tell, 
only exists in your testing branch, so I find it highly unlikely that we 
would be breaking anyone. It is not in mainline and it is not even in 
linux-next.

> Jonathan
>> ---
>>  .../devicetree/bindings/iio/adc/ti-ads7950.txt     | 23 ++++++++++++++++++++++
>>  1 file changed, 23 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/iio/adc/ti-ads7950.txt
>>
>> diff --git a/Documentation/devicetree/bindings/iio/adc/ti-ads7950.txt b/Documentation/devicetree/bindings/iio/adc/ti-ads7950.txt
>> new file mode 100644
>> index 0000000..e77a6f7
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/iio/adc/ti-ads7950.txt
>> @@ -0,0 +1,23 @@
>> +* Texas Instruments ADS7950 family of A/DC chips
>> +
>> +Required properties:
>> + - compatible: Must be one of "ti,ads7950", "ti,ads7951", "ti,ads7952",
>> +   "ti,ads7953", "ti,ads7954", "ti,ads7955", "ti,ads7956", "ti,ads7957",
>> +   "ti,ads7958", "ti,ads7959", "ti,ads7960", or "ti,ads7961"
>> + - reg: SPI chip select number for the device
>> + - #io-channel-cells: Must be 1 as per ../iio-bindings.txt
>> + - vref-supply: phandle to a regulator node that supplies the 2.5V or 5V
>> +   reference voltage
>> +
>> +Recommended properties:
>> + - spi-max-frequency: Definition as per
>> +		Documentation/devicetree/bindings/spi/spi-bus.txt
>> +
>> +Example:
>> +adc@0 {
>> +	compatible = "ti,ads7957";
>> +	reg = <0>;
>> +	#io-channel-cells = <1>;
>> +	vref-supply = <&refin_supply>;
>> +	spi-max-frequency = <10000000>;
>> +};
>>
>

^ permalink raw reply

* Re: [PATCH 2/3] iio: adc: ti-ads7950: Drop "ti-" prefix from module name
From: David Lechner @ 2017-01-14 18:07 UTC (permalink / raw)
  To: Jonathan Cameron, devicetree, linux-iio
  Cc: Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Rob Herring, Mark Rutland, linux-kernel
In-Reply-To: <4dd9883a-5e50-36a9-135c-802dac4f93b8@kernel.org>

On 01/14/2017 06:49 AM, Jonathan Cameron wrote:
> On 11/01/17 17:52, David Lechner wrote:
>> This drops the "ti-" prefix from the module name. It makes the module name
>> consistent with other iio ti-ads* drivers and it makes the driver work
>> with device tree (the spi subsystem drops the "ti," prefix when matching
>> compatible strings from device tree).
>>
>> Tested working on LEGO MINDSTORMS EV3 with the following device tree node:
>>
>> 	adc@3 {
>> 		compatible = "ti,ads7957";
>> 		reg = <3>;
>> 		#io-channel-cells = <1>;
>> 		spi-max-frequency = <10000000>;
>> 		vref-supply = <&adc_ref>;
>> 	};
>>
>> Signed-off-by: David Lechner <david@lechnology.com>
> What worries me here is that we might break existing setups.  I agree
> we should have gotten this 'right' in the first place, but can we fix
> it now.  Not so sure. We'd be better off perhaps adding an of_device_id
> table with the write entries for device tree.

As far as I can tell, this driver only exists in your testing branch. 
Does that really mean that it is too late to get it right?

>> ---
>>  drivers/iio/adc/ti-ads7950.c | 26 +++++++++++++-------------
>>  1 file changed, 13 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c
>> index 0330361..b587fa6 100644
>> --- a/drivers/iio/adc/ti-ads7950.c
>> +++ b/drivers/iio/adc/ti-ads7950.c
>> @@ -459,25 +459,25 @@ static int ti_ads7950_remove(struct spi_device *spi)
>>  }
>>
>>  static const struct spi_device_id ti_ads7950_id[] = {
>> -	{"ti-ads7950", TI_ADS7950},
>> -	{"ti-ads7951", TI_ADS7951},
>> -	{"ti-ads7952", TI_ADS7952},
>> -	{"ti-ads7953", TI_ADS7953},
>> -	{"ti-ads7954", TI_ADS7954},
>> -	{"ti-ads7955", TI_ADS7955},
>> -	{"ti-ads7956", TI_ADS7956},
>> -	{"ti-ads7957", TI_ADS7957},
>> -	{"ti-ads7958", TI_ADS7958},
>> -	{"ti-ads7959", TI_ADS7959},
>> -	{"ti-ads7960", TI_ADS7960},
>> -	{"ti-ads7961", TI_ADS7961},
>> +	{ "ads7950", TI_ADS7950 },
>> +	{ "ads7951", TI_ADS7951 },
>> +	{ "ads7952", TI_ADS7952 },
>> +	{ "ads7953", TI_ADS7953 },
>> +	{ "ads7954", TI_ADS7954 },
>> +	{ "ads7955", TI_ADS7955 },
>> +	{ "ads7956", TI_ADS7956 },
>> +	{ "ads7957", TI_ADS7957 },
>> +	{ "ads7958", TI_ADS7958 },
>> +	{ "ads7959", TI_ADS7959 },
>> +	{ "ads7960", TI_ADS7960 },
>> +	{ "ads7961", TI_ADS7961 },
>>  	{ }
>>  };
>>  MODULE_DEVICE_TABLE(spi, ti_ads7950_id);
>>
>>  static struct spi_driver ti_ads7950_driver = {
>>  	.driver = {
>> -		.name	= "ti-ads7950",
>> +		.name	= "ads7950",
>>  	},
>>  	.probe		= ti_ads7950_probe,
>>  	.remove		= ti_ads7950_remove,
>>
>

^ permalink raw reply

* Re: [PATCH 3/3] iio: adc: ti-ads7950: Change regulator matching string to "vref"
From: David Lechner @ 2017-01-14 18:09 UTC (permalink / raw)
  To: Jonathan Cameron, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA
  Cc: Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Rob Herring, Mark Rutland, linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <47d15fe8-85c5-6e1c-cd89-71398ad79def-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

On 01/14/2017 06:52 AM, Jonathan Cameron wrote:
> On 11/01/17 17:52, David Lechner wrote:
>> This changes the reference voltage regulator matching string from "refin"
>> to "vref". This is to be consistent with other A/DC chips that also use
>> "vref-supply" in their device tree bindings.
>>
>> Signed-off-by: David Lechner <david-nq/r/kbU++upp/zk7JDF2g@public.gmane.org>
>> ---
>>  drivers/iio/adc/ti-ads7950.c | 6 +++---
> Again, we missed this before and it would have been nice to have
> had it as vref (which is matches the datasheet).  The question
> becomes how do we handle this going forward with no risk of breaking
> existing device trees.  We may have to do an optional get on one
> name and then a non optional on the second. It's ugly, but
> would fix this up in a 'safe' way.
>

Again, I don't think it is too late since this driver only exists in the 
iio/testing branch.

> Jonathan
>>  1 file changed, 3 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c
>> index b587fa6..16a0663 100644
>> --- a/drivers/iio/adc/ti-ads7950.c
>> +++ b/drivers/iio/adc/ti-ads7950.c
>> @@ -411,15 +411,15 @@ static int ti_ads7950_probe(struct spi_device *spi)
>>  	spi_message_init_with_transfers(&st->scan_single_msg,
>>  					st->scan_single_xfer, 3);
>>
>> -	st->reg = devm_regulator_get(&spi->dev, "refin");
>> +	st->reg = devm_regulator_get(&spi->dev, "vref");
>>  	if (IS_ERR(st->reg)) {
>> -		dev_err(&spi->dev, "Failed get get regulator \"refin\"\n");
>> +		dev_err(&spi->dev, "Failed get get regulator \"vref\"\n");
>>  		return PTR_ERR(st->reg);
>>  	}
>>
>>  	ret = regulator_enable(st->reg);
>>  	if (ret) {
>> -		dev_err(&spi->dev, "Failed to enable regulator \"refin\"\n");
>> +		dev_err(&spi->dev, "Failed to enable regulator \"vref\"\n");
>>  		return ret;
>>  	}
>>
>>
>

^ permalink raw reply

* [PATCH] reset: uniphier: add compatible string for LD11 SD-reset block
From: Masahiro Yamada @ 2017-01-14 19:04 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Mark Rutland, devicetree, linux-kernel, Masahiro Yamada,
	Rob Herring, linux-arm-kernel

The LD11 SoC is equipped with not only MIO-reset but also SD-reset
for controlling RST_n pin of the eMMC device.

Update the binding document and remove unneeded "." from each line
in itemization.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

 .../devicetree/bindings/reset/uniphier-reset.txt   | 47 +++++++++++-----------
 drivers/reset/reset-uniphier.c                     |  4 ++
 2 files changed, 28 insertions(+), 23 deletions(-)

diff --git a/Documentation/devicetree/bindings/reset/uniphier-reset.txt b/Documentation/devicetree/bindings/reset/uniphier-reset.txt
index 5020524..83ab0f5 100644
--- a/Documentation/devicetree/bindings/reset/uniphier-reset.txt
+++ b/Documentation/devicetree/bindings/reset/uniphier-reset.txt
@@ -6,14 +6,14 @@ System reset
 
 Required properties:
 - compatible: should be one of the following:
-    "socionext,uniphier-sld3-reset" - for sLD3 SoC.
-    "socionext,uniphier-ld4-reset"  - for LD4 SoC.
-    "socionext,uniphier-pro4-reset" - for Pro4 SoC.
-    "socionext,uniphier-sld8-reset" - for sLD8 SoC.
-    "socionext,uniphier-pro5-reset" - for Pro5 SoC.
-    "socionext,uniphier-pxs2-reset" - for PXs2/LD6b SoC.
-    "socionext,uniphier-ld11-reset" - for LD11 SoC.
-    "socionext,uniphier-ld20-reset" - for LD20 SoC.
+    "socionext,uniphier-sld3-reset" - for sLD3 SoC
+    "socionext,uniphier-ld4-reset"  - for LD4 SoC
+    "socionext,uniphier-pro4-reset" - for Pro4 SoC
+    "socionext,uniphier-sld8-reset" - for sLD8 SoC
+    "socionext,uniphier-pro5-reset" - for Pro5 SoC
+    "socionext,uniphier-pxs2-reset" - for PXs2/LD6b SoC
+    "socionext,uniphier-ld11-reset" - for LD11 SoC
+    "socionext,uniphier-ld20-reset" - for LD20 SoC
 - #reset-cells: should be 1.
 
 Example:
@@ -37,14 +37,15 @@ Media I/O (MIO) reset, SD reset
 
 Required properties:
 - compatible: should be one of the following:
-    "socionext,uniphier-sld3-mio-reset" - for sLD3 SoC.
-    "socionext,uniphier-ld4-mio-reset"  - for LD4 SoC.
-    "socionext,uniphier-pro4-mio-reset" - for Pro4 SoC.
-    "socionext,uniphier-sld8-mio-reset" - for sLD8 SoC.
-    "socionext,uniphier-pro5-sd-reset"  - for Pro5 SoC.
-    "socionext,uniphier-pxs2-sd-reset"  - for PXs2/LD6b SoC.
-    "socionext,uniphier-ld11-mio-reset" - for LD11 SoC.
-    "socionext,uniphier-ld20-sd-reset"  - for LD20 SoC.
+    "socionext,uniphier-sld3-mio-reset" - for sLD3 SoC
+    "socionext,uniphier-ld4-mio-reset"  - for LD4 SoC
+    "socionext,uniphier-pro4-mio-reset" - for Pro4 SoC
+    "socionext,uniphier-sld8-mio-reset" - for sLD8 SoC
+    "socionext,uniphier-pro5-sd-reset"  - for Pro5 SoC
+    "socionext,uniphier-pxs2-sd-reset"  - for PXs2/LD6b SoC
+    "socionext,uniphier-ld11-mio-reset" - for LD11 SoC (MIO)
+    "socionext,uniphier-ld11-sd-reset"  - for LD11 SoC (SD)
+    "socionext,uniphier-ld20-sd-reset"  - for LD20 SoC
 - #reset-cells: should be 1.
 
 Example:
@@ -68,13 +69,13 @@ Peripheral reset
 
 Required properties:
 - compatible: should be one of the following:
-    "socionext,uniphier-ld4-peri-reset"  - for LD4 SoC.
-    "socionext,uniphier-pro4-peri-reset" - for Pro4 SoC.
-    "socionext,uniphier-sld8-peri-reset" - for sLD8 SoC.
-    "socionext,uniphier-pro5-peri-reset" - for Pro5 SoC.
-    "socionext,uniphier-pxs2-peri-reset" - for PXs2/LD6b SoC.
-    "socionext,uniphier-ld11-peri-reset" - for LD11 SoC.
-    "socionext,uniphier-ld20-peri-reset" - for LD20 SoC.
+    "socionext,uniphier-ld4-peri-reset"  - for LD4 SoC
+    "socionext,uniphier-pro4-peri-reset" - for Pro4 SoC
+    "socionext,uniphier-sld8-peri-reset" - for sLD8 SoC
+    "socionext,uniphier-pro5-peri-reset" - for Pro5 SoC
+    "socionext,uniphier-pxs2-peri-reset" - for PXs2/LD6b SoC
+    "socionext,uniphier-ld11-peri-reset" - for LD11 SoC
+    "socionext,uniphier-ld20-peri-reset" - for LD20 SoC
 - #reset-cells: should be 1.
 
 Example:
diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c
index 968c3ae..9c11be3 100644
--- a/drivers/reset/reset-uniphier.c
+++ b/drivers/reset/reset-uniphier.c
@@ -390,6 +390,10 @@ static const struct of_device_id uniphier_reset_match[] = {
 		.data = uniphier_sld3_mio_reset_data,
 	},
 	{
+		.compatible = "socionext,uniphier-ld11-sd-reset",
+		.data = uniphier_pro5_sd_reset_data,
+	},
+	{
 		.compatible = "socionext,uniphier-ld20-sd-reset",
 		.data = uniphier_pro5_sd_reset_data,
 	},
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH 1/2] input: touchscreen: add driver for Zeitec ZET6223
From: Dmitry Torokhov @ 2017-01-14 19:14 UTC (permalink / raw)
  To: Jelle van der Waa
  Cc: Rob Herring, linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20161223163214.7716-1-jelle-oJJ1AqDjjO4@public.gmane.org>

Hi Jelle,

On Fri, Dec 23, 2016 at 05:32:13PM +0100, Jelle van der Waa wrote:
> This is a basic driver for the Zeitec ZET6223 I2C touchscreen
> controllers. The driver does not support firmware loading, which is not
> required for all tablets which contain this chip.
> 
> Signed-off-by: Jelle van der Waa <jelle-oJJ1AqDjjO4@public.gmane.org>

This looks mostly good with exception of this:

> +
> +static const struct of_device_id zet6223_of_match[] = {
> +	{ .compatible = "zeitec", "zet6223" },

The compatible should be "zeitec,zet6223", what you have here is
equivalent of:

	{ .compatible = "zeitec", .data = "zet6223" },

I also have been looking at you previosu submission and had some draft
changes. I reconciled them in the patch below, if it still works for you
then I'll fold everything together and apply. Please let me know.

Thanks.

-- 
Dmitry


Input: zeitech - misc changes

From: Dmitry Torokhov <dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

Signed-off-by: Dmitry Torokhov <dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 .../bindings/input/touchscreen/zet6223.txt         |   29 +-
 drivers/input/touchscreen/Kconfig                  |   22 +-
 drivers/input/touchscreen/Makefile                 |    2 
 drivers/input/touchscreen/zet6223.c                |  262 ++++++++++++++------
 4 files changed, 209 insertions(+), 106 deletions(-)

diff --git a/Documentation/devicetree/bindings/input/touchscreen/zet6223.txt b/Documentation/devicetree/bindings/input/touchscreen/zet6223.txt
index cc0f7d06bc8b..fe6a1feef703 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/zet6223.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/zet6223.txt
@@ -1,16 +1,19 @@
 Zeitec ZET6223 I2C touchscreen controller
 
 Required properties:
- - compatible            : "zeitec,zet6223"
- - reg                   : I2C slave address of the chip (0x76)
- - interrupt-parent      : a phandle pointing to the interrupt controller
-                           serving the interrupt for this chip
- - interrupts            : interrupt specification for the zet6223 interrupt
+- compatible		  : "zeitec,zet6223"
+- reg			  : I2C slave address of the chip (0x76)
+- interrupt-parent	  : a phandle pointing to the interrupt controller
+			    serving the interrupt for this chip
+- interrupts		  : interrupt specification for the zet6223 interrupt
 
 Optional properties:
 
-- touchscreen-size-x     : See touchscreen.txt
-- touchscreen-size-y     : See touchscreen.txt
+- vio-supply		  : Specification for VIO supply (1.8V or 3.3V,
+			    depending on system interface needs).
+- vcc-supply		  : Specification for 3.3V VCC supply.
+- touchscreen-size-x	  : See touchscreen.txt
+- touchscreen-size-y	  : See touchscreen.txt
 - touchscreen-inverted-x  : See touchscreen.txt
 - touchscreen-inverted-y  : See touchscreen.txt
 - touchscreen-swapped-x-y : See touchscreen.txt
@@ -19,11 +22,11 @@ Example:
 
 i2c@00000000 {
 
-       zet6223: touchscreen@76 {
-               compatible = "zeitec,zet6223";
-               reg = <0x76>;
-               interrupt-parent = <&pio>;
-               interrupts = <6 11 IRQ_TYPE_EDGE_FALLING>
-       };
+	zet6223: touchscreen@76 {
+		compatible = "zeitec,zet6223";
+		reg = <0x76>;
+		interrupt-parent = <&pio>;
+		interrupts = <6 11 IRQ_TYPE_EDGE_FALLING>
+	};
 
 };
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 270ce9317842..033599777651 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1165,6 +1165,17 @@ config TOUCHSCREEN_TPS6507X
 	  To compile this driver as a module, choose M here: the
 	  module will be called tps6507x_ts.
 
+config TOUCHSCREEN_ZET6223
+	tristate "Zeitec ZET6223 touchscreen driver"
+	depends on I2C
+	help
+	  Say Y here if you have a touchscreen using Zeitec ZET6223
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called zet6223.
+
 config TOUCHSCREEN_ZFORCE
 	tristate "Neonode zForce infrared touchscreens"
 	depends on I2C
@@ -1202,15 +1213,4 @@ config TOUCHSCREEN_ROHM_BU21023
 	  To compile this driver as a module, choose M here: the
 	  module will be called bu21023_ts.
 
-config TOUCHSCREEN_ZET6223
-       tristate "Zeitec ZET6223 touchscreen driver"
-       depends on I2C
-       help
-         Say Y here if you have a touchscreen using Zeitec ZET6223
-
-         If unsure, say N.
-
-         To compile this driver as a module, choose M here: the
-         module will be called zet6223.
-
 endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 03dc730c096c..b622e5344137 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -95,7 +95,7 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
 obj-$(CONFIG_TOUCHSCREEN_SX8654)	+= sx8654.o
 obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
+obj-$(CONFIG_TOUCHSCREEN_ZET6223)	+= zet6223.o
 obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o
 obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50)	+= colibri-vf50-ts.o
 obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023)	+= rohm_bu21023.o
-obj-$(CONFIG_TOUCHSCREEN_ZET6223)       += zet6223.o
diff --git a/drivers/input/touchscreen/zet6223.c b/drivers/input/touchscreen/zet6223.c
index aecae06877cf..8702d31958aa 100644
--- a/drivers/input/touchscreen/zet6223.c
+++ b/drivers/input/touchscreen/zet6223.c
@@ -1,70 +1,83 @@
 /*
  * Copyright (C) 2016, Jelle van der Waa <jelle-oJJ1AqDjjO4@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 as published by the Free
- *  Software Foundation; either version 2 of the License, or (at your option)
- *  any later version.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
  *
- *  This program is distributed in the hope that it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- *  more details.
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
  */
 
-#include <asm/unaligned.h>
-#include <linux/gpio/consumer.h>
-#include <linux/interrupt.h>
+#include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/input/mt.h>
 #include <linux/input/touchscreen.h>
+#include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <asm/unaligned.h>
+
+#define ZET6223_MAX_FINGERS		16
+#define ZET6223_MAX_PKT_SIZE		(3 + 4 * ZET6223_MAX_FINGERS)
+
+#define ZET6223_CMD_INFO		0xB2
+#define ZET6223_CMD_INFO_LENGTH		17
+#define ZET6223_VALID_PACKET		0x3c
 
-#define ZET6223_CMD_INFO 0xB2
-#define ZET6223_CMD_INFO_LENGTH 17
-#define ZET6223_VALID_PACKET 0x3c
+#define ZET6223_POWER_ON_DELAY_MSEC	30
 
-struct zet6223_data {
+struct zet6223_ts {
 	struct i2c_client *client;
 	struct input_dev *input;
+	struct regulator *vcc;
+	struct regulator *vio;
 	struct touchscreen_properties prop;
+	u16 max_x;
+	u16 max_y;
 	u8 fingernum;
 };
 
 static int zet6223_start(struct input_dev *dev)
 {
-	struct zet6223_data *data = input_get_drvdata(dev);
+	struct zet6223_ts *ts = input_get_drvdata(dev);
 
-	enable_irq(data->client->irq);
+	enable_irq(ts->client->irq);
 
 	return 0;
 }
 
 static void zet6223_stop(struct input_dev *dev)
 {
-	struct zet6223_data *data = input_get_drvdata(dev);
+	struct zet6223_ts *ts = input_get_drvdata(dev);
 
-	disable_irq(data->client->irq);
+	disable_irq(ts->client->irq);
 }
 
-static irqreturn_t irqreturn_t_zet6223(int irq, void *dev_id)
+static irqreturn_t zet6223_irq(int irq, void *dev_id)
 {
-	struct zet6223_data *data = dev_id;
-	struct device *dev = &data->client->dev;
+	struct zet6223_ts *ts = dev_id;
+	u16 finger_bits;
+
 	/*
 	 * First 3 bytes are an identifier, two bytes of finger data.
 	 * X, Y data per finger is 4 bytes.
 	 */
-	u8 bufsize = 3 + 4 * data->fingernum;
-	u8 buf[bufsize];
-	u8 i;
-	u16 finger_bits;
+	u8 bufsize = 3 + 4 * ts->fingernum;
+	u8 buf[ZET6223_MAX_PKT_SIZE];
+	int i;
 	int ret;
+	int error;
 
-	ret = i2c_master_recv(data->client, buf, bufsize);
+	ret = i2c_master_recv(ts->client, buf, bufsize);
 	if (ret != bufsize) {
-		dev_err_ratelimited(dev, "Error reading input data: %d\n", ret);
+		error = ret < 0 ? ret : -EIO;
+		dev_err_ratelimited(&ts->client->dev,
+				    "Error reading input data: %d\n", error);
 		return IRQ_HANDLED;
 	}
 
@@ -72,113 +85,201 @@ static irqreturn_t irqreturn_t_zet6223(int irq, void *dev_id)
 		return IRQ_HANDLED;
 
 	finger_bits = get_unaligned_be16(buf + 1);
-	for (i = 0; i < data->fingernum; i++) {
+	for (i = 0; i < ts->fingernum; i++) {
 		if (!(finger_bits & BIT(15 - i)))
 			continue;
 
-		input_mt_slot(data->input, i);
-		input_mt_report_slot_state(data->input, MT_TOOL_FINGER, true);
-		input_event(data->input, EV_ABS, ABS_MT_POSITION_X,
+		input_mt_slot(ts->input, i);
+		input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true);
+		input_event(ts->input, EV_ABS, ABS_MT_POSITION_X,
 				((buf[i + 3] >> 4) << 8) + buf[i + 4]);
-		input_event(data->input, EV_ABS, ABS_MT_POSITION_Y,
+		input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y,
 				((buf[i + 3] & 0xF) << 8) + buf[i + 5]);
 	}
 
-	input_mt_sync_frame(data->input);
-	input_sync(data->input);
+	input_mt_sync_frame(ts->input);
+	input_sync(ts->input);
 
 	return IRQ_HANDLED;
 }
 
-static int zet6223_probe(struct i2c_client *client,
-			const struct i2c_device_id *id)
+static int zet6223_power_on(struct zet6223_ts *ts)
+{
+	int error;
+
+	if (ts->vio) {
+		error = regulator_enable(ts->vio);
+		if (error) {
+			dev_err(&ts->client->dev,
+				"failed to enable vio supply: %d\n", error);
+			return error;
+		}
+	}
+
+	if (ts->vcc) {
+		error = regulator_enable(ts->vcc);
+		if (error) {
+			dev_err(&ts->client->dev,
+				"failed to enable vcc supply: %d\n", error);
+			goto err_disable_vio;
+		}
+	}
+
+	if (ts->vio || ts->vcc)
+		msleep(ZET6223_POWER_ON_DELAY_MSEC);
+
+	return 0;
+
+err_disable_vio:
+	if (ts->vio)
+		regulator_disable(ts->vio);
+
+	return error;
+}
+
+static void zet6223_power_off(void *_ts)
+{
+	struct zet6223_ts *ts = _ts;
+
+	if (ts->vcc)
+		regulator_disable(ts->vcc);
+
+	if (ts->vio)
+		regulator_disable(ts->vio);
+}
+
+static int zet6223_query_device(struct zet6223_ts *ts)
 {
-	struct device *dev = &client->dev;
-	struct zet6223_data *data;
-	struct input_dev *input;
 	u8 buf[ZET6223_CMD_INFO_LENGTH];
 	u8 cmd = ZET6223_CMD_INFO;
 	int ret;
+	int error;
+
+	ret = i2c_master_send(ts->client, &cmd, sizeof(cmd));
+	if (ret != sizeof(cmd)) {
+		error = ret < 0 ? ret : -EIO;
+		dev_err(&ts->client->dev,
+			"touchpanel info cmd failed: %d\n", error);
+		return error;
+	}
+
+	ret = i2c_master_recv(ts->client, buf, sizeof(buf));
+	if (ret != sizeof(buf)) {
+		error = ret < 0 ? ret : -EIO;
+		dev_err(&ts->client->dev,
+			"failed to retrieve touchpanel info: %d\n", error);
+		return error;
+	}
+
+	ts->fingernum = buf[15] & 0x7F;
+	if (ts->fingernum > ZET6223_MAX_FINGERS) {
+		dev_warn(&ts->client->dev,
+			 "touchpanel reports %d fingers, limiting to %d\n",
+			 ts->fingernum, ZET6223_MAX_FINGERS);
+		ts->fingernum = 16;
+	}
+
+	ts->max_x = get_unaligned_le16(&buf[8]);
+	ts->max_y = get_unaligned_le16(&buf[10]);
+
+	return 0;
+}
+
+static int zet6223_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct zet6223_ts *ts;
+	struct input_dev *input;
+	int error;
 
 	if (!client->irq) {
-		dev_err(dev, "Error no irq specified\n");
+		dev_err(dev, "no irq specified\n");
 		return -EINVAL;
 	}
 
-	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
-	if (!data)
+	ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
+	if (!ts)
 		return -ENOMEM;
 
-	ret = i2c_master_send(client, &cmd, 1);
-	if (ret < 0) {
-		dev_err(dev, "touchpanel info cmd failed: %d\n", ret);
-		return -ENODEV;
+	ts->client = client;
+
+	ts->vio = devm_regulator_get_optional(dev, "vio");
+	if (IS_ERR(ts->vio)) {
+		error = PTR_ERR(ts->vio);
+		dev_err(dev, "failed to get 'vio' regulator: %d\n", error);
+		return error;
 	}
 
-	ret = i2c_master_recv(client, buf, ZET6223_CMD_INFO_LENGTH);
-	if (ret < 0) {
-		dev_err(dev, "cannot retrieve touchpanel info: %d\n", ret);
-		return -ENODEV;
+	ts->vcc = devm_regulator_get_optional(dev, "vcc");
+	if (IS_ERR(ts->vcc)) {
+		error = PTR_ERR(ts->vcc);
+		dev_err(dev, "failed to get 'vcc' regulator: %d\n", error);
+		return error;
 	}
 
-	data->fingernum = buf[15] & 0x7F;
-	if (data->fingernum > 16) {
-		data->fingernum = 16;
-		dev_warn(dev, "touchpanel reports more then 16 fingers, limit to 16");
+	error = zet6223_power_on(ts);
+	if (error)
+		return error;
+
+	error = devm_add_action_or_reset(dev, zet6223_power_off, ts);
+	if (error) {
+		dev_err(dev, "failed to install poweroff action: %d\n", error);
+		return error;
 	}
 
-	input = devm_input_allocate_device(dev);
+	error = zet6223_query_device(ts);
+	if (error)
+		return error;
+
+	ts->input = input = devm_input_allocate_device(dev);
 	if (!input)
 		return -ENOMEM;
 
-	input_set_abs_params(input, ABS_MT_POSITION_X, 0,
-			get_unaligned_le16(&buf[8]), 0, 0);
-	input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
-			get_unaligned_le16(&buf[10]), 0, 0);
-	touchscreen_parse_properties(input, true, &data->prop);
+	input_set_drvdata(input, ts);
 
 	input->name = client->name;
 	input->id.bustype = BUS_I2C;
-	input->dev.parent = dev;
 	input->open = zet6223_start;
 	input->close = zet6223_stop;
 
-	ret = input_mt_init_slots(input, data->fingernum,
-		INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
-	if (ret)
-		return ret;
+	input_set_abs_params(input, ABS_MT_POSITION_X, 0, ts->max_x, 0, 0);
+	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ts->max_y, 0, 0);
 
-	data->client = client;
-	data->input = input;
+	touchscreen_parse_properties(input, true, &ts->prop);
 
-	input_set_drvdata(input, data);
+	error = input_mt_init_slots(input, ts->fingernum,
+				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+	if (error)
+		return error;
 
-	ret = devm_request_threaded_irq(dev, client->irq, NULL,
-			irqreturn_t_zet6223, IRQF_ONESHOT, client->name, data);
-	if (ret) {
-		dev_err(dev, "Error requesting irq: %d\n", ret);
-		return ret;
+	error = devm_request_threaded_irq(dev, client->irq, NULL, zet6223_irq,
+					  IRQF_ONESHOT, client->name, ts);
+	if (error) {
+		dev_err(dev, "failed to request irq %d: %d\n",
+			client->irq, error);
+		return error;
 	}
 
 	zet6223_stop(input);
 
-	ret = input_register_device(input);
-	if (ret)
-		return ret;
+	error = input_register_device(input);
+	if (error)
+		return error;
 
-	i2c_set_clientdata(client, data);
+	i2c_set_clientdata(client, ts);
 
 	return 0;
 }
 
 static const struct of_device_id zet6223_of_match[] = {
-	{ .compatible = "zeitec", "zet6223" },
+	{ .compatible = "zeitec,zet6223" },
 	{ }
 };
 
 static const struct i2c_device_id zet6223_id[] = {
 	{ "zet6223", 0},
-	{}
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, zet6223_id);
 
@@ -190,7 +291,6 @@ static struct i2c_driver zet6223_driver = {
 	.probe = zet6223_probe,
 	.id_table = zet6223_id
 };
-
 module_i2c_driver(zet6223_driver);
 
 MODULE_AUTHOR("Jelle van der Waa <jelle-oJJ1AqDjjO4@public.gmane.org>");
--
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 related

* Re: [PATCH v2 1/3] Input: pwm-beeper: suppress error message on probe defer
From: Dmitry Torokhov @ 2017-01-14 19:17 UTC (permalink / raw)
  To: David Lechner
  Cc: linux-input, devicetree, Rob Herring, Mark Rutland, linux-kernel
In-Reply-To: <1484164921-30587-2-git-send-email-david@lechnology.com>

On Wed, Jan 11, 2017 at 02:01:59PM -0600, David Lechner wrote:
> This suppress printing an error message when pwm_get returns -EPROBE_DEFER.
> Otherwise you get a bunch of noise in the kernel log.
> 
> Signed-off-by: David Lechner <david@lechnology.com>
> ---
>  drivers/input/misc/pwm-beeper.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
> index ce6eec4..30ac227 100644
> --- a/drivers/input/misc/pwm-beeper.c
> +++ b/drivers/input/misc/pwm-beeper.c
> @@ -104,9 +104,10 @@ static int pwm_beeper_probe(struct platform_device *pdev)
>  		return -ENOMEM;
>  
>  	beeper->pwm = devm_pwm_get(dev, NULL);
> -	if (IS_ERR(beeper->pwm)) {
> -		error = PTR_ERR(beeper->pwm);
> -		dev_err(dev, "Failed to request pwm device: %d\n", error);
> +	error = PTR_ERR_OR_ZERO(beeper->pwm);
> +	if (error) {

I do not find it in any way clearer than

	if (IS_ERR()) {
		...

I prefer PTR_ERR_OR_ZERO be used when you need to return value without
acting on it.

I can adjust locally, no need to resubmit.

> +		if (error != -EPROBE_DEFER)
> +			dev_err(dev, "Failed to request pwm device\n");
>  		return error;
>  	}
>  
> -- 
> 2.7.4
> 

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH v2 3/3] Input: pwm-beeper: add optional amplifier regulator
From: Dmitry Torokhov @ 2017-01-14 19:19 UTC (permalink / raw)
  To: David Lechner
  Cc: linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Mark Rutland,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1484164921-30587-4-git-send-email-david-nq/r/kbU++upp/zk7JDF2g@public.gmane.org>

On Wed, Jan 11, 2017 at 02:02:01PM -0600, David Lechner wrote:
> This adds an optional regulator to the pwm-beeper device. This regulator
> acts as an amplifier. The amplifier is only enabled while beeping in order
> to reduce power consumption.
> 
> Tested on LEGO MINDSTORMS EV3, which has a speaker connected to PWM through
> an amplifier.
> 
> Signed-off-by: David Lechner <david-nq/r/kbU++upp/zk7JDF2g@public.gmane.org>
> ---
>  drivers/input/misc/pwm-beeper.c | 29 ++++++++++++++++++++++++++++-
>  1 file changed, 28 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
> index 30ac227..708e88e 100644
> --- a/drivers/input/misc/pwm-beeper.c
> +++ b/drivers/input/misc/pwm-beeper.c
> @@ -14,6 +14,7 @@
>   */
>  
>  #include <linux/input.h>
> +#include <linux/regulator/consumer.h>
>  #include <linux/module.h>
>  #include <linux/kernel.h>
>  #include <linux/of.h>
> @@ -25,8 +26,10 @@
>  struct pwm_beeper {
>  	struct input_dev *input;
>  	struct pwm_device *pwm;
> +	struct regulator *reg;
>  	struct work_struct work;
>  	unsigned long period;
> +	bool reg_enabled;
>  };
>  
>  #define HZ_TO_NANOSECONDS(x) (1000000000UL/(x))
> @@ -38,8 +41,20 @@ static void __pwm_beeper_set(struct pwm_beeper *beeper)
>  	if (period) {
>  		pwm_config(beeper->pwm, period / 2, period);
>  		pwm_enable(beeper->pwm);
> -	} else
> +		if (beeper->reg) {
> +			int error;
> +
> +			error = regulator_enable(beeper->reg);
> +			if (!error)
> +				beeper->reg_enabled = true;
> +		}
> +	} else {
> +		if (beeper->reg_enabled) {
> +			regulator_disable(beeper->reg);
> +			beeper->reg_enabled = false;
> +		}
>  		pwm_disable(beeper->pwm);
> +	}
>  }
>  
>  static void pwm_beeper_work(struct work_struct *work)
> @@ -82,6 +97,10 @@ static void pwm_beeper_stop(struct pwm_beeper *beeper)
>  {
>  	cancel_work_sync(&beeper->work);
>  
> +	if (beeper->reg_enabled) {
> +		regulator_disable(beeper->reg);
> +		beeper->reg_enabled = false;
> +	}
>  	if (beeper->period)
>  		pwm_disable(beeper->pwm);
>  }
> @@ -111,6 +130,14 @@ static int pwm_beeper_probe(struct platform_device *pdev)
>  		return error;
>  	}
>  
> +	beeper->reg = devm_regulator_get_optional(&pdev->dev, "amp");

If you do not use optional regulator then you will not have to check if
you have it or not everywhere: regulator core will give you a dummy that
you can toggle to your heart's content.

> +	error = PTR_ERR_OR_ZERO(beeper->reg);
> +	if (error) {
> +		if (error != -EPROBE_DEFER)
> +			dev_err(dev, "Failed to get amp regulator\n");
> +		return error;
> +	}
> +
>  	/*
>  	 * FIXME: pwm_apply_args() should be removed when switching to
>  	 * the atomic PWM API.
> -- 
> 2.7.4
> 

Thanks.

-- 
Dmitry
--
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 v3] iio: max5481: Add support for Maxim digital potentiometers
From: Slawomir Stepien @ 2017-01-14 21:21 UTC (permalink / raw)
  To: linux-iio-u79uwXL29TY76Z2rM5mHXA
  Cc: matthew.weber-lFk7bPDcGtkY5TsXZYaR1UEOCMrvLtNR,
	maury.anderson-lFk7bPDcGtkY5TsXZYaR1UEOCMrvLtNR,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Mark Rutland, Rob Herring

From: Matt Weber <matthew.weber-lFk7bPDcGtkY5TsXZYaR1UEOCMrvLtNR@public.gmane.org>

Add implementation for Maxim Integrated 5481, 5482, 5483,
and 5484 digital potentiometer devices.

Datasheet:
http://datasheets.maximintegrated.com/en/ds/MAX5481-MAX5484.pdf

Signed-off-by: Maury Anderson <maury.anderson-lFk7bPDcGtkY5TsXZYaR1UEOCMrvLtNR@public.gmane.org>
Signed-off-by: Matthew Weber <matthew.weber-lFk7bPDcGtkY5TsXZYaR1UEOCMrvLtNR@public.gmane.org>
Signed-off-by: Slawomir Stepien <sst-IjDXvh/HVVUAvxtiuMwx3w@public.gmane.org>
---

This is my resubmission of this patch after original authors decided not to
pursuit it inclusion into kernel.

Tested using signal analyzer.

Changes since v2:
* spi write buffer moved to struct max5481_data and ____cacheline_aligned.
* max5481_write_cmd now uses pointer to struct max5481_data as a first argument.

Changes since v1:
* removed not needed '``' and 'c' chars
* includes are now sorted
* added coma to last item in enum max5481_variant
* removed maxpos from struct max5481_cfg
* max5481_CHANNEL is no MAX5481_CHANNEL and it does not have 'ch' argument
* max5481_write_cmd is now based around switch
* removed not needed cast in max5481_write_cmd
* wpier state is saved after iio_device_unregister
* changed names in spi_device_id and acpi_device_id to be equal to names in of_device_id

---
 .../bindings/iio/potentiometer/max5481.txt         |  23 +++
 drivers/iio/potentiometer/Kconfig                  |  11 ++
 drivers/iio/potentiometer/Makefile                 |   1 +
 drivers/iio/potentiometer/max5481.c                | 216 +++++++++++++++++++++
 4 files changed, 251 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/potentiometer/max5481.txt
 create mode 100644 drivers/iio/potentiometer/max5481.c

diff --git a/Documentation/devicetree/bindings/iio/potentiometer/max5481.txt b/Documentation/devicetree/bindings/iio/potentiometer/max5481.txt
new file mode 100644
index 000000000000..6a91b106e076
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/potentiometer/max5481.txt
@@ -0,0 +1,23 @@
+* Maxim Linear-Taper Digital Potentiometer MAX5481-MAX5484
+
+The node for this driver must be a child node of a SPI controller, hence
+all mandatory properties described in
+
+        Documentation/devicetree/bindings/spi/spi-bus.txt
+
+must be specified.
+
+Required properties:
+	- compatible:  	Must be one of the following, depending on the
+			model:
+			"maxim,max5481"
+			"maxim,max5482"
+			"maxim,max5483"
+			"maxim,max5484"
+
+Example:
+max548x: max548x@0 {
+	compatible = "maxim,max5482";
+	spi-max-frequency = <7000000>;
+	reg = <0>; /* chip-select */
+};
diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig
index 2e9da1cf3297..8bf282510be6 100644
--- a/drivers/iio/potentiometer/Kconfig
+++ b/drivers/iio/potentiometer/Kconfig
@@ -15,6 +15,17 @@ config DS1803
 	  To compile this driver as a module, choose M here: the
 	  module will be called ds1803.
 
+config MAX5481
+        tristate "Maxim MAX5481-MAX5484 Digital Potentiometer driver"
+        depends on SPI
+        help
+          Say yes here to build support for the Maxim
+          MAX5481, MAX5482, MAX5483, MAX5484 digital potentiometer
+          chips.
+
+          To compile this driver as a module, choose M here: the
+          module will be called max5481.
+
 config MAX5487
         tristate "Maxim MAX5487/MAX5488/MAX5489 Digital Potentiometer driver"
         depends on SPI
diff --git a/drivers/iio/potentiometer/Makefile b/drivers/iio/potentiometer/Makefile
index 8adb58f38c0b..2260d40e0936 100644
--- a/drivers/iio/potentiometer/Makefile
+++ b/drivers/iio/potentiometer/Makefile
@@ -4,6 +4,7 @@
 
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_DS1803) += ds1803.o
+obj-$(CONFIG_MAX5481) += max5481.o
 obj-$(CONFIG_MAX5487) += max5487.o
 obj-$(CONFIG_MCP4131) += mcp4131.o
 obj-$(CONFIG_MCP4531) += mcp4531.o
diff --git a/drivers/iio/potentiometer/max5481.c b/drivers/iio/potentiometer/max5481.c
new file mode 100644
index 000000000000..559f1635be0a
--- /dev/null
+++ b/drivers/iio/potentiometer/max5481.c
@@ -0,0 +1,216 @@
+/*
+ * Maxim Integrated MAX5481-MAX5484 digital potentiometer driver
+ * Copyright 2016 Rockwell Collins
+ *
+ * Datasheet:
+ * http://datasheets.maximintegrated.com/en/ds/MAX5481-MAX5484.pdf
+ *
+ * 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/acpi.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+
+/* write wiper reg */
+#define MAX5481_WRITE_WIPER (0 << 4)
+/* copy wiper reg to NV reg */
+#define MAX5481_COPY_AB_TO_NV (2 << 4)
+/* copy NV reg to wiper reg */
+#define MAX5481_COPY_NV_TO_AB (3 << 4)
+
+#define MAX5481_MAX_POS    1023
+
+enum max5481_variant {
+	max5481,
+	max5482,
+	max5483,
+	max5484,
+};
+
+struct max5481_cfg {
+	int kohms;
+};
+
+static const struct max5481_cfg max5481_cfg[] = {
+	[max5481] = { .kohms =  10, },
+	[max5482] = { .kohms =  50, },
+	[max5483] = { .kohms =  10, },
+	[max5484] = { .kohms =  50, },
+};
+
+struct max5481_data {
+	struct spi_device *spi;
+	const struct max5481_cfg *cfg;
+	u8 msg[3] ____cacheline_aligned;
+};
+
+#define MAX5481_CHANNEL {					\
+	.type = IIO_RESISTANCE,					\
+	.indexed = 1,						\
+	.output = 1,						\
+	.channel = 0,						\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
+}
+
+static const struct iio_chan_spec max5481_channels[] = {
+	MAX5481_CHANNEL,
+};
+
+static int max5481_write_cmd(struct max5481_data *data, u8 cmd, u16 val)
+{
+	struct spi_device *spi = data->spi;
+
+	data->msg[0] = cmd;
+
+	switch (cmd) {
+	case MAX5481_WRITE_WIPER:
+		data->msg[1] = val >> 2;
+		data->msg[2] = (val & 0x3) << 6;
+		return spi_write(spi, data->msg, ARRAY_SIZE(data->msg));
+
+	case MAX5481_COPY_AB_TO_NV:
+	case MAX5481_COPY_NV_TO_AB:
+		return spi_write(spi, data->msg, sizeof(data->msg[0]));
+
+	default:
+		return -EIO;
+	}
+}
+
+static int max5481_read_raw(struct iio_dev *indio_dev,
+		struct iio_chan_spec const *chan,
+		int *val, int *val2, long mask)
+{
+	struct max5481_data *data = iio_priv(indio_dev);
+
+	if (mask != IIO_CHAN_INFO_SCALE)
+		return -EINVAL;
+
+	*val = 1000 * data->cfg->kohms;
+	*val2 = MAX5481_MAX_POS;
+
+	return IIO_VAL_FRACTIONAL;
+}
+
+static int max5481_write_raw(struct iio_dev *indio_dev,
+		struct iio_chan_spec const *chan,
+		int val, int val2, long mask)
+{
+	struct max5481_data *data = iio_priv(indio_dev);
+
+	if (mask != IIO_CHAN_INFO_RAW)
+		return -EINVAL;
+
+	if (val < 0 || val > MAX5481_MAX_POS)
+		return -EINVAL;
+
+	return max5481_write_cmd(data, MAX5481_WRITE_WIPER, val);
+}
+
+static const struct iio_info max5481_info = {
+	.read_raw = max5481_read_raw,
+	.write_raw = max5481_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int max5481_probe(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev;
+	struct max5481_data *data;
+	const struct spi_device_id *id = spi_get_device_id(spi);
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	dev_set_drvdata(&spi->dev, indio_dev);
+	data = iio_priv(indio_dev);
+
+	data->spi = spi;
+	data->cfg = &max5481_cfg[id->driver_data];
+
+	indio_dev->name = id->name;
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	/* variant specific configuration */
+	indio_dev->info = &max5481_info;
+	indio_dev->channels = max5481_channels;
+	indio_dev->num_channels = ARRAY_SIZE(max5481_channels);
+
+	/* restore wiper from NV */
+	ret = max5481_write_cmd(data, MAX5481_COPY_NV_TO_AB, 0);
+	if (ret < 0)
+		return ret;
+
+	return iio_device_register(indio_dev);
+}
+
+static int max5481_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(&spi->dev);
+	struct max5481_data *data = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	/* save wiper reg to NV reg */
+	return max5481_write_cmd(data, MAX5481_COPY_AB_TO_NV, 0);
+}
+
+static const struct spi_device_id max5481_id_table[] = {
+	{ "max5481", max5481 },
+	{ "max5482", max5482 },
+	{ "max5483", max5483 },
+	{ "max5484", max5484 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, max5481_id_table);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id max5481_match[] = {
+	{ .compatible = "maxim,max5481", .data = &max5481_cfg[max5481] },
+	{ .compatible = "maxim,max5482", .data = &max5481_cfg[max5482] },
+	{ .compatible = "maxim,max5483", .data = &max5481_cfg[max5483] },
+	{ .compatible = "maxim,max5484", .data = &max5481_cfg[max5484] },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max5481_match);
+#endif
+
+#if defined(CONFIG_ACPI)
+static const struct acpi_device_id max5481_acpi_match[] = {
+	{ "max5481", max5481 },
+	{ "max5482", max5482 },
+	{ "max5483", max5483 },
+	{ "max5484", max5484 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, max5481_acpi_match);
+#endif
+
+static struct spi_driver max5481_driver = {
+	.driver = {
+		.name  = "max5481",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(max5481_match),
+		.acpi_match_table = ACPI_PTR(max5481_acpi_match),
+	},
+	.probe = max5481_probe,
+	.remove = max5481_remove,
+	.id_table = max5481_id_table,
+};
+
+module_spi_driver(max5481_driver);
+
+MODULE_AUTHOR("Maury Anderson <maury.anderson-lFk7bPDcGtkY5TsXZYaR1UEOCMrvLtNR@public.gmane.org>");
+MODULE_DESCRIPTION("max5481 SPI driver");
+MODULE_LICENSE("GPL v2");
-- 
2.11.0

^ permalink raw reply related

* Re: [PATCH v2 2/2] mmc: pwrseq: add support for Marvell SD8787 chip
From: kbuild test robot @ 2017-01-14 21:37 UTC (permalink / raw)
  Cc: kbuild-all, linux-wireless, linux-kernel, linux-mmc, devicetree,
	tony, Matt Ranostay, Ulf Hansson
In-Reply-To: <20170113052218.10534-3-matt@ranostay.consulting>

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

Hi Matt,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.10-rc3 next-20170113]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Matt-Ranostay/mmc-pwrseq-add-support-for-Marvell-SD8787-chip/20170115-030459
config: i386-allmodconfig (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

>> make[4]: *** No rule to make target 'drivers/mmc/core/pwrseq_sd8787.c', needed by 'drivers/mmc/core/pwrseq_sd8787.o'.
   make[4]: Target '__build' not remade because of errors.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 57927 bytes --]

^ permalink raw reply


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