From dea120e665712a9be41a6c846e73c6af19e00af7 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 24 Mar 2013 16:58:00 +0000 Subject: [PATCH 1/7] staging:iio:magnetometer:ak8975 drop unused eoc_irq Signed-off-by: Jonathan Cameron Acked-by: Laxman Dewangan --- drivers/staging/iio/magnetometer/ak8975.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/iio/magnetometer/ak8975.c b/drivers/staging/iio/magnetometer/ak8975.c index b614da1b21f8..8726ea1de083 100644 --- a/drivers/staging/iio/magnetometer/ak8975.c +++ b/drivers/staging/iio/magnetometer/ak8975.c @@ -94,7 +94,6 @@ struct ak8975_data { long raw_to_gauss[3]; u8 reg_cache[AK8975_MAX_REGS]; int eoc_gpio; - int eoc_irq; }; static const int ak8975_index_to_reg[] = { @@ -452,7 +451,6 @@ static int ak8975_probe(struct i2c_client *client, data->client = client; mutex_init(&data->lock); - data->eoc_irq = client->irq; data->eoc_gpio = eoc_gpio; indio_dev->dev.parent = &client->dev; indio_dev->channels = ak8975_channels; From aa9922579fee20ac4f2bb959a79bbfbff2c04585 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 24 Mar 2013 16:58:00 +0000 Subject: [PATCH 2/7] staging:iio:magnetometer:ak8975 drop I2C_M_NOSTART flag in read_data This flag makes no sense whatsoever where it is. Documentation/i2c/i2c-protocol states: If you set the I2C_M_NOSTART variable for the first partial message, we do not generate Addr, but we do generate the startbit S. This will probably confuse all other clients on your bus, so don't try this. This is exactly what is going on here. Likelihood given that the driver never checked for this protocol mangling being available is that it wasn't present on the test boards and hence this flag was simply ignored. No indication of why it would be necessary has been found in the datasheets. Signed-off-by: Jonathan Cameron Acked-by: Laxman Dewangan --- drivers/staging/iio/magnetometer/ak8975.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/iio/magnetometer/ak8975.c b/drivers/staging/iio/magnetometer/ak8975.c index 8726ea1de083..1428849fd5a2 100644 --- a/drivers/staging/iio/magnetometer/ak8975.c +++ b/drivers/staging/iio/magnetometer/ak8975.c @@ -132,7 +132,6 @@ static int ak8975_read_data(struct i2c_client *client, struct i2c_msg msg[2] = { { .addr = client->addr, - .flags = I2C_M_NOSTART, .len = 1, .buf = ®, }, { From c411f600cea54d1e00a32071502226acc5072428 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 24 Mar 2013 16:58:00 +0000 Subject: [PATCH 3/7] staging:iio:magnetometer:ak8975 use standard i2c_smbus read functions. Now the mysterious NOSTART flag is gone from the read, we can use the i2c_smbus_read_byte/word/i2c_block_data functions instead of the local reimplementation of these standard functions. Signed-off-by: Jonathan Cameron Acked-by: Laxman Dewangan --- drivers/staging/iio/magnetometer/ak8975.c | 66 ++++++----------------- 1 file changed, 17 insertions(+), 49 deletions(-) diff --git a/drivers/staging/iio/magnetometer/ak8975.c b/drivers/staging/iio/magnetometer/ak8975.c index 1428849fd5a2..af6c320a534e 100644 --- a/drivers/staging/iio/magnetometer/ak8975.c +++ b/drivers/staging/iio/magnetometer/ak8975.c @@ -122,35 +122,6 @@ static int ak8975_write_data(struct i2c_client *client, return 0; } -/* - * Helper function to read a contiguous set of the I2C device's registers. - */ -static int ak8975_read_data(struct i2c_client *client, - u8 reg, u8 length, u8 *buffer) -{ - int ret; - struct i2c_msg msg[2] = { - { - .addr = client->addr, - .len = 1, - .buf = ®, - }, { - .addr = client->addr, - .flags = I2C_M_RD, - .len = length, - .buf = buffer, - } - }; - - ret = i2c_transfer(client->adapter, msg, 2); - if (ret < 0) { - dev_err(&client->dev, "Read from device fails\n"); - return ret; - } - - return 0; -} - /* * Perform some start-of-day setup, including reading the asa calibration * values and caching them. @@ -163,11 +134,12 @@ static int ak8975_setup(struct i2c_client *client) int ret; /* Confirm that the device we're talking to is really an AK8975. */ - ret = ak8975_read_data(client, AK8975_REG_WIA, 1, &device_id); + ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA); if (ret < 0) { dev_err(&client->dev, "Error reading WIA\n"); return ret; } + device_id = ret; if (device_id != AK8975_DEVICE_ID) { dev_err(&client->dev, "Device ak8975 not found\n"); return -ENODEV; @@ -185,7 +157,8 @@ static int ak8975_setup(struct i2c_client *client) } /* Get asa data and store in the device data. */ - ret = ak8975_read_data(client, AK8975_REG_ASAX, 3, data->asa); + ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX, + 3, data->asa); if (ret < 0) { dev_err(&client->dev, "Not able to read asa data\n"); return ret; @@ -247,7 +220,6 @@ static int ak8975_setup(struct i2c_client *client) static int wait_conversion_complete_gpio(struct ak8975_data *data) { struct i2c_client *client = data->client; - u8 read_status; u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT; int ret; @@ -263,12 +235,11 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data) return -EINVAL; } - ret = ak8975_read_data(client, AK8975_REG_ST1, 1, &read_status); - if (ret < 0) { + ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1); + if (ret < 0) dev_err(&client->dev, "Error in reading ST1\n"); - return ret; - } - return read_status; + + return ret; } static int wait_conversion_complete_polled(struct ak8975_data *data) @@ -281,11 +252,12 @@ static int wait_conversion_complete_polled(struct ak8975_data *data) /* Wait for the conversion to complete. */ while (timeout_ms) { msleep(AK8975_CONVERSION_DONE_POLL_TIME); - ret = ak8975_read_data(client, AK8975_REG_ST1, 1, &read_status); + ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1); if (ret < 0) { dev_err(&client->dev, "Error in reading ST1\n"); return ret; } + read_status = ret; if (read_status) break; timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME; @@ -306,7 +278,6 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) struct i2c_client *client = data->client; u16 meas_reg; s16 raw; - u8 read_status; int ret; mutex_lock(&data->lock); @@ -330,18 +301,15 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) if (ret < 0) goto exit; - read_status = ret; - - if (read_status & AK8975_REG_ST1_DRDY_MASK) { - ret = ak8975_read_data(client, AK8975_REG_ST2, 1, &read_status); + if (ret & AK8975_REG_ST1_DRDY_MASK) { + ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2); if (ret < 0) { dev_err(&client->dev, "Error in reading ST2\n"); goto exit; } - if (read_status & (AK8975_REG_ST2_DERR_MASK | - AK8975_REG_ST2_HOFL_MASK)) { - dev_err(&client->dev, "ST2 status error 0x%x\n", - read_status); + if (ret & (AK8975_REG_ST2_DERR_MASK | + AK8975_REG_ST2_HOFL_MASK)) { + dev_err(&client->dev, "ST2 status error 0x%x\n", ret); ret = -EINVAL; goto exit; } @@ -349,12 +317,12 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) /* Read the flux value from the appropriate register (the register is specified in the iio device attributes). */ - ret = ak8975_read_data(client, ak8975_index_to_reg[index], - 2, (u8 *)&meas_reg); + ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]); if (ret < 0) { dev_err(&client->dev, "Read axis data fails\n"); goto exit; } + meas_reg = ret; mutex_unlock(&data->lock); From 2fc72cd8354e3e9c4893fc082614266ddb599902 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 24 Mar 2013 16:58:00 +0000 Subject: [PATCH 4/7] iio:magnetometer:ak8975 move driver out of staging Issues raised in last series to propose this have now been resolved so there should be no reason this driver cannot graduate from staging. Signed-off-by: Jonathan Cameron Acked-by: Laxman Dewangan --- drivers/iio/magnetometer/Kconfig | 11 +++++++++++ drivers/iio/magnetometer/Makefile | 1 + drivers/{staging => }/iio/magnetometer/ak8975.c | 0 drivers/staging/iio/magnetometer/Kconfig | 11 ----------- drivers/staging/iio/magnetometer/Makefile | 1 - 5 files changed, 12 insertions(+), 12 deletions(-) rename drivers/{staging => }/iio/magnetometer/ak8975.c (100%) diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index cd29be54f643..bd1cfb666695 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -3,6 +3,17 @@ # menu "Magnetometer sensors" +config AK8975 + tristate "Asahi Kasei AK8975 3-Axis Magnetometer" + depends on I2C + depends on GPIOLIB + help + Say yes here to build support for Asahi Kasei AK8975 3-Axis + Magnetometer. + + To compile this driver as a module, choose M here: the module + will be called ak8975. + config HID_SENSOR_MAGNETOMETER_3D depends on HID_SENSOR_HUB select IIO_BUFFER diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile index e78672876dc2..7f328e37fbab 100644 --- a/drivers/iio/magnetometer/Makefile +++ b/drivers/iio/magnetometer/Makefile @@ -2,6 +2,7 @@ # Makefile for industrial I/O Magnetometer sensor drivers # +obj-$(CONFIG_AK8975) += ak8975.o obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o obj-$(CONFIG_IIO_ST_MAGN_3AXIS) += st_magn.o diff --git a/drivers/staging/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c similarity index 100% rename from drivers/staging/iio/magnetometer/ak8975.c rename to drivers/iio/magnetometer/ak8975.c diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig index df5e0d4ea295..a3ea69e9d800 100644 --- a/drivers/staging/iio/magnetometer/Kconfig +++ b/drivers/staging/iio/magnetometer/Kconfig @@ -3,17 +3,6 @@ # menu "Magnetometer sensors" -config SENSORS_AK8975 - tristate "Asahi Kasei AK8975 3-Axis Magnetometer" - depends on I2C - depends on GPIOLIB - help - Say yes here to build support for Asahi Kasei AK8975 3-Axis - Magnetometer. - - To compile this driver as a module, choose M here: the module - will be called ak8975. - config SENSORS_HMC5843 tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer" depends on I2C diff --git a/drivers/staging/iio/magnetometer/Makefile b/drivers/staging/iio/magnetometer/Makefile index f2a753f80796..f9bfb2e11d7d 100644 --- a/drivers/staging/iio/magnetometer/Makefile +++ b/drivers/staging/iio/magnetometer/Makefile @@ -2,5 +2,4 @@ # Makefile for industrial I/O Magnetometer sensors # -obj-$(CONFIG_SENSORS_AK8975) += ak8975.o obj-$(CONFIG_SENSORS_HMC5843) += hmc5843.o From 47be16b6683b86653545bf98f6f57019bb99969c Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Fri, 29 Mar 2013 14:54:00 +0000 Subject: [PATCH 5/7] iio: at91_adc: add low and high res support at91 adc offers the choice between two resolutions: low and high. The low and high resolution values depends on adc IP version, as many IP properties have been exposed through device tree, these settings have also been added to the dt bindings. Signed-off-by: Ludovic Desroches Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/arm/atmel-adc.txt | 11 +++ drivers/iio/adc/at91_adc.c | 74 ++++++++++++++++++- 2 files changed, 81 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt index c63097d6afeb..fd2d69ee2876 100644 --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt @@ -14,9 +14,17 @@ Required properties: - atmel,adc-status-register: Offset of the Interrupt Status Register - atmel,adc-trigger-register: Offset of the Trigger Register - atmel,adc-vref: Reference voltage in millivolts for the conversions + - atmel,adc-res: List of resolution in bits supported by the ADC. List size + must be two at least. + - atmel,adc-res-names: Contains one identifier string for each resolution + in atmel,adc-res property. "lowres" and "highres" + identifiers are required. Optional properties: - atmel,adc-use-external: Boolean to enable of external triggers + - atmel,adc-use-res: String corresponding to an identifier from + atmel,adc-res-names property. If not specified, the highest + resolution will be used. Optional trigger Nodes: - Required properties: @@ -40,6 +48,9 @@ adc0: adc@fffb0000 { atmel,adc-trigger-register = <0x08>; atmel,adc-use-external; atmel,adc-vref = <3300>; + atmel,adc-res = <8 10>; + atmel,adc-res-names = "lowres", "highres"; + atmel,adc-use-res = "lowres"; trigger@0 { trigger-name = "external-rising"; diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 6fc43c15f028..3fb3fe48a98c 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -57,6 +57,8 @@ struct at91_adc_state { u32 trigger_number; bool use_external; u32 vref_mv; + u32 res; /* resolution used for convertions */ + bool low_res; /* the resolution corresponds to the lowest one */ wait_queue_head_t wq_data_avail; }; @@ -138,7 +140,7 @@ static int at91_adc_channel_init(struct iio_dev *idev) chan->channel = bit; chan->scan_index = idx; chan->scan_type.sign = 'u'; - chan->scan_type.realbits = 10; + chan->scan_type.realbits = st->res; chan->scan_type.storagebits = 16; chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); @@ -372,6 +374,59 @@ static int at91_adc_read_raw(struct iio_dev *idev, return -EINVAL; } +static int at91_adc_of_get_resolution(struct at91_adc_state *st, + struct platform_device *pdev) +{ + struct iio_dev *idev = iio_priv_to_dev(st); + struct device_node *np = pdev->dev.of_node; + int count, i, ret = 0; + char *res_name, *s; + u32 *resolutions; + + count = of_property_count_strings(np, "atmel,adc-res-names"); + if (count < 2) { + dev_err(&idev->dev, "You must specified at least two resolution names for " + "adc-res-names property in the DT\n"); + return count; + } + + resolutions = kmalloc(count * sizeof(*resolutions), GFP_KERNEL); + if (!resolutions) + return -ENOMEM; + + if (of_property_read_u32_array(np, "atmel,adc-res", resolutions, count)) { + dev_err(&idev->dev, "Missing adc-res property in the DT.\n"); + ret = -ENODEV; + goto ret; + } + + if (of_property_read_string(np, "atmel,adc-use-res", (const char **)&res_name)) + res_name = "highres"; + + for (i = 0; i < count; i++) { + if (of_property_read_string_index(np, "atmel,adc-res-names", i, (const char **)&s)) + continue; + + if (strcmp(res_name, s)) + continue; + + st->res = resolutions[i]; + if (!strcmp(res_name, "lowres")) + st->low_res = true; + else + st->low_res = false; + + dev_info(&idev->dev, "Resolution used: %u bits\n", st->res); + goto ret; + } + + dev_err(&idev->dev, "There is no resolution for %s\n", res_name); + +ret: + kfree(resolutions); + return ret; +} + static int at91_adc_probe_dt(struct at91_adc_state *st, struct platform_device *pdev) { @@ -415,6 +470,10 @@ static int at91_adc_probe_dt(struct at91_adc_state *st, } st->vref_mv = prop; + ret = at91_adc_of_get_resolution(st, pdev); + if (ret) + goto error_ret; + st->registers = devm_kzalloc(&idev->dev, sizeof(struct at91_adc_reg_desc), GFP_KERNEL); @@ -628,9 +687,16 @@ static int at91_adc_probe(struct platform_device *pdev) */ ticks = round_up((st->startup_time * adc_clk / 1000000) - 1, 8) / 8; - at91_adc_writel(st, AT91_ADC_MR, - (AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL) | - (AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP)); + + if (st->low_res) + at91_adc_writel(st, AT91_ADC_MR, + AT91_ADC_LOWRES | + (AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL) | + (AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP)); + else + at91_adc_writel(st, AT91_ADC_MR, + (AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL) | + (AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP)); /* Setup the ADC channels available on the board */ ret = at91_adc_channel_init(idev); From e748783c55f074046134d2ef15a6e04dd467ecfc Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Fri, 29 Mar 2013 14:54:00 +0000 Subject: [PATCH 6/7] iio: at91_adc: add sleep mode support The sleep mode will allow to put the adc in sleep between conversion. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Ludovic Desroches Acked-by: Maxime Ripard Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/arm/atmel-adc.txt | 1 + drivers/iio/adc/at91_adc.c | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt index fd2d69ee2876..3a05492acdaf 100644 --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt @@ -25,6 +25,7 @@ Optional properties: - atmel,adc-use-res: String corresponding to an identifier from atmel,adc-res-names property. If not specified, the highest resolution will be used. + - atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion Optional trigger Nodes: - Required properties: diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 3fb3fe48a98c..7295bc5280bd 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -52,6 +52,7 @@ struct at91_adc_state { void __iomem *reg_base; struct at91_adc_reg_desc *registers; u8 startup_time; + bool sleep_mode; struct iio_trigger **trig; struct at91_adc_trigger *trigger_list; u32 trigger_number; @@ -455,6 +456,8 @@ static int at91_adc_probe_dt(struct at91_adc_state *st, } st->num_channels = prop; + st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode"); + if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) { dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n"); ret = -EINVAL; @@ -580,6 +583,7 @@ static int at91_adc_probe(struct platform_device *pdev) struct iio_dev *idev; struct at91_adc_state *st; struct resource *res; + u32 reg; idev = iio_device_alloc(sizeof(struct at91_adc_state)); if (idev == NULL) { @@ -687,16 +691,13 @@ static int at91_adc_probe(struct platform_device *pdev) */ ticks = round_up((st->startup_time * adc_clk / 1000000) - 1, 8) / 8; - + reg = AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL; + reg |= AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP; if (st->low_res) - at91_adc_writel(st, AT91_ADC_MR, - AT91_ADC_LOWRES | - (AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL) | - (AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP)); - else - at91_adc_writel(st, AT91_ADC_MR, - (AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL) | - (AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP)); + reg |= AT91_ADC_LOWRES; + if (st->sleep_mode) + reg |= AT91_ADC_SLEEP; + at91_adc_writel(st, AT91_ADC_MR, reg); /* Setup the ADC channels available on the board */ ret = at91_adc_channel_init(idev); From beca9e767e27f756d6aed9a62665e3f73546aabb Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Fri, 29 Mar 2013 14:54:00 +0000 Subject: [PATCH 7/7] iio: at91_adc: fix missing Sample and Hold time On the at91_adc a minimal Sample and Hold Time is necessary for the ADC to guarantee the best converted final value between two channels selection. This time has to be programmed through the bitfield SHTIM in the Mode Register ADC_MR. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Ludovic Desroches Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/arm/atmel-adc.txt | 1 + drivers/iio/adc/at91_adc.c | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt index 3a05492acdaf..16769d9cedd6 100644 --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt @@ -26,6 +26,7 @@ Optional properties: atmel,adc-res-names property. If not specified, the highest resolution will be used. - atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion + - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds Optional trigger Nodes: - Required properties: diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 7295bc5280bd..e5b88d5d3b59 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -52,6 +52,7 @@ struct at91_adc_state { void __iomem *reg_base; struct at91_adc_reg_desc *registers; u8 startup_time; + u8 sample_hold_time; bool sleep_mode; struct iio_trigger **trig; struct at91_adc_trigger *trigger_list; @@ -465,6 +466,9 @@ static int at91_adc_probe_dt(struct at91_adc_state *st, } st->startup_time = prop; + prop = 0; + of_property_read_u32(node, "atmel,adc-sample-hold-time", &prop); + st->sample_hold_time = prop; if (of_property_read_u32(node, "atmel,adc-vref", &prop)) { dev_err(&idev->dev, "Missing adc-vref property in the DT.\n"); @@ -578,7 +582,7 @@ static const struct iio_info at91_adc_info = { static int at91_adc_probe(struct platform_device *pdev) { - unsigned int prsc, mstrclk, ticks, adc_clk; + unsigned int prsc, mstrclk, ticks, adc_clk, shtim; int ret; struct iio_dev *idev; struct at91_adc_state *st; @@ -691,12 +695,21 @@ static int at91_adc_probe(struct platform_device *pdev) */ ticks = round_up((st->startup_time * adc_clk / 1000000) - 1, 8) / 8; + /* + * a minimal Sample and Hold Time is necessary for the ADC to guarantee + * the best converted final value between two channels selection + * The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock + */ + shtim = round_up((st->sample_hold_time * adc_clk / + 1000000) - 1, 1); + reg = AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL; reg |= AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP; if (st->low_res) reg |= AT91_ADC_LOWRES; if (st->sleep_mode) reg |= AT91_ADC_SLEEP; + reg |= AT91_ADC_SHTIM_(shtim) & AT91_ADC_SHTIM; at91_adc_writel(st, AT91_ADC_MR, reg); /* Setup the ADC channels available on the board */