From 1dcafd3aeb0a70dbdd11b10269da2afc454e2395 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Sun, 19 Jul 2015 01:33:55 +0300 Subject: iio: Documentation: Remove bytes_per_datum attribute Remove sysfs bytes_per_datum device attribute ABI documentation since the attribute is not present anymore. Signed-off-by: Cristina Opriceana Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 666a341b01b8..400d23441a61 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1040,13 +1040,6 @@ Contact: linux-iio@vger.kernel.org Description: Number of scans contained by the buffer. -What: /sys/bus/iio/devices/iio:deviceX/buffer/bytes_per_datum -KernelVersion: 2.6.37 -Contact: linux-iio@vger.kernel.org -Description: - Bytes per scan. Due to alignment fun, the scan may be larger - than implied directly by the scan_element parameters. - What: /sys/bus/iio/devices/iio:deviceX/buffer/enable KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org -- cgit v1.2.3 From 07a4257e3d758af96cf98b1e9baadeb627475b03 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 18 Jul 2015 12:30:41 +0000 Subject: iio: mxs-lradc: clarify supported devices At the beginning the driver supported only i.MX28 SoC, but now the whole MXS platform. So remove any confusing comments which apply only to i.MX28. Signed-off-by: Stefan Wahren Reviewed-by: Marek Vasut Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/staging/iio/adc/mxs-lradc.txt | 2 +- drivers/staging/iio/adc/mxs-lradc.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt index 307537787574..555fb117d4fa 100644 --- a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt +++ b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt @@ -1,4 +1,4 @@ -* Freescale i.MX28 LRADC device driver +* Freescale MXS LRADC device driver Required properties: - compatible: Should be "fsl,imx23-lradc" for i.MX23 SoC and "fsl,imx28-lradc" diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index d7c5223f1c3e..1ccb3676f2e5 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -1,5 +1,5 @@ /* - * Freescale i.MX28 LRADC driver + * Freescale MXS LRADC driver * * Copyright (c) 2012 DENX Software Engineering, GmbH. * Marek Vasut @@ -1392,7 +1392,7 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = { MXS_ADC_CHAN(4, IIO_VOLTAGE), MXS_ADC_CHAN(5, IIO_VOLTAGE), MXS_ADC_CHAN(6, IIO_VOLTAGE), - MXS_ADC_CHAN(7, IIO_VOLTAGE), /* VBATT */ + MXS_ADC_CHAN(7, IIO_VOLTAGE), /* Combined Temperature sensors */ { .type = IIO_TEMP, @@ -1411,12 +1411,12 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = { .scan_index = -1, .channel = 9, }, - MXS_ADC_CHAN(10, IIO_VOLTAGE), /* VDDIO */ - MXS_ADC_CHAN(11, IIO_VOLTAGE), /* VTH */ - MXS_ADC_CHAN(12, IIO_VOLTAGE), /* VDDA */ - MXS_ADC_CHAN(13, IIO_VOLTAGE), /* VDDD */ - MXS_ADC_CHAN(14, IIO_VOLTAGE), /* VBG */ - MXS_ADC_CHAN(15, IIO_VOLTAGE), /* VDD5V */ + MXS_ADC_CHAN(10, IIO_VOLTAGE), + MXS_ADC_CHAN(11, IIO_VOLTAGE), + MXS_ADC_CHAN(12, IIO_VOLTAGE), + MXS_ADC_CHAN(13, IIO_VOLTAGE), + MXS_ADC_CHAN(14, IIO_VOLTAGE), + MXS_ADC_CHAN(15, IIO_VOLTAGE), }; static int mxs_lradc_hw_init(struct mxs_lradc *lradc) @@ -1707,6 +1707,6 @@ static struct platform_driver mxs_lradc_driver = { module_platform_driver(mxs_lradc_driver); MODULE_AUTHOR("Marek Vasut "); -MODULE_DESCRIPTION("Freescale i.MX28 LRADC driver"); +MODULE_DESCRIPTION("Freescale MXS LRADC driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRIVER_NAME); -- cgit v1.2.3 From 66926d11f326355abbd4e290047a67f17731b404 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 18 Jul 2015 12:30:42 +0000 Subject: iio: mxs-lradc: fix some spelling errors This patch fix some spelling errors in the comments. Signed-off-by: Stefan Wahren Reviewed-by: Marek Vasut Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 1ccb3676f2e5..386a44da7248 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -65,14 +65,14 @@ * Once the pen touches the touchscreen, the touchscreen switches from * IRQ-driven mode to polling mode to prevent interrupt storm. The polling * is realized by worker thread, which is called every 20 or so milliseconds. - * This gives the touchscreen enough fluence and does not strain the system + * This gives the touchscreen enough fluency and does not strain the system * too much. */ #define LRADC_TS_SAMPLE_DELAY_MS 5 /* * The LRADC reads the following amount of samples from each touchscreen - * channel and the driver then computes avarage of these. + * channel and the driver then computes average of these. */ #define LRADC_TS_SAMPLE_AMOUNT 4 @@ -238,7 +238,7 @@ struct mxs_lradc { * CH5 -- Touch screen YNLR * CH6 -- Touch screen WIPER (5-wire only) * - * The bitfields below represents which parts of the LRADC block are + * The bit fields below represents which parts of the LRADC block are * switched into special mode of operation. These channels can not * be sampled as regular LRADC channels. The driver will refuse any * attempt to sample these channels. @@ -252,7 +252,7 @@ struct mxs_lradc { struct input_dev *ts_input; enum mxs_lradc_id soc; - enum lradc_ts_plate cur_plate; /* statemachine */ + enum lradc_ts_plate cur_plate; /* state machine */ bool ts_valid; unsigned ts_x_pos; unsigned ts_y_pos; @@ -812,7 +812,7 @@ static int mxs_lradc_read_single(struct iio_dev *iio_dev, int chan, int *val) int ret; /* - * See if there is no buffered operation in progess. If there is, simply + * See if there is no buffered operation in progress. If there is, simply * bail out. This can be improved to support both buffered and raw IO at * the same time, yet the code becomes horribly complicated. Therefore I * applied KISS principle here. -- cgit v1.2.3 From 5723dde958582483501fc2307cf2258060151339 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 18 Jul 2015 12:30:43 +0000 Subject: iio: mxs-lradc: add missing include This patch adds the missing include for mutex handling. Signed-off-by: Stefan Wahren Reviewed-by: Marek Vasut Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 386a44da7248..763075ba3423 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 3eaf20288c9e0e5a2620c4908ac215655ebf0a00 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 18 Jul 2015 12:30:44 +0000 Subject: iio: mxs-lradc: remove unnecessary header includes This patch removes the unnecessary header includes. Signed-off-by: Stefan Wahren Reviewed-by: Marek Vasut Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 763075ba3423..21b0ccfe5603 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -23,18 +23,13 @@ #include #include #include -#include #include #include #include #include -#include -#include -#include #include #include #include -#include #include #include -- cgit v1.2.3 From ae5896d48180520629655a9356737fe6dbc5e9e5 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 18 Jul 2015 12:30:45 +0000 Subject: iio: mxs-lradc: reorder header includes This patch reorder the header includes alphabetically. Signed-off-by: Stefan Wahren Reviewed-by: Marek Vasut Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 21b0ccfe5603..3a549eff7e71 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -15,30 +15,30 @@ * GNU General Public License for more details. */ +#include +#include +#include +#include #include +#include #include -#include -#include -#include -#include -#include -#include #include +#include #include #include +#include +#include #include +#include #include -#include -#include -#include -#include +#include -#include -#include #include +#include #include #include #include +#include #define DRIVER_NAME "mxs-lradc" -- cgit v1.2.3 From 829aed1a6e2cbceb2d2fe0f7557dea71fb38cec6 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 18 Jul 2015 12:30:46 +0000 Subject: iio: mxs-lradc: add datasheet name for every usable channel In order to provide a channel name to in kernel consumers add the datasheet names for every usable AD channel. Since the channel names differ between i.MX23 and i.MX28, we need to separate the channel specs. Signed-off-by: Stefan Wahren Reviewed-by: Marek Vasut Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 80 ++++++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 18 deletions(-) diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 3a549eff7e71..3f7715c9968b 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -1365,7 +1365,7 @@ static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = { * Driver initialization */ -#define MXS_ADC_CHAN(idx, chan_type) { \ +#define MXS_ADC_CHAN(idx, chan_type, name) { \ .type = (chan_type), \ .indexed = 1, \ .scan_index = (idx), \ @@ -1378,17 +1378,18 @@ static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = { .realbits = LRADC_RESOLUTION, \ .storagebits = 32, \ }, \ + .datasheet_name = (name), \ } -static const struct iio_chan_spec mxs_lradc_chan_spec[] = { - MXS_ADC_CHAN(0, IIO_VOLTAGE), - MXS_ADC_CHAN(1, IIO_VOLTAGE), - MXS_ADC_CHAN(2, IIO_VOLTAGE), - MXS_ADC_CHAN(3, IIO_VOLTAGE), - MXS_ADC_CHAN(4, IIO_VOLTAGE), - MXS_ADC_CHAN(5, IIO_VOLTAGE), - MXS_ADC_CHAN(6, IIO_VOLTAGE), - MXS_ADC_CHAN(7, IIO_VOLTAGE), +static const struct iio_chan_spec mx23_lradc_chan_spec[] = { + MXS_ADC_CHAN(0, IIO_VOLTAGE, "LRADC0"), + MXS_ADC_CHAN(1, IIO_VOLTAGE, "LRADC1"), + MXS_ADC_CHAN(2, IIO_VOLTAGE, "LRADC2"), + MXS_ADC_CHAN(3, IIO_VOLTAGE, "LRADC3"), + MXS_ADC_CHAN(4, IIO_VOLTAGE, "LRADC4"), + MXS_ADC_CHAN(5, IIO_VOLTAGE, "LRADC5"), + MXS_ADC_CHAN(6, IIO_VOLTAGE, "VDDIO"), + MXS_ADC_CHAN(7, IIO_VOLTAGE, "VBATT"), /* Combined Temperature sensors */ { .type = IIO_TEMP, @@ -1399,6 +1400,7 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = { BIT(IIO_CHAN_INFO_SCALE), .channel = 8, .scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,}, + .datasheet_name = "TEMP_DIE", }, /* Hidden channel to keep indexes */ { @@ -1407,12 +1409,48 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = { .scan_index = -1, .channel = 9, }, - MXS_ADC_CHAN(10, IIO_VOLTAGE), - MXS_ADC_CHAN(11, IIO_VOLTAGE), - MXS_ADC_CHAN(12, IIO_VOLTAGE), - MXS_ADC_CHAN(13, IIO_VOLTAGE), - MXS_ADC_CHAN(14, IIO_VOLTAGE), - MXS_ADC_CHAN(15, IIO_VOLTAGE), + MXS_ADC_CHAN(10, IIO_VOLTAGE, NULL), + MXS_ADC_CHAN(11, IIO_VOLTAGE, NULL), + MXS_ADC_CHAN(12, IIO_VOLTAGE, "USB_DP"), + MXS_ADC_CHAN(13, IIO_VOLTAGE, "USB_DN"), + MXS_ADC_CHAN(14, IIO_VOLTAGE, "VBG"), + MXS_ADC_CHAN(15, IIO_VOLTAGE, "VDD5V"), +}; + +static const struct iio_chan_spec mx28_lradc_chan_spec[] = { + MXS_ADC_CHAN(0, IIO_VOLTAGE, "LRADC0"), + MXS_ADC_CHAN(1, IIO_VOLTAGE, "LRADC1"), + MXS_ADC_CHAN(2, IIO_VOLTAGE, "LRADC2"), + MXS_ADC_CHAN(3, IIO_VOLTAGE, "LRADC3"), + MXS_ADC_CHAN(4, IIO_VOLTAGE, "LRADC4"), + MXS_ADC_CHAN(5, IIO_VOLTAGE, "LRADC5"), + MXS_ADC_CHAN(6, IIO_VOLTAGE, "LRADC6"), + MXS_ADC_CHAN(7, IIO_VOLTAGE, "VBATT"), + /* Combined Temperature sensors */ + { + .type = IIO_TEMP, + .indexed = 1, + .scan_index = 8, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE), + .channel = 8, + .scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,}, + .datasheet_name = "TEMP_DIE", + }, + /* Hidden channel to keep indexes */ + { + .type = IIO_TEMP, + .indexed = 1, + .scan_index = -1, + .channel = 9, + }, + MXS_ADC_CHAN(10, IIO_VOLTAGE, "VDDIO"), + MXS_ADC_CHAN(11, IIO_VOLTAGE, "VTH"), + MXS_ADC_CHAN(12, IIO_VOLTAGE, "VDDA"), + MXS_ADC_CHAN(13, IIO_VOLTAGE, "VDDD"), + MXS_ADC_CHAN(14, IIO_VOLTAGE, "VBG"), + MXS_ADC_CHAN(15, IIO_VOLTAGE, "VDD5V"), }; static int mxs_lradc_hw_init(struct mxs_lradc *lradc) @@ -1608,10 +1646,16 @@ static int mxs_lradc_probe(struct platform_device *pdev) iio->dev.parent = &pdev->dev; iio->info = &mxs_lradc_iio_info; iio->modes = INDIO_DIRECT_MODE; - iio->channels = mxs_lradc_chan_spec; - iio->num_channels = ARRAY_SIZE(mxs_lradc_chan_spec); iio->masklength = LRADC_MAX_TOTAL_CHANS; + if (lradc->soc == IMX23_LRADC) { + iio->channels = mx23_lradc_chan_spec; + iio->num_channels = ARRAY_SIZE(mx23_lradc_chan_spec); + } else { + iio->channels = mx28_lradc_chan_spec; + iio->num_channels = ARRAY_SIZE(mx28_lradc_chan_spec); + } + ret = iio_triggered_buffer_setup(iio, &iio_pollfunc_store_time, &mxs_lradc_trigger_handler, &mxs_lradc_buffer_ops); -- cgit v1.2.3 From 23633314e60796f860d5a0484b722557061cde7c Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sat, 18 Jul 2015 00:56:57 +0200 Subject: iio:light:acpi-als: add missing prefixes Some macros and a function were missing the acpi_als_ prefix, so add it. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/light/acpi-als.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c index 1dafa0756bfa..60537ec0c923 100644 --- a/drivers/iio/light/acpi-als.c +++ b/drivers/iio/light/acpi-als.c @@ -65,20 +65,20 @@ static const struct iio_chan_spec acpi_als_channels[] = { * to acpi_als_channels[], the evt_buffer below will grow * automatically. */ -#define EVT_NR_SOURCES ARRAY_SIZE(acpi_als_channels) -#define EVT_BUFFER_SIZE \ - (sizeof(s64) + (EVT_NR_SOURCES * sizeof(s32))) +#define ACPI_ALS_EVT_NR_SOURCES ARRAY_SIZE(acpi_als_channels) +#define ACPI_ALS_EVT_BUFFER_SIZE \ + (sizeof(s64) + (ACPI_ALS_EVT_NR_SOURCES * sizeof(s32))) struct acpi_als { struct acpi_device *device; struct mutex lock; - s32 evt_buffer[EVT_BUFFER_SIZE]; + s32 evt_buffer[ACPI_ALS_EVT_BUFFER_SIZE]; }; /* * All types of properties the ACPI0008 block can report. The ALI, ALC, ALT - * and ALP can all be handled by als_read_value() below, while the ALR is + * and ALP can all be handled by acpi_als_read_value() below, while the ALR is * special. * * The _ALR property returns tables that can be used to fine-tune the values @@ -93,7 +93,7 @@ struct acpi_als { #define ACPI_ALS_POLLING "_ALP" #define ACPI_ALS_TABLES "_ALR" -static int als_read_value(struct acpi_als *als, char *prop, s32 *val) +static int acpi_als_read_value(struct acpi_als *als, char *prop, s32 *val) { unsigned long long temp_val; acpi_status status; @@ -122,11 +122,11 @@ static void acpi_als_notify(struct acpi_device *device, u32 event) mutex_lock(&als->lock); - memset(buffer, 0, EVT_BUFFER_SIZE); + memset(buffer, 0, ACPI_ALS_EVT_BUFFER_SIZE); switch (event) { case ACPI_ALS_NOTIFY_ILLUMINANCE: - ret = als_read_value(als, ACPI_ALS_ILLUMINANCE, &val); + ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &val); if (ret < 0) goto out; *buffer++ = val; @@ -159,7 +159,7 @@ static int acpi_als_read_raw(struct iio_dev *indio_dev, if (chan->type != IIO_LIGHT) return -EINVAL; - ret = als_read_value(als, ACPI_ALS_ILLUMINANCE, &temp_val); + ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &temp_val); if (ret < 0) return ret; -- cgit v1.2.3 From 7dbf1ea8aade8c3b2759acc96e5e709016e6ae28 Mon Sep 17 00:00:00 2001 From: Jandy Gou Date: Fri, 17 Jul 2015 16:34:35 +0800 Subject: iio: magnetometer: mmc35240: Add DT binding Signed-off-by: Jandy Gou Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/mmc35240.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index 7a2ea71c659a..9bc542daa732 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -550,6 +550,12 @@ static const struct dev_pm_ops mmc35240_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(mmc35240_suspend, mmc35240_resume) }; +static const struct of_device_id mmc35240_of_match[] = { + { .compatible = "memsic,mmc35240", }, + { } +}; +MODULE_DEVICE_TABLE(of, mmc35240_of_match); + static const struct acpi_device_id mmc35240_acpi_match[] = { {"MMC35240", 0}, { }, @@ -565,6 +571,7 @@ MODULE_DEVICE_TABLE(i2c, mmc35240_id); static struct i2c_driver mmc35240_driver = { .driver = { .name = MMC35240_DRV_NAME, + .of_match_table = mmc35240_of_match, .pm = &mmc35240_pm_ops, .acpi_match_table = ACPI_PTR(mmc35240_acpi_match), }, -- cgit v1.2.3 From 2563f7fc83d655792ec9999e2dda7a37172ae6aa Mon Sep 17 00:00:00 2001 From: Jandy Gou Date: Fri, 17 Jul 2015 16:34:36 +0800 Subject: iio: magnetometer: mmc35240: Add DT binding doc Signed-off-by: Jandy Gou Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/magnetometer/mmc35240.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/magnetometer/mmc35240.txt diff --git a/Documentation/devicetree/bindings/iio/magnetometer/mmc35240.txt b/Documentation/devicetree/bindings/iio/magnetometer/mmc35240.txt new file mode 100644 index 000000000000..a01235c7fa15 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/magnetometer/mmc35240.txt @@ -0,0 +1,13 @@ +* MEMSIC MMC35240 magnetometer sensor + +Required properties: + + - compatible : should be "memsic,mmc35240" + - reg : the I2C address of the magnetometer + +Example: + +mmc35240@30 { + compatible = "memsic,mmc35240"; + reg = <0x30>; +}; -- cgit v1.2.3 From 47764c7918f5dd648ae8f6f61db1aaab1b9c09dd Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Fri, 17 Jul 2015 10:52:27 +0200 Subject: iio:magnetometer:bmc150_magn: replace magic value Construct the scanmask using its descriptive axis names (as used in iio_chan_spec) instead of a 'magic' value. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/bmc150_magn.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index cd002710dd02..074a99da7367 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -651,7 +651,9 @@ static const struct iio_info bmc150_magn_info = { .driver_module = THIS_MODULE, }; -static const unsigned long bmc150_magn_scan_masks[] = {0x07, 0}; +static const unsigned long bmc150_magn_scan_masks[] = { + BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), + 0}; static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p) { -- cgit v1.2.3 From f686a36b4b79782a94f07769fb1c0187d24ea8a8 Mon Sep 17 00:00:00 2001 From: Andrea Galbusera Date: Tue, 14 Jul 2015 15:36:21 +0200 Subject: iio: adc: mcp320x: Add support for mcp3301 This adds support for Microchip's 13 bit 1 channel AD converter MCP3301 Signed-off-by: Andrea Galbusera Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/mcp320x.txt | 1 + drivers/iio/adc/Kconfig | 4 ++-- drivers/iio/adc/mcp320x.c | 16 +++++++++++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/mcp320x.txt b/Documentation/devicetree/bindings/iio/adc/mcp320x.txt index b85184391b78..2a1f3af30155 100644 --- a/Documentation/devicetree/bindings/iio/adc/mcp320x.txt +++ b/Documentation/devicetree/bindings/iio/adc/mcp320x.txt @@ -18,6 +18,7 @@ Required properties: "mcp3202" "mcp3204" "mcp3208" + "mcp3301" Examples: diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index dace593b158b..2714f043fa6c 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -229,8 +229,8 @@ config MCP320X depends on SPI help Say yes here to build support for Microchip Technology's - MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204 or - MCP3208 analog to digital converter. + MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204, + MCP3208 or MCP3301 analog to digital converter. This driver can also be built as a module. If so, the module will be called mcp320x. diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c index 8d9c9b9215dd..72969c8a0a51 100644 --- a/drivers/iio/adc/mcp320x.c +++ b/drivers/iio/adc/mcp320x.c @@ -25,6 +25,7 @@ * http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf mcp3201 * http://ww1.microchip.com/downloads/en/DeviceDoc/21034D.pdf mcp3202 * http://ww1.microchip.com/downloads/en/DeviceDoc/21298c.pdf mcp3204/08 + * http://ww1.microchip.com/downloads/en/DeviceDoc/21700E.pdf mcp3301 * * 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 @@ -47,6 +48,7 @@ enum { mcp3202, mcp3204, mcp3208, + mcp3301, }; struct mcp320x_chip_info { @@ -76,6 +78,7 @@ static int mcp320x_channel_to_tx_data(int device_index, switch (device_index) { case mcp3001: case mcp3201: + case mcp3301: return 0; case mcp3002: case mcp3202: @@ -102,7 +105,7 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel, adc->tx_buf = mcp320x_channel_to_tx_data(device_index, channel, differential); - if (device_index != mcp3001 && device_index != mcp3201) { + if (device_index != mcp3001 && device_index != mcp3201 && device_index != mcp3301) { ret = spi_sync(adc->spi, &adc->msg); if (ret < 0) return ret; @@ -125,6 +128,8 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel, case mcp3204: case mcp3208: return (adc->rx_buf[0] << 4 | adc->rx_buf[1] >> 4); + case mcp3301: + return sign_extend32((adc->rx_buf[0] & 0x1f) << 8 | adc->rx_buf[1], 12); default: return -EINVAL; } @@ -274,6 +279,11 @@ static const struct mcp320x_chip_info mcp320x_chip_infos[] = { .num_channels = ARRAY_SIZE(mcp3208_channels), .resolution = 12 }, + [mcp3301] = { + .channels = mcp3201_channels, + .num_channels = ARRAY_SIZE(mcp3201_channels), + .resolution = 13 + }, }; static int mcp320x_probe(struct spi_device *spi) @@ -366,6 +376,9 @@ static const struct of_device_id mcp320x_dt_ids[] = { }, { .compatible = "mcp3208", .data = &mcp320x_chip_infos[mcp3208], + }, { + .compatible = "mcp3301", + .data = &mcp320x_chip_infos[mcp3301], }, { } }; @@ -381,6 +394,7 @@ static const struct spi_device_id mcp320x_id[] = { { "mcp3202", mcp3202 }, { "mcp3204", mcp3204 }, { "mcp3208", mcp3208 }, + { "mcp3301", mcp3301 }, { } }; MODULE_DEVICE_TABLE(spi, mcp320x_id); -- cgit v1.2.3 From 5e9972cd6f1a69ee8a8ee8664d3e4c4ea59c0901 Mon Sep 17 00:00:00 2001 From: Sanchayan Maity Date: Tue, 14 Jul 2015 19:23:22 +0530 Subject: iio: adc: vf610: Determine sampling frequencies by using minimum sample time The driver currently does not take into account the minimum sample time as per the Figure 6-8 Chapter 9.1.1 12-bit ADC electrical characteristics. We set a static amount of cycles instead of considering the sample time as a given value, which depends on hardware characteristics. Determine sampling frequencies by first reading the device tree property node and then calculating the required Long Sample Time Adder (LSTAdder) value, based on the ADC clock frequency and sample time value obtained from the device tree. This LSTAdder value is then used for calculating the sampling frequencies possible. In case the sample time property is not specified through the device tree, a safe default value of 1000ns is assumed. Signed-off-by: Sanchayan Maity Acked-by: Stefan Agner Acked-by: Fugang Duan Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/vf610-adc.txt | 5 ++ drivers/iio/adc/vf610_adc.c | 79 ++++++++++++++++++++-- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt index 3eb40e20c143..1aad0514e647 100644 --- a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt @@ -17,6 +17,11 @@ Recommended properties: - Frequency in normal mode (ADLPC=0, ADHSC=0) - Frequency in high-speed mode (ADLPC=0, ADHSC=1) - Frequency in low-power mode (ADLPC=1, ADHSC=0) +- min-sample-time: Minimum sampling time in nanoseconds. This value has + to be chosen according to the conversion mode and the connected analog + source resistance (R_as) and capacitance (C_as). Refer the datasheet's + operating requirements. A safe default across a wide range of R_as and + C_as as well as conversion modes is 1000ns. Example: adc0: adc@4003b000 { diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 480f335a0f9f..23b8fb94ec09 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -68,6 +68,9 @@ #define VF610_ADC_CLK_DIV8 0x60 #define VF610_ADC_CLK_MASK 0x60 #define VF610_ADC_ADLSMP_LONG 0x10 +#define VF610_ADC_ADSTS_SHORT 0x100 +#define VF610_ADC_ADSTS_NORMAL 0x200 +#define VF610_ADC_ADSTS_LONG 0x300 #define VF610_ADC_ADSTS_MASK 0x300 #define VF610_ADC_ADLPC_EN 0x80 #define VF610_ADC_ADHSC_EN 0x400 @@ -98,6 +101,8 @@ #define VF610_ADC_CALF 0x2 #define VF610_ADC_TIMEOUT msecs_to_jiffies(100) +#define DEFAULT_SAMPLE_TIME 1000 + enum clk_sel { VF610_ADCIOC_BUSCLK_SET, VF610_ADCIOC_ALTCLK_SET, @@ -124,6 +129,17 @@ enum conversion_mode_sel { VF610_ADC_CONV_LOW_POWER, }; +enum lst_adder_sel { + VF610_ADCK_CYCLES_3, + VF610_ADCK_CYCLES_5, + VF610_ADCK_CYCLES_7, + VF610_ADCK_CYCLES_9, + VF610_ADCK_CYCLES_13, + VF610_ADCK_CYCLES_17, + VF610_ADCK_CYCLES_21, + VF610_ADCK_CYCLES_25, +}; + struct vf610_adc_feature { enum clk_sel clk_sel; enum vol_ref vol_ref; @@ -132,6 +148,8 @@ struct vf610_adc_feature { int clk_div; int sample_rate; int res_mode; + u32 lst_adder_index; + u32 default_sample_time; bool calibration; bool ovwren; @@ -155,11 +173,13 @@ struct vf610_adc { }; static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 }; +static const u32 vf610_lst_adder[] = { 3, 5, 7, 9, 13, 17, 21, 25 }; static inline void vf610_adc_calculate_rates(struct vf610_adc *info) { struct vf610_adc_feature *adc_feature = &info->adc_feature; unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk); + u32 adck_period, lst_addr_min; int divisor, i; adck_rate = info->max_adck_rate[adc_feature->conv_mode]; @@ -173,6 +193,19 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info) adc_feature->clk_div = 8; } + /* + * Determine the long sample time adder value to be used based + * on the default minimum sample time provided. + */ + adck_period = NSEC_PER_SEC / adck_rate; + lst_addr_min = adc_feature->default_sample_time / adck_period; + for (i = 0; i < ARRAY_SIZE(vf610_lst_adder); i++) { + if (vf610_lst_adder[i] > lst_addr_min) { + adc_feature->lst_adder_index = i; + break; + } + } + /* * Calculate ADC sample frequencies * Sample time unit is ADCK cycles. ADCK clk source is ipg clock, @@ -182,12 +215,13 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info) * SFCAdder: fixed to 6 ADCK cycles * AverageNum: 1, 4, 8, 16, 32 samples for hardware average. * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode - * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles + * LSTAdder(Long Sample Time): 3, 5, 7, 9, 13, 17, 21, 25 ADCK cycles */ adck_rate = ipg_rate / info->adc_feature.clk_div; for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++) info->sample_freq_avail[i] = - adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3)); + adck_rate / (6 + vf610_hw_avgs[i] * + (25 + vf610_lst_adder[adc_feature->lst_adder_index])); } static inline void vf610_adc_cfg_init(struct vf610_adc *info) @@ -347,8 +381,40 @@ static void vf610_adc_sample_set(struct vf610_adc *info) break; } - /* Use the short sample mode */ - cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK); + /* + * Set ADLSMP and ADSTS based on the Long Sample Time Adder value + * determined. + */ + switch (adc_feature->lst_adder_index) { + case VF610_ADCK_CYCLES_3: + break; + case VF610_ADCK_CYCLES_5: + cfg_data |= VF610_ADC_ADSTS_SHORT; + break; + case VF610_ADCK_CYCLES_7: + cfg_data |= VF610_ADC_ADSTS_NORMAL; + break; + case VF610_ADCK_CYCLES_9: + cfg_data |= VF610_ADC_ADSTS_LONG; + break; + case VF610_ADCK_CYCLES_13: + cfg_data |= VF610_ADC_ADLSMP_LONG; + break; + case VF610_ADCK_CYCLES_17: + cfg_data |= VF610_ADC_ADLSMP_LONG; + cfg_data |= VF610_ADC_ADSTS_SHORT; + break; + case VF610_ADCK_CYCLES_21: + cfg_data |= VF610_ADC_ADLSMP_LONG; + cfg_data |= VF610_ADC_ADSTS_NORMAL; + break; + case VF610_ADCK_CYCLES_25: + cfg_data |= VF610_ADC_ADLSMP_LONG; + cfg_data |= VF610_ADC_ADSTS_NORMAL; + break; + default: + dev_err(info->dev, "error in sample time select\n"); + } /* update hardware average selection */ cfg_data &= ~VF610_ADC_AVGS_MASK; @@ -713,6 +779,11 @@ static int vf610_adc_probe(struct platform_device *pdev) of_property_read_u32_array(pdev->dev.of_node, "fsl,adck-max-frequency", info->max_adck_rate, 3); + ret = of_property_read_u32(pdev->dev.of_node, "min-sample-time", + &info->adc_feature.default_sample_time); + if (ret) + info->adc_feature.default_sample_time = DEFAULT_SAMPLE_TIME; + platform_set_drvdata(pdev, indio_dev); init_completion(&info->completion); -- cgit v1.2.3 From 889c5e9b668670c91dcd3a8f2b15a0b2086f4827 Mon Sep 17 00:00:00 2001 From: Harald Geyer Date: Tue, 7 Jul 2015 13:39:28 +0000 Subject: iio: dht11: whitespace changes to make checkpatch.pl --strict happy * add spaces around binary operators in cases where it reduces readability * align multiline statements around opening parenthesis Reported-by: Hartmut Knaack in Message-ID: <55919E72.3010807@gmx.de> Signed-off-by: Harald Geyer Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/dht11.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index 7d79a1ac5f5f..343d26af1dd8 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -46,7 +46,8 @@ * Note that when reading the sensor actually 84 edges are detected, but * since the last edge is not significant, we only store 83: */ -#define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE + 1) +#define DHT11_EDGES_PER_READ (2 * DHT11_BITS_PER_READ + \ + DHT11_EDGES_PREAMBLE + 1) /* Data transmission timing (nano seconds) */ #define DHT11_START_TRANSMISSION 18 /* ms */ @@ -95,24 +96,24 @@ static int dht11_decode(struct dht11 *dht11, int offset) /* Calculate timestamp resolution */ for (i = 1; i < dht11->num_edges; ++i) { - t = dht11->edges[i].ts - dht11->edges[i-1].ts; + t = dht11->edges[i].ts - dht11->edges[i - 1].ts; if (t > 0 && t < timeres) timeres = t; } - if (2*timeres > DHT11_DATA_BIT_HIGH) { + if (2 * timeres > DHT11_DATA_BIT_HIGH) { pr_err("dht11: timeresolution %d too bad for decoding\n", - timeres); + timeres); return -EIO; } threshold = DHT11_DATA_BIT_HIGH / timeres; - if (DHT11_DATA_BIT_LOW/timeres + 1 >= threshold) + if (DHT11_DATA_BIT_LOW / timeres + 1 >= threshold) pr_err("dht11: WARNING: decoding ambiguous\n"); /* scale down with timeres and check validity */ for (i = 0; i < DHT11_BITS_PER_READ; ++i) { - t = dht11->edges[offset + 2*i + 2].ts - - dht11->edges[offset + 2*i + 1].ts; - if (!dht11->edges[offset + 2*i + 1].value) + t = dht11->edges[offset + 2 * i + 2].ts - + dht11->edges[offset + 2 * i + 1].ts; + if (!dht11->edges[offset + 2 * i + 1].value) return -EIO; /* lost synchronisation */ timing[i] = t / timeres; } @@ -166,7 +167,7 @@ static irqreturn_t dht11_handle_irq(int irq, void *data) } static int dht11_read_raw(struct iio_dev *iio_dev, - const struct iio_chan_spec *chan, + const struct iio_chan_spec *chan, int *val, int *val2, long m) { struct dht11 *dht11 = iio_priv(iio_dev); @@ -192,13 +193,13 @@ static int dht11_read_raw(struct iio_dev *iio_dev, goto err; ret = wait_for_completion_killable_timeout(&dht11->completion, - HZ); + HZ); free_irq(dht11->irq, iio_dev); if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) { dev_err(&iio_dev->dev, - "Only %d signal edges detected\n", + "Only %d signal edges detected\n", dht11->num_edges); ret = -ETIMEDOUT; } @@ -206,7 +207,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev, goto err; ret = dht11_decode(dht11, - dht11->num_edges == DHT11_EDGES_PER_READ ? + dht11->num_edges == DHT11_EDGES_PER_READ ? DHT11_EDGES_PREAMBLE : DHT11_EDGES_PREAMBLE - 2); if (ret) -- cgit v1.2.3 From a7126003b6dd47c0088d952734379ef471156c5f Mon Sep 17 00:00:00 2001 From: Harald Geyer Date: Tue, 7 Jul 2015 13:39:29 +0000 Subject: iio: dht11: add comment to make checkpatch.pl --strict happy Explain why the driver needs a mutex. Signed-off-by: Harald Geyer Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/dht11.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index 343d26af1dd8..bb5ad57ed2a2 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -63,6 +63,7 @@ struct dht11 { int irq; struct completion completion; + /* The iio sysfs interface doesn't prevent concurrent reads: */ struct mutex lock; s64 timestamp; -- cgit v1.2.3 From 5fbb0bc466b7b43036b1dd8c9e9166ca9e69e07a Mon Sep 17 00:00:00 2001 From: Harald Geyer Date: Tue, 7 Jul 2015 13:39:30 +0000 Subject: iio: dht11: avoid multiple assignments to make checkpatch.pl --strict happy We just do the assignments in two steps. Signed-off-by: Harald Geyer Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/dht11.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index bb5ad57ed2a2..91976e06f1c6 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -263,9 +263,10 @@ static int dht11_probe(struct platform_device *pdev) dht11 = iio_priv(iio); dht11->dev = dev; - dht11->gpio = ret = of_get_gpio(node, 0); + ret = of_get_gpio(node, 0); if (ret < 0) return ret; + dht11->gpio = ret; ret = devm_gpio_request_one(dev, dht11->gpio, GPIOF_IN, pdev->name); if (ret) return ret; -- cgit v1.2.3 From 081d974031bafb204d64de3e82f398daf1d0b899 Mon Sep 17 00:00:00 2001 From: Harald Geyer Date: Tue, 7 Jul 2015 13:39:31 +0000 Subject: iio: dht11: Use new function ktime_get_resolution_ns() This cleans up the most ugly workaround in this driver. There are no functional changes yet in the decoding algorithm, but we improve the following things: * Get rid of spurious warning messages on systems with fast HRTIMER. * If the clock is not fast enough for decoding to work, we give up immediately. * In that case we return EAGAIN instead of EIO, so it's easier to discriminate causes of failure. Returning EAGAIN is somewhat controversial: It's technically correct as a faster clock might become available. OTOH once all clocks are enabled this is a permanent error. There is no ECLOCKTOOSLOW error code. Signed-off-by: Harald Geyer Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/dht11.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index 91976e06f1c6..1165b1c4f9d6 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -89,23 +90,11 @@ static unsigned char dht11_decode_byte(int *timing, int threshold) return ret; } -static int dht11_decode(struct dht11 *dht11, int offset) +static int dht11_decode(struct dht11 *dht11, int offset, int timeres) { - int i, t, timing[DHT11_BITS_PER_READ], threshold, - timeres = DHT11_SENSOR_RESPONSE; + int i, t, timing[DHT11_BITS_PER_READ], threshold; unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum; - /* Calculate timestamp resolution */ - for (i = 1; i < dht11->num_edges; ++i) { - t = dht11->edges[i].ts - dht11->edges[i - 1].ts; - if (t > 0 && t < timeres) - timeres = t; - } - if (2 * timeres > DHT11_DATA_BIT_HIGH) { - pr_err("dht11: timeresolution %d too bad for decoding\n", - timeres); - return -EIO; - } threshold = DHT11_DATA_BIT_HIGH / timeres; if (DHT11_DATA_BIT_LOW / timeres + 1 >= threshold) pr_err("dht11: WARNING: decoding ambiguous\n"); @@ -128,7 +117,7 @@ static int dht11_decode(struct dht11 *dht11, int offset) if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum) return -EIO; - dht11->timestamp = iio_get_time_ns(); + dht11->timestamp = ktime_get_real_ns(); if (hum_int < 20) { /* DHT22 */ dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) * ((temp_int & 0x80) ? -100 : 100); @@ -156,7 +145,7 @@ static irqreturn_t dht11_handle_irq(int irq, void *data) /* TODO: Consider making the handler safe for IRQ sharing */ if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) { - dht11->edges[dht11->num_edges].ts = iio_get_time_ns(); + dht11->edges[dht11->num_edges].ts = ktime_get_real_ns(); dht11->edges[dht11->num_edges++].value = gpio_get_value(dht11->gpio); @@ -172,10 +161,22 @@ static int dht11_read_raw(struct iio_dev *iio_dev, int *val, int *val2, long m) { struct dht11 *dht11 = iio_priv(iio_dev); - int ret; + int ret, timeres; mutex_lock(&dht11->lock); - if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) { + if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_real_ns()) { + timeres = ktime_get_resolution_ns(); + if (DHT11_DATA_BIT_HIGH < 2 * timeres) { + dev_err(dht11->dev, "timeresolution %dns too low\n", + timeres); + /* In theory a better clock could become available + * at some point ... and there is no error code + * that really fits better. + */ + ret = -EAGAIN; + goto err; + } + reinit_completion(&dht11->completion); dht11->num_edges = 0; @@ -210,7 +211,8 @@ static int dht11_read_raw(struct iio_dev *iio_dev, ret = dht11_decode(dht11, dht11->num_edges == DHT11_EDGES_PER_READ ? DHT11_EDGES_PREAMBLE : - DHT11_EDGES_PREAMBLE - 2); + DHT11_EDGES_PREAMBLE - 2, + timeres); if (ret) goto err; } @@ -277,7 +279,7 @@ static int dht11_probe(struct platform_device *pdev) return -EINVAL; } - dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1; + dht11->timestamp = ktime_get_real_ns() - DHT11_DATA_VALID_TIME - 1; dht11->num_edges = -1; platform_set_drvdata(pdev, iio); -- cgit v1.2.3 From 94a9b7b1809f56cfaa080e70ec49b6979563a237 Mon Sep 17 00:00:00 2001 From: Andreas Dannenberg Date: Thu, 2 Jul 2015 17:27:58 -0500 Subject: iio: light: add support for TI's opt3001 light sensor TI's opt3001 light sensor is a simple and yet powerful little device. The device provides 99% IR rejection, automatic full-scale, very low power consumption and measurements from 0.01 to 83k lux. This patch adds support for that device using the IIO framework. See http://www.ti.com/product/opt3001 for more information. Signed-off-by: Felipe Balbi Signed-off-by: Andreas Dannenberg Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 10 + drivers/iio/light/Makefile | 1 + drivers/iio/light/opt3001.c | 804 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 815 insertions(+) create mode 100644 drivers/iio/light/opt3001.c diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 730fa80c83ea..5c0854a7e3e0 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -209,6 +209,16 @@ config LTR501 This driver can also be built as a module. If so, the module will be called ltr501. +config OPT3001 + tristate "Texas Instruments OPT3001 Light Sensor" + depends on I2C + help + If you say Y or M here, you get support for Texas Instruments + OPT3001 Ambient Light Sensor. + + If built as a dynamically linked module, it will be called + opt3001. + config STK3310 tristate "STK3310 ALS and proximity sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index adf97237db72..5345969f7000 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_ISL29125) += isl29125.o obj-$(CONFIG_JSA1212) += jsa1212.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o obj-$(CONFIG_LTR501) += ltr501.o +obj-$(CONFIG_OPT3001) += opt3001.o obj-$(CONFIG_RPR0521) += rpr0521.o obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o obj-$(CONFIG_STK3310) += stk3310.o diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c new file mode 100644 index 000000000000..923aa6aef0ed --- /dev/null +++ b/drivers/iio/light/opt3001.c @@ -0,0 +1,804 @@ +/** + * opt3001.c - Texas Instruments OPT3001 Light Sensor + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Andreas Dannenberg + * Based on previous work from: Felipe Balbi + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 of the License + * as published by the Free Software Foundation. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define OPT3001_RESULT 0x00 +#define OPT3001_CONFIGURATION 0x01 +#define OPT3001_LOW_LIMIT 0x02 +#define OPT3001_HIGH_LIMIT 0x03 +#define OPT3001_MANUFACTURER_ID 0x7e +#define OPT3001_DEVICE_ID 0x7f + +#define OPT3001_CONFIGURATION_RN_MASK (0xf << 12) +#define OPT3001_CONFIGURATION_RN_AUTO (0xc << 12) + +#define OPT3001_CONFIGURATION_CT BIT(11) + +#define OPT3001_CONFIGURATION_M_MASK (3 << 9) +#define OPT3001_CONFIGURATION_M_SHUTDOWN (0 << 9) +#define OPT3001_CONFIGURATION_M_SINGLE (1 << 9) +#define OPT3001_CONFIGURATION_M_CONTINUOUS (2 << 9) /* also 3 << 9 */ + +#define OPT3001_CONFIGURATION_OVF BIT(8) +#define OPT3001_CONFIGURATION_CRF BIT(7) +#define OPT3001_CONFIGURATION_FH BIT(6) +#define OPT3001_CONFIGURATION_FL BIT(5) +#define OPT3001_CONFIGURATION_L BIT(4) +#define OPT3001_CONFIGURATION_POL BIT(3) +#define OPT3001_CONFIGURATION_ME BIT(2) + +#define OPT3001_CONFIGURATION_FC_MASK (3 << 0) + +/* The end-of-conversion enable is located in the low-limit register */ +#define OPT3001_LOW_LIMIT_EOC_ENABLE 0xc000 + +#define OPT3001_REG_EXPONENT(n) ((n) >> 12) +#define OPT3001_REG_MANTISSA(n) ((n) & 0xfff) + +/* + * Time to wait for conversion result to be ready. The device datasheet + * worst-case max value is 880ms. Add some slack to be on the safe side. + */ +#define OPT3001_RESULT_READY_TIMEOUT msecs_to_jiffies(1000) + +struct opt3001 { + struct i2c_client *client; + struct device *dev; + + struct mutex lock; + u16 ok_to_ignore_lock:1; + u16 result_ready:1; + wait_queue_head_t result_ready_queue; + u16 result; + + u32 int_time; + u32 mode; + + u16 high_thresh_mantissa; + u16 low_thresh_mantissa; + + u8 high_thresh_exp; + u8 low_thresh_exp; +}; + +struct opt3001_scale { + int val; + int val2; +}; + +static const struct opt3001_scale opt3001_scales[] = { + { + .val = 40, + .val2 = 950000, + }, + { + .val = 81, + .val2 = 900000, + }, + { + .val = 163, + .val2 = 800000, + }, + { + .val = 327, + .val2 = 600000, + }, + { + .val = 655, + .val2 = 200000, + }, + { + .val = 1310, + .val2 = 400000, + }, + { + .val = 2620, + .val2 = 800000, + }, + { + .val = 5241, + .val2 = 600000, + }, + { + .val = 10483, + .val2 = 200000, + }, + { + .val = 20966, + .val2 = 400000, + }, + { + .val = 83865, + .val2 = 600000, + }, +}; + +static int opt3001_find_scale(const struct opt3001 *opt, int val, + int val2, u8 *exponent) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(opt3001_scales); i++) { + const struct opt3001_scale *scale = &opt3001_scales[i]; + + /* + * Combine the integer and micro parts for comparison + * purposes. Use milli lux precision to avoid 32-bit integer + * overflows. + */ + if ((val * 1000 + val2 / 1000) <= + (scale->val * 1000 + scale->val2 / 1000)) { + *exponent = i; + return 0; + } + } + + return -EINVAL; +} + +static void opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent, + u16 mantissa, int *val, int *val2) +{ + int lux; + + lux = 10 * (mantissa << exponent); + *val = lux / 1000; + *val2 = (lux - (*val * 1000)) * 1000; +} + +static void opt3001_set_mode(struct opt3001 *opt, u16 *reg, u16 mode) +{ + *reg &= ~OPT3001_CONFIGURATION_M_MASK; + *reg |= mode; + opt->mode = mode; +} + +static IIO_CONST_ATTR_INT_TIME_AVAIL("0.1 0.8"); + +static struct attribute *opt3001_attributes[] = { + &iio_const_attr_integration_time_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group opt3001_attribute_group = { + .attrs = opt3001_attributes, +}; + +static const struct iio_event_spec opt3001_event_spec[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + +static const struct iio_chan_spec opt3001_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_INT_TIME), + .event_spec = opt3001_event_spec, + .num_event_specs = ARRAY_SIZE(opt3001_event_spec), + }, + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static int opt3001_get_lux(struct opt3001 *opt, int *val, int *val2) +{ + int ret; + u16 mantissa; + u16 reg; + u8 exponent; + u16 value; + + /* + * Enable the end-of-conversion interrupt mechanism. Note that doing + * so will overwrite the low-level limit value however we will restore + * this value later on. + */ + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_LOW_LIMIT, + OPT3001_LOW_LIMIT_EOC_ENABLE); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_LOW_LIMIT); + return ret; + } + + /* Reset data-ready indicator flag (will be set in the IRQ routine) */ + opt->result_ready = false; + + /* Allow IRQ to access the device despite lock being set */ + opt->ok_to_ignore_lock = true; + + /* Configure for single-conversion mode and start a new conversion */ + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + goto err; + } + + reg = ret; + opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SINGLE); + + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, + reg); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_CONFIGURATION); + goto err; + } + + /* Wait for the IRQ to indicate the conversion is complete */ + ret = wait_event_timeout(opt->result_ready_queue, opt->result_ready, + OPT3001_RESULT_READY_TIMEOUT); + +err: + /* Disallow IRQ to access the device while lock is active */ + opt->ok_to_ignore_lock = false; + + if (ret == 0) + return -ETIMEDOUT; + else if (ret < 0) + return ret; + + /* + * Disable the end-of-conversion interrupt mechanism by restoring the + * low-level limit value (clearing OPT3001_LOW_LIMIT_EOC_ENABLE). Note + * that selectively clearing those enable bits would affect the actual + * limit value due to bit-overlap and therefore can't be done. + */ + value = (opt->low_thresh_exp << 12) | opt->low_thresh_mantissa; + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_LOW_LIMIT, + value); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_LOW_LIMIT); + return ret; + } + + exponent = OPT3001_REG_EXPONENT(opt->result); + mantissa = OPT3001_REG_MANTISSA(opt->result); + + opt3001_to_iio_ret(opt, exponent, mantissa, val, val2); + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int opt3001_get_int_time(struct opt3001 *opt, int *val, int *val2) +{ + *val = 0; + *val2 = opt->int_time; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int opt3001_set_int_time(struct opt3001 *opt, int time) +{ + int ret; + u16 reg; + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return ret; + } + + reg = ret; + + switch (time) { + case 100000: + reg &= ~OPT3001_CONFIGURATION_CT; + opt->int_time = 100000; + break; + case 800000: + reg |= OPT3001_CONFIGURATION_CT; + opt->int_time = 800000; + break; + default: + return -EINVAL; + } + + return i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, + reg); +} + +static int opt3001_read_raw(struct iio_dev *iio, + struct iio_chan_spec const *chan, int *val, int *val2, + long mask) +{ + struct opt3001 *opt = iio_priv(iio); + int ret; + + if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) + return -EBUSY; + + if (chan->type != IIO_LIGHT) + return -EINVAL; + + mutex_lock(&opt->lock); + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + ret = opt3001_get_lux(opt, val, val2); + break; + case IIO_CHAN_INFO_INT_TIME: + ret = opt3001_get_int_time(opt, val, val2); + break; + default: + ret = -EINVAL; + } + + mutex_unlock(&opt->lock); + + return ret; +} + +static int opt3001_write_raw(struct iio_dev *iio, + struct iio_chan_spec const *chan, int val, int val2, + long mask) +{ + struct opt3001 *opt = iio_priv(iio); + int ret; + + if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) + return -EBUSY; + + if (chan->type != IIO_LIGHT) + return -EINVAL; + + if (mask != IIO_CHAN_INFO_INT_TIME) + return -EINVAL; + + if (val != 0) + return -EINVAL; + + mutex_lock(&opt->lock); + ret = opt3001_set_int_time(opt, val2); + mutex_unlock(&opt->lock); + + return ret; +} + +static int opt3001_read_event_value(struct iio_dev *iio, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, + int *val, int *val2) +{ + struct opt3001 *opt = iio_priv(iio); + int ret = IIO_VAL_INT_PLUS_MICRO; + + mutex_lock(&opt->lock); + + switch (dir) { + case IIO_EV_DIR_RISING: + opt3001_to_iio_ret(opt, opt->high_thresh_exp, + opt->high_thresh_mantissa, val, val2); + break; + case IIO_EV_DIR_FALLING: + opt3001_to_iio_ret(opt, opt->low_thresh_exp, + opt->low_thresh_mantissa, val, val2); + break; + default: + ret = -EINVAL; + } + + mutex_unlock(&opt->lock); + + return ret; +} + +static int opt3001_write_event_value(struct iio_dev *iio, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, + int val, int val2) +{ + struct opt3001 *opt = iio_priv(iio); + int ret; + + u16 mantissa; + u16 value; + u16 reg; + + u8 exponent; + + if (val < 0) + return -EINVAL; + + mutex_lock(&opt->lock); + + ret = opt3001_find_scale(opt, val, val2, &exponent); + if (ret < 0) { + dev_err(opt->dev, "can't find scale for %d.%06u\n", val, val2); + goto err; + } + + mantissa = (((val * 1000) + (val2 / 1000)) / 10) >> exponent; + value = (exponent << 12) | mantissa; + + switch (dir) { + case IIO_EV_DIR_RISING: + reg = OPT3001_HIGH_LIMIT; + opt->high_thresh_mantissa = mantissa; + opt->high_thresh_exp = exponent; + break; + case IIO_EV_DIR_FALLING: + reg = OPT3001_LOW_LIMIT; + opt->low_thresh_mantissa = mantissa; + opt->low_thresh_exp = exponent; + break; + default: + ret = -EINVAL; + goto err; + } + + ret = i2c_smbus_write_word_swapped(opt->client, reg, value); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", reg); + goto err; + } + +err: + mutex_unlock(&opt->lock); + + return ret; +} + +static int opt3001_read_event_config(struct iio_dev *iio, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir) +{ + struct opt3001 *opt = iio_priv(iio); + + return opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS; +} + +static int opt3001_write_event_config(struct iio_dev *iio, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, int state) +{ + struct opt3001 *opt = iio_priv(iio); + int ret; + u16 mode; + u16 reg; + + if (state && opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) + return 0; + + if (!state && opt->mode == OPT3001_CONFIGURATION_M_SHUTDOWN) + return 0; + + mutex_lock(&opt->lock); + + mode = state ? OPT3001_CONFIGURATION_M_CONTINUOUS + : OPT3001_CONFIGURATION_M_SHUTDOWN; + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + goto err; + } + + reg = ret; + opt3001_set_mode(opt, ®, mode); + + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, + reg); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_CONFIGURATION); + goto err; + } + +err: + mutex_unlock(&opt->lock); + + return ret; +} + +static const struct iio_info opt3001_info = { + .driver_module = THIS_MODULE, + .attrs = &opt3001_attribute_group, + .read_raw = opt3001_read_raw, + .write_raw = opt3001_write_raw, + .read_event_value = opt3001_read_event_value, + .write_event_value = opt3001_write_event_value, + .read_event_config = opt3001_read_event_config, + .write_event_config = opt3001_write_event_config, +}; + +static int opt3001_read_id(struct opt3001 *opt) +{ + char manufacturer[2]; + u16 device_id; + int ret; + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_MANUFACTURER_ID); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_MANUFACTURER_ID); + return ret; + } + + manufacturer[0] = ret >> 8; + manufacturer[1] = ret & 0xff; + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_DEVICE_ID); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_DEVICE_ID); + return ret; + } + + device_id = ret; + + dev_info(opt->dev, "Found %c%c OPT%04x\n", manufacturer[0], + manufacturer[1], device_id); + + return 0; +} + +static int opt3001_configure(struct opt3001 *opt) +{ + int ret; + u16 reg; + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return ret; + } + + reg = ret; + + /* Enable automatic full-scale setting mode */ + reg &= ~OPT3001_CONFIGURATION_RN_MASK; + reg |= OPT3001_CONFIGURATION_RN_AUTO; + + /* Reflect status of the device's integration time setting */ + if (reg & OPT3001_CONFIGURATION_CT) + opt->int_time = 800000; + else + opt->int_time = 100000; + + /* Ensure device is in shutdown initially */ + opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SHUTDOWN); + + /* Configure for latched window-style comparison operation */ + reg |= OPT3001_CONFIGURATION_L; + reg &= ~OPT3001_CONFIGURATION_POL; + reg &= ~OPT3001_CONFIGURATION_ME; + reg &= ~OPT3001_CONFIGURATION_FC_MASK; + + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, + reg); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_CONFIGURATION); + return ret; + } + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_LOW_LIMIT); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_LOW_LIMIT); + return ret; + } + + opt->low_thresh_mantissa = OPT3001_REG_MANTISSA(ret); + opt->low_thresh_exp = OPT3001_REG_EXPONENT(ret); + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_HIGH_LIMIT); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_HIGH_LIMIT); + return ret; + } + + opt->high_thresh_mantissa = OPT3001_REG_MANTISSA(ret); + opt->high_thresh_exp = OPT3001_REG_EXPONENT(ret); + + return 0; +} + +static irqreturn_t opt3001_irq(int irq, void *_iio) +{ + struct iio_dev *iio = _iio; + struct opt3001 *opt = iio_priv(iio); + int ret; + + if (!opt->ok_to_ignore_lock) + mutex_lock(&opt->lock); + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + goto out; + } + + if ((ret & OPT3001_CONFIGURATION_M_MASK) == + OPT3001_CONFIGURATION_M_CONTINUOUS) { + if (ret & OPT3001_CONFIGURATION_FH) + iio_push_event(iio, + IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns()); + if (ret & OPT3001_CONFIGURATION_FL) + iio_push_event(iio, + IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns()); + } else if (ret & OPT3001_CONFIGURATION_CRF) { + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_RESULT); + goto out; + } + opt->result = ret; + opt->result_ready = true; + wake_up(&opt->result_ready_queue); + } + +out: + if (!opt->ok_to_ignore_lock) + mutex_unlock(&opt->lock); + + return IRQ_HANDLED; +} + +static int opt3001_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + + struct iio_dev *iio; + struct opt3001 *opt; + int irq = client->irq; + int ret; + + iio = devm_iio_device_alloc(dev, sizeof(*opt)); + if (!iio) + return -ENOMEM; + + opt = iio_priv(iio); + opt->client = client; + opt->dev = dev; + + mutex_init(&opt->lock); + init_waitqueue_head(&opt->result_ready_queue); + i2c_set_clientdata(client, iio); + + ret = opt3001_read_id(opt); + if (ret) + return ret; + + ret = opt3001_configure(opt); + if (ret) + return ret; + + iio->name = client->name; + iio->channels = opt3001_channels; + iio->num_channels = ARRAY_SIZE(opt3001_channels); + iio->dev.parent = dev; + iio->modes = INDIO_DIRECT_MODE; + iio->info = &opt3001_info; + + ret = devm_iio_device_register(dev, iio); + if (ret) { + dev_err(dev, "failed to register IIO device\n"); + return ret; + } + + ret = request_threaded_irq(irq, NULL, opt3001_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "opt3001", iio); + if (ret) { + dev_err(dev, "failed to request IRQ #%d\n", irq); + return ret; + } + + return 0; +} + +static int opt3001_remove(struct i2c_client *client) +{ + struct iio_dev *iio = i2c_get_clientdata(client); + struct opt3001 *opt = iio_priv(iio); + int ret; + u16 reg; + + free_irq(client->irq, iio); + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return ret; + } + + reg = ret; + opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SHUTDOWN); + + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, + reg); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_CONFIGURATION); + return ret; + } + + return 0; +} + +static const struct i2c_device_id opt3001_id[] = { + { "opt3001", 0 }, + { } /* Terminating Entry */ +}; +MODULE_DEVICE_TABLE(i2c, opt3001_id); + +static const struct of_device_id opt3001_of_match[] = { + { .compatible = "ti,opt3001" }, + { } +}; + +static struct i2c_driver opt3001_driver = { + .probe = opt3001_probe, + .remove = opt3001_remove, + .id_table = opt3001_id, + + .driver = { + .name = "opt3001", + .of_match_table = of_match_ptr(opt3001_of_match), + .owner = THIS_MODULE, + }, +}; + +module_i2c_driver(opt3001_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Andreas Dannenberg "); +MODULE_DESCRIPTION("Texas Instruments OPT3001 Light Sensor Driver"); -- cgit v1.2.3 From 8ab6abfca09c1800dccb753775f6ce8ee82f50dd Mon Sep 17 00:00:00 2001 From: Adriana Reus Date: Tue, 7 Jul 2015 14:07:13 +0300 Subject: iio: light: Add support for TXC PA12 als and proximity sensor Add support for TXC PA12203001 als and proximity sensor. Support for raw illuminance and proximity readings. Signed-off-by: Adriana Reus Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 11 + drivers/iio/light/Makefile | 1 + drivers/iio/light/pa12203001.c | 483 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 495 insertions(+) create mode 100644 drivers/iio/light/pa12203001.c diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 5c0854a7e3e0..a459341a79f9 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -219,6 +219,17 @@ config OPT3001 If built as a dynamically linked module, it will be called opt3001. +config PA12203001 + tristate "TXC PA12203001 light and proximity sensor" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for the TXC PA12203001 + ambient light and proximity sensor. + + This driver can also be built as a module. If so, the module + will be called pa12203001. + config STK3310 tristate "STK3310 ALS and proximity sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 5345969f7000..91c74c014b6f 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_JSA1212) += jsa1212.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o obj-$(CONFIG_LTR501) += ltr501.o obj-$(CONFIG_OPT3001) += opt3001.o +obj-$(CONFIG_PA12203001) += pa12203001.o obj-$(CONFIG_RPR0521) += rpr0521.o obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o obj-$(CONFIG_STK3310) += stk3310.o diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c new file mode 100644 index 000000000000..45f7bde02bbf --- /dev/null +++ b/drivers/iio/light/pa12203001.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2015 Intel Corporation + * + * Driver for TXC PA12203001 Proximity and Ambient Light Sensor. + * + * 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. + * To do: Interrupt support. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PA12203001_DRIVER_NAME "pa12203001" + +#define PA12203001_REG_CFG0 0x00 +#define PA12203001_REG_CFG1 0x01 +#define PA12203001_REG_CFG2 0x02 +#define PA12203001_REG_CFG3 0x03 + +#define PA12203001_REG_ADL 0x0b +#define PA12203001_REG_PDH 0x0e + +#define PA12203001_REG_POFS 0x10 +#define PA12203001_REG_PSET 0x11 + +#define PA12203001_ALS_EN_MASK BIT(0) +#define PA12203001_PX_EN_MASK BIT(1) +#define PA12203001_PX_NORMAL_MODE_MASK GENMASK(7, 6) +#define PA12203001_AFSR_MASK GENMASK(5, 4) +#define PA12203001_AFSR_SHIFT 4 + +#define PA12203001_PSCAN 0x03 + +/* als range 31000, ps, als disabled */ +#define PA12203001_REG_CFG0_DEFAULT 0x30 + +/* led current: 100 mA */ +#define PA12203001_REG_CFG1_DEFAULT 0x20 + +/* ps mode: normal, interrupts not active */ +#define PA12203001_REG_CFG2_DEFAULT 0xcc + +#define PA12203001_REG_CFG3_DEFAULT 0x00 + +#define PA12203001_SLEEP_DELAY_MS 3000 + +#define PA12203001_CHIP_ENABLE 0xff +#define PA12203001_CHIP_DISABLE 0x00 + +/* available scales: corresponding to [500, 4000, 7000, 31000] lux */ +static const int pa12203001_scales[] = { 7629, 61036, 106813, 473029}; + +struct pa12203001_data { + struct i2c_client *client; + + /* protect device states */ + struct mutex lock; + + bool als_enabled; + bool px_enabled; + bool als_needs_enable; + bool px_needs_enable; + + struct regmap *map; +}; + +static const struct { + u8 reg; + u8 val; +} regvals[] = { + {PA12203001_REG_CFG0, PA12203001_REG_CFG0_DEFAULT}, + {PA12203001_REG_CFG1, PA12203001_REG_CFG1_DEFAULT}, + {PA12203001_REG_CFG2, PA12203001_REG_CFG2_DEFAULT}, + {PA12203001_REG_CFG3, PA12203001_REG_CFG3_DEFAULT}, + {PA12203001_REG_PSET, PA12203001_PSCAN}, +}; + +static IIO_CONST_ATTR(in_illuminance_scale_available, + "0.007629 0.061036 0.106813 0.473029"); + +static struct attribute *pa12203001_attrs[] = { + &iio_const_attr_in_illuminance_scale_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group pa12203001_attr_group = { + .attrs = pa12203001_attrs, +}; + +static const struct iio_chan_spec pa12203001_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_PROXIMITY, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + } +}; + +static const struct regmap_range pa12203001_volatile_regs_ranges[] = { + regmap_reg_range(PA12203001_REG_ADL, PA12203001_REG_ADL + 1), + regmap_reg_range(PA12203001_REG_PDH, PA12203001_REG_PDH), +}; + +static const struct regmap_access_table pa12203001_volatile_regs = { + .yes_ranges = pa12203001_volatile_regs_ranges, + .n_yes_ranges = ARRAY_SIZE(pa12203001_volatile_regs_ranges), +}; + +static const struct regmap_config pa12203001_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = PA12203001_REG_PSET, + .cache_type = REGCACHE_RBTREE, + .volatile_table = &pa12203001_volatile_regs, +}; + +static inline int pa12203001_als_enable(struct pa12203001_data *data, u8 enable) +{ + int ret; + + ret = regmap_update_bits(data->map, PA12203001_REG_CFG0, + PA12203001_ALS_EN_MASK, enable); + if (ret < 0) + return ret; + + data->als_enabled = !!enable; + + return 0; +} + +static inline int pa12203001_px_enable(struct pa12203001_data *data, u8 enable) +{ + int ret; + + ret = regmap_update_bits(data->map, PA12203001_REG_CFG0, + PA12203001_PX_EN_MASK, enable); + if (ret < 0) + return ret; + + data->px_enabled = !!enable; + + return 0; +} + +static int pa12203001_set_power_state(struct pa12203001_data *data, bool on, + u8 mask) +{ +#ifdef CONFIG_PM + int ret; + + if (on && (mask & PA12203001_ALS_EN_MASK)) { + mutex_lock(&data->lock); + if (data->px_enabled) { + ret = pa12203001_als_enable(data, + PA12203001_ALS_EN_MASK); + if (ret < 0) + goto err; + } else { + data->als_needs_enable = true; + } + mutex_unlock(&data->lock); + } + + if (on && (mask & PA12203001_PX_EN_MASK)) { + mutex_lock(&data->lock); + if (data->als_enabled) { + ret = pa12203001_px_enable(data, PA12203001_PX_EN_MASK); + if (ret < 0) + goto err; + } else { + data->px_needs_enable = true; + } + mutex_unlock(&data->lock); + } + + if (on) { + ret = pm_runtime_get_sync(&data->client->dev); + if (ret < 0) + pm_runtime_put_noidle(&data->client->dev); + + } else { + pm_runtime_mark_last_busy(&data->client->dev); + ret = pm_runtime_put_autosuspend(&data->client->dev); + } + + return ret; + +err: + mutex_unlock(&data->lock); + return ret; + +#endif + return 0; +} + +static int pa12203001_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct pa12203001_data *data = iio_priv(indio_dev); + int ret; + u8 dev_mask; + unsigned int reg_byte; + __le16 reg_word; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_LIGHT: + dev_mask = PA12203001_ALS_EN_MASK; + ret = pa12203001_set_power_state(data, true, dev_mask); + if (ret < 0) + return ret; + /* + * ALS ADC value is stored in registers + * PA12203001_REG_ADL and in PA12203001_REG_ADL + 1. + */ + ret = regmap_bulk_read(data->map, PA12203001_REG_ADL, + ®_word, 2); + if (ret < 0) + goto reg_err; + + *val = le16_to_cpu(reg_word); + ret = pa12203001_set_power_state(data, false, dev_mask); + if (ret < 0) + return ret; + break; + case IIO_PROXIMITY: + dev_mask = PA12203001_PX_EN_MASK; + ret = pa12203001_set_power_state(data, true, dev_mask); + if (ret < 0) + return ret; + ret = regmap_read(data->map, PA12203001_REG_PDH, + ®_byte); + if (ret < 0) + goto reg_err; + + *val = reg_byte; + ret = pa12203001_set_power_state(data, false, dev_mask); + if (ret < 0) + return ret; + break; + default: + return -EINVAL; + } + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = regmap_read(data->map, PA12203001_REG_CFG0, ®_byte); + if (ret < 0) + return ret; + *val = 0; + reg_byte = (reg_byte & PA12203001_AFSR_MASK); + *val2 = pa12203001_scales[reg_byte >> 4]; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + +reg_err: + pa12203001_set_power_state(data, false, dev_mask); + return ret; +} + +static int pa12203001_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct pa12203001_data *data = iio_priv(indio_dev); + int i, ret, new_val; + unsigned int reg_byte; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + ret = regmap_read(data->map, PA12203001_REG_CFG0, ®_byte); + if (val != 0 || ret < 0) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(pa12203001_scales); i++) { + if (val2 == pa12203001_scales[i]) { + new_val = i << PA12203001_AFSR_SHIFT; + return regmap_update_bits(data->map, + PA12203001_REG_CFG0, + PA12203001_AFSR_MASK, + new_val); + } + } + break; + default: + break; + } + + return -EINVAL; +} + +static const struct iio_info pa12203001_info = { + .driver_module = THIS_MODULE, + .read_raw = pa12203001_read_raw, + .write_raw = pa12203001_write_raw, + .attrs = &pa12203001_attr_group, +}; + +static int pa12203001_init(struct iio_dev *indio_dev) +{ + struct pa12203001_data *data = iio_priv(indio_dev); + int i, ret; + + for (i = 0; i < ARRAY_SIZE(regvals); i++) { + ret = regmap_write(data->map, regvals[i].reg, regvals[i].val); + if (ret < 0) + return ret; + } + + return 0; +} + +static int pa12203001_power_chip(struct iio_dev *indio_dev, u8 state) +{ + struct pa12203001_data *data = iio_priv(indio_dev); + int ret; + + mutex_lock(&data->lock); + ret = pa12203001_als_enable(data, state); + if (ret < 0) + goto out; + + ret = pa12203001_px_enable(data, state); + +out: + mutex_unlock(&data->lock); + return ret; +} + +static int pa12203001_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pa12203001_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, + sizeof(struct pa12203001_data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + + data->map = devm_regmap_init_i2c(client, &pa12203001_regmap_config); + if (IS_ERR(data->map)) + return PTR_ERR(data->map); + + mutex_init(&data->lock); + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &pa12203001_info; + indio_dev->name = PA12203001_DRIVER_NAME; + indio_dev->channels = pa12203001_channels; + indio_dev->num_channels = ARRAY_SIZE(pa12203001_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = pa12203001_init(indio_dev); + if (ret < 0) + return ret; + + ret = pa12203001_power_chip(indio_dev, PA12203001_CHIP_ENABLE); + if (ret < 0) + return ret; + + ret = pm_runtime_set_active(&client->dev); + if (ret < 0) { + pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE); + return ret; + } + + pm_runtime_enable(&client->dev); + pm_runtime_set_autosuspend_delay(&client->dev, + PA12203001_SLEEP_DELAY_MS); + pm_runtime_use_autosuspend(&client->dev); + + return iio_device_register(indio_dev); +} + +static int pa12203001_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + + return pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE); +} + +#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM) +static int pa12203001_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + + return pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE); +} +#endif + +#ifdef CONFIG_PM_SLEEP +static int pa12203001_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + + return pa12203001_power_chip(indio_dev, PA12203001_CHIP_ENABLE); +} +#endif + +#ifdef CONFIG_PM +static int pa12203001_runtime_resume(struct device *dev) +{ + struct pa12203001_data *data; + + data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); + + mutex_lock(&data->lock); + if (data->als_needs_enable) { + pa12203001_als_enable(data, PA12203001_ALS_EN_MASK); + data->als_needs_enable = false; + } + if (data->px_needs_enable) { + pa12203001_px_enable(data, PA12203001_PX_EN_MASK); + data->px_needs_enable = false; + } + mutex_unlock(&data->lock); + + return 0; +} +#endif + +static const struct dev_pm_ops pa12203001_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pa12203001_suspend, pa12203001_resume) + SET_RUNTIME_PM_OPS(pa12203001_suspend, pa12203001_runtime_resume, NULL) +}; + +static const struct acpi_device_id pa12203001_acpi_match[] = { + { "TXCPA122", 0}, + {} +}; + +MODULE_DEVICE_TABLE(acpi, pa12203001_acpi_match); + +static const struct i2c_device_id pa12203001_id[] = { + {"txcpa122", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, pa12203001_id); + +static struct i2c_driver pa12203001_driver = { + .driver = { + .name = PA12203001_DRIVER_NAME, + .pm = &pa12203001_pm_ops, + .acpi_match_table = ACPI_PTR(pa12203001_acpi_match), + }, + .probe = pa12203001_probe, + .remove = pa12203001_remove, + .id_table = pa12203001_id, + +}; +module_i2c_driver(pa12203001_driver); + +MODULE_AUTHOR("Adriana Reus "); +MODULE_DESCRIPTION("Driver for TXC PA12203001 Proximity and Light Sensor"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From ff1ac639b395d58bbd99ff4a36b10eebb81544a3 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Mon, 13 Jul 2015 16:15:56 +0300 Subject: tools: iio: Remove explicit NULL comparison Remove explicit NULL comparison and write it in its simpler form as recommended by checkpatch.pl. Signed-off-by: Cristina Opriceana Reviewed-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- tools/iio/generic_buffer.c | 4 ++-- tools/iio/iio_utils.c | 56 +++++++++++++++++++++++----------------------- tools/iio/lsiio.c | 10 ++++----- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/tools/iio/generic_buffer.c b/tools/iio/generic_buffer.c index 0e737238ca74..9535c2dc25af 100644 --- a/tools/iio/generic_buffer.c +++ b/tools/iio/generic_buffer.c @@ -270,7 +270,7 @@ int main(int argc, char **argv) } } - if (device_name == NULL) { + if (!device_name) { printf("Device name not set\n"); print_usage(); return -1; @@ -290,7 +290,7 @@ int main(int argc, char **argv) return -ENOMEM; if (!notrigger) { - if (trigger_name == NULL) { + if (!trigger_name) { /* * Build the trigger name. If it is device associated * its name is _dev[n] where n matches diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index 8fb3214c70f2..4a7e4801cebf 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -117,13 +117,13 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, } dp = opendir(scan_el_dir); - if (dp == NULL) { + if (!dp) { ret = -errno; goto error_free_builtname_generic; } ret = -ENOENT; - while (ent = readdir(dp), ent != NULL) + while (ent = readdir(dp), ent) /* * Do we allow devices to override a generic name with * a specific one? @@ -138,7 +138,7 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, } sysfsfp = fopen(filename, "r"); - if (sysfsfp == NULL) { + if (!sysfsfp) { ret = -errno; printf("failed to open %s\n", filename); goto error_free_filename; @@ -235,13 +235,13 @@ int iioutils_get_param_float(float *output, const char *param_name, } dp = opendir(device_dir); - if (dp == NULL) { + if (!dp) { ret = -errno; goto error_free_builtname_generic; } ret = -ENOENT; - while (ent = readdir(dp), ent != NULL) + while (ent = readdir(dp), ent) if ((strcmp(builtname, ent->d_name) == 0) || (strcmp(builtname_generic, ent->d_name) == 0)) { ret = asprintf(&filename, @@ -325,12 +325,12 @@ int build_channel_array(const char *device_dir, return -ENOMEM; dp = opendir(scan_el_dir); - if (dp == NULL) { + if (!dp) { ret = -errno; goto error_free_name; } - while (ent = readdir(dp), ent != NULL) + while (ent = readdir(dp), ent) if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) { ret = asprintf(&filename, @@ -341,7 +341,7 @@ int build_channel_array(const char *device_dir, } sysfsfp = fopen(filename, "r"); - if (sysfsfp == NULL) { + if (!sysfsfp) { ret = -errno; free(filename); goto error_close_dir; @@ -369,13 +369,13 @@ int build_channel_array(const char *device_dir, } *ci_array = malloc(sizeof(**ci_array) * (*counter)); - if (*ci_array == NULL) { + if (!*ci_array) { ret = -ENOMEM; goto error_close_dir; } seekdir(dp, 0); - while (ent = readdir(dp), ent != NULL) { + while (ent = readdir(dp), ent) { if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) { int current_enabled = 0; @@ -391,7 +391,7 @@ int build_channel_array(const char *device_dir, } sysfsfp = fopen(filename, "r"); - if (sysfsfp == NULL) { + if (!sysfsfp) { ret = -errno; free(filename); count--; @@ -424,7 +424,7 @@ int build_channel_array(const char *device_dir, current->name = strndup(ent->d_name, strlen(ent->d_name) - strlen("_en")); - if (current->name == NULL) { + if (!current->name) { free(filename); ret = -ENOMEM; count--; @@ -452,7 +452,7 @@ int build_channel_array(const char *device_dir, } sysfsfp = fopen(filename, "r"); - if (sysfsfp == NULL) { + if (!sysfsfp) { ret = -errno; printf("failed to open %s\n", filename); free(filename); @@ -567,12 +567,12 @@ int find_type_by_name(const char *name, const char *type) char *filename; dp = opendir(iio_dir); - if (dp == NULL) { + if (!dp) { printf("No industrialio devices available\n"); return -ENODEV; } - while (ent = readdir(dp), ent != NULL) { + while (ent = readdir(dp), ent) { if (strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0 && strlen(ent->d_name) > strlen(type) && @@ -595,7 +595,7 @@ int find_type_by_name(const char *name, const char *type) ":", 1) != 0) { filename = malloc(strlen(iio_dir) + strlen(type) + numstrlen + 6); - if (filename == NULL) { + if (!filename) { ret = -ENOMEM; goto error_close_dir; } @@ -654,7 +654,7 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val, int test; char *temp = malloc(strlen(basedir) + strlen(filename) + 2); - if (temp == NULL) + if (!temp) return -ENOMEM; ret = sprintf(temp, "%s/%s", basedir, filename); @@ -662,7 +662,7 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val, goto error_free; sysfsfp = fopen(temp, "w"); - if (sysfsfp == NULL) { + if (!sysfsfp) { ret = -errno; printf("failed to open %s\n", temp); goto error_free; @@ -683,7 +683,7 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val, if (verify) { sysfsfp = fopen(temp, "r"); - if (sysfsfp == NULL) { + if (!sysfsfp) { ret = -errno; printf("failed to open %s\n", temp); goto error_free; @@ -749,7 +749,7 @@ static int _write_sysfs_string(const char *filename, const char *basedir, FILE *sysfsfp; char *temp = malloc(strlen(basedir) + strlen(filename) + 2); - if (temp == NULL) { + if (!temp) { printf("Memory allocation failed\n"); return -ENOMEM; } @@ -759,7 +759,7 @@ static int _write_sysfs_string(const char *filename, const char *basedir, goto error_free; sysfsfp = fopen(temp, "w"); - if (sysfsfp == NULL) { + if (!sysfsfp) { ret = -errno; printf("Could not open %s\n", temp); goto error_free; @@ -780,7 +780,7 @@ static int _write_sysfs_string(const char *filename, const char *basedir, if (verify) { sysfsfp = fopen(temp, "r"); - if (sysfsfp == NULL) { + if (!sysfsfp) { ret = -errno; printf("Could not open file to verify\n"); goto error_free; @@ -855,7 +855,7 @@ int read_sysfs_posint(const char *filename, const char *basedir) FILE *sysfsfp; char *temp = malloc(strlen(basedir) + strlen(filename) + 2); - if (temp == NULL) { + if (!temp) { printf("Memory allocation failed"); return -ENOMEM; } @@ -865,7 +865,7 @@ int read_sysfs_posint(const char *filename, const char *basedir) goto error_free; sysfsfp = fopen(temp, "r"); - if (sysfsfp == NULL) { + if (!sysfsfp) { ret = -errno; goto error_free; } @@ -902,7 +902,7 @@ int read_sysfs_float(const char *filename, const char *basedir, float *val) FILE *sysfsfp; char *temp = malloc(strlen(basedir) + strlen(filename) + 2); - if (temp == NULL) { + if (!temp) { printf("Memory allocation failed"); return -ENOMEM; } @@ -912,7 +912,7 @@ int read_sysfs_float(const char *filename, const char *basedir, float *val) goto error_free; sysfsfp = fopen(temp, "r"); - if (sysfsfp == NULL) { + if (!sysfsfp) { ret = -errno; goto error_free; } @@ -949,7 +949,7 @@ int read_sysfs_string(const char *filename, const char *basedir, char *str) FILE *sysfsfp; char *temp = malloc(strlen(basedir) + strlen(filename) + 2); - if (temp == NULL) { + if (!temp) { printf("Memory allocation failed"); return -ENOMEM; } @@ -959,7 +959,7 @@ int read_sysfs_string(const char *filename, const char *basedir, char *str) goto error_free; sysfsfp = fopen(temp, "r"); - if (sysfsfp == NULL) { + if (!sysfsfp) { ret = -errno; goto error_free; } diff --git a/tools/iio/lsiio.c b/tools/iio/lsiio.c index 7f432a55a6c4..4f8172fe7881 100644 --- a/tools/iio/lsiio.c +++ b/tools/iio/lsiio.c @@ -46,10 +46,10 @@ static int dump_channels(const char *dev_dir_name) const struct dirent *ent; dp = opendir(dev_dir_name); - if (dp == NULL) + if (!dp) return -errno; - while (ent = readdir(dp), ent != NULL) + while (ent = readdir(dp), ent) if (check_prefix(ent->d_name, "in_") && check_postfix(ent->d_name, "_raw")) printf(" %-10s\n", ent->d_name); @@ -107,12 +107,12 @@ static int dump_devices(void) DIR *dp; dp = opendir(iio_dir); - if (dp == NULL) { + if (!dp) { printf("No industrial I/O devices available\n"); return -ENODEV; } - while (ent = readdir(dp), ent != NULL) { + while (ent = readdir(dp), ent) { if (check_prefix(ent->d_name, type_device)) { char *dev_dir_name; @@ -134,7 +134,7 @@ static int dump_devices(void) } } rewinddir(dp); - while (ent = readdir(dp), ent != NULL) { + while (ent = readdir(dp), ent) { if (check_prefix(ent->d_name, type_trigger)) { char *dev_dir_name; -- cgit v1.2.3 From 37d38e2bcce055c3988977429dc4336c866df73d Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Mon, 13 Jul 2015 16:17:47 +0300 Subject: tools: iio: Remove unnecessary braces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Single statement blocks don’t need braces. Found with checkpatch.pl. Signed-off-by: Cristina Opriceana Acked-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- tools/iio/iio_event_monitor.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index 703f4cb0e8e9..9ee195949a4a 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -262,9 +262,8 @@ int main(int argc, char **argv) printf("Found IIO device with name %s with device number %d\n", device_name, dev_num); ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num); - if (ret < 0) { + if (ret < 0) return -ENOMEM; - } } else { /* * If we can't find an IIO device by name assume device_name is -- cgit v1.2.3 From 34cbea1908fb686b037e01e5b1ab8e0e67b09ed3 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Mon, 13 Jul 2015 16:20:11 +0300 Subject: tools: iio: Add ARRAY_SIZE macro Calculation of the length of an array can be done with the ARRAY_SIZE macro to make code more abstract and remove the associated checkpatch.pl warning. Signed-off-by: Cristina Opriceana Acked-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- tools/iio/iio_utils.c | 2 +- tools/iio/iio_utils.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index 4a7e4801cebf..e177f4022d40 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -39,7 +39,7 @@ int iioutils_break_up_name(const char *full_name, char **generic_name) char *working, *prefix = ""; int i, ret; - for (i = 0; i < sizeof(iio_direction) / sizeof(iio_direction[0]); i++) + for (i = 0; i < ARRAY_SIZE(iio_direction); i++) if (!strncmp(full_name, iio_direction[i], strlen(iio_direction[i]))) { prefix = iio_direction[i]; diff --git a/tools/iio/iio_utils.h b/tools/iio/iio_utils.h index 086610139ade..f30a1091b53e 100644 --- a/tools/iio/iio_utils.h +++ b/tools/iio/iio_utils.h @@ -18,6 +18,8 @@ #define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements" #define FORMAT_TYPE_FILE "%s_type" +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) + extern const char *iio_dir; /** -- cgit v1.2.3 From d9abc615ea1659b6967a00e95b1b3a7fd4079b80 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Fri, 17 Jul 2015 18:43:42 +0300 Subject: tools: iio: Send error messages to stderr This patch indends to make some cleanup and send printf error messages to stderr. The changes were performed with coccinelle for failure messages and manual for other cases, such as wrong usage messages. Signed-off-by: Cristina Opriceana Reviewed-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- tools/iio/generic_buffer.c | 39 ++++++++++++++++++--------------- tools/iio/iio_event_monitor.c | 14 ++++++------ tools/iio/iio_utils.c | 51 +++++++++++++++++++++++++------------------ tools/iio/lsiio.c | 2 +- 4 files changed, 59 insertions(+), 47 deletions(-) diff --git a/tools/iio/generic_buffer.c b/tools/iio/generic_buffer.c index 9535c2dc25af..32f389ebb94d 100644 --- a/tools/iio/generic_buffer.c +++ b/tools/iio/generic_buffer.c @@ -193,15 +193,15 @@ void process_scan(char *data, void print_usage(void) { - printf("Usage: generic_buffer [options]...\n" - "Capture, convert and output data from IIO device buffer\n" - " -c Do n conversions\n" - " -e Disable wait for event (new data)\n" - " -g Use trigger-less mode\n" - " -l Set buffer length to n samples\n" - " -n Set device name (mandatory)\n" - " -t Set trigger name\n" - " -w Set delay between reads in us (event-less mode)\n"); + fprintf(stderr, "Usage: generic_buffer [options]...\n" + "Capture, convert and output data from IIO device buffer\n" + " -c Do n conversions\n" + " -e Disable wait for event (new data)\n" + " -g Use trigger-less mode\n" + " -l Set buffer length to n samples\n" + " -n Set device name (mandatory)\n" + " -t Set trigger name\n" + " -w Set delay between reads in us (event-less mode)\n"); } int main(int argc, char **argv) @@ -271,7 +271,7 @@ int main(int argc, char **argv) } if (!device_name) { - printf("Device name not set\n"); + fprintf(stderr, "Device name not set\n"); print_usage(); return -1; } @@ -279,7 +279,7 @@ int main(int argc, char **argv) /* Find the device requested */ dev_num = find_type_by_name(device_name, "iio:device"); if (dev_num < 0) { - printf("Failed to find the %s\n", device_name); + fprintf(stderr, "Failed to find the %s\n", device_name); return dev_num; } @@ -307,7 +307,8 @@ int main(int argc, char **argv) /* Verify the trigger exists */ trig_num = find_type_by_name(trigger_name, "trigger"); if (trig_num < 0) { - printf("Failed to find the trigger %s\n", trigger_name); + fprintf(stderr, "Failed to find the trigger %s\n", + trigger_name); ret = trig_num; goto error_free_triggername; } @@ -323,8 +324,8 @@ int main(int argc, char **argv) */ ret = build_channel_array(dev_dir_name, &channels, &num_channels); if (ret) { - printf("Problem reading scan element information\n"); - printf("diag %s\n", dev_dir_name); + fprintf(stderr, "Problem reading scan element information\n" + "diag %s\n", dev_dir_name); goto error_free_triggername; } @@ -350,7 +351,8 @@ int main(int argc, char **argv) dev_dir_name, trigger_name); if (ret < 0) { - printf("Failed to write current_trigger file\n"); + fprintf(stderr, + "Failed to write current_trigger file\n"); goto error_free_buf_dir_name; } } @@ -382,7 +384,7 @@ int main(int argc, char **argv) fp = open(buffer_access, O_RDONLY | O_NONBLOCK); if (fp == -1) { /* TODO: If it isn't there make the node */ ret = -errno; - printf("Failed to open %s\n", buffer_access); + fprintf(stderr, "Failed to open %s\n", buffer_access); goto error_free_buffer_access; } @@ -410,7 +412,7 @@ int main(int argc, char **argv) read_size = read(fp, data, toread * scan_size); if (read_size < 0) { if (errno == EAGAIN) { - printf("nothing available\n"); + fprintf(stderr, "nothing available\n"); continue; } else { break; @@ -431,7 +433,8 @@ int main(int argc, char **argv) ret = write_sysfs_string("trigger/current_trigger", dev_dir_name, "NULL"); if (ret < 0) - printf("Failed to write to %s\n", dev_dir_name); + fprintf(stderr, "Failed to write to %s\n", + dev_dir_name); error_close_buffer_access: if (close(fp) == -1) diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index 9ee195949a4a..cd3fd41b481d 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -215,8 +215,8 @@ static void print_event(struct iio_event_data *event) bool diff = IIO_EVENT_CODE_EXTRACT_DIFF(event->id); if (!event_is_known(event)) { - printf("Unknown event: time: %lld, id: %llx\n", - event->timestamp, event->id); + fprintf(stderr, "Unknown event: time: %lld, id: %llx\n", + event->timestamp, event->id); return; } @@ -251,7 +251,7 @@ int main(int argc, char **argv) int fd, event_fd; if (argc <= 1) { - printf("Usage: %s \n", argv[0]); + fprintf(stderr, "Usage: %s \n", argv[0]); return -1; } @@ -277,14 +277,14 @@ int main(int argc, char **argv) fd = open(chrdev_name, 0); if (fd == -1) { ret = -errno; - fprintf(stdout, "Failed to open %s\n", chrdev_name); + fprintf(stderr, "Failed to open %s\n", chrdev_name); goto error_free_chrdev_name; } ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd); if (ret == -1 || event_fd == -1) { ret = -errno; - fprintf(stdout, "Failed to retrieve event fd\n"); + fprintf(stderr, "Failed to retrieve event fd\n"); if (close(fd) == -1) perror("Failed to close character device file"); @@ -300,7 +300,7 @@ int main(int argc, char **argv) ret = read(event_fd, &event, sizeof(event)); if (ret == -1) { if (errno == EAGAIN) { - printf("nothing available\n"); + fprintf(stderr, "nothing available\n"); continue; } else { ret = -errno; @@ -310,7 +310,7 @@ int main(int argc, char **argv) } if (ret != sizeof(event)) { - printf("Reading event failed!\n"); + fprintf(stderr, "Reading event failed!\n"); ret = -EIO; break; } diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index e177f4022d40..c3f9e37333e7 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -140,7 +140,8 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, sysfsfp = fopen(filename, "r"); if (!sysfsfp) { ret = -errno; - printf("failed to open %s\n", filename); + fprintf(stderr, "failed to open %s\n", + filename); goto error_free_filename; } @@ -152,11 +153,13 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, &padint, shift); if (ret < 0) { ret = -errno; - printf("failed to pass scan type description\n"); + fprintf(stderr, + "failed to pass scan type description\n"); goto error_close_sysfsfp; } else if (ret != 5) { ret = -EIO; - printf("scan type description didn't match\n"); + fprintf(stderr, + "scan type description didn't match\n"); goto error_close_sysfsfp; } @@ -170,7 +173,8 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, *is_signed = (signchar == 's'); if (fclose(sysfsfp)) { ret = -errno; - printf("Failed to close %s\n", filename); + fprintf(stderr, "Failed to close %s\n", + filename); goto error_free_filename; } @@ -454,7 +458,8 @@ int build_channel_array(const char *device_dir, sysfsfp = fopen(filename, "r"); if (!sysfsfp) { ret = -errno; - printf("failed to open %s\n", filename); + fprintf(stderr, "failed to open %s\n", + filename); free(filename); goto error_cleanup_array; } @@ -568,7 +573,7 @@ int find_type_by_name(const char *name, const char *type) dp = opendir(iio_dir); if (!dp) { - printf("No industrialio devices available\n"); + fprintf(stderr, "No industrialio devices available\n"); return -ENODEV; } @@ -581,11 +586,13 @@ int find_type_by_name(const char *name, const char *type) ret = sscanf(ent->d_name + strlen(type), "%d", &number); if (ret < 0) { ret = -errno; - printf("failed to read element number\n"); + fprintf(stderr, + "failed to read element number\n"); goto error_close_dir; } else if (ret != 1) { ret = -EIO; - printf("failed to match element number\n"); + fprintf(stderr, + "failed to match element number\n"); goto error_close_dir; } @@ -664,7 +671,7 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val, sysfsfp = fopen(temp, "w"); if (!sysfsfp) { ret = -errno; - printf("failed to open %s\n", temp); + fprintf(stderr, "failed to open %s\n", temp); goto error_free; } @@ -685,7 +692,7 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val, sysfsfp = fopen(temp, "r"); if (!sysfsfp) { ret = -errno; - printf("failed to open %s\n", temp); + fprintf(stderr, "failed to open %s\n", temp); goto error_free; } @@ -703,8 +710,9 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val, } if (test != val) { - printf("Possible failure in int write %d to %s/%s\n", - val, basedir, filename); + fprintf(stderr, + "Possible failure in int write %d to %s/%s\n", + val, basedir, filename); ret = -1; } } @@ -750,7 +758,7 @@ static int _write_sysfs_string(const char *filename, const char *basedir, char *temp = malloc(strlen(basedir) + strlen(filename) + 2); if (!temp) { - printf("Memory allocation failed\n"); + fprintf(stderr, "Memory allocation failed\n"); return -ENOMEM; } @@ -761,7 +769,7 @@ static int _write_sysfs_string(const char *filename, const char *basedir, sysfsfp = fopen(temp, "w"); if (!sysfsfp) { ret = -errno; - printf("Could not open %s\n", temp); + fprintf(stderr, "Could not open %s\n", temp); goto error_free; } @@ -782,7 +790,7 @@ static int _write_sysfs_string(const char *filename, const char *basedir, sysfsfp = fopen(temp, "r"); if (!sysfsfp) { ret = -errno; - printf("Could not open file to verify\n"); + fprintf(stderr, "Could not open file to verify\n"); goto error_free; } @@ -800,9 +808,10 @@ static int _write_sysfs_string(const char *filename, const char *basedir, } if (strcmp(temp, val) != 0) { - printf("Possible failure in string write of %s " - "Should be %s written to %s/%s\n", temp, val, - basedir, filename); + fprintf(stderr, + "Possible failure in string write of %s " + "Should be %s written to %s/%s\n", temp, val, + basedir, filename); ret = -1; } } @@ -856,7 +865,7 @@ int read_sysfs_posint(const char *filename, const char *basedir) char *temp = malloc(strlen(basedir) + strlen(filename) + 2); if (!temp) { - printf("Memory allocation failed"); + fprintf(stderr, "Memory allocation failed"); return -ENOMEM; } @@ -903,7 +912,7 @@ int read_sysfs_float(const char *filename, const char *basedir, float *val) char *temp = malloc(strlen(basedir) + strlen(filename) + 2); if (!temp) { - printf("Memory allocation failed"); + fprintf(stderr, "Memory allocation failed"); return -ENOMEM; } @@ -950,7 +959,7 @@ int read_sysfs_string(const char *filename, const char *basedir, char *str) char *temp = malloc(strlen(basedir) + strlen(filename) + 2); if (!temp) { - printf("Memory allocation failed"); + fprintf(stderr, "Memory allocation failed"); return -ENOMEM; } diff --git a/tools/iio/lsiio.c b/tools/iio/lsiio.c index 4f8172fe7881..b271a9a796d2 100644 --- a/tools/iio/lsiio.c +++ b/tools/iio/lsiio.c @@ -108,7 +108,7 @@ static int dump_devices(void) dp = opendir(iio_dir); if (!dp) { - printf("No industrial I/O devices available\n"); + fprintf(stderr, "No industrial I/O devices available\n"); return -ENODEV; } -- cgit v1.2.3 From c176becd81843426eb8ab3b03aeeb19e387345fe Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Fri, 5 Jun 2015 16:59:42 +0300 Subject: iio: fix drivers that consider 0 as a valid IRQ in client->irq Since patch "i2c / ACPI: Use 0 to indicate that device does not have interrupt assigned" [1], 0 is not a valid i2c client irq anymore, so change all driver's checks accordingly. The same issue occurs when the device is instantiated via device tree with no IRQ, or from the i2c sysfs interface, even before the patch above. [1] http://lkml.kernel.org/g/<1430908148-201129-3-git-send-email-mika.westerberg@linux.intel.com> Signed-off-by: Octavian Purdila Reviewed-by: Mika Westerberg Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 2 +- drivers/iio/accel/kxcjk-1013.c | 2 +- drivers/iio/accel/mma9553.c | 2 +- drivers/iio/imu/kmx61.c | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index 47c6013ab376..21b665fc0739 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -1670,7 +1670,7 @@ static int bmc150_accel_probe(struct i2c_client *client, if (client->irq < 0) client->irq = bmc150_accel_gpio_probe(client, data); - if (client->irq >= 0) { + if (client->irq > 0) { ret = devm_request_threaded_irq( &client->dev, client->irq, bmc150_accel_irq_handler, diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 8128579bff79..3292bc0c1d0e 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1240,7 +1240,7 @@ static int kxcjk1013_probe(struct i2c_client *client, if (client->irq < 0) client->irq = kxcjk1013_gpio_probe(client, data); - if (client->irq >= 0) { + if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, kxcjk1013_data_rdy_trig_poll, kxcjk1013_event_handler, diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index a605280637e9..771858cb67a1 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -1149,7 +1149,7 @@ static int mma9553_probe(struct i2c_client *client, if (client->irq < 0) client->irq = mma9553_gpio_probe(client); - if (client->irq >= 0) { + if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, mma9553_irq_handler, mma9553_event_handler, diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index 462a010628cd..82cdf5090fa7 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -1363,7 +1363,7 @@ static int kmx61_probe(struct i2c_client *client, if (client->irq < 0) client->irq = kmx61_gpio_probe(client, data); - if (client->irq >= 0) { + if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, kmx61_data_rdy_trig_poll, kmx61_event_handler, @@ -1445,10 +1445,10 @@ err_iio_unregister_mag: err_iio_unregister_acc: iio_device_unregister(data->acc_indio_dev); err_buffer_cleanup_mag: - if (client->irq >= 0) + if (client->irq > 0) iio_triggered_buffer_cleanup(data->mag_indio_dev); err_buffer_cleanup_acc: - if (client->irq >= 0) + if (client->irq > 0) iio_triggered_buffer_cleanup(data->acc_indio_dev); err_trigger_unregister_motion: iio_trigger_unregister(data->motion_trig); @@ -1472,7 +1472,7 @@ static int kmx61_remove(struct i2c_client *client) iio_device_unregister(data->acc_indio_dev); iio_device_unregister(data->mag_indio_dev); - if (client->irq >= 0) { + if (client->irq > 0) { iio_triggered_buffer_cleanup(data->acc_indio_dev); iio_triggered_buffer_cleanup(data->mag_indio_dev); iio_trigger_unregister(data->acc_dready_trig); -- cgit v1.2.3 From bc27381edbeb654d819b7e1464091c456a0d3e64 Mon Sep 17 00:00:00 2001 From: Giuseppe Barba Date: Tue, 21 Jul 2015 10:35:41 +0200 Subject: iio: st-sensors: add configuration for WhoAmI address This patch permits to configure the WhoAmI register address because some device could have not a standard address for this register. Signed-off-by: Giuseppe Barba Reviewed-by: Denis Ciocca Acked-by: Denis Ciocca Signed-off-by: Jonathan Cameron --- drivers/iio/accel/st_accel_core.c | 5 +++ drivers/iio/common/st_sensors/st_sensors_core.c | 49 ++++++++++++------------- drivers/iio/gyro/st_gyro_core.c | 3 ++ drivers/iio/magnetometer/st_magn_core.c | 3 ++ drivers/iio/pressure/st_pressure_core.c | 3 ++ include/linux/iio/common/st_sensors.h | 2 + 6 files changed, 39 insertions(+), 26 deletions(-) diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 4002e6410444..12b42f6e70ab 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -226,6 +226,7 @@ static const struct iio_chan_spec st_accel_16bit_channels[] = { static const struct st_sensor_settings st_accel_sensors_settings[] = { { .wai = ST_ACCEL_1_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS3DH_ACCEL_DEV_NAME, [1] = LSM303DLHC_ACCEL_DEV_NAME, @@ -297,6 +298,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { }, { .wai = ST_ACCEL_2_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS331DLH_ACCEL_DEV_NAME, [1] = LSM303DL_ACCEL_DEV_NAME, @@ -359,6 +361,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { }, { .wai = ST_ACCEL_3_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LSM330_ACCEL_DEV_NAME, }, @@ -437,6 +440,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { }, { .wai = ST_ACCEL_4_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS3LV02DL_ACCEL_DEV_NAME, }, @@ -494,6 +498,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { }, { .wai = ST_ACCEL_5_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS331DL_ACCEL_DEV_NAME, }, diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 8086cbcff87d..d44bf1680859 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -479,46 +479,43 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev, int num_sensors_list, const struct st_sensor_settings *sensor_settings) { - u8 wai; int i, n, err; + u8 wai; struct st_sensor_data *sdata = iio_priv(indio_dev); - err = sdata->tf->read_byte(&sdata->tb, sdata->dev, - ST_SENSORS_DEFAULT_WAI_ADDRESS, &wai); - if (err < 0) { - dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n"); - goto read_wai_error; - } - for (i = 0; i < num_sensors_list; i++) { - if (sensor_settings[i].wai == wai) + for (n = 0; n < ST_SENSORS_MAX_4WAI; n++) { + if (strcmp(indio_dev->name, + sensor_settings[i].sensors_supported[n]) == 0) { + break; + } + } + if (n < ST_SENSORS_MAX_4WAI) break; } - if (i == num_sensors_list) - goto device_not_supported; + if (i == num_sensors_list) { + dev_err(&indio_dev->dev, "device name %s not recognized.\n", + indio_dev->name); + return -ENODEV; + } - for (n = 0; n < ARRAY_SIZE(sensor_settings[i].sensors_supported); n++) { - if (strcmp(indio_dev->name, - &sensor_settings[i].sensors_supported[n][0]) == 0) - break; + err = sdata->tf->read_byte(&sdata->tb, sdata->dev, + sensor_settings[i].wai_addr, &wai); + if (err < 0) { + dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n"); + return err; } - if (n == ARRAY_SIZE(sensor_settings[i].sensors_supported)) { - dev_err(&indio_dev->dev, "device name \"%s\" and WhoAmI (0x%02x) mismatch", - indio_dev->name, wai); - goto sensor_name_mismatch; + + if (sensor_settings[i].wai != wai) { + dev_err(&indio_dev->dev, "%s: WhoAmI mismatch (0x%x).\n", + indio_dev->name, wai); + return -EINVAL; } sdata->sensor_settings = (struct st_sensor_settings *)&sensor_settings[i]; return i; - -device_not_supported: - dev_err(&indio_dev->dev, "device not supported: WhoAmI (0x%x).\n", wai); -sensor_name_mismatch: - err = -ENODEV; -read_wai_error: - return err; } EXPORT_SYMBOL(st_sensors_check_device_support); diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index ffe96642b6d0..4b993a5bc9a1 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -131,6 +131,7 @@ static const struct iio_chan_spec st_gyro_16bit_channels[] = { static const struct st_sensor_settings st_gyro_sensors_settings[] = { { .wai = ST_GYRO_1_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = L3G4200D_GYRO_DEV_NAME, [1] = LSM330DL_GYRO_DEV_NAME, @@ -190,6 +191,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = { }, { .wai = ST_GYRO_2_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = L3GD20_GYRO_DEV_NAME, [1] = LSM330D_GYRO_DEV_NAME, @@ -252,6 +254,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = { }, { .wai = ST_GYRO_3_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = L3GD20_GYRO_DEV_NAME, }, diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index b4bcfb790f49..8d7d3a172874 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -192,6 +192,7 @@ static const struct iio_chan_spec st_magn_2_16bit_channels[] = { static const struct st_sensor_settings st_magn_sensors_settings[] = { { .wai = 0, /* This sensor has no valid WhoAmI report 0 */ + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LSM303DLH_MAGN_DEV_NAME, }, @@ -268,6 +269,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { }, { .wai = ST_MAGN_1_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LSM303DLHC_MAGN_DEV_NAME, [1] = LSM303DLM_MAGN_DEV_NAME, @@ -346,6 +348,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { }, { .wai = ST_MAGN_2_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS3MDL_MAGN_DEV_NAME, }, diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index e881fa6291e9..eb41d2b92c24 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -178,6 +178,7 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = { static const struct st_sensor_settings st_press_sensors_settings[] = { { .wai = ST_PRESS_LPS331AP_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LPS331AP_PRESS_DEV_NAME, }, @@ -225,6 +226,7 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { }, { .wai = ST_PRESS_LPS001WP_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LPS001WP_PRESS_DEV_NAME, }, @@ -260,6 +262,7 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { }, { .wai = ST_PRESS_LPS25H_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LPS25H_PRESS_DEV_NAME, }, diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index 2c476acb87d9..3c17cd7fdf06 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -166,6 +166,7 @@ struct st_sensor_transfer_function { /** * struct st_sensor_settings - ST specific sensor settings * @wai: Contents of WhoAmI register. + * @wai_addr: The address of WhoAmI register. * @sensors_supported: List of supported sensors by struct itself. * @ch: IIO channels for the sensor. * @odr: Output data rate register and ODR list available. @@ -179,6 +180,7 @@ struct st_sensor_transfer_function { */ struct st_sensor_settings { u8 wai; + u8 wai_addr; char sensors_supported[ST_SENSORS_MAX_4WAI][ST_SENSORS_MAX_NAME]; struct iio_chan_spec *ch; int num_ch; -- cgit v1.2.3 From bb602f8c61e289389e7c2af1b577303a841f6d34 Mon Sep 17 00:00:00 2001 From: Giuseppe Barba Date: Tue, 21 Jul 2015 10:35:42 +0200 Subject: iio: st-sensors: add support for single full scale device Some sensors could have only one full scale value. This means that the sensor hasn't a full scale register. This commit add a check on the configured full scale address to support such kind of sensors. Signed-off-by: Giuseppe Barba Acked-by: Denis Ciocca Signed-off-by: Jonathan Cameron --- drivers/iio/common/st_sensors/st_sensors_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index d44bf1680859..2e7fdb502645 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -126,6 +126,9 @@ static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs) int err, i = 0; struct st_sensor_data *sdata = iio_priv(indio_dev); + if (sdata->sensor_settings->fs.addr == 0) + return 0; + err = st_sensors_match_fs(sdata->sensor_settings, fs, &i); if (err < 0) goto st_accel_set_fullscale_error; -- cgit v1.2.3 From 74f5683f35fe6feae33b96815c1d40f13468d614 Mon Sep 17 00:00:00 2001 From: Giuseppe Barba Date: Tue, 21 Jul 2015 10:35:43 +0200 Subject: iio: st_magn: Add irq trigger handling Add irq trigger handling for magnetometer also Signed-off-by: Giuseppe Barba Acked-by: Denis Ciocca Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/st_magn.h | 2 ++ drivers/iio/magnetometer/st_magn_buffer.c | 7 +++++++ drivers/iio/magnetometer/st_magn_core.c | 13 ++++++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h index 287691ca56c1..604410236d99 100644 --- a/drivers/iio/magnetometer/st_magn.h +++ b/drivers/iio/magnetometer/st_magn.h @@ -25,6 +25,8 @@ void st_magn_common_remove(struct iio_dev *indio_dev); #ifdef CONFIG_IIO_BUFFER int st_magn_allocate_ring(struct iio_dev *indio_dev); void st_magn_deallocate_ring(struct iio_dev *indio_dev); +int st_magn_trig_set_state(struct iio_trigger *trig, bool state); +#define ST_MAGN_TRIGGER_SET_STATE (&st_magn_trig_set_state) #else /* CONFIG_IIO_BUFFER */ static inline int st_magn_probe_trigger(struct iio_dev *indio_dev, int irq) { diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c index bf427dc0d226..ecd3bd0a9769 100644 --- a/drivers/iio/magnetometer/st_magn_buffer.c +++ b/drivers/iio/magnetometer/st_magn_buffer.c @@ -23,6 +23,13 @@ #include #include "st_magn.h" +int st_magn_trig_set_state(struct iio_trigger *trig, bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + + return st_sensors_set_dataready_irq(indio_dev, state); +} + static int st_magn_buffer_preenable(struct iio_dev *indio_dev) { return st_sensors_set_enable(indio_dev, true); diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 8d7d3a172874..4c0cef865517 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -480,6 +480,16 @@ static const struct iio_info magn_info = { .write_raw = &st_magn_write_raw, }; +#ifdef CONFIG_IIO_TRIGGER +static const struct iio_trigger_ops st_magn_trigger_ops = { + .owner = THIS_MODULE, + .set_trigger_state = ST_MAGN_TRIGGER_SET_STATE, +}; +#define ST_MAGN_TRIGGER_OPS (&st_magn_trigger_ops) +#else +#define ST_MAGN_TRIGGER_OPS NULL +#endif + int st_magn_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *mdata = iio_priv(indio_dev); @@ -516,7 +526,8 @@ int st_magn_common_probe(struct iio_dev *indio_dev) return err; if (irq > 0) { - err = st_sensors_allocate_trigger(indio_dev, NULL); + err = st_sensors_allocate_trigger(indio_dev, + ST_MAGN_TRIGGER_OPS); if (err < 0) goto st_magn_probe_trigger_error; } -- cgit v1.2.3 From ddc05fa286068a2d0cf87a47739b155806d46670 Mon Sep 17 00:00:00 2001 From: Giuseppe Barba Date: Tue, 21 Jul 2015 10:35:44 +0200 Subject: iio: st-accel: add support for lsm303agr accelerometer This adds support for the lsm303agr accelerometer. Signed-off-by: Giuseppe Barba Acked-by: Denis Ciocca Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/st-sensors.txt | 1 + drivers/iio/accel/st_accel.h | 1 + drivers/iio/accel/st_accel_core.c | 1 + drivers/iio/accel/st_accel_i2c.c | 5 +++++ drivers/iio/accel/st_accel_spi.c | 1 + 5 files changed, 9 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/st-sensors.txt b/Documentation/devicetree/bindings/iio/st-sensors.txt index 8a6be3bdf267..d80bdaa75754 100644 --- a/Documentation/devicetree/bindings/iio/st-sensors.txt +++ b/Documentation/devicetree/bindings/iio/st-sensors.txt @@ -35,6 +35,7 @@ Accelerometers: - st,lsm303dl-accel - st,lsm303dlm-accel - st,lsm330-accel +- st,lsm303agr-accel Gyroscopes: - st,l3g4200d-gyro diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index aa1001931d0c..468f21fa2950 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -26,6 +26,7 @@ #define LSM303DLH_ACCEL_DEV_NAME "lsm303dlh_accel" #define LSM303DLM_ACCEL_DEV_NAME "lsm303dlm_accel" #define LSM330_ACCEL_DEV_NAME "lsm330_accel" +#define LSM303AGR_ACCEL_DEV_NAME "lsm303agr_accel" /** * struct st_sensors_platform_data - default accel platform data diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 12b42f6e70ab..ff30f8806880 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -233,6 +233,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { [2] = LSM330D_ACCEL_DEV_NAME, [3] = LSM330DL_ACCEL_DEV_NAME, [4] = LSM330DLC_ACCEL_DEV_NAME, + [5] = LSM303AGR_ACCEL_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_accel_12bit_channels, .odr = { diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index a2f1c20319eb..8b9cc84fd44f 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -68,6 +68,10 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "st,lsm330-accel", .data = LSM330_ACCEL_DEV_NAME, }, + { + .compatible = "st,lsm303agr-accel", + .data = LSM303AGR_ACCEL_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_accel_of_match); @@ -116,6 +120,7 @@ static const struct i2c_device_id st_accel_id_table[] = { { LSM303DL_ACCEL_DEV_NAME }, { LSM303DLM_ACCEL_DEV_NAME }, { LSM330_ACCEL_DEV_NAME }, + { LSM303AGR_ACCEL_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(i2c, st_accel_id_table); diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index 12ec29389e4b..54b61a3961c3 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -57,6 +57,7 @@ static const struct spi_device_id st_accel_id_table[] = { { LSM303DL_ACCEL_DEV_NAME }, { LSM303DLM_ACCEL_DEV_NAME }, { LSM330_ACCEL_DEV_NAME }, + { LSM303AGR_ACCEL_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(spi, st_accel_id_table); -- cgit v1.2.3 From 1e9676a8474b657b6a793f0abff2205783a1ce6f Mon Sep 17 00:00:00 2001 From: Giuseppe Barba Date: Tue, 21 Jul 2015 10:35:45 +0200 Subject: iio: st-magn: add support for lsm303agr magnetometer This adds support for the lsm303agr magnetometer. Signed-off-by: Giuseppe Barba Acked-by: Denis Ciocca Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/st-sensors.txt | 1 + drivers/iio/magnetometer/st_magn.h | 1 + drivers/iio/magnetometer/st_magn_core.c | 82 ++++++++++++++++++++++ drivers/iio/magnetometer/st_magn_i2c.c | 5 ++ drivers/iio/magnetometer/st_magn_spi.c | 1 + 5 files changed, 90 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/st-sensors.txt b/Documentation/devicetree/bindings/iio/st-sensors.txt index d80bdaa75754..d3ccdb190c53 100644 --- a/Documentation/devicetree/bindings/iio/st-sensors.txt +++ b/Documentation/devicetree/bindings/iio/st-sensors.txt @@ -47,6 +47,7 @@ Gyroscopes: - st,lsm330-gyro Magnetometers: +- st,lsm303agr-magn - st,lsm303dlh-magn - st,lsm303dlhc-magn - st,lsm303dlm-magn diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h index 604410236d99..06a4d9c35581 100644 --- a/drivers/iio/magnetometer/st_magn.h +++ b/drivers/iio/magnetometer/st_magn.h @@ -18,6 +18,7 @@ #define LSM303DLHC_MAGN_DEV_NAME "lsm303dlhc_magn" #define LSM303DLM_MAGN_DEV_NAME "lsm303dlm_magn" #define LIS3MDL_MAGN_DEV_NAME "lis3mdl" +#define LSM303AGR_MAGN_DEV_NAME "lsm303agr_magn" int st_magn_common_probe(struct iio_dev *indio_dev); void st_magn_common_remove(struct iio_dev *indio_dev); diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 4c0cef865517..f8dc4b85d70c 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -43,6 +43,7 @@ #define ST_MAGN_FS_AVL_8000MG 8000 #define ST_MAGN_FS_AVL_8100MG 8100 #define ST_MAGN_FS_AVL_12000MG 12000 +#define ST_MAGN_FS_AVL_15000MG 15000 #define ST_MAGN_FS_AVL_16000MG 16000 /* CUSTOM VALUES FOR SENSOR 0 */ @@ -157,6 +158,29 @@ #define ST_MAGN_2_OUT_Y_L_ADDR 0x2a #define ST_MAGN_2_OUT_Z_L_ADDR 0x2c +/* CUSTOM VALUES FOR SENSOR 3 */ +#define ST_MAGN_3_WAI_ADDR 0x4f +#define ST_MAGN_3_WAI_EXP 0x40 +#define ST_MAGN_3_ODR_ADDR 0x60 +#define ST_MAGN_3_ODR_MASK 0x0c +#define ST_MAGN_3_ODR_AVL_10HZ_VAL 0x00 +#define ST_MAGN_3_ODR_AVL_20HZ_VAL 0x01 +#define ST_MAGN_3_ODR_AVL_50HZ_VAL 0x02 +#define ST_MAGN_3_ODR_AVL_100HZ_VAL 0x03 +#define ST_MAGN_3_PW_ADDR 0x60 +#define ST_MAGN_3_PW_MASK 0x03 +#define ST_MAGN_3_PW_ON 0x00 +#define ST_MAGN_3_PW_OFF 0x03 +#define ST_MAGN_3_BDU_ADDR 0x62 +#define ST_MAGN_3_BDU_MASK 0x10 +#define ST_MAGN_3_DRDY_IRQ_ADDR 0x62 +#define ST_MAGN_3_DRDY_INT_MASK 0x01 +#define ST_MAGN_3_FS_AVL_15000_GAIN 1500 +#define ST_MAGN_3_MULTIREAD_BIT false +#define ST_MAGN_3_OUT_X_L_ADDR 0x68 +#define ST_MAGN_3_OUT_Y_L_ADDR 0x6a +#define ST_MAGN_3_OUT_Z_L_ADDR 0x6c + static const struct iio_chan_spec st_magn_16bit_channels[] = { ST_SENSORS_LSM_CHANNELS(IIO_MAGN, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), @@ -189,6 +213,22 @@ static const struct iio_chan_spec st_magn_2_16bit_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(3) }; +static const struct iio_chan_spec st_magn_3_16bit_channels[] = { + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16, + ST_MAGN_3_OUT_X_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16, + ST_MAGN_3_OUT_Y_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16, + ST_MAGN_3_OUT_Z_L_ADDR), + IIO_CHAN_SOFT_TIMESTAMP(3) +}; + static const struct st_sensor_settings st_magn_sensors_settings[] = { { .wai = 0, /* This sensor has no valid WhoAmI report 0 */ @@ -402,6 +442,48 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { .multi_read_bit = ST_MAGN_2_MULTIREAD_BIT, .bootime = 2, }, + { + .wai = ST_MAGN_3_WAI_EXP, + .wai_addr = ST_MAGN_3_WAI_ADDR, + .sensors_supported = { + [0] = LSM303AGR_MAGN_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_magn_3_16bit_channels, + .odr = { + .addr = ST_MAGN_3_ODR_ADDR, + .mask = ST_MAGN_3_ODR_MASK, + .odr_avl = { + { 10, ST_MAGN_3_ODR_AVL_10HZ_VAL, }, + { 20, ST_MAGN_3_ODR_AVL_20HZ_VAL, }, + { 50, ST_MAGN_3_ODR_AVL_50HZ_VAL, }, + { 100, ST_MAGN_3_ODR_AVL_100HZ_VAL, }, + }, + }, + .pw = { + .addr = ST_MAGN_3_PW_ADDR, + .mask = ST_MAGN_3_PW_MASK, + .value_on = ST_MAGN_3_PW_ON, + .value_off = ST_MAGN_3_PW_OFF, + }, + .fs = { + .fs_avl = { + [0] = { + .num = ST_MAGN_FS_AVL_15000MG, + .gain = ST_MAGN_3_FS_AVL_15000_GAIN, + }, + }, + }, + .bdu = { + .addr = ST_MAGN_3_BDU_ADDR, + .mask = ST_MAGN_3_BDU_MASK, + }, + .drdy_irq = { + .addr = ST_MAGN_3_DRDY_IRQ_ADDR, + .mask_int1 = ST_MAGN_3_DRDY_INT_MASK, + }, + .multi_read_bit = ST_MAGN_3_MULTIREAD_BIT, + .bootime = 2, + }, }; static int st_magn_read_raw(struct iio_dev *indio_dev, diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 28aa80731cea..8aa37af306ed 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -36,6 +36,10 @@ static const struct of_device_id st_magn_of_match[] = { .compatible = "st,lis3mdl-magn", .data = LIS3MDL_MAGN_DEV_NAME, }, + { + .compatible = "st,lsm303agr-magn", + .data = LSM303AGR_MAGN_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_magn_of_match); @@ -79,6 +83,7 @@ static const struct i2c_device_id st_magn_id_table[] = { { LSM303DLHC_MAGN_DEV_NAME }, { LSM303DLM_MAGN_DEV_NAME }, { LIS3MDL_MAGN_DEV_NAME }, + { LSM303AGR_MAGN_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(i2c, st_magn_id_table); diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 7adacf160146..0abca2c6afa6 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -51,6 +51,7 @@ static const struct spi_device_id st_magn_id_table[] = { { LSM303DLHC_MAGN_DEV_NAME }, { LSM303DLM_MAGN_DEV_NAME }, { LIS3MDL_MAGN_DEV_NAME }, + { LSM303AGR_MAGN_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(spi, st_magn_id_table); -- cgit v1.2.3 From 7868dfd216074fc5f902e7befacda2a0ec76e403 Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Thu, 23 Jul 2015 12:53:47 +1000 Subject: tools: iio: make scale and offset files optional Make scale and offset optional by adding -ENOENT check as not all drivers implement them. Signed-off-by: Joo Aun Saw Acked-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- tools/iio/iio_utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index c3f9e37333e7..1dcdf03955cb 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -487,7 +487,7 @@ int build_channel_array(const char *device_dir, device_dir, current->name, current->generic_name); - if (ret < 0) + if ((ret < 0) && (ret != -ENOENT)) goto error_cleanup_array; ret = iioutils_get_param_float(¤t->offset, @@ -495,7 +495,7 @@ int build_channel_array(const char *device_dir, device_dir, current->name, current->generic_name); - if (ret < 0) + if ((ret < 0) && (ret != -ENOENT)) goto error_cleanup_array; ret = iioutils_get_type(¤t->is_signed, -- cgit v1.2.3 From 58e446fcc69436988fdab4a81981f44193f064f7 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Jul 2015 18:18:28 +0200 Subject: iio: Export I2C module alias information in missing drivers The I2C core always reports the MODALIAS uevent as "i2c: Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 1 + drivers/iio/accel/stk8ba50.c | 1 + drivers/iio/light/stk3310.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index c2bd1444d6da..a553736b6e51 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -662,6 +662,7 @@ static const struct i2c_device_id stk8312_i2c_id[] = { {"STK8312", 0}, {} }; +MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id); static const struct acpi_device_id stk8312_acpi_id[] = { {"STK8312", 0}, diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 16cee637109b..80f77d8704b5 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -572,6 +572,7 @@ static const struct i2c_device_id stk8ba50_i2c_id[] = { {"stk8ba50", 0}, {} }; +MODULE_DEVICE_TABLE(i2c, stk8ba50_i2c_id); static const struct acpi_device_id stk8ba50_acpi_id[] = { {"STK8BA50", 0}, diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index fee4297d7c8f..d26b931730ee 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -695,6 +695,7 @@ static const struct i2c_device_id stk3310_i2c_id[] = { {"STK3311", 0}, {} }; +MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id); static const struct acpi_device_id stk3310_acpi_id[] = { {"STK3310", 0}, -- cgit v1.2.3 From 119c4fce683a22a2fdbe343e00bc1a20cc1dd11c Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Jul 2015 18:18:42 +0200 Subject: iio: Export OF module alias information in missing drivers The I2C core always reports the MODALIAS uevent as "i2c: Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 1 + drivers/iio/light/cm32181.c | 1 + drivers/iio/light/cm3232.c | 1 + drivers/iio/light/cm36651.c | 1 + drivers/iio/light/gp2ap020a00f.c | 1 + 5 files changed, 5 insertions(+) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index e8e2077c7244..3c4ad1563ca4 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -968,6 +968,7 @@ static const struct of_device_id mma8452_dt_ids[] = { { .compatible = "fsl,mma8452" }, { } }; +MODULE_DEVICE_TABLE(of, mma8452_dt_ids); static struct i2c_driver mma8452_driver = { .driver = { diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c index 1c0de2f8885d..d6fd0dace74f 100644 --- a/drivers/iio/light/cm32181.c +++ b/drivers/iio/light/cm32181.c @@ -353,6 +353,7 @@ static const struct of_device_id cm32181_of_match[] = { { .compatible = "capella,cm32181" }, { } }; +MODULE_DEVICE_TABLE(of, cm32181_of_match); static struct i2c_driver cm32181_driver = { .driver = { diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c index 1b508c65877c..fe89b6823217 100644 --- a/drivers/iio/light/cm3232.c +++ b/drivers/iio/light/cm3232.c @@ -417,6 +417,7 @@ static const struct of_device_id cm3232_of_match[] = { {.compatible = "capella,cm3232"}, {} }; +MODULE_DEVICE_TABLE(of, cm3232_of_match); static struct i2c_driver cm3232_driver = { .driver = { diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index 2a39e141e90c..c8d7b5ea7e78 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -731,6 +731,7 @@ static const struct of_device_id cm36651_of_match[] = { { .compatible = "capella,cm36651" }, { } }; +MODULE_DEVICE_TABLE(of, cm36651_of_match); static struct i2c_driver cm36651_driver = { .driver = { diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index 0334a814b5eb..6d41086f7c64 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1634,6 +1634,7 @@ static const struct of_device_id gp2ap020a00f_of_match[] = { { .compatible = "sharp,gp2ap020a00f" }, { } }; +MODULE_DEVICE_TABLE(of, gp2ap020a00f_of_match); #endif static struct i2c_driver gp2ap020a00f_driver = { -- cgit v1.2.3 From 9e35d366a1e8bd710fbebcf9af90d3fafbc55e36 Mon Sep 17 00:00:00 2001 From: Teodora Baluta Date: Fri, 31 Jul 2015 17:27:24 +0300 Subject: iio: mmc35240: minor change to improve code readibility This patch changes two variables to arrays to improve code readibility. Signed-off-by: Teodora Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/mmc35240.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index 9bc542daa732..fa4ccd070e56 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -308,31 +308,31 @@ static int mmc35240_read_measurement(struct mmc35240_data *data, __le16 buf[3]) static int mmc35240_raw_to_mgauss(struct mmc35240_data *data, int index, __le16 buf[], int *val) { - int raw_x, raw_y, raw_z; - int sens_x, sens_y, sens_z; + int raw[3]; + int sens[3]; int nfo; - raw_x = le16_to_cpu(buf[AXIS_X]); - raw_y = le16_to_cpu(buf[AXIS_Y]); - raw_z = le16_to_cpu(buf[AXIS_Z]); + raw[AXIS_X] = le16_to_cpu(buf[AXIS_X]); + raw[AXIS_Y] = le16_to_cpu(buf[AXIS_Y]); + raw[AXIS_Z] = le16_to_cpu(buf[AXIS_Z]); - sens_x = mmc35240_props_table[data->res].sens[AXIS_X]; - sens_y = mmc35240_props_table[data->res].sens[AXIS_Y]; - sens_z = mmc35240_props_table[data->res].sens[AXIS_Z]; + sens[AXIS_X] = mmc35240_props_table[data->res].sens[AXIS_X]; + sens[AXIS_Y] = mmc35240_props_table[data->res].sens[AXIS_Y]; + sens[AXIS_Z] = mmc35240_props_table[data->res].sens[AXIS_Z]; nfo = mmc35240_props_table[data->res].nfo; switch (index) { case AXIS_X: - *val = (raw_x - nfo) * 1000 / sens_x; + *val = (raw[AXIS_X] - nfo) * 1000 / sens[AXIS_X]; break; case AXIS_Y: - *val = (raw_y - nfo) * 1000 / sens_y - - (raw_z - nfo) * 1000 / sens_z; + *val = (raw[AXIS_Y] - nfo) * 1000 / sens[AXIS_Y] - + (raw[AXIS_Z] - nfo) * 1000 / sens[AXIS_Z]; break; case AXIS_Z: - *val = (raw_y - nfo) * 1000 / sens_y + - (raw_z - nfo) * 1000 / sens_z; + *val = (raw[AXIS_Y] - nfo) * 1000 / sens[AXIS_Y] + + (raw[AXIS_Z] - nfo) * 1000 / sens[AXIS_Z]; break; default: return -EINVAL; -- cgit v1.2.3 From f9ba1ab4d19a79b4bef4baf21f559f9dd8ba33f9 Mon Sep 17 00:00:00 2001 From: Crt Mori Date: Mon, 20 Jul 2015 21:38:27 +0200 Subject: iio: mlx90614: Define magic numbers Translates the magic constant numbers to named macros and add some additional comments about their meaning. The diff is made towards togreg branch as that branch seems to have the most recent updates of mlx90614 driver (many are yet to be merged). Signed-off-by: Crt Mori Acked-by: Peter Meerwald Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/mlx90614.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index 90f70b461567..5d033a5af615 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -65,6 +65,13 @@ #define MLX90614_AUTOSLEEP_DELAY 5000 /* default autosleep delay */ +/* Magic constants */ +#define MLX90614_CONST_OFFSET_DEC -13657 /* decimal part of the Kelvin offset */ +#define MLX90614_CONST_OFFSET_REM 500000 /* remainder of offset (273.15*50) */ +#define MLX90614_CONST_SCALE 20 /* Scale in milliKelvin (0.02 * 1000) */ +#define MLX90614_CONST_RAW_EMISSIVITY_MAX 65535 /* max value for emissivity */ +#define MLX90614_CONST_EMISSIVITY_RESOLUTION 15259 /* 1/65535 ~ 0.000015259 */ + struct mlx90614_data { struct i2c_client *client; struct mutex lock; /* for EEPROM access only */ @@ -204,11 +211,11 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev, *val = ret; return IIO_VAL_INT; case IIO_CHAN_INFO_OFFSET: - *val = 13657; - *val2 = 500000; + *val = MLX90614_CONST_OFFSET_DEC; + *val2 = MLX90614_CONST_OFFSET_REM; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SCALE: - *val = 20; + *val = MLX90614_CONST_SCALE; return IIO_VAL_INT; case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */ mlx90614_power_get(data, false); @@ -221,12 +228,12 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; - if (ret == 65535) { + if (ret == MLX90614_CONST_RAW_EMISSIVITY_MAX) { *val = 1; *val2 = 0; } else { *val = 0; - *val2 = ret * 15259; /* 1/65535 ~ 0.000015259 */ + *val2 = ret * MLX90614_CONST_EMISSIVITY_RESOLUTION; } return IIO_VAL_INT_PLUS_NANO; default: @@ -245,7 +252,8 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */ if (val < 0 || val2 < 0 || val > 1 || (val == 1 && val2 != 0)) return -EINVAL; - val = val * 65535 + val2 / 15259; /* 1/65535 ~ 0.000015259 */ + val = val * MLX90614_CONST_RAW_EMISSIVITY_MAX + + val2 / MLX90614_CONST_EMISSIVITY_RESOLUTION; mlx90614_power_get(data, false); mutex_lock(&data->lock); -- cgit v1.2.3 From 3021678a94cdb942bea4e634a37e91fe341b27b0 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Fri, 17 Jul 2015 10:52:30 +0200 Subject: iio:magnetometer:bmc150_magn: expand mutex in trigger_handler Keep the mutex locked, until the content of data->buffer has been pushed out. Signed-off-by: Hartmut Knaack Acked-by: Irina Tirdea Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/bmc150_magn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index 074a99da7367..324412d51cf8 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -664,7 +664,6 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p) mutex_lock(&data->mutex); ret = bmc150_magn_read_xyz(data, data->buffer); - mutex_unlock(&data->mutex); if (ret < 0) goto err; @@ -672,6 +671,7 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p) pf->timestamp); err: + mutex_unlock(&data->mutex); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; -- cgit v1.2.3 From 1506f3cd0b8169773188a080d367c2ed019373a3 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Fri, 17 Jul 2015 10:52:31 +0200 Subject: iio:magnetometer:bmc150_magn: use descriptive name for mask Define and use a descriptive name for the repetition registers data mask, instead of a 'magic' value. Signed-off-by: Hartmut Knaack Acked-by: Irina Tirdea Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/bmc150_magn.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index 324412d51cf8..9ae6479b8d84 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -85,6 +85,7 @@ #define BMC150_MAGN_REG_HIGH_THRESH 0x50 #define BMC150_MAGN_REG_REP_XY 0x51 #define BMC150_MAGN_REG_REP_Z 0x52 +#define BMC150_MAGN_REG_REP_DATAMASK GENMASK(7, 0) #define BMC150_MAGN_REG_TRIM_START 0x5D #define BMC150_MAGN_REG_TRIM_END 0x71 @@ -559,7 +560,7 @@ static int bmc150_magn_write_raw(struct iio_dev *indio_dev, } ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_REP_XY, - 0xFF, + BMC150_MAGN_REG_REP_DATAMASK, BMC150_MAGN_REPXY_TO_REGVAL (val)); mutex_unlock(&data->mutex); @@ -575,7 +576,7 @@ static int bmc150_magn_write_raw(struct iio_dev *indio_dev, } ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_REP_Z, - 0xFF, + BMC150_MAGN_REG_REP_DATAMASK, BMC150_MAGN_REPZ_TO_REGVAL (val)); mutex_unlock(&data->mutex); -- cgit v1.2.3 From 019cc46d0a5c559bca6c7e949cc277f529a51296 Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Thu, 23 Jul 2015 20:15:01 +0300 Subject: iio: magn: bmc150_magn: add locking comment for runtime resume Runtime resume function is called with the data->mutex lock held. Add a comment to indicate this. Signed-off-by: Irina Tirdea Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/bmc150_magn.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index 9ae6479b8d84..57f21fe10dd7 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -1044,6 +1044,9 @@ static int bmc150_magn_runtime_suspend(struct device *dev) return 0; } +/* + * Should be called with data->mutex held. + */ static int bmc150_magn_runtime_resume(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); -- cgit v1.2.3 From 5ab744d0d6e7fc90572250239ac796cd79b0ed77 Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Thu, 23 Jul 2015 20:15:02 +0300 Subject: iio: magn: bmc150_magn: do not set power state twice when setting trigger state When setting the trigger state, the device power state is set through buffer preenable and postdisable hooks. There is no need to also set it in the trigger set state call. Remove duplicate set power state from the trigger set state call. Signed-off-by: Irina Tirdea Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/bmc150_magn.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index 57f21fe10dd7..bf47c8838b49 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -784,29 +784,23 @@ static int bmc150_magn_data_rdy_trigger_set_state(struct iio_trigger *trig, if (state == data->dready_trigger_on) goto err_unlock; - ret = bmc150_magn_set_power_state(data, state); - if (ret < 0) - goto err_unlock; - ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_INT_DRDY, BMC150_MAGN_MASK_DRDY_EN, state << BMC150_MAGN_SHIFT_DRDY_EN); if (ret < 0) - goto err_poweroff; + goto err_unlock; data->dready_trigger_on = state; if (state) { ret = bmc150_magn_reset_intr(data); if (ret < 0) - goto err_poweroff; + goto err_unlock; } mutex_unlock(&data->mutex); return 0; -err_poweroff: - bmc150_magn_set_power_state(data, false); err_unlock: mutex_unlock(&data->mutex); return ret; -- cgit v1.2.3 From 2498dcf6e09b3ecce2b32ed6434bd02fc4219d5b Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Fri, 24 Jul 2015 16:16:19 +0300 Subject: iio: core: Add function params for kernel docs This patch adds the missing fields in kernel docs to remove some warnings that appear when the IIO Documentation DocBook is generated. Signed-off-by: Cristina Opriceana Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index d8051cdcbdc2..b3fcc2c449d8 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -406,10 +406,16 @@ EXPORT_SYMBOL_GPL(iio_enum_write); /** * iio_format_value() - Formats a IIO value into its string representation - * @buf: The buffer to which the formated value gets written - * @type: One of the IIO_VAL_... constants. This decides how the val and val2 - * parameters are formatted. - * @vals: pointer to the values, exact meaning depends on the type parameter. + * @buf: The buffer to which the formatted value gets written + * @type: One of the IIO_VAL_... constants. This decides how the val + * and val2 parameters are formatted. + * @size: Number of IIO value entries contained in vals + * @vals: Pointer to the values, exact meaning depends on the + * type parameter. + * + * Return: 0 by default, a negative number on failure or the + * total number of characters written for a type that belongs + * to the IIO_VAL_... constant. */ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals) { @@ -1096,6 +1102,11 @@ EXPORT_SYMBOL_GPL(devm_iio_device_free); /** * iio_chrdev_open() - chrdev file open for buffer access and ioctls + * @inode: Inode structure for identifying the device in the file system + * @filp: File structure for iio device used to keep and later access + * private data + * + * Return: 0 on success or -EBUSY if the device is already opened **/ static int iio_chrdev_open(struct inode *inode, struct file *filp) { @@ -1114,7 +1125,11 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp) /** * iio_chrdev_release() - chrdev file close buffer access and ioctls - **/ + * @inode: Inode structure pointer for the char device + * @filp: File structure pointer for the char device + * + * Return: 0 for successful release + */ static int iio_chrdev_release(struct inode *inode, struct file *filp) { struct iio_dev *indio_dev = container_of(inode->i_cdev, -- cgit v1.2.3 From 0123635a77f72e0787f6f8b3ac796a40f796fcc4 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Fri, 24 Jul 2015 16:18:09 +0300 Subject: iio: buffer: Fix kernel docs warnings Fix kernel docs for structures and functions in order to remove some warnings when the documentation gets generated. Signed-off-by: Cristina Opriceana Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index f72be48e650c..faed6efa49ec 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -91,9 +91,16 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf, /** * iio_buffer_read_first_n_outer() - chrdev read for buffer access + * @filp: File structure pointer for the char device + * @buf: Destination buffer for iio buffer read + * @n: First n bytes to read + * @f_ps: Long offset provided by the user as a seek position * * This function relies on all buffer implementations having an * iio_buffer as their first element. + * + * Return: negative values corresponding to error codes or ret != 0 + * for ending the reading activity **/ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, size_t n, loff_t *f_ps) @@ -143,6 +150,12 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, /** * iio_buffer_poll() - poll the buffer to find out if it has data + * @filp: File structure pointer for device access + * @wait: Poll table structure pointer for which the driver adds + * a wait queue + * + * Return: (POLLIN | POLLRDNORM) if data is available for reading + * or 0 for other cases */ unsigned int iio_buffer_poll(struct file *filp, struct poll_table_struct *wait) @@ -1136,7 +1149,7 @@ int iio_scan_mask_query(struct iio_dev *indio_dev, EXPORT_SYMBOL_GPL(iio_scan_mask_query); /** - * struct iio_demux_table() - table describing demux memcpy ops + * struct iio_demux_table - table describing demux memcpy ops * @from: index to copy from * @to: index to copy to * @length: how many bytes to copy -- cgit v1.2.3 From a316c01d59e9d45ede1083a81ae82eb15ae7eab3 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Fri, 24 Jul 2015 16:21:50 +0300 Subject: iio: event: Add missing fields in kernel docs Fix kernel docs warnings by adding the missing fields, each with its associated description. Signed-off-by: Cristina Opriceana Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-event.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 894d8137c4cf..b2f63f919cc4 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -32,6 +32,7 @@ * @dev_attr_list: list of event interface sysfs attribute * @flags: file operations related flags including busy flag. * @group: event interface sysfs attribute group + * @read_lock: lock to protect kfifo read operations */ struct iio_event_interface { wait_queue_head_t wait; @@ -75,6 +76,11 @@ EXPORT_SYMBOL(iio_push_event); /** * iio_event_poll() - poll the event queue to find out if it has data + * @filep: File structure pointer to identify the device + * @wait: Poll table pointer to add the wait queue on + * + * Return: (POLLIN | POLLRDNORM) if data is available for reading + * or a negative error code on failure */ static unsigned int iio_event_poll(struct file *filep, struct poll_table_struct *wait) -- cgit v1.2.3 From e52e95199d0c1aa8a06dbbc07b30562fded8b298 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Fri, 24 Jul 2015 16:23:43 +0300 Subject: include: linux: iio: Fix function parameter name in kernel doc Fix buffer name from kernel doc according to the function parameter. Signed-off-by: Cristina Opriceana Signed-off-by: Jonathan Cameron --- include/linux/iio/consumer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 26fb8f6342bb..fad58671c49e 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -100,7 +100,7 @@ void iio_channel_stop_all_cb(struct iio_cb_buffer *cb_buff); /** * iio_channel_cb_get_channels() - get access to the underlying channels. - * @cb_buff: The callback buffer from whom we want the channel + * @cb_buffer: The callback buffer from whom we want the channel * information. * * This function allows one to obtain information about the channels. -- cgit v1.2.3 From 2854c098e222a706b91cc83b4a91dbfd97212765 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Fri, 24 Jul 2015 16:26:09 +0300 Subject: include: linux: iio: Add missing kernel doc field Fix kernel doc for the iio_dev_attr structure by adding its missing field. Signed-off-by: Cristina Opriceana Signed-off-by: Jonathan Cameron --- include/linux/iio/sysfs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/iio/sysfs.h b/include/linux/iio/sysfs.h index 8a1d18640ab9..9cd8f747212f 100644 --- a/include/linux/iio/sysfs.h +++ b/include/linux/iio/sysfs.h @@ -18,7 +18,8 @@ struct iio_chan_spec; * struct iio_dev_attr - iio specific device attribute * @dev_attr: underlying device attribute * @address: associated register address - * @l: list head for maintaining list of dynamically created attrs. + * @l: list head for maintaining list of dynamically created attrs + * @c: specification for the underlying channel */ struct iio_dev_attr { struct device_attribute dev_attr; -- cgit v1.2.3 From ae067cb68d2ef42d4a84eeaf07411fe2936f48c4 Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Fri, 24 Jul 2015 16:28:05 +0300 Subject: tools: iio: fix mask for 32 bit sensor data When the the sensor data uses 32 bits out of 32, generic_buffer prints the value 0 for all data read. In this case, the mask is shifted 32 bits, which is beyond the size of an integer. This will lead to the mask always being 0. Before printing, the mask is applied to the raw value, thus generating a final value of 0. Fix the mask by shifting a 64 bit value instead of an integer. Signed-off-by: Irina Tirdea Acked-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- tools/iio/iio_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index 1dcdf03955cb..a95270f33353 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -168,7 +168,7 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, if (*bits_used == 64) *mask = ~0; else - *mask = (1 << *bits_used) - 1; + *mask = (1ULL << *bits_used) - 1; *is_signed = (signchar == 's'); if (fclose(sysfsfp)) { -- cgit v1.2.3 From e7231491ce6ae2053569166f60835a5594b3c0af Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Fri, 24 Jul 2015 16:28:06 +0300 Subject: tools: iio: print error message when buffer enable fails Running generic_buffer without enabling any channel of the sensor will fail without printing any error message. Add an error message that indicates buffer enable failed. Signed-off-by: Irina Tirdea Acked-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- tools/iio/generic_buffer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/iio/generic_buffer.c b/tools/iio/generic_buffer.c index 32f389ebb94d..9f7b85bf6ada 100644 --- a/tools/iio/generic_buffer.c +++ b/tools/iio/generic_buffer.c @@ -364,8 +364,11 @@ int main(int argc, char **argv) /* Enable the buffer */ ret = write_sysfs_int("enable", buf_dir_name, 1); - if (ret < 0) + if (ret < 0) { + fprintf(stderr, + "Failed to enable buffer: %s\n", strerror(-ret)); goto error_free_buf_dir_name; + } scan_size = size_from_channelarray(channels, num_channels); data = malloc(scan_size * buf_len); -- cgit v1.2.3 From 280f09256ab6f6180132da193b9f2e0b2fa61c51 Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Wed, 29 Jul 2015 01:12:24 +1000 Subject: tools: iio: iio_utils: remove unnecessary define guard Signed-off-by: Joo Aun Saw Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- tools/iio/iio_utils.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index a95270f33353..31aca9ab078b 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -6,9 +6,6 @@ * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. */ -#ifndef _IIO_UTILS_H -#define _IIO_UTILS_H - #include #include #include @@ -990,5 +987,3 @@ error_free: return ret; } - -#endif /* _IIO_UTILS_H */ -- cgit v1.2.3 From 5e37c523921480093323c06529ab854f0635c59d Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Tue, 28 Jul 2015 11:46:13 +1000 Subject: tools: iio: iio_utils: Make calc_digits static Signed-off-by: Joo Aun Saw Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- tools/iio/iio_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index 31aca9ab078b..4bbd6e7959cd 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -537,7 +537,7 @@ error_free_name: return ret; } -int calc_digits(int num) +static int calc_digits(int num) { int count = 0; -- cgit v1.2.3 From 19d566420b8c5a26d4f9666ef665e088173d3df3 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Tue, 28 Jul 2015 00:38:58 +0200 Subject: iio:adc:berlin2-adc: pass up real error code Pass up the real error code returned by platform_get_irq_byname(). Signed-off-by: Hartmut Knaack Acked-by: Antoine Tenart Signed-off-by: Jonathan Cameron --- drivers/iio/adc/berlin2-adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c index aecc9ad995ad..30e2090df96d 100644 --- a/drivers/iio/adc/berlin2-adc.c +++ b/drivers/iio/adc/berlin2-adc.c @@ -301,11 +301,11 @@ static int berlin2_adc_probe(struct platform_device *pdev) irq = platform_get_irq_byname(pdev, "adc"); if (irq < 0) - return -ENODEV; + return irq; tsen_irq = platform_get_irq_byname(pdev, "tsen"); if (tsen_irq < 0) - return -ENODEV; + return tsen_irq; ret = devm_request_irq(&pdev->dev, irq, berlin2_adc_irq, 0, pdev->dev.driver->name, indio_dev); -- cgit v1.2.3 From 688febbd168c52ab54ad29c210aceecb72386398 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Tue, 28 Jul 2015 00:39:00 +0200 Subject: iio:adc:berlin2-adc: constify iio_chan_spec Mark berlin2_adc_channels array as constant. Signed-off-by: Hartmut Knaack Acked-by: Antoine Tenart Signed-off-by: Jonathan Cameron --- drivers/iio/adc/berlin2-adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c index 30e2090df96d..2084b0b66ea0 100644 --- a/drivers/iio/adc/berlin2-adc.c +++ b/drivers/iio/adc/berlin2-adc.c @@ -86,7 +86,7 @@ struct berlin2_adc_priv { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ } -static struct iio_chan_spec berlin2_adc_channels[] = { +static const struct iio_chan_spec berlin2_adc_channels[] = { BERLIN2_ADC_CHANNEL(0, IIO_VOLTAGE), /* external input */ BERLIN2_ADC_CHANNEL(1, IIO_VOLTAGE), /* external input */ BERLIN2_ADC_CHANNEL(2, IIO_VOLTAGE), /* external input */ -- cgit v1.2.3 From 609e9d88f277bfe83392595745cc3976d42125b2 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Tue, 28 Jul 2015 00:39:01 +0200 Subject: iio:adc:berlin2-adc: use short operator format Use augmented assignment to subtract the offset for negative temperature values. Specify the amount of private data to be allocated through devm_iio_device_alloc() with sizeof(*priv), as it is shorter and common practice in IIO. Signed-off-by: Hartmut Knaack Acked-by: Antoine Tenart Signed-off-by: Jonathan Cameron --- drivers/iio/adc/berlin2-adc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c index 2084b0b66ea0..e04b7734df1d 100644 --- a/drivers/iio/adc/berlin2-adc.c +++ b/drivers/iio/adc/berlin2-adc.c @@ -221,7 +221,7 @@ static int berlin2_adc_read_raw(struct iio_dev *indio_dev, return temp; if (temp > 2047) - temp = -(4096 - temp); + temp -= 4096; /* Convert to milli Celsius */ *val = ((temp * 100000) / 264 - 270000); @@ -286,8 +286,7 @@ static int berlin2_adc_probe(struct platform_device *pdev) int irq, tsen_irq; int ret; - indio_dev = devm_iio_device_alloc(&pdev->dev, - sizeof(struct berlin2_adc_priv)); + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); if (!indio_dev) return -ENOMEM; -- cgit v1.2.3 From 546384c968383b512ba50f77c76ae7bdfa321f31 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Tue, 28 Jul 2015 00:39:02 +0200 Subject: iio:adc:berlin2-adc: use channel-array size directly Drop the otherwise unused definition of the channel-array size and use it directly in _probe - makes it a bit more obvious. Signed-off-by: Hartmut Knaack Acked-by: Antoine Tenart Signed-off-by: Jonathan Cameron --- drivers/iio/adc/berlin2-adc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c index e04b7734df1d..3aaf3a975c79 100644 --- a/drivers/iio/adc/berlin2-adc.c +++ b/drivers/iio/adc/berlin2-adc.c @@ -103,7 +103,6 @@ static const struct iio_chan_spec berlin2_adc_channels[] = { BERLIN2_ADC_CHANNEL(7, IIO_VOLTAGE), /* reserved */ IIO_CHAN_SOFT_TIMESTAMP(8), /* timestamp */ }; -#define BERLIN2_N_CHANNELS ARRAY_SIZE(berlin2_adc_channels) static int berlin2_adc_read(struct iio_dev *indio_dev, int channel) { @@ -324,8 +323,8 @@ static int berlin2_adc_probe(struct platform_device *pdev) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &berlin2_adc_info; - indio_dev->num_channels = BERLIN2_N_CHANNELS; indio_dev->channels = berlin2_adc_channels; + indio_dev->num_channels = ARRAY_SIZE(berlin2_adc_channels); /* Power up the ADC */ regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, -- cgit v1.2.3 From 946448e08e2f693ff21418d92a598b7aa296816d Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Tue, 28 Jul 2015 00:49:21 +0200 Subject: iio:accel:stk8312: add triggered buffer dependency Add the still missing dependencies for triggered buffer support. Fixes: 95c12bba51c37 ("iio: accel: Add buffer mode for Sensortek STK8312") Signed-off-by: Hartmut Knaack Reviewed-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 00e7bcbdbe24..c99d8e242218 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -140,6 +140,8 @@ config MMA9553 config STK8312 tristate "Sensortek STK8312 3-Axis Accelerometer Driver" depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Say yes here to get support for the Sensortek STK8312 3-axis accelerometer. -- cgit v1.2.3 From b41e63cf83affa50a6141eba52be1fbd05f29b21 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Tue, 28 Jul 2015 00:49:22 +0200 Subject: iio:accel:stk8312: check for invalid value Revision 1.2 of the datasheet recommends on page 22 to only write non-zero values read from OTP register 0x70 into AFECTRL register. Signed-off-by: Hartmut Knaack Reviewed-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index a553736b6e51..8280a37e0068 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -150,6 +150,8 @@ static int stk8312_otp_init(struct stk8312_data *data) goto exit_err; ret = i2c_smbus_read_byte_data(client, STK8312_REG_OTPDATA); + if (ret == 0) + ret = -EINVAL; if (ret < 0) goto exit_err; -- cgit v1.2.3 From 18422bb3c1d89b510bb7c590c716dd6ad8e1a1e4 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Wed, 29 Jul 2015 23:39:36 +0200 Subject: iio:accel:stk8312: improve error handling Improve error handling in the following ways: - set return value on error condition to an appropriate error code - return error code immediately in case of an error (slightly changes code structure) - pass up real error code - add missing error handling - return 0 when error have been caught already - put device back in active mode after error occurs Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 60 ++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index 8280a37e0068..82ad283b8c60 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -146,8 +146,10 @@ static int stk8312_otp_init(struct stk8312_data *data) count--; } while (!(ret & 0x80) && count > 0); - if (count == 0) + if (count == 0) { + ret = -ETIMEDOUT; goto exit_err; + } ret = i2c_smbus_read_byte_data(client, STK8312_REG_OTPDATA); if (ret == 0) @@ -161,7 +163,7 @@ static int stk8312_otp_init(struct stk8312_data *data) goto exit_err; msleep(150); - return ret; + return 0; exit_err: dev_err(&client->dev, "failed to initialize sensor\n"); @@ -205,8 +207,11 @@ static int stk8312_set_interrupts(struct stk8312_data *data, u8 int_mask) return ret; ret = i2c_smbus_write_byte_data(client, STK8312_REG_INTSU, int_mask); - if (ret < 0) + if (ret < 0) { dev_err(&client->dev, "failed to set interrupts\n"); + stk8312_set_mode(data, mode); + return ret; + } return stk8312_set_mode(data, mode); } @@ -230,7 +235,7 @@ static int stk8312_data_rdy_trigger_set_state(struct iio_trigger *trig, data->dready_trigger_on = state; - return ret; + return 0; } static const struct iio_trigger_ops stk8312_trigger_ops = { @@ -255,20 +260,24 @@ static int stk8312_set_sample_rate(struct stk8312_data *data, int rate) return ret; ret = i2c_smbus_read_byte_data(client, STK8312_REG_SR); - if (ret < 0) { - dev_err(&client->dev, "failed to set sampling rate\n"); - return ret; - } + if (ret < 0) + goto err_activate; masked_reg = (ret & (~STK8312_SR_MASK)) | rate; ret = i2c_smbus_write_byte_data(client, STK8312_REG_SR, masked_reg); if (ret < 0) - dev_err(&client->dev, "failed to set sampling rate\n"); - else - data->sample_rate_idx = rate; + goto err_activate; + + data->sample_rate_idx = rate; return stk8312_set_mode(data, mode); + +err_activate: + dev_err(&client->dev, "failed to set sampling rate\n"); + stk8312_set_mode(data, mode); + + return ret; } static int stk8312_set_range(struct stk8312_data *data, u8 range) @@ -290,21 +299,25 @@ static int stk8312_set_range(struct stk8312_data *data, u8 range) return ret; ret = i2c_smbus_read_byte_data(client, STK8312_REG_STH); - if (ret < 0) { - dev_err(&client->dev, "failed to change sensor range\n"); - return ret; - } + if (ret < 0) + goto err_activate; masked_reg = ret & (~STK8312_RNG_MASK); masked_reg |= range << STK8312_RNG_SHIFT; ret = i2c_smbus_write_byte_data(client, STK8312_REG_STH, masked_reg); if (ret < 0) - dev_err(&client->dev, "failed to change sensor range\n"); - else - data->range = range; + goto err_activate; + + data->range = range; return stk8312_set_mode(data, mode); + +err_activate: + dev_err(&client->dev, "failed to change sensor range\n"); + stk8312_set_mode(data, mode); + + return ret; } static int stk8312_read_accel(struct stk8312_data *data, u8 address) @@ -337,18 +350,21 @@ static int stk8312_read_raw(struct iio_dev *indio_dev, ret = stk8312_set_mode(data, data->mode | STK8312_MODE_ACTIVE); if (ret < 0) { mutex_unlock(&data->lock); - return -EINVAL; + return ret; } ret = stk8312_read_accel(data, chan->address); if (ret < 0) { stk8312_set_mode(data, data->mode & (~STK8312_MODE_ACTIVE)); mutex_unlock(&data->lock); - return -EINVAL; + return ret; } *val = sign_extend32(ret, 7); - stk8312_set_mode(data, data->mode & (~STK8312_MODE_ACTIVE)); + ret = stk8312_set_mode(data, + data->mode & (~STK8312_MODE_ACTIVE)); mutex_unlock(&data->lock); + if (ret < 0) + return ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = stk8312_scale_table[data->range - 1][0]; @@ -608,7 +624,7 @@ static int stk8312_probe(struct i2c_client *client, goto err_buffer_cleanup; } - return ret; + return 0; err_buffer_cleanup: iio_triggered_buffer_cleanup(indio_dev); -- cgit v1.2.3 From 03ecd50c50450b3e3173c9dda8adab241b46ae1e Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Wed, 29 Jul 2015 23:39:37 +0200 Subject: iio:accel:stk8312: rework macro definitions Make use of BIT to describe register bits, GENMASK for consecutive bitmasks, rename and sort existing definitions, replace magic value with an expressive definition, drop an unused definition. Signed-off-by: Hartmut Knaack Reviewed-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index 82ad283b8c60..d406ad05b8e5 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -37,16 +37,16 @@ #define STK8312_REG_OTPDATA 0x3E #define STK8312_REG_OTPCTRL 0x3F -#define STK8312_MODE_ACTIVE 0x01 +#define STK8312_MODE_ACTIVE BIT(0) #define STK8312_MODE_STANDBY 0x00 -#define STK8312_DREADY_BIT 0x10 -#define STK8312_INT_MODE 0xC0 -#define STK8312_RNG_MASK 0xC0 -#define STK8312_SR_MASK 0x07 -#define STK8312_SR_400HZ_IDX 0 +#define STK8312_MODE_INT_AH_PP 0xC0 /* active-high, push-pull */ +#define STK8312_DREADY_BIT BIT(4) +#define STK8312_RNG_6G 1 #define STK8312_RNG_SHIFT 6 -#define STK8312_READ_RETRIES 16 -#define STK8312_ALL_CHANNEL_MASK 7 +#define STK8312_RNG_MASK GENMASK(7, 6) +#define STK8312_SR_MASK GENMASK(2, 0) +#define STK8312_SR_400HZ_IDX 0 +#define STK8312_ALL_CHANNEL_MASK GENMASK(2, 0) #define STK8312_ALL_CHANNEL_SIZE 3 #define STK8312_DRIVER_NAME "stk8312" @@ -144,7 +144,7 @@ static int stk8312_otp_init(struct stk8312_data *data) if (ret < 0) goto exit_err; count--; - } while (!(ret & 0x80) && count > 0); + } while (!(ret & BIT(7)) && count > 0); if (count == 0) { ret = -ETIMEDOUT; @@ -565,11 +565,12 @@ static int stk8312_probe(struct i2c_client *client, return ret; } data->sample_rate_idx = STK8312_SR_400HZ_IDX; - ret = stk8312_set_range(data, 1); + ret = stk8312_set_range(data, STK8312_RNG_6G); if (ret < 0) return ret; - ret = stk8312_set_mode(data, STK8312_INT_MODE | STK8312_MODE_ACTIVE); + ret = stk8312_set_mode(data, + STK8312_MODE_INT_AH_PP | STK8312_MODE_ACTIVE); if (ret < 0) return ret; @@ -691,7 +692,7 @@ MODULE_DEVICE_TABLE(acpi, stk8312_acpi_id); static struct i2c_driver stk8312_driver = { .driver = { - .name = "stk8312", + .name = STK8312_DRIVER_NAME, .pm = STK8312_PM_OPS, .acpi_match_table = ACPI_PTR(stk8312_acpi_id), }, -- cgit v1.2.3 From 7d73e02c5d11ac1298b0a363b57d713969c02bbd Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Wed, 29 Jul 2015 23:39:38 +0200 Subject: iio:accel:stk8312: use appropriate variable types Adapt some variable types to reduce unnecessary casting. Signed-off-by: Hartmut Knaack Reviewed-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index d406ad05b8e5..4a697446f196 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -69,8 +69,8 @@ static const int stk8312_scale_table[][2] = { }; static const struct { - u16 val; - u32 val2; + int val; + int val2; } stk8312_samp_freq_table[] = { {400, 0}, {200, 0}, {100, 0}, {50, 0}, {25, 0}, {12, 500000}, {6, 250000}, {3, 125000} @@ -103,7 +103,7 @@ static const struct iio_chan_spec stk8312_channels[] = { struct stk8312_data { struct i2c_client *client; struct mutex lock; - int range; + u8 range; u8 sample_rate_idx; u8 mode; struct iio_trigger *dready_trig; @@ -243,7 +243,7 @@ static const struct iio_trigger_ops stk8312_trigger_ops = { .owner = THIS_MODULE, }; -static int stk8312_set_sample_rate(struct stk8312_data *data, int rate) +static int stk8312_set_sample_rate(struct stk8312_data *data, u8 rate) { int ret; u8 masked_reg; -- cgit v1.2.3 From dca5d2846514c0f3d95827d291310a403fc0ebb7 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Wed, 29 Jul 2015 23:39:39 +0200 Subject: iio:accel:stk8312: code style cleanup Adjust some indentation issues to make checkpatch.pl happy in strict mode. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index 4a697446f196..c5a47650b453 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -157,8 +157,7 @@ static int stk8312_otp_init(struct stk8312_data *data) if (ret < 0) goto exit_err; - ret = i2c_smbus_write_byte_data(data->client, - STK8312_REG_AFECTRL, ret); + ret = i2c_smbus_write_byte_data(data->client, STK8312_REG_AFECTRL, ret); if (ret < 0) goto exit_err; msleep(150); @@ -458,7 +457,7 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p) data->buffer[2] = buffer[2]; } else { for_each_set_bit(bit, indio_dev->active_scan_mask, - indio_dev->masklength) { + indio_dev->masklength) { ret = stk8312_read_accel(data, bit); if (ret < 0) { mutex_unlock(&data->lock); -- cgit v1.2.3 From 7a9fbd250ce274a1a625b1e2055abfe26328e46b Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Wed, 29 Jul 2015 23:39:40 +0200 Subject: iio:accel:stk8312: drop local buffer Drop the local buffer in stk8312_trigger_handler() and use data->buffer instead for bulk reads. Signed-off-by: Hartmut Knaack Reviewed-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index c5a47650b453..c764af284c94 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -435,7 +435,6 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct stk8312_data *data = iio_priv(indio_dev); int bit, ret, i = 0; - u8 buffer[STK8312_ALL_CHANNEL_SIZE]; mutex_lock(&data->lock); /* @@ -446,15 +445,12 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p) ret = i2c_smbus_read_i2c_block_data(data->client, STK8312_REG_XOUT, STK8312_ALL_CHANNEL_SIZE, - buffer); + data->buffer); if (ret < STK8312_ALL_CHANNEL_SIZE) { dev_err(&data->client->dev, "register read failed\n"); mutex_unlock(&data->lock); goto err; } - data->buffer[0] = buffer[0]; - data->buffer[1] = buffer[1]; - data->buffer[2] = buffer[2]; } else { for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) { -- cgit v1.2.3 From ad30bad3a5474f2585a7f2a35d4705c7f85210f3 Mon Sep 17 00:00:00 2001 From: Pengyu Ma Date: Tue, 4 Aug 2015 16:32:18 +0800 Subject: iio: declare struct to fix warning When compile iio related driver the following warning shown: include/linux/iio/trigger.h:35:34: warning: 'struct iio_trigger' declared inside parameter list int (*set_trigger_state)(struct iio_trigger *trig, bool state); include/linux/iio/trigger.h:38:18: warning: 'struct iio_dev' declared inside parameter list struct iio_dev *indio_dev); 'struct iio_dev' and 'struct iio_trigger' was used before declaration, forward declaration for these structs to fix warning. Signed-off-by: Pengyu Ma Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- include/linux/iio/trigger.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h index fa76c79a52a1..1c9e028e0d4a 100644 --- a/include/linux/iio/trigger.h +++ b/include/linux/iio/trigger.h @@ -18,6 +18,9 @@ struct iio_subirq { bool enabled; }; +struct iio_dev; +struct iio_trigger; + /** * struct iio_trigger_ops - operations structure for an iio_trigger. * @owner: used to monitor usage count of the trigger. -- cgit v1.2.3 From aab978772a4fbe71d8231cb58d0989737db27a36 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 4 Aug 2015 17:20:08 +0300 Subject: DocBook: Add initial documentation for IIO This is intended to help developers faster find their way inside the Industrial I/O core and reduce time spent on IIO drivers development. Signed-off-by: Daniel Baluta Acked-by: Crt Mori Reviewed-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- Documentation/DocBook/Makefile | 2 +- Documentation/DocBook/iio.tmpl | 697 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 698 insertions(+), 1 deletion(-) create mode 100644 Documentation/DocBook/iio.tmpl diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index b6a6a2e0dd3b..9e086067b4ae 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -15,7 +15,7 @@ DOCBOOKS := z8530book.xml device-drivers.xml \ 80211.xml debugobjects.xml sh.xml regulator.xml \ alsa-driver-api.xml writing-an-alsa-driver.xml \ tracepoint.xml drm.xml media_api.xml w1.xml \ - writing_musb_glue_layer.xml crypto-API.xml + writing_musb_glue_layer.xml crypto-API.xml iio.xml include Documentation/DocBook/media/Makefile diff --git a/Documentation/DocBook/iio.tmpl b/Documentation/DocBook/iio.tmpl new file mode 100644 index 000000000000..06bb53de5a47 --- /dev/null +++ b/Documentation/DocBook/iio.tmpl @@ -0,0 +1,697 @@ + + + + + + Industrial I/O driver developer's guide + + + + Daniel + Baluta + +
+ daniel.baluta@intel.com +
+
+
+
+ + + 2015 + Intel Corporation + + + + + This documentation is free software; you can redistribute + it and/or modify it under the terms of the GNU General Public + License version 2. + + +
+ + + + + Introduction + + The main purpose of the Industrial I/O subsystem (IIO) is to provide + support for devices that in some sense perform either analog-to-digital + conversion (ADC) or digital-to-analog conversion (DAC) or both. The aim + is to fill the gap between the somewhat similar hwmon and input + subsystems. + Hwmon is directed at low sample rate sensors used to monitor and + control the system itself, like fan speed control or temperature + measurement. Input is, as its name suggests, focused on human interaction + input devices (keyboard, mouse, touchscreen). In some cases there is + considerable overlap between these and IIO. + + + Devices that fall into this category include: + + + analog to digital converters (ADCs) + + + accelerometers + + + capacitance to digital converters (CDCs) + + + digital to analog converters (DACs) + + + gyroscopes + + + inertial measurement units (IMUs) + + + color and light sensors + + + magnetometers + + + pressure sensors + + + proximity sensors + + + temperature sensors + + + Usually these sensors are connected via SPI or I2C. A common use case of the + sensors devices is to have combined functionality (e.g. light plus proximity + sensor). + + + + Industrial I/O core + + The Industrial I/O core offers: + + + a unified framework for writing drivers for many different types of + embedded sensors. + + + a standard interface to user space applications manipulating sensors. + + + The implementation can be found under + drivers/iio/industrialio-* + + + Industrial I/O devices + +!Finclude/linux/iio/iio.h iio_dev +!Fdrivers/iio/industrialio-core.c iio_device_alloc +!Fdrivers/iio/industrialio-core.c iio_device_free +!Fdrivers/iio/industrialio-core.c iio_device_register +!Fdrivers/iio/industrialio-core.c iio_device_unregister + + + An IIO device usually corresponds to a single hardware sensor and it + provides all the information needed by a driver handling a device. + Let's first have a look at the functionality embedded in an IIO + device then we will show how a device driver makes use of an IIO + device. + + + There are two ways for a user space application to interact + with an IIO driver. + + + /sys/bus/iio/iio:deviceX/, this + represents a hardware sensor and groups together the data + channels of the same chip. + + + /dev/iio:deviceX, character device node + interface used for buffered data transfer and for events information + retrieval. + + + + A typical IIO driver will register itself as an I2C or SPI driver and will + create two routines, probe and remove + . At probe: + + call iio_device_alloc, which allocates memory + for an IIO device. + + initialize IIO device fields with driver specific information + (e.g. device name, device channels). + + call iio_device_register, this registers the + device with the IIO core. After this call the device is ready to accept + requests from user space applications. + + + At remove, we free the resources allocated in + probe in reverse order: + + iio_device_unregister, unregister the device + from the IIO core. + + iio_device_free, free the memory allocated + for the IIO device. + + + + IIO device sysfs interface + + Attributes are sysfs files used to expose chip info and also allowing + applications to set various configuration parameters. For device + with index X, attributes can be found under + /sys/bus/iio/iio:deviceX/ directory. + Common attributes are: + + name, description of the physical + chip. + + dev, shows the major:minor pair + associated with /dev/iio:deviceX node. + + sampling_frequency_available, + available discrete set of sampling frequency values for + device. + + + Available standard attributes for IIO devices are described in the + Documentation/ABI/testing/sysfs-bus-iio file + in the Linux kernel sources. + + + IIO device channels +!Finclude/linux/iio/iio.h iio_chan_spec structure. + + An IIO device channel is a representation of a data channel. An + IIO device can have one or multiple channels. For example: + + + a thermometer sensor has one channel representing the + temperature measurement. + + + a light sensor with two channels indicating the measurements in + the visible and infrared spectrum. + + + an accelerometer can have up to 3 channels representing + acceleration on X, Y and Z axes. + + + An IIO channel is described by the struct iio_chan_spec + . A thermometer driver for the temperature sensor in the + example above would have to describe its channel as follows: + + static const struct iio_chan_spec temp_channel[] = { + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, + }; + + + Channel sysfs attributes exposed to userspace are specified in + the form of bitmasks. Depending on their + shared info, attributes can be set in one of the following masks: + + info_mask_separate, attributes will + be specific to this channel + info_mask_shared_by_type, + attributes are shared by all channels of the same type + info_mask_shared_by_dir, attributes + are shared by all channels of the same direction + info_mask_shared_by_all, + attributes are shared by all channels + + When there are multiple data channels per channel type we have two + ways to distinguish between them: + + set .modified field of + iio_chan_spec to 1. Modifiers are specified using + .channel2 field of the same + iio_chan_spec structure and are used to indicate a + physically unique characteristic of the channel such as its direction + or spectral response. For example, a light sensor can have two channels, + one for infrared light and one for both infrared and visible light. + + set .indexed field of + iio_chan_spec to 1. In this case the channel is + simply another instance with an index specified by the + .channel field. + + + Here is how we can make use of the channel's modifiers: + + static const struct iio_chan_spec light_channels[] = { + { + .type = IIO_INTENSITY, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_IR, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ), + }, + { + .type = IIO_INTENSITY, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_BOTH, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ), + }, + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ), + }, + + } + + This channel's definition will generate two separate sysfs files + for raw data retrieval: + + + /sys/bus/iio/iio:deviceX/in_intensity_ir_raw + + + /sys/bus/iio/iio:deviceX/in_intensity_both_raw + + + one file for processed data: + + + /sys/bus/iio/iio:deviceX/in_illuminance_input + + + + and one shared sysfs file for sampling frequency: + + + /sys/bus/iio/iio:deviceX/sampling_frequency. + + + + + + Here is how we can make use of the channel's indexing: + + static const struct iio_chan_spec light_channels[] = { + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, + } + + This will generate two separate attributes files for raw data + retrieval: + + + /sys/bus/iio/devices/iio:deviceX/in_voltage0_raw, + representing voltage measurement for channel 0. + + + /sys/bus/iio/devices/iio:deviceX/in_voltage1_raw, + representing voltage measurement for channel 1. + + + + + + + Industrial I/O buffers +!Finclude/linux/iio/buffer.h iio_buffer +!Edrivers/iio/industrialio-buffer.c + + + The Industrial I/O core offers a way for continuous data capture + based on a trigger source. Multiple data channels can be read at once + from /dev/iio:deviceX character device node, + thus reducing the CPU load. + + + + IIO buffer sysfs interface + + An IIO buffer has an associated attributes directory under + /sys/bus/iio/iio:deviceX/buffer/. Here are the existing + attributes: + + + length, the total number of data samples + (capacity) that can be stored by the buffer. + + + enable, activate buffer capture. + + + + + + IIO buffer setup + The meta information associated with a channel reading + placed in a buffer is called a scan element . + The important bits configuring scan elements are exposed to + userspace applications via the + /sys/bus/iio/iio:deviceX/scan_elements/ directory. This + file contains attributes of the following form: + + enable, used for enabling a channel. + If and only if its attribute is non zero, then a triggered capture + will contain data samples for this channel. + + type, description of the scan element + data storage within the buffer and hence the form in which it is + read from user space. Format is + [be|le]:[s|u]bits/storagebitsXrepeat[>>shift] . + + be or le, specifies + big or little endian. + + + s or u, specifies if + signed (2's complement) or unsigned. + + bits, is the number of valid data + bits. + + storagebits, is the number of bits + (after padding) that it occupies in the buffer. + + + shift, if specified, is the shift that needs + to be applied prior to masking out unused bits. + + + repeat, specifies the number of bits/storagebits + repetitions. When the repeat element is 0 or 1, then the repeat + value is omitted. + + + + + For example, a driver for a 3-axis accelerometer with 12 bit + resolution where data is stored in two 8-bits registers as + follows: + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + |D3 |D2 |D1 |D0 | X | X | X | X | (LOW byte, address 0x06) + +---+---+---+---+---+---+---+---+ + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + |D11|D10|D9 |D8 |D7 |D6 |D5 |D4 | (HIGH byte, address 0x07) + +---+---+---+---+---+---+---+---+ + + + will have the following scan element type for each axis: + + $ cat /sys/bus/iio/devices/iio:device0/scan_elements/in_accel_y_type + le:s12/16>>4 + + A user space application will interpret data samples read from the + buffer as two byte little endian signed data, that needs a 4 bits + right shift before masking out the 12 valid bits of data. + + + For implementing buffer support a driver should initialize the following + fields in iio_chan_spec definition: + + struct iio_chan_spec { + /* other members */ + int scan_index + struct { + char sign; + u8 realbits; + u8 storagebits; + u8 shift; + u8 repeat; + enum iio_endian endianness; + } scan_type; + }; + + The driver implementing the accelerometer described above will + have the following channel definition: + + struct struct iio_chan_spec accel_channels[] = { + { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_X, + /* other stuff here */ + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 12, + .storgebits = 16, + .shift = 4, + .endianness = IIO_LE, + }, + } + /* similar for Y (with channel2 = IIO_MOD_Y, scan_index = 1) + * and Z (with channel2 = IIO_MOD_Z, scan_index = 2) axis + */ + } + + + + Here scan_index defines the order in which + the enabled channels are placed inside the buffer. Channels with a lower + scan_index will be placed before channels with a higher index. Each + channel needs to have a unique scan_index. + + + Setting scan_index to -1 can be used to indicate that the specific + channel does not support buffered capture. In this case no entries will + be created for the channel in the scan_elements directory. + + + + + Industrial I/O triggers +!Finclude/linux/iio/trigger.h iio_trigger +!Edrivers/iio/industrialio-trigger.c + + In many situations it is useful for a driver to be able to + capture data based on some external event (trigger) as opposed + to periodically polling for data. An IIO trigger can be provided + by a device driver that also has an IIO device based on hardware + generated events (e.g. data ready or threshold exceeded) or + provided by a separate driver from an independent interrupt + source (e.g. GPIO line connected to some external system, timer + interrupt or user space writing a specific file in sysfs). A + trigger may initiate data capture for a number of sensors and + also it may be completely unrelated to the sensor itself. + + + IIO trigger sysfs interface + There are two locations in sysfs related to triggers: + + /sys/bus/iio/devices/triggerY, + this file is created once an IIO trigger is registered with + the IIO core and corresponds to trigger with index Y. Because + triggers can be very different depending on type there are few + standard attributes that we can describe here: + + + name, trigger name that can be later + used for association with a device. + + + sampling_frequency, some timer based + triggers use this attribute to specify the frequency for + trigger calls. + + + + + /sys/bus/iio/devices/iio:deviceX/trigger/, this + directory is created once the device supports a triggered + buffer. We can associate a trigger with our device by writing + the trigger's name in the current_trigger file. + + + + + IIO trigger setup + + + Let's see a simple example of how to setup a trigger to be used + by a driver. + + + struct iio_trigger_ops trigger_ops = { + .set_trigger_state = sample_trigger_state, + .validate_device = sample_validate_device, + } + + struct iio_trigger *trig; + + /* first, allocate memory for our trigger */ + trig = iio_trigger_alloc(dev, "trig-%s-%d", name, idx); + + /* setup trigger operations field */ + trig->ops = &trigger_ops; + + /* now register the trigger with the IIO core */ + iio_trigger_register(trig); + + + + + IIO trigger ops +!Finclude/linux/iio/trigger.h iio_trigger_ops + + Notice that a trigger has a set of operations attached: + + + set_trigger_state, switch the trigger on/off + on demand. + + + validate_device, function to validate the + device when the current trigger gets changed. + + + + + + + Industrial I/O triggered buffers + + Now that we know what buffers and triggers are let's see how they + work together. + + IIO triggered buffer setup +!Edrivers/iio/industrialio-triggered-buffer.c +!Finclude/linux/iio/iio.h iio_buffer_setup_ops + + + + A typical triggered buffer setup looks like this: + + const struct iio_buffer_setup_ops sensor_buffer_setup_ops = { + .preenable = sensor_buffer_preenable, + .postenable = sensor_buffer_postenable, + .postdisable = sensor_buffer_postdisable, + .predisable = sensor_buffer_predisable, + }; + + irqreturn_t sensor_iio_pollfunc(int irq, void *p) + { + pf->timestamp = iio_get_time_ns(); + return IRQ_WAKE_THREAD; + } + + irqreturn_t sensor_trigger_handler(int irq, void *p) + { + u16 buf[8]; + int i = 0; + + /* read data for each active channel */ + for_each_set_bit(bit, active_scan_mask, masklength) + buf[i++] = sensor_get_data(bit) + + iio_push_to_buffers_with_timestamp(indio_dev, buf, timestamp); + + iio_trigger_notify_done(trigger); + return IRQ_HANDLED; + } + + /* setup triggered buffer, usually in probe function */ + iio_triggered_buffer_setup(indio_dev, sensor_iio_polfunc, + sensor_trigger_handler, + sensor_buffer_setup_ops); + + + The important things to notice here are: + + iio_buffer_setup_ops, the buffer setup + functions to be called at predefined points in the buffer configuration + sequence (e.g. before enable, after disable). If not specified, the + IIO core uses the default iio_triggered_buffer_setup_ops. + + sensor_iio_pollfunc, the function that + will be used as top half of poll function. It should do as little + processing as possible, because it runs in interrupt context. The most + common operation is recording of the current timestamp and for this reason + one can use the IIO core defined iio_pollfunc_store_time + function. + + sensor_trigger_handler, the function that + will be used as bottom half of the poll function. This runs in the + context of a kernel thread and all the processing takes place here. + It usually reads data from the device and stores it in the internal + buffer together with the timestamp recorded in the top half. + + + + + + + Resources + IIO core may change during time so the best documentation to read is the + source code. There are several locations where you should look: + + + drivers/iio/, contains the IIO core plus + and directories for each sensor type (e.g. accel, magnetometer, + etc.) + + + include/linux/iio/, contains the header + files, nice to read for the internal kernel interfaces. + + + include/uapi/linux/iio/, contains files to be + used by user space applications. + + + tools/iio/, contains tools for rapidly + testing buffers, events and device creation. + + + drivers/staging/iio/, contains code for some + drivers or experimental features that are not yet mature enough + to be moved out. + + + + Besides the code, there are some good online documentation sources: + + + Industrial I/O mailing + list + + + + Analog Device IIO wiki page + + + + Using the Linux IIO framework for SDR, Lars-Peter Clausen's + presentation at FOSDEM + + + + +
+ + -- cgit v1.2.3 From 655665d67c8465501a46aa8ffde4e6e29201ba99 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Thu, 6 Aug 2015 14:17:53 +0300 Subject: iio: Documentation: Add trigger name attribute ABI documentation This patch adds an entry in ABI Documentation for the name attribute issued when a trigger is created. Signed-off-by: Cristina Opriceana Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs b/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs index 5235e6c749ab..bbb039237a25 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs +++ b/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs @@ -9,3 +9,12 @@ Description: automated testing or in situations, where other trigger methods are not applicable. For example no RTC or spare GPIOs. X is the IIO index of the trigger. + +What: /sys/bus/iio/devices/triggerX/name +KernelVersion: 2.6.39 +Contact: linux-iio@vger.kernel.org +Description: + The name attribute holds a description string for the current + trigger. In order to associate the trigger with an IIO device + one should write this name string to + /sys/bus/iio/devices/iio:deviceY/trigger/current_trigger. -- cgit v1.2.3 From 8e563b0dabcce7cad80af9bb40b220004f411092 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Thu, 6 Aug 2015 14:56:02 +0300 Subject: iio: trigger: Add missing fields in kernel docs Fix kernel docs warnings by adding the missing description for each of the existing function parameters. Signed-off-by: Cristina Opriceana Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-trigger.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index d31098e0c43f..570606c2adbd 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -40,7 +40,14 @@ static DEFINE_MUTEX(iio_trigger_list_lock); /** * iio_trigger_read_name() - retrieve useful identifying name - **/ + * @dev: device associated with the iio_trigger + * @attr: pointer to the device_attribute structure that is + * being processed + * @buf: buffer to print the name into + * + * Return: a negative number on failure or the number of written + * characters on success. + */ static ssize_t iio_trigger_read_name(struct device *dev, struct device_attribute *attr, char *buf) @@ -288,10 +295,17 @@ EXPORT_SYMBOL_GPL(iio_dealloc_pollfunc); /** * iio_trigger_read_current() - trigger consumer sysfs query current trigger + * @dev: device associated with an industrial I/O device + * @attr: pointer to the device_attribute structure that + * is being processed + * @buf: buffer where the current trigger name will be printed into * * For trigger consumers the current_trigger interface allows the trigger * used by the device to be queried. - **/ + * + * Return: a negative number on failure, the number of characters written + * on success or 0 if no trigger is available + */ static ssize_t iio_trigger_read_current(struct device *dev, struct device_attribute *attr, char *buf) @@ -305,11 +319,18 @@ static ssize_t iio_trigger_read_current(struct device *dev, /** * iio_trigger_write_current() - trigger consumer sysfs set current trigger + * @dev: device associated with an industrial I/O device + * @attr: device attribute that is being processed + * @buf: string buffer that holds the name of the trigger + * @len: length of the trigger name held by buf * * For trigger consumers the current_trigger interface allows the trigger * used for this device to be specified at run time based on the trigger's * name. - **/ + * + * Return: negative error code on failure or length of the buffer + * on success + */ static ssize_t iio_trigger_write_current(struct device *dev, struct device_attribute *attr, const char *buf, -- cgit v1.2.3 From 8166537283b31d7abaae9e56bd48fbbc30cdc579 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:13 +0200 Subject: iio: adis16400: Fix adis16448 gyroscope scale Use the correct scale for the adis16448 gyroscope output. Signed-off-by: Lars-Peter Clausen Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index 2fd68f2219a7..d42e4fe2c7ed 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -780,7 +780,7 @@ static struct adis16400_chip_info adis16400_chips[] = { .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SERIAL_NUMBER | ADIS16400_BURST_DIAG_STAT, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */ + .gyro_scale_micro = IIO_DEGREE_TO_RAD(40000), /* 0.04 deg/s */ .accel_scale_micro = IIO_G_TO_M_S_2(833), /* 1/1200 g */ .temp_scale_nano = 73860000, /* 0.07386 C */ .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */ -- cgit v1.2.3 From c689a923c867eac40ed3826c1d9328edea8b6bc7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:14 +0200 Subject: iio: Add inverse unit conversion macros Add inverse unit conversion macro to convert from standard IIO units to units that might be used by some devices. Those are useful in combination with scale factors that are specified as IIO_VAL_FRACTIONAL. Typically the denominator for those specifications will contain the maximum raw value the sensor will generate and the numerator the value it maps to in a specific unit. Sometimes datasheets specify those in different units than the standard IIO units (e.g. degree/s instead of rad/s) and so we need to do a unit conversion. From a mathematical point of view it does not make a difference whether we apply the unit conversion to the numerator or the inverse unit conversion to the denominator since (x / y) / z = x / (y * z). But as the denominator is typically a larger value and we are rounding both the numerator and denominator to integer values using the later method gives us a better precision (E.g. the relative error is smaller if we round 8000.3 to 8000 rather than rounding 8.3 to 8). This is where in inverse unit conversion macros will be used. Marked for stable as used by some upcoming fixes. Signed-off-by: Lars-Peter Clausen Cc: Signed-off-by: Jonathan Cameron --- include/linux/iio/iio.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index f79148261d16..7bb7f673cb3f 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -644,6 +644,15 @@ int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer, */ #define IIO_DEGREE_TO_RAD(deg) (((deg) * 314159ULL + 9000000ULL) / 18000000ULL) +/** + * IIO_RAD_TO_DEGREE() - Convert rad to degree + * @rad: A value in rad + * + * Returns the given value converted from rad to degree + */ +#define IIO_RAD_TO_DEGREE(rad) \ + (((rad) * 18000000ULL + 314159ULL / 2) / 314159ULL) + /** * IIO_G_TO_M_S_2() - Convert g to meter / second**2 * @g: A value in g @@ -652,4 +661,12 @@ int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer, */ #define IIO_G_TO_M_S_2(g) ((g) * 980665ULL / 100000ULL) +/** + * IIO_M_S_2_TO_G() - Convert meter / second**2 to g + * @ms2: A value in meter / second**2 + * + * Returns the given value converted from meter / second**2 to g + */ +#define IIO_M_S_2_TO_G(ms2) (((ms2) * 100000ULL + 980665ULL / 2) / 980665ULL) + #endif /* _INDUSTRIAL_IO_H_ */ -- cgit v1.2.3 From 7abad1063deb0f77d275c61f58863ec319c58c5c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:15 +0200 Subject: iio: adis16480: Fix scale factors The different devices support by the adis16480 driver have slightly different scales for the gyroscope and accelerometer channels. Signed-off-by: Lars-Peter Clausen Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16480.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index 989605dd6f78..b94bfd3f595b 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -110,6 +110,10 @@ struct adis16480_chip_info { unsigned int num_channels; const struct iio_chan_spec *channels; + unsigned int gyro_max_val; + unsigned int gyro_max_scale; + unsigned int accel_max_val; + unsigned int accel_max_scale; }; struct adis16480 { @@ -497,19 +501,21 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, static int adis16480_read_raw(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, int *val, int *val2, long info) { + struct adis16480 *st = iio_priv(indio_dev); + switch (info) { case IIO_CHAN_INFO_RAW: return adis_single_conversion(indio_dev, chan, 0, val); case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL: - *val = 0; - *val2 = IIO_DEGREE_TO_RAD(20000); /* 0.02 degree/sec */ - return IIO_VAL_INT_PLUS_MICRO; + *val = st->chip_info->gyro_max_scale; + *val2 = st->chip_info->gyro_max_val; + return IIO_VAL_FRACTIONAL; case IIO_ACCEL: - *val = 0; - *val2 = IIO_G_TO_M_S_2(800); /* 0.8 mg */ - return IIO_VAL_INT_PLUS_MICRO; + *val = st->chip_info->accel_max_scale; + *val2 = st->chip_info->accel_max_val; + return IIO_VAL_FRACTIONAL; case IIO_MAGN: *val = 0; *val2 = 100; /* 0.0001 gauss */ @@ -674,18 +680,39 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { [ADIS16375] = { .channels = adis16485_channels, .num_channels = ARRAY_SIZE(adis16485_channels), + /* + * storing the value in rad/degree and the scale in degree + * gives us the result in rad and better precession than + * storing the scale directly in rad. + */ + .gyro_max_val = IIO_RAD_TO_DEGREE(22887), + .gyro_max_scale = 300, + .accel_max_val = IIO_M_S_2_TO_G(21973), + .accel_max_scale = 18, }, [ADIS16480] = { .channels = adis16480_channels, .num_channels = ARRAY_SIZE(adis16480_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(22500), + .gyro_max_scale = 450, + .accel_max_val = IIO_M_S_2_TO_G(12500), + .accel_max_scale = 5, }, [ADIS16485] = { .channels = adis16485_channels, .num_channels = ARRAY_SIZE(adis16485_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(22500), + .gyro_max_scale = 450, + .accel_max_val = IIO_M_S_2_TO_G(20000), + .accel_max_scale = 5, }, [ADIS16488] = { .channels = adis16480_channels, .num_channels = ARRAY_SIZE(adis16480_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(22500), + .gyro_max_scale = 450, + .accel_max_val = IIO_M_S_2_TO_G(22500), + .accel_max_scale = 18, }, }; -- cgit v1.2.3 From bd95a89e7a80cb0ee57e9ccd62de0dd80f98a270 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:16 +0200 Subject: iio: adis16400: adis16300 has product ID and serial number The ADIS16300 has the product ID and serial number registers, they are just not documented. Set the appropriate flags so the driver makes use of them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index d42e4fe2c7ed..7d612ab79a87 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -696,7 +696,8 @@ static struct adis16400_chip_info adis16400_chips[] = { [ADIS16300] = { .channels = adis16300_channels, .num_channels = ARRAY_SIZE(adis16300_channels), - .flags = ADIS16400_HAS_SLOW_MODE, + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | + ADIS16400_HAS_SERIAL_NUMBER, .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ .accel_scale_micro = 5884, .temp_scale_nano = 140000000, /* 0.14 C */ -- cgit v1.2.3 From 3c386760790e3d3d5cb3ac2f0e09f3710eab7f99 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:17 +0200 Subject: iio: adis16400: Add ADIS16305 support The ADIS16305 is fully register map compatible to the ADIS16300. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index 7d612ab79a87..e4cc2ecb42e2 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -927,6 +927,7 @@ static int adis16400_remove(struct spi_device *spi) static const struct spi_device_id adis16400_id[] = { {"adis16300", ADIS16300}, + {"adis16305", ADIS16300}, {"adis16334", ADIS16334}, {"adis16350", ADIS16350}, {"adis16354", ADIS16350}, -- cgit v1.2.3 From f1afda124badf1cf4b013722d55934536ff0892c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:18 +0200 Subject: iio: adis16260: Add ADIS16266 support The ADIS16266 is mostly register compatible to the ADIS16260. The difference is a different gyroscope scale factor as well not having the relative angular displacement channel. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/adis16260.c | 137 +++++++++++++++++++++++++++++++------------ 1 file changed, 98 insertions(+), 39 deletions(-) diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c index 75fe0edd3d0f..00c6ad9bf35f 100644 --- a/drivers/iio/gyro/adis16260.c +++ b/drivers/iio/gyro/adis16260.c @@ -101,19 +101,24 @@ #define ADIS16260_SCAN_TEMP 3 #define ADIS16260_SCAN_ANGL 4 -/* Power down the device */ -static int adis16260_stop_device(struct iio_dev *indio_dev) -{ - struct adis *adis = iio_priv(indio_dev); - int ret; - u16 val = ADIS16260_SLP_CNT_POWER_OFF; +struct adis16260_chip_info { + unsigned int gyro_max_val; + unsigned int gyro_max_scale; + const struct iio_chan_spec *channels; + unsigned int num_channels; +}; - ret = adis_write_reg_16(adis, ADIS16260_SLP_CNT, val); - if (ret) - dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT"); +struct adis16260 { + const struct adis16260_chip_info *info; - return ret; -} + struct adis adis; +}; + +enum adis16260_type { + ADIS16251, + ADIS16260, + ADIS16266, +}; static const struct iio_chan_spec adis16260_channels[] = { ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO, @@ -131,6 +136,55 @@ static const struct iio_chan_spec adis16260_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(5), }; +static const struct iio_chan_spec adis16266_channels[] = { + ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO, + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + BIT(IIO_CHAN_INFO_SAMP_FREQ), 14), + ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP, + BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), + ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY, + BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), + ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC, + BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +static const struct adis16260_chip_info adis16260_chip_info_table[] = { + [ADIS16251] = { + .gyro_max_scale = 80, + .gyro_max_val = IIO_RAD_TO_DEGREE(4368), + .channels = adis16260_channels, + .num_channels = ARRAY_SIZE(adis16260_channels), + }, + [ADIS16260] = { + .gyro_max_scale = 320, + .gyro_max_val = IIO_RAD_TO_DEGREE(4368), + .channels = adis16260_channels, + .num_channels = ARRAY_SIZE(adis16260_channels), + }, + [ADIS16266] = { + .gyro_max_scale = 14000, + .gyro_max_val = IIO_RAD_TO_DEGREE(3357), + .channels = adis16266_channels, + .num_channels = ARRAY_SIZE(adis16266_channels), + }, +}; + +/* Power down the device */ +static int adis16260_stop_device(struct iio_dev *indio_dev) +{ + struct adis16260 *adis16260 = iio_priv(indio_dev); + int ret; + u16 val = ADIS16260_SLP_CNT_POWER_OFF; + + ret = adis_write_reg_16(&adis16260->adis, ADIS16260_SLP_CNT, val); + if (ret) + dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT"); + + return ret; +} + static const u8 adis16260_addresses[][2] = { [ADIS16260_SCAN_GYRO] = { ADIS16260_GYRO_OFF, ADIS16260_GYRO_SCALE }, }; @@ -140,7 +194,9 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { - struct adis *adis = iio_priv(indio_dev); + struct adis16260 *adis16260 = iio_priv(indio_dev); + const struct adis16260_chip_info *info = adis16260->info; + struct adis *adis = &adis16260->adis; int ret; u8 addr; s16 val16; @@ -152,15 +208,9 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL: - *val = 0; - if (spi_get_device_id(adis->spi)->driver_data) { - /* 0.01832 degree / sec */ - *val2 = IIO_DEGREE_TO_RAD(18320); - } else { - /* 0.07326 degree / sec */ - *val2 = IIO_DEGREE_TO_RAD(73260); - } - return IIO_VAL_INT_PLUS_MICRO; + *val = info->gyro_max_scale; + *val2 = info->gyro_max_val; + return IIO_VAL_FRACTIONAL; case IIO_INCLI: *val = 0; *val2 = IIO_DEGREE_TO_RAD(36630); @@ -224,7 +274,8 @@ static int adis16260_write_raw(struct iio_dev *indio_dev, int val2, long mask) { - struct adis *adis = iio_priv(indio_dev); + struct adis16260 *adis16260 = iio_priv(indio_dev); + struct adis *adis = &adis16260->adis; int ret; u8 addr; u8 t; @@ -305,35 +356,42 @@ static const struct adis_data adis16260_data = { static int adis16260_probe(struct spi_device *spi) { + const struct spi_device_id *id; + struct adis16260 *adis16260; struct iio_dev *indio_dev; - struct adis *adis; int ret; + id = spi_get_device_id(spi); + if (!id) + return -ENODEV; + /* setup the industrialio driver allocated elements */ - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16260)); if (!indio_dev) return -ENOMEM; - adis = iio_priv(indio_dev); + adis16260 = iio_priv(indio_dev); /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); - indio_dev->name = spi_get_device_id(spi)->name; + adis16260->info = &adis16260_chip_info_table[id->driver_data]; + + indio_dev->name = id->name; indio_dev->dev.parent = &spi->dev; indio_dev->info = &adis16260_info; - indio_dev->channels = adis16260_channels; - indio_dev->num_channels = ARRAY_SIZE(adis16260_channels); + indio_dev->channels = adis16260->info->channels; + indio_dev->num_channels = adis16260->info->num_channels; indio_dev->modes = INDIO_DIRECT_MODE; - ret = adis_init(adis, indio_dev, spi, &adis16260_data); + ret = adis_init(&adis16260->adis, indio_dev, spi, &adis16260_data); if (ret) return ret; - ret = adis_setup_buffer_and_trigger(adis, indio_dev, NULL); + ret = adis_setup_buffer_and_trigger(&adis16260->adis, indio_dev, NULL); if (ret) return ret; /* Get the device into a sane initial state */ - ret = adis_initial_startup(adis); + ret = adis_initial_startup(&adis16260->adis); if (ret) goto error_cleanup_buffer_trigger; ret = iio_device_register(indio_dev); @@ -343,18 +401,18 @@ static int adis16260_probe(struct spi_device *spi) return 0; error_cleanup_buffer_trigger: - adis_cleanup_buffer_and_trigger(adis, indio_dev); + adis_cleanup_buffer_and_trigger(&adis16260->adis, indio_dev); return ret; } static int adis16260_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct adis *adis = iio_priv(indio_dev); + struct adis16260 *adis16260 = iio_priv(indio_dev); iio_device_unregister(indio_dev); adis16260_stop_device(indio_dev); - adis_cleanup_buffer_and_trigger(adis, indio_dev); + adis_cleanup_buffer_and_trigger(&adis16260->adis, indio_dev); return 0; } @@ -364,11 +422,12 @@ static int adis16260_remove(struct spi_device *spi) * support for the on chip filtering. */ static const struct spi_device_id adis16260_id[] = { - {"adis16260", 0}, - {"adis16265", 0}, - {"adis16250", 0}, - {"adis16255", 0}, - {"adis16251", 1}, + {"adis16260", ADIS16260}, + {"adis16265", ADIS16260}, + {"adis16266", ADIS16266}, + {"adis16250", ADIS16260}, + {"adis16255", ADIS16260}, + {"adis16251", ADIS16251}, {} }; MODULE_DEVICE_TABLE(spi, adis16260_id); -- cgit v1.2.3 From dc8615ce34cf72955f098750eef81a5501c107d1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:19 +0200 Subject: iio: adis16400: Add ADIS16367 support The ADIS16367 is mostly register compatible to the ADIS16360. The only difference is the scale factor for the gyroscope output. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400_core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index e4cc2ecb42e2..a9f4043b409f 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -139,6 +139,7 @@ enum adis16400_chip_variant { ADIS16360, ADIS16362, ADIS16364, + ADIS16367, ADIS16400, ADIS16448, }; @@ -764,6 +765,18 @@ static struct adis16400_chip_info adis16400_chips[] = { .set_freq = adis16400_set_freq, .get_freq = adis16400_get_freq, }, + [ADIS16367] = { + .channels = adis16350_channels, + .num_channels = ARRAY_SIZE(adis16350_channels), + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | + ADIS16400_HAS_SERIAL_NUMBER, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(2000), /* 0.2 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ + .temp_scale_nano = 136000000, /* 0.136 C */ + .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ + .set_freq = adis16400_set_freq, + .get_freq = adis16400_get_freq, + }, [ADIS16400] = { .channels = adis16400_channels, .num_channels = ARRAY_SIZE(adis16400_channels), @@ -936,6 +949,7 @@ static const struct spi_device_id adis16400_id[] = { {"adis16362", ADIS16362}, {"adis16364", ADIS16364}, {"adis16365", ADIS16360}, + {"adis16367", ADIS16367}, {"adis16400", ADIS16400}, {"adis16405", ADIS16400}, {"adis16448", ADIS16448}, -- cgit v1.2.3 From 72d9c9869df3149316af6cd70585eee15f643f40 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:20 +0200 Subject: iio: adis16400: Add ADIS16445 support The ADIS16445 is similar to the ADIS16448, but without the magnetometer and pressure channels as well as different scale factors for the gyroscope and accelerometer outputs. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400_core.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index a9f4043b409f..abc4c50de9e8 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -141,6 +141,7 @@ enum adis16400_chip_variant { ADIS16364, ADIS16367, ADIS16400, + ADIS16445, ADIS16448, }; @@ -623,6 +624,17 @@ static const struct iio_chan_spec adis16400_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), }; +static const struct iio_chan_spec adis16445_channels[] = { + ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16), + ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16), + ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 16), + ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 16), + ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 16), + ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 16), + ADIS16400_TEMP_CHAN(ADIS16448_TEMP_OUT, 12), + IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), +}; + static const struct iio_chan_spec adis16448_channels[] = { ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16), ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16), @@ -788,6 +800,19 @@ static struct adis16400_chip_info adis16400_chips[] = { .set_freq = adis16400_set_freq, .get_freq = adis16400_get_freq, }, + [ADIS16445] = { + .channels = adis16445_channels, + .num_channels = ARRAY_SIZE(adis16445_channels), + .flags = ADIS16400_HAS_PROD_ID | + ADIS16400_HAS_SERIAL_NUMBER | + ADIS16400_BURST_DIAG_STAT, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(250), /* 1/4000 g */ + .temp_scale_nano = 73860000, /* 0.07386 C */ + .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */ + .set_freq = adis16334_set_freq, + .get_freq = adis16334_get_freq, + }, [ADIS16448] = { .channels = adis16448_channels, .num_channels = ARRAY_SIZE(adis16448_channels), @@ -952,6 +977,7 @@ static const struct spi_device_id adis16400_id[] = { {"adis16367", ADIS16367}, {"adis16400", ADIS16400}, {"adis16405", ADIS16400}, + {"adis16445", ADIS16445}, {"adis16448", ADIS16448}, {} }; -- cgit v1.2.3 From 5450c360d4608b70ebd85f4ae2f2ce779a296a93 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:21 +0200 Subject: iio: adis16136: Add ADIS16137 support The ADIS16137 is register map compatible to the ADIS16136, but has a different scale factor for the gyroscope output. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/adis16136.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c index 591bd555e1f3..26de876b223d 100644 --- a/drivers/iio/gyro/adis16136.c +++ b/drivers/iio/gyro/adis16136.c @@ -473,6 +473,7 @@ enum adis16136_id { ID_ADIS16133, ID_ADIS16135, ID_ADIS16136, + ID_ADIS16137, }; static const struct adis16136_chip_info adis16136_chip_info[] = { @@ -488,6 +489,10 @@ static const struct adis16136_chip_info adis16136_chip_info[] = { .precision = IIO_DEGREE_TO_RAD(450), .fullscale = 24623, }, + [ID_ADIS16137] = { + .precision = IIO_DEGREE_TO_RAD(1000), + .fullscale = 24609, + }, }; static int adis16136_probe(struct spi_device *spi) @@ -557,6 +562,7 @@ static const struct spi_device_id adis16136_ids[] = { { "adis16133", ID_ADIS16133 }, { "adis16135", ID_ADIS16135 }, { "adis16136", ID_ADIS16136 }, + { "adis16137", ID_ADIS16137 }, { } }; MODULE_DEVICE_TABLE(spi, adis16136_ids); -- cgit v1.2.3 From ee33ddd2915cca51ce9acb1e5584631b74d92b3c Mon Sep 17 00:00:00 2001 From: Lars Svensson Date: Wed, 5 Aug 2015 14:15:12 +0200 Subject: staging: iio_simple_dummy: Fix indentation errors Fixing indentation errors in drivers/staging/iio/iio_simple_dummy_events.c. Signed-off-by: Lars Svensson Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/staging/iio/iio_simple_dummy_events.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/iio/iio_simple_dummy_events.c b/drivers/staging/iio/iio_simple_dummy_events.c index ecc563cb6cb9..73108baf80ad 100644 --- a/drivers/staging/iio/iio_simple_dummy_events.c +++ b/drivers/staging/iio/iio_simple_dummy_events.c @@ -120,7 +120,7 @@ int iio_simple_dummy_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, - enum iio_event_info info, + enum iio_event_info info, int *val, int *val2) { struct iio_dummy_state *st = iio_priv(indio_dev); @@ -143,7 +143,7 @@ int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, - enum iio_event_info info, + enum iio_event_info info, int val, int val2) { struct iio_dummy_state *st = iio_priv(indio_dev); -- cgit v1.2.3 From c4eaab798bd459f0c3f8917e74abf1851f3e1cb5 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 23 Jul 2015 17:20:59 +0200 Subject: iio:accel:bmc150-accel: Move bmc150_accel_chip_init() Move bmc150_accel_chip_init() so that we can use bmc150_accel_chip_info_tbl[] in it. Signed-off-by: Bastien Nocera Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 114 +++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index 21b665fc0739..5be65e2cb244 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -345,63 +345,6 @@ static int bmc150_accel_any_motion_setup(struct bmc150_accel_trigger *t, return 0; } -static int bmc150_accel_chip_init(struct bmc150_accel_data *data) -{ - int ret; - - ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID); - if (ret < 0) { - dev_err(&data->client->dev, "Error: Reading chip id\n"); - return ret; - } - - dev_dbg(&data->client->dev, "Chip Id %x\n", ret); - if (ret != data->chip_info->chip_id) { - dev_err(&data->client->dev, "Invalid chip %x\n", ret); - return -ENODEV; - } - - ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); - if (ret < 0) - return ret; - - /* Set Bandwidth */ - ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0); - if (ret < 0) - return ret; - - /* Set Default Range */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_PMU_RANGE, - BMC150_ACCEL_DEF_RANGE_4G); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_pmu_range\n"); - return ret; - } - - data->range = BMC150_ACCEL_DEF_RANGE_4G; - - /* Set default slope duration and thresholds */ - data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD; - data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION; - ret = bmc150_accel_update_slope(data); - if (ret < 0) - return ret; - - /* Set default as latched interrupts */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_RST_LATCH, - BMC150_ACCEL_INT_MODE_LATCH_INT | - BMC150_ACCEL_INT_MODE_LATCH_RESET); - if (ret < 0) { - dev_err(&data->client->dev, - "Error writing reg_int_rst_latch\n"); - return ret; - } - - return 0; -} - static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val, int *val2) { @@ -1618,6 +1561,63 @@ static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = { .postdisable = bmc150_accel_buffer_postdisable, }; +static int bmc150_accel_chip_init(struct bmc150_accel_data *data) +{ + int ret; + + ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID); + if (ret < 0) { + dev_err(&data->client->dev, "Error: Reading chip id\n"); + return ret; + } + + dev_dbg(&data->client->dev, "Chip Id %x\n", ret); + if (ret != data->chip_info->chip_id) { + dev_err(&data->client->dev, "Invalid chip %x\n", ret); + return -ENODEV; + } + + ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); + if (ret < 0) + return ret; + + /* Set Bandwidth */ + ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0); + if (ret < 0) + return ret; + + /* Set Default Range */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_PMU_RANGE, + BMC150_ACCEL_DEF_RANGE_4G); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_pmu_range\n"); + return ret; + } + + data->range = BMC150_ACCEL_DEF_RANGE_4G; + + /* Set default slope duration and thresholds */ + data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD; + data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION; + ret = bmc150_accel_update_slope(data); + if (ret < 0) + return ret; + + /* Set default as latched interrupts */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_int_rst_latch\n"); + return ret; + } + + return 0; +} + static int bmc150_accel_probe(struct i2c_client *client, const struct i2c_device_id *id) { -- cgit v1.2.3 From 0ad4bf37017621e25fe157fa095fd8849779a873 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 23 Jul 2015 17:21:07 +0200 Subject: iio:accel:bmc150-accel: Use the chip ID to detect sensor variant Instead of using the I2C or ACPI ID to determine which variant of the chipset to use, determine that from the chip ID. Under Windows, the same driver is used for those variants and, despite incorrect ACPI data, it is able to load and operate the accelerometer. Fixes the accelerometer failing with: bmc150_accel i2c-BMA250E:00: Invalid chip f8 on the WinBook TW100 Signed-off-by: Bastien Nocera Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 46 +++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index 5be65e2cb244..a7b66edf2a38 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -151,6 +151,7 @@ struct bmc150_scale_info { }; struct bmc150_accel_chip_info { + const char *name; u8 chip_id; const struct iio_chan_spec *channels; int num_channels; @@ -1062,6 +1063,7 @@ enum { static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { [bmc150] = { + .name = "BMC150A", .chip_id = 0xFA, .channels = bmc150_accel_channels, .num_channels = ARRAY_SIZE(bmc150_accel_channels), @@ -1071,6 +1073,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { {76590, BMC150_ACCEL_DEF_RANGE_16G} }, }, [bmi055] = { + .name = "BMI055A", .chip_id = 0xFA, .channels = bmc150_accel_channels, .num_channels = ARRAY_SIZE(bmc150_accel_channels), @@ -1080,6 +1083,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { {76590, BMC150_ACCEL_DEF_RANGE_16G} }, }, [bma255] = { + .name = "BMA0255", .chip_id = 0xFA, .channels = bmc150_accel_channels, .num_channels = ARRAY_SIZE(bmc150_accel_channels), @@ -1089,6 +1093,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { {76590, BMC150_ACCEL_DEF_RANGE_16G} }, }, [bma250e] = { + .name = "BMA250E", .chip_id = 0xF9, .channels = bma250e_accel_channels, .num_channels = ARRAY_SIZE(bma250e_accel_channels), @@ -1098,6 +1103,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { {306457, BMC150_ACCEL_DEF_RANGE_16G} }, }, [bma222e] = { + .name = "BMA222E", .chip_id = 0xF8, .channels = bma222e_accel_channels, .num_channels = ARRAY_SIZE(bma222e_accel_channels), @@ -1107,6 +1113,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { {1225831, BMC150_ACCEL_DEF_RANGE_16G} }, }, [bma280] = { + .name = "BMA0280", .chip_id = 0xFB, .channels = bma280_accel_channels, .num_channels = ARRAY_SIZE(bma280_accel_channels), @@ -1353,20 +1360,6 @@ static irqreturn_t bmc150_accel_irq_handler(int irq, void *private) return IRQ_NONE; } -static const char *bmc150_accel_match_acpi_device(struct device *dev, int *data) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - - if (!id) - return NULL; - - *data = (int)id->driver_data; - - return dev_name(dev); -} - static int bmc150_accel_gpio_probe(struct i2c_client *client, struct bmc150_accel_data *data) { @@ -1563,7 +1556,7 @@ static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = { static int bmc150_accel_chip_init(struct bmc150_accel_data *data) { - int ret; + int ret, i; ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID); if (ret < 0) { @@ -1572,8 +1565,15 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) } dev_dbg(&data->client->dev, "Chip Id %x\n", ret); - if (ret != data->chip_info->chip_id) { - dev_err(&data->client->dev, "Invalid chip %x\n", ret); + for (i = 0; i < ARRAY_SIZE(bmc150_accel_chip_info_tbl); i++) { + if (bmc150_accel_chip_info_tbl[i].chip_id == ret) { + data->chip_info = &bmc150_accel_chip_info_tbl[i]; + break; + } + } + + if (!data->chip_info) { + dev_err(&data->client->dev, "Unsupported chip %x\n", ret); return -ENODEV; } @@ -1625,7 +1625,6 @@ static int bmc150_accel_probe(struct i2c_client *client, struct iio_dev *indio_dev; int ret; const char *name = NULL; - int chip_id = 0; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -1635,15 +1634,8 @@ static int bmc150_accel_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); data->client = client; - if (id) { + if (id) name = id->name; - chip_id = id->driver_data; - } - - if (ACPI_HANDLE(&client->dev)) - name = bmc150_accel_match_acpi_device(&client->dev, &chip_id); - - data->chip_info = &bmc150_accel_chip_info_tbl[chip_id]; ret = bmc150_accel_chip_init(data); if (ret < 0) @@ -1654,7 +1646,7 @@ static int bmc150_accel_probe(struct i2c_client *client, indio_dev->dev.parent = &client->dev; indio_dev->channels = data->chip_info->channels; indio_dev->num_channels = data->chip_info->num_channels; - indio_dev->name = name; + indio_dev->name = name ? name : data->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &bmc150_accel_info; -- cgit v1.2.3 From 001fceb9c64a39aebb85d31134182d39c1628a21 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sun, 2 Aug 2015 22:43:46 +0200 Subject: iio:accel:mma8452: fix _get_hp_filter_index To iterate through the available frequencies of mma8452_hp_filter_cutoff[], the array size of a row of that table needs to be provided to _get_int_plus_micros_index(). Fixes: 1e79841a00e46 ("iio: mma8452: Add highpass filter configuration.") Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 3c4ad1563ca4..d78d4a97d753 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -229,7 +229,7 @@ static int mma8452_get_hp_filter_index(struct mma8452_data *data, int i = mma8452_get_odr_index(data); return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[i], - ARRAY_SIZE(mma8452_scales[0]), val, val2); + ARRAY_SIZE(mma8452_hp_filter_cutoff[0]), val, val2); } static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz) -- cgit v1.2.3 From 8337455296385b45822dc46c2b25db4c361d734c Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sun, 2 Aug 2015 22:43:47 +0200 Subject: iio:accel:mma8452: drop double include One inclusion of linux/iio/trigger_consumer.h is sufficient. Fixes: ae6d9ce05691b ("iio: mma8452: Add support for interrupt driven triggers.") Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index d78d4a97d753..d87799fe7161 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From b9fddcdb44c2e274193b119dd6c3af3a9324640a Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sun, 2 Aug 2015 22:43:48 +0200 Subject: iio:accel:mma8452: pass up real error code Pass up the error code provided by functions. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index d87799fe7161..9607f830a13b 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -343,7 +343,7 @@ static int mma8452_set_hp_filter_frequency(struct mma8452_data *data, i = mma8452_get_hp_filter_index(data, val, val2); if (i < 0) - return -EINVAL; + return i; reg = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF); @@ -369,7 +369,7 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SAMP_FREQ: i = mma8452_get_samp_freq_index(data, val, val2); if (i < 0) - return -EINVAL; + return i; data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK; data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT; @@ -378,7 +378,7 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: i = mma8452_get_scale_index(data, val, val2); if (i < 0) - return -EINVAL; + return i; data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK; data->data_cfg |= i; return mma8452_change_config(data, MMA8452_DATA_CFG, -- cgit v1.2.3 From 11218226184b6b2be5cde4bf16f647dda225d4f3 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sun, 2 Aug 2015 22:43:49 +0200 Subject: iio:accel:mma8452: check values to be written Check values to be written to the device for valid lower and upper bounds. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 9607f830a13b..42640b1df870 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -471,15 +471,17 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev, switch (info) { case IIO_EV_INFO_VALUE: - return mma8452_change_config(data, MMA8452_TRANSIENT_THS, - val & MMA8452_TRANSIENT_THS_MASK); + if (val < 0 || val > MMA8452_TRANSIENT_THS_MASK) + return -EINVAL; + + return mma8452_change_config(data, MMA8452_TRANSIENT_THS, val); case IIO_EV_INFO_PERIOD: steps = (val * USEC_PER_SEC + val2) / mma8452_transient_time_step_us[ mma8452_get_odr_index(data)]; - if (steps > 0xff) + if (steps < 0 || steps > 0xff) return -EINVAL; return mma8452_change_config(data, MMA8452_TRANSIENT_COUNT, -- cgit v1.2.3 From 69abff81d7fa59a0dfca5c72a7f1006f17a06d11 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sun, 2 Aug 2015 22:43:50 +0200 Subject: iio:accel:mma8452: rework register definitions Rework register definitions to be sorted by register and bit number, with bit definitions cascaded under the appropriate register, use GENMASK for consecutive bitmasks and realign properly. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 93 ++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 48 deletions(-) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 42640b1df870..2d5ee4607081 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -23,54 +23,51 @@ #include #include -#define MMA8452_STATUS 0x00 -#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */ -#define MMA8452_OUT_Y 0x03 -#define MMA8452_OUT_Z 0x05 -#define MMA8452_INT_SRC 0x0c -#define MMA8452_WHO_AM_I 0x0d -#define MMA8452_DATA_CFG 0x0e -#define MMA8452_HP_FILTER_CUTOFF 0x0f -#define MMA8452_HP_FILTER_CUTOFF_SEL_MASK (BIT(0) | BIT(1)) -#define MMA8452_TRANSIENT_CFG 0x1d -#define MMA8452_TRANSIENT_CFG_ELE BIT(4) -#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1) -#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0) -#define MMA8452_TRANSIENT_SRC 0x1e -#define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1) -#define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3) -#define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5) -#define MMA8452_TRANSIENT_THS 0x1f -#define MMA8452_TRANSIENT_THS_MASK 0x7f -#define MMA8452_TRANSIENT_COUNT 0x20 -#define MMA8452_OFF_X 0x2f -#define MMA8452_OFF_Y 0x30 -#define MMA8452_OFF_Z 0x31 -#define MMA8452_CTRL_REG1 0x2a -#define MMA8452_CTRL_REG2 0x2b -#define MMA8452_CTRL_REG2_RST BIT(6) -#define MMA8452_CTRL_REG4 0x2d -#define MMA8452_CTRL_REG5 0x2e - -#define MMA8452_MAX_REG 0x31 - -#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) - -#define MMA8452_CTRL_DR_MASK (BIT(5) | BIT(4) | BIT(3)) -#define MMA8452_CTRL_DR_SHIFT 3 -#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */ -#define MMA8452_CTRL_ACTIVE BIT(0) - -#define MMA8452_DATA_CFG_FS_MASK (BIT(1) | BIT(0)) -#define MMA8452_DATA_CFG_FS_2G 0 -#define MMA8452_DATA_CFG_FS_4G 1 -#define MMA8452_DATA_CFG_FS_8G 2 -#define MMA8452_DATA_CFG_HPF_MASK BIT(4) - -#define MMA8452_INT_DRDY BIT(0) -#define MMA8452_INT_TRANS BIT(5) - -#define MMA8452_DEVICE_ID 0x2a +#define MMA8452_STATUS 0x00 +#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) +#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */ +#define MMA8452_OUT_Y 0x03 +#define MMA8452_OUT_Z 0x05 +#define MMA8452_INT_SRC 0x0c +#define MMA8452_WHO_AM_I 0x0d +#define MMA8452_DATA_CFG 0x0e +#define MMA8452_DATA_CFG_FS_MASK GENMASK(1, 0) +#define MMA8452_DATA_CFG_FS_2G 0 +#define MMA8452_DATA_CFG_FS_4G 1 +#define MMA8452_DATA_CFG_FS_8G 2 +#define MMA8452_DATA_CFG_HPF_MASK BIT(4) +#define MMA8452_HP_FILTER_CUTOFF 0x0f +#define MMA8452_HP_FILTER_CUTOFF_SEL_MASK GENMASK(1, 0) +#define MMA8452_TRANSIENT_CFG 0x1d +#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0) +#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1) +#define MMA8452_TRANSIENT_CFG_ELE BIT(4) +#define MMA8452_TRANSIENT_SRC 0x1e +#define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1) +#define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3) +#define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5) +#define MMA8452_TRANSIENT_THS 0x1f +#define MMA8452_TRANSIENT_THS_MASK GENMASK(6, 0) +#define MMA8452_TRANSIENT_COUNT 0x20 +#define MMA8452_CTRL_REG1 0x2a +#define MMA8452_CTRL_ACTIVE BIT(0) +#define MMA8452_CTRL_DR_MASK GENMASK(5, 3) +#define MMA8452_CTRL_DR_SHIFT 3 +#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */ +#define MMA8452_CTRL_REG2 0x2b +#define MMA8452_CTRL_REG2_RST BIT(6) +#define MMA8452_CTRL_REG4 0x2d +#define MMA8452_CTRL_REG5 0x2e +#define MMA8452_OFF_X 0x2f +#define MMA8452_OFF_Y 0x30 +#define MMA8452_OFF_Z 0x31 + +#define MMA8452_MAX_REG 0x31 + +#define MMA8452_INT_DRDY BIT(0) +#define MMA8452_INT_TRANS BIT(5) + +#define MMA8452_DEVICE_ID 0x2a struct mma8452_data { struct i2c_client *client; -- cgit v1.2.3 From 686027fbc602e715aae2d1b7987daefc2ff82a8a Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sun, 2 Aug 2015 22:43:51 +0200 Subject: iio:accel:mma8452: coding style cleanup Some coding style cleanups, mainly indicated by checkpatch.pl, which includes indentation changes, drop spaces after casts and befor tabs. Also insert empty lines after logical blocks and before unconditional returns. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 106 ++++++++++++++++++++++++++++---------------- 1 file changed, 68 insertions(+), 38 deletions(-) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 2d5ee4607081..85283eab2ea7 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -87,30 +87,34 @@ static int mma8452_drdy(struct mma8452_data *data) return ret; if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY) return 0; + msleep(20); } dev_err(&data->client->dev, "data not ready\n"); + return -EIO; } static int mma8452_read(struct mma8452_data *data, __be16 buf[3]) { int ret = mma8452_drdy(data); + if (ret < 0) return ret; - return i2c_smbus_read_i2c_block_data(data->client, - MMA8452_OUT_X, 3 * sizeof(__be16), (u8 *) buf); + + return i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X, + 3 * sizeof(__be16), (u8 *)buf); } -static ssize_t mma8452_show_int_plus_micros(char *buf, - const int (*vals)[2], int n) +static ssize_t mma8452_show_int_plus_micros(char *buf, const int (*vals)[2], + int n) { size_t len = 0; while (n-- > 0) - len += scnprintf(buf + len, PAGE_SIZE - len, - "%d.%06d ", vals[n][0], vals[n][1]); + len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ", + vals[n][0], vals[n][1]); /* replace trailing space by newline */ buf[len - 1] = '\n'; @@ -119,7 +123,7 @@ static ssize_t mma8452_show_int_plus_micros(char *buf, } static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n, - int val, int val2) + int val, int val2) { while (n-- > 0) if (val == vals[n][0] && val2 == vals[n][1]) @@ -143,7 +147,7 @@ static const int mma8452_samp_freq[8][2] = { * Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048 * The userspace interface uses m/s^2 and we declare micro units * So scale factor is given by: - * g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665 + * g * N * 1000000 / 2048 for N = 2, 4, 8 and g = 9.80665 */ static const int mma8452_scales[3][2] = { {0, 9577}, {0, 19154}, {0, 38307} @@ -174,17 +178,19 @@ static const int mma8452_hp_filter_cutoff[8][4][2] = { }; static ssize_t mma8452_show_samp_freq_avail(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { return mma8452_show_int_plus_micros(buf, mma8452_samp_freq, - ARRAY_SIZE(mma8452_samp_freq)); + ARRAY_SIZE(mma8452_samp_freq)); } static ssize_t mma8452_show_scale_avail(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { return mma8452_show_int_plus_micros(buf, mma8452_scales, - ARRAY_SIZE(mma8452_scales)); + ARRAY_SIZE(mma8452_scales)); } static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev, @@ -201,22 +207,23 @@ static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev, static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail); static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO, - mma8452_show_scale_avail, NULL, 0); + mma8452_show_scale_avail, NULL, 0); static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available, - S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0); + S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0); static int mma8452_get_samp_freq_index(struct mma8452_data *data, - int val, int val2) + int val, int val2) { return mma8452_get_int_plus_micros_index(mma8452_samp_freq, - ARRAY_SIZE(mma8452_samp_freq), val, val2); + ARRAY_SIZE(mma8452_samp_freq), + val, val2); } -static int mma8452_get_scale_index(struct mma8452_data *data, - int val, int val2) +static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2) { return mma8452_get_int_plus_micros_index(mma8452_scales, - ARRAY_SIZE(mma8452_scales), val, val2); + ARRAY_SIZE(mma8452_scales), + val, val2); } static int mma8452_get_hp_filter_index(struct mma8452_data *data, @@ -262,25 +269,31 @@ static int mma8452_read_raw(struct iio_dev *indio_dev, mutex_unlock(&data->lock); if (ret < 0) return ret; - *val = sign_extend32( - be16_to_cpu(buffer[chan->scan_index]) >> 4, 11); + + *val = sign_extend32(be16_to_cpu(buffer[chan->scan_index]) >> 4, + 11); + return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK; *val = mma8452_scales[i][0]; *val2 = mma8452_scales[i][1]; + return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ: i = mma8452_get_odr_index(data); *val = mma8452_samp_freq[i][0]; *val2 = mma8452_samp_freq[i][1]; + return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_CALIBBIAS: - ret = i2c_smbus_read_byte_data(data->client, MMA8452_OFF_X + - chan->scan_index); + ret = i2c_smbus_read_byte_data(data->client, + MMA8452_OFF_X + chan->scan_index); if (ret < 0) return ret; + *val = sign_extend32(ret, 7); + return IIO_VAL_INT; case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: if (data->data_cfg & MMA8452_DATA_CFG_HPF_MASK) { @@ -291,21 +304,23 @@ static int mma8452_read_raw(struct iio_dev *indio_dev, *val = 0; *val2 = 0; } + return IIO_VAL_INT_PLUS_MICRO; } + return -EINVAL; } static int mma8452_standby(struct mma8452_data *data) { return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, - data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE); + data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE); } static int mma8452_active(struct mma8452_data *data) { return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, - data->ctrl_reg1); + data->ctrl_reg1); } static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val) @@ -330,6 +345,7 @@ static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val) ret = 0; fail: mutex_unlock(&data->lock); + return ret; } @@ -346,6 +362,7 @@ static int mma8452_set_hp_filter_frequency(struct mma8452_data *data, MMA8452_HP_FILTER_CUTOFF); if (reg < 0) return reg; + reg &= ~MMA8452_HP_FILTER_CUTOFF_SEL_MASK; reg |= i; @@ -370,21 +387,26 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK; data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT; + return mma8452_change_config(data, MMA8452_CTRL_REG1, - data->ctrl_reg1); + data->ctrl_reg1); case IIO_CHAN_INFO_SCALE: i = mma8452_get_scale_index(data, val, val2); if (i < 0) return i; + data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK; data->data_cfg |= i; + return mma8452_change_config(data, MMA8452_DATA_CFG, - data->data_cfg); + data->data_cfg); case IIO_CHAN_INFO_CALIBBIAS: if (val < -128 || val > 127) return -EINVAL; - return mma8452_change_config(data, MMA8452_OFF_X + - chan->scan_index, val); + + return mma8452_change_config(data, + MMA8452_OFF_X + chan->scan_index, + val); case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: if (val == 0 && val2 == 0) { @@ -395,8 +417,9 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; } + return mma8452_change_config(data, MMA8452_DATA_CFG, - data->data_cfg); + data->data_cfg); default: return -EINVAL; @@ -421,6 +444,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev, return ret; *val = ret & MMA8452_TRANSIENT_THS_MASK; + return IIO_VAL_INT; case IIO_EV_INFO_PERIOD: @@ -433,6 +457,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev, mma8452_get_odr_index(data)]; *val = us / USEC_PER_SEC; *val2 = us % USEC_PER_SEC; + return IIO_VAL_INT_PLUS_MICRO; case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: @@ -449,6 +474,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev, if (ret < 0) return ret; } + return IIO_VAL_INT_PLUS_MICRO; default: @@ -483,6 +509,7 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev, return mma8452_change_config(data, MMA8452_TRANSIENT_COUNT, steps); + case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: reg = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG); @@ -497,6 +524,7 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev, if (ret < 0) return ret; } + return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, reg); default: @@ -606,15 +634,16 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p) u8 buffer[16]; /* 3 16-bit channels + padding + ts */ int ret; - ret = mma8452_read(data, (__be16 *) buffer); + ret = mma8452_read(data, (__be16 *)buffer); if (ret < 0) goto done; iio_push_to_buffers_with_timestamp(indio_dev, buffer, - iio_get_time_ns()); + iio_get_time_ns()); done: iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; } @@ -672,10 +701,10 @@ static struct attribute_group mma8452_event_attribute_group = { .modified = 1, \ .channel2 = IIO_MOD_##axis, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_CALIBBIAS), \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ - BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ .scan_index = idx, \ .scan_type = { \ .sign = 's', \ @@ -778,6 +807,7 @@ static int mma8452_trigger_setup(struct iio_dev *indio_dev) return ret; indio_dev->trig = trig; + return 0; } @@ -847,7 +877,7 @@ static int mma8452_probe(struct i2c_client *client, data->data_cfg = MMA8452_DATA_CFG_FS_2G; ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG, - data->data_cfg); + data->data_cfg); if (ret < 0) return ret; @@ -889,14 +919,14 @@ static int mma8452_probe(struct i2c_client *client, } data->ctrl_reg1 = MMA8452_CTRL_ACTIVE | - (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT); + (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT); ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1, data->ctrl_reg1); if (ret < 0) goto trigger_cleanup; ret = iio_triggered_buffer_setup(indio_dev, NULL, - mma8452_trigger_handler, NULL); + mma8452_trigger_handler, NULL); if (ret < 0) goto trigger_cleanup; -- cgit v1.2.3 From 8838cc7f3c584d6aaf56c66577f8a2bfb21081ec Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sun, 2 Aug 2015 22:43:52 +0200 Subject: iio:accel:mma8452: reorder Kconfig entry Move the entry in Kconfig to its alphabetically correct position. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index c99d8e242218..a59047d7657e 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -86,18 +86,6 @@ config KXSD9 To compile this driver as a module, choose M here: the module will be called kxsd9. -config MMA8452 - tristate "Freescale MMA8452Q Accelerometer Driver" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for the Freescale MMA8452Q 3-axis - accelerometer. - - To compile this driver as a module, choose M here: the module - will be called mma8452. - config KXCJK1013 tristate "Kionix 3-Axis Accelerometer Driver" depends on I2C @@ -111,6 +99,18 @@ config KXCJK1013 To compile this driver as a module, choose M here: the module will be called kxcjk-1013. +config MMA8452 + tristate "Freescale MMA8452Q Accelerometer Driver" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for the Freescale MMA8452Q 3-axis + accelerometer. + + To compile this driver as a module, choose M here: the module + will be called mma8452. + config MMA9551_CORE tristate -- cgit v1.2.3 From bdb25b0af8bd225ddf82083d767fada56fb2c1ae Mon Sep 17 00:00:00 2001 From: Vladimir Barinov Date: Wed, 29 Jul 2015 15:57:41 +0300 Subject: iio: Fix typos in ABI documentation Fix typos in ABI documentation Signed-off-by: Vladimir Barinov Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 400d23441a61..abe228dc0dac 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -493,7 +493,7 @@ Contact: linux-iio@vger.kernel.org Description: Specifies the output powerdown mode. DAC output stage is disconnected from the amplifier and - 1kohm_to_gnd: connected to ground via an 1kOhm resistor, + 1kohm_to_gnd: connected to ground via an 1kOhm resistor, 6kohm_to_gnd: connected to ground via a 6kOhm resistor, 20kohm_to_gnd: connected to ground via a 20kOhm resistor, 100kohm_to_gnd: connected to ground via an 100kOhm resistor, @@ -503,9 +503,9 @@ Description: outX_powerdown_mode_available. If Y is not present the mode is shared across all outputs. -What: /sys/.../iio:deviceX/out_votlageY_powerdown_mode_available +What: /sys/.../iio:deviceX/out_voltageY_powerdown_mode_available What: /sys/.../iio:deviceX/out_voltage_powerdown_mode_available -What: /sys/.../iio:deviceX/out_altvotlageY_powerdown_mode_available +What: /sys/.../iio:deviceX/out_altvoltageY_powerdown_mode_available What: /sys/.../iio:deviceX/out_altvoltage_powerdown_mode_available KernelVersion: 2.6.38 Contact: linux-iio@vger.kernel.org -- cgit v1.2.3 From 6b20f40679108e3c04e9bdb3d719e364ec29289e Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Sat, 25 Jul 2015 01:23:28 +1000 Subject: tools: iio: Set caller's ci_array pointer to NULL after free On error, caller's ci_array is freed and set to NULL to avoid potential double free if some other user of this code is not sufficiently careful. Counter is reset to zero for consistency. Signed-off-by: Joo Aun Saw Signed-off-by: Jonathan Cameron --- tools/iio/iio_utils.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index 4bbd6e7959cd..8475b832ee39 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -526,6 +526,8 @@ error_cleanup_array: free((*ci_array)[i].generic_name); } free(*ci_array); + *ci_array = NULL; + *counter = 0; error_close_dir: if (dp) if (closedir(dp) == -1) -- cgit v1.2.3 From 95ddd3f4b17e1df20b5e23d7b81614e7c8a643da Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Sat, 25 Jul 2015 01:23:29 +1000 Subject: tools: iio: remove unnecessary double pointer Remove unnecessary double pointer from channel sorting function. Signed-off-by: Joo Aun Saw Signed-off-by: Jonathan Cameron --- tools/iio/iio_utils.c | 12 ++++++------ tools/iio/iio_utils.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index 8475b832ee39..5eb6793f3972 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -286,17 +286,17 @@ error_free_builtname: * @cnt: the amount of array elements **/ -void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt) +void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt) { struct iio_channel_info temp; int x, y; for (x = 0; x < cnt; x++) for (y = 0; y < (cnt - 1); y++) - if ((*ci_array)[y].index > (*ci_array)[y + 1].index) { - temp = (*ci_array)[y + 1]; - (*ci_array)[y + 1] = (*ci_array)[y]; - (*ci_array)[y] = temp; + if (ci_array[y].index > ci_array[y + 1].index) { + temp = ci_array[y + 1]; + ci_array[y + 1] = ci_array[y]; + ci_array[y] = temp; } } @@ -516,7 +516,7 @@ int build_channel_array(const char *device_dir, free(scan_el_dir); /* reorder so that the array is in index order */ - bsort_channel_array_by_index(ci_array, *counter); + bsort_channel_array_by_index(*ci_array, *counter); return 0; diff --git a/tools/iio/iio_utils.h b/tools/iio/iio_utils.h index f30a1091b53e..e3503bfe538b 100644 --- a/tools/iio/iio_utils.h +++ b/tools/iio/iio_utils.h @@ -60,7 +60,7 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, int iioutils_get_param_float(float *output, const char *param_name, const char *device_dir, const char *name, const char *generic_name); -void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt); +void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt); int build_channel_array(const char *device_dir, struct iio_channel_info **ci_array, int *counter); int find_type_by_name(const char *name, const char *type); -- cgit v1.2.3 From 57cb06762d5e587d58005b17b0fa99bd1e391c29 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Tue, 28 Jul 2015 00:38:57 +0200 Subject: iio:adc:berlin2-adc: Fix register definition Active channel number is stored in BERLIN2_SM_CTRL as value, instead of a bit map. The masks for channel interrupts and data ready are a 16 bits wide bit map each, instead of just 4 bits. Also correct the data mask for the temperature sensor, which was Reported-by: Antoine Tenart Signed-off-by: Hartmut Knaack Acked-by: Antoine Tenart Signed-off-by: Jonathan Cameron --- drivers/iio/adc/berlin2-adc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c index 3aaf3a975c79..4946d9bf1764 100644 --- a/drivers/iio/adc/berlin2-adc.c +++ b/drivers/iio/adc/berlin2-adc.c @@ -26,7 +26,7 @@ #define BERLIN2_SM_CTRL 0x14 #define BERLIN2_SM_CTRL_SM_SOC_INT BIT(1) #define BERLIN2_SM_CTRL_SOC_SM_INT BIT(2) -#define BERLIN2_SM_CTRL_ADC_SEL(x) (BIT(x) << 5) /* 0-15 */ +#define BERLIN2_SM_CTRL_ADC_SEL(x) ((x) << 5) /* 0-15 */ #define BERLIN2_SM_CTRL_ADC_SEL_MASK (0xf << 5) #define BERLIN2_SM_CTRL_ADC_POWER BIT(9) #define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV2 (0x0 << 10) @@ -53,14 +53,14 @@ #define BERLIN2_SM_ADC_MASK 0x3ff #define BERLIN2_SM_ADC_STATUS 0x1c #define BERLIN2_SM_ADC_STATUS_DATA_RDY(x) BIT(x) /* 0-15 */ -#define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK 0xf +#define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK GENMASK(15, 0) #define BERLIN2_SM_ADC_STATUS_INT_EN(x) (BIT(x) << 16) /* 0-15 */ -#define BERLIN2_SM_ADC_STATUS_INT_EN_MASK (0xf << 16) +#define BERLIN2_SM_ADC_STATUS_INT_EN_MASK GENMASK(31, 16) #define BERLIN2_SM_TSEN_STATUS 0x24 #define BERLIN2_SM_TSEN_STATUS_DATA_RDY BIT(0) #define BERLIN2_SM_TSEN_STATUS_INT_EN BIT(1) #define BERLIN2_SM_TSEN_DATA 0x28 -#define BERLIN2_SM_TSEN_MASK 0xfff +#define BERLIN2_SM_TSEN_MASK GENMASK(9, 0) #define BERLIN2_SM_TSEN_CTRL 0x74 #define BERLIN2_SM_TSEN_CTRL_START BIT(8) #define BERLIN2_SM_TSEN_CTRL_SETTLING_4 (0x0 << 21) /* 4 us */ -- cgit v1.2.3 From 06d2f6ca5a38abe92f1f3a132b331eee773868c3 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Wed, 29 Jul 2015 15:46:03 +0200 Subject: iio: bmg160: IIO_BUFFER and IIO_TRIGGERED_BUFFER are required This patch adds selects for IIO_BUFFER and IIO_TRIGGERED_BUFFER. Without IIO_BUFFER, the driver does not compile. Signed-off-by: Markus Pargmann Reviewed-by: Srinivas Pandruvada Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index b3d0e94f72eb..8d2439345673 100644 --- a/drivers/iio/gyro/Kconfig +++ b/drivers/iio/gyro/Kconfig @@ -53,7 +53,8 @@ config ADXRS450 config BMG160 tristate "BOSCH BMG160 Gyro Sensor" depends on I2C - select IIO_TRIGGERED_BUFFER if IIO_BUFFER + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Say yes here to build support for Bosch BMG160 Tri-axis Gyro Sensor driver. This driver also supports BMI055 gyroscope. -- cgit v1.2.3 From af255cd562aaa72455f9022a26afacd68f3fbf73 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 4 Aug 2015 16:21:49 +0200 Subject: iio: lsiio: fix error code handling error commit acf50b3586f8d8a7530b905e111dda41876d38f4 "tools:iio:lsiio: add error handling" introduced error handling of errors returned from read_sysfs_string(), but with a simple if (retval), missing the fact that these functions return a positive value if the read was successful. As a result lsiio regresses and does not show any devices on my filesystem. Fix this by checking for only negative error codes. Cc: Hartmut Knaack Signed-off-by: Linus Walleij Acked-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- tools/iio/lsiio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/iio/lsiio.c b/tools/iio/lsiio.c index b271a9a796d2..3d650e668252 100644 --- a/tools/iio/lsiio.c +++ b/tools/iio/lsiio.c @@ -69,7 +69,7 @@ static int dump_one_device(const char *dev_dir_name) return -EINVAL; ret = read_sysfs_string("name", dev_dir_name, name); - if (ret) + if (ret < 0) return ret; printf("Device %03d: %s\n", dev_idx, name); @@ -92,7 +92,7 @@ static int dump_one_trigger(const char *dev_dir_name) return -EINVAL; ret = read_sysfs_string("name", dev_dir_name, name); - if (ret) + if (ret < 0) return ret; printf("Trigger %03d: %s\n", dev_idx, name); -- cgit v1.2.3 From 1bdc0293901cbea23c6dc29432e81919d4719844 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Mon, 3 Aug 2015 13:37:40 +0300 Subject: iio: industrialio-buffer: Fix iio_buffer_poll return value Change return value to 0 if no device is bound since unsigned int cannot support negative error codes. Fixes: f18e7a068 ("iio: Return -ENODEV for file operations if the device has been unregistered") Signed-off-by: Cristina Opriceana Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index faed6efa49ec..d7e908acb480 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -164,7 +164,7 @@ unsigned int iio_buffer_poll(struct file *filp, struct iio_buffer *rb = indio_dev->buffer; if (!indio_dev->info) - return -ENODEV; + return 0; poll_wait(filp, &rb->pollq, wait); if (iio_buffer_ready(indio_dev, rb, rb->watermark, 0)) -- cgit v1.2.3 From 41d903c00051d8f31c98a8136edbac67e6f8688f Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Mon, 3 Aug 2015 13:00:47 +0300 Subject: iio: event: Remove negative error code from iio_event_poll Negative return values are not supported by iio_event_poll since its return type is unsigned int. Fixes: f18e7a068a0a3 ("iio: Return -ENODEV for file operations if the device has been unregistered") Signed-off-by: Cristina Opriceana Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index b2f63f919cc4..cae332b1d7ea 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -90,7 +90,7 @@ static unsigned int iio_event_poll(struct file *filep, unsigned int events = 0; if (!indio_dev->info) - return -ENODEV; + return events; poll_wait(filep, &ev_int->wait, wait); -- cgit v1.2.3