Merge tag 'iio-for-4.17a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 20 Feb 2018 09:23:17 +0000 (10:23 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 20 Feb 2018 09:23:17 +0000 (10:23 +0100)
Jonathan writes:

First round of new devices, features and cleanups for IIO in the 4.17 cycle.

Outside of IIO
* Strongly typed 64bit int_sqrt function needed by the mlx90632

New device support
* adc081s
  - New driver supporting adc081s, adc101s and adc121s TI ADCs.
* ad5272
  - New driver supproting the ad5272 and ad5274 ADI digital potentiometers
    with DT bindings.
* axp20x_adc
  - support the AXP813 ADC - includes rework patches to prepare for this.
* mlx90632
  - New driver with dt bindings for this IR temperature sensor.

Features
* axp20x_adc
  - Add DT bindings and probing.
* dht11
  - The sensor has a wider range than advertised in the datasheet - support it.
* st_lsm6dsx
  - Add hardware timestamp su9pport.

Cleanups
* ABI docs
  - Update email contact for Matt Ranostay
* SPDX changes
  - Matt Ranostay has moved his drivers over to SPDX.  Currently we are making
    this an author choice in IIO.
* ad7192
  - Disable burnout current on misconfiguration.  No actually effect as
    they simply won't work otherwise.
* ad7476
  - Drop a license definition that was replicating information in SPDX tag.
ade7758
  - Expand buf_lock to cover both buffer and state protection allowing
    unintented uses of mlock in the core to be removed.
ade7759
  - Align parameters to opening parenthesis.
* at91_adc
  - Depend on sysfs instead of selecting it - for try wide consistency.
* ccs811
  - trivial naming type for a define.
* ep93xx
  - Drop a redundant return as a result checking platform_get_resource.
* hts221
  - Regmap conversion which simplifies the driver somewhat.
  - Clean up some restricted endian cast warnings.
  - Drop a trailing whitespace from a comment
  - Drop an unnecessary get_unaligned by changing to the right 16bit data type.
* ms5611
  - Fix coding style in the probe function (whitespace)
* st_accel
  - Use strlcpy instead of strncpy to avoid potentially truncating a string.

48 files changed:
Documentation/ABI/testing/sysfs-bus-iio-chemical-vz89x
Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935
Documentation/devicetree/bindings/iio/adc/axp20x_adc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/potentiometer/ad5272.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/temperature/mlx90632.txt [new file with mode: 0644]
MAINTAINERS
drivers/iio/accel/st_accel_i2c.c
drivers/iio/adc/Kconfig
drivers/iio/adc/ad7476.c
drivers/iio/adc/axp20x_adc.c
drivers/iio/adc/ep93xx_adc.c
drivers/iio/adc/ti-adc161s626.c
drivers/iio/chemical/ams-iaq-core.c
drivers/iio/chemical/atlas-ph-sensor.c
drivers/iio/chemical/ccs811.c
drivers/iio/chemical/vz89x.c
drivers/iio/health/max30100.c
drivers/iio/humidity/Kconfig
drivers/iio/humidity/dht11.c
drivers/iio/humidity/hdc100x.c
drivers/iio/humidity/hts221.h
drivers/iio/humidity/hts221_buffer.c
drivers/iio/humidity/hts221_core.c
drivers/iio/humidity/hts221_i2c.c
drivers/iio/humidity/hts221_spi.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
drivers/iio/light/apds9960.c
drivers/iio/potentiometer/Kconfig
drivers/iio/potentiometer/Makefile
drivers/iio/potentiometer/ad5272.c [new file with mode: 0644]
drivers/iio/potentiometer/tpl0102.c
drivers/iio/potentiostat/lmp91000.c
drivers/iio/pressure/ms5611.h
drivers/iio/proximity/as3935.c
drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
drivers/iio/temperature/Kconfig
drivers/iio/temperature/Makefile
drivers/iio/temperature/maxim_thermocouple.c
drivers/iio/temperature/mlx90632.c [new file with mode: 0644]
drivers/staging/iio/adc/ad7192.c
drivers/staging/iio/meter/ade7758.h
drivers/staging/iio/meter/ade7758_core.c
drivers/staging/iio/meter/ade7759.c
include/linux/kernel.h
include/linux/mfd/axp20x.h
lib/int_sqrt.c

index c0c1ea9245356fece024a1207de3501e8b18cf32..d512f865600e6b758a647149628d64549e44942b 100644 (file)
@@ -1,7 +1,7 @@
 What:          /sys/bus/iio/devices/iio:deviceX/in_concentration_VOC_short_raw
 Date:          September 2015
 KernelVersion: 4.3
-Contact:       Matt Ranostay <mranostay@gmail.com>
+Contact:       Matt Ranostay <matt.ranostay@konsulko.com>
 Description:
                Get the raw calibration VOC value from the sensor.
                This value has little application outside of calibration.
index 147d4e8a140393ce06a1076183b5a4a62432c7da..9a17ab5036a4cbb4dba37e420ecc5d5bed071d0d 100644 (file)
@@ -1,7 +1,7 @@
 What           /sys/bus/iio/devices/iio:deviceX/in_proximity_input
 Date:          March 2014
 KernelVersion: 3.15
-Contact:       Matt Ranostay <mranostay@gmail.com>
+Contact:       Matt Ranostay <matt.ranostay@konsulko.com>
 Description:
                Get the current distance in meters of storm (1km steps)
                1000-40000 = distance in meters
@@ -9,7 +9,7 @@ Description:
 What           /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
 Date:          March 2014
 KernelVersion: 3.15
-Contact:       Matt Ranostay <mranostay@gmail.com>
+Contact:       Matt Ranostay <matt.ranostay@konsulko.com>
 Description:
                Show or set the gain boost of the amp, from 0-31 range.
                18 = indoors (default)
diff --git a/Documentation/devicetree/bindings/iio/adc/axp20x_adc.txt b/Documentation/devicetree/bindings/iio/adc/axp20x_adc.txt
new file mode 100644 (file)
index 0000000..7a63139
--- /dev/null
@@ -0,0 +1,48 @@
+* X-Powers AXP ADC bindings
+
+Required properties:
+  - compatible: should be one of:
+    - "x-powers,axp209-adc",
+    - "x-powers,axp221-adc",
+    - "x-powers,axp813-adc",
+  - #io-channel-cells: should be 1,
+
+Example:
+
+&axp22x {
+       adc {
+               compatible = "x-powers,axp221-adc";
+               #io-channel-cells = <1>;
+       };
+};
+
+ADC channels and their indexes per variant:
+
+AXP209
+------
+ 0 | acin_v
+ 1 | acin_i
+ 2 | vbus_v
+ 3 | vbus_i
+ 4 | pmic_temp
+ 5 | gpio0_v
+ 6 | gpio1_v
+ 7 | ipsout_v
+ 8 | batt_v
+ 9 | batt_chrg_i
+10 | batt_dischrg_i
+
+AXP22x
+------
+ 0 | pmic_temp
+ 1 | batt_v
+ 2 | batt_chrg_i
+ 3 | batt_dischrg_i
+
+AXP813
+------
+ 0 | pmic_temp
+ 1 | gpio0_v
+ 2 | batt_v
+ 3 | batt_chrg_i
+ 4 | batt_dischrg_i
diff --git a/Documentation/devicetree/bindings/iio/potentiometer/ad5272.txt b/Documentation/devicetree/bindings/iio/potentiometer/ad5272.txt
new file mode 100644 (file)
index 0000000..f9b2eef
--- /dev/null
@@ -0,0 +1,27 @@
+* Analog Devices AD5272 digital potentiometer
+
+The node for this device must be a child node of a I2C controller, hence
+all mandatory properties for your controller must be specified. See directory:
+
+        Documentation/devicetree/bindings/i2c
+
+for more details.
+
+Required properties:
+       - compatible:   Must be one of the following, depending on the model:
+                       adi,ad5272-020
+                       adi,ad5272-050
+                       adi,ad5272-100
+                       adi,ad5274-020
+                       adi,ad5274-100
+
+Optional properties:
+ - reset-gpios: GPIO specification for the RESET input. This is an
+               active low signal to the AD5272.
+
+Example:
+ad5272: potentiometer@2f {
+       reg = <0x2F>;
+       compatible = "adi,ad5272-020";
+       reset-gpios = <&gpio3 6 GPIO_ACTIVE_HIGH>;
+};
diff --git a/Documentation/devicetree/bindings/iio/temperature/mlx90632.txt b/Documentation/devicetree/bindings/iio/temperature/mlx90632.txt
new file mode 100644 (file)
index 0000000..0b05812
--- /dev/null
@@ -0,0 +1,28 @@
+* Melexis MLX90632 contactless Infra Red temperature sensor
+
+Link to datasheet: https://www.melexis.com/en/documents/documentation/datasheets/datasheet-mlx90632
+
+There are various applications for the Infra Red contactless temperature sensor
+and MLX90632 is most suitable for consumer applications where measured object
+temperature is in range between -20 to 200 degrees Celsius with relative error
+of measurement below 1 degree Celsius in object temperature range for
+industrial applications. Since it can operate and measure ambient temperature
+in range of -20 to 85 degrees Celsius it is suitable also for outdoor use.
+
+Be aware that electronics surrounding the sensor can increase ambient
+temperature. MLX90632 can be calibrated to reduce the housing effect via
+already existing EEPROM parameters.
+
+Since measured object emissivity effects Infra Red energy emitted, emissivity
+should be set before requesting the object temperature.
+
+Required properties:
+  - compatible: should be "melexis,mlx90632"
+  - reg: the I2C address of the sensor (default 0x3a)
+
+Example:
+
+mlx90632@3a {
+       compatible = "melexis,mlx90632";
+       reg = <0x3a>;
+};
index 3bdc260e36b7a7eaac26003b187c436655fc3412..0c34d96c54e7a3e16d7bdc25698d04cd1c39e2e3 100644 (file)
@@ -8878,6 +8878,13 @@ W:       http://www.melexis.com
 S:     Supported
 F:     drivers/iio/temperature/mlx90614.c
 
+MELEXIS MLX90632 DRIVER
+M:     Crt Mori <cmo@melexis.com>
+L:     linux-iio@vger.kernel.org
+W:     http://www.melexis.com
+S:     Supported
+F:     drivers/iio/temperature/mlx90632.c
+
 MELFAS MIP4 TOUCHSCREEN DRIVER
 M:     Sangwon Jee <jeesw@melfas.com>
 W:     http://www.melfas.com
index 363429b5686c77abd254364015eff7a901c29480..6bdec8c451e0b89965cc7731b4aaeb4489734618 100644 (file)
@@ -159,9 +159,8 @@ static int st_accel_i2c_probe(struct i2c_client *client,
                if ((ret < 0) || (ret >= ST_ACCEL_MAX))
                        return -ENODEV;
 
-               strncpy(client->name, st_accel_id_table[ret].name,
+               strlcpy(client->name, st_accel_id_table[ret].name,
                                sizeof(client->name));
-               client->name[sizeof(client->name) - 1] = '\0';
        } else if (!id)
                return -ENODEV;
 
index 72bc2b71765ae2ff4a0199e0e507c1944ba74593..914b6f849a298b7bc244b81f646539105b73e724 100644 (file)
@@ -144,10 +144,9 @@ config ASPEED_ADC
 config AT91_ADC
        tristate "Atmel AT91 ADC"
        depends on ARCH_AT91
-       depends on INPUT
+       depends on INPUT && SYSFS
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
-       select SYSFS
        help
          Say yes here to build support for Atmel AT91 ADC.
 
index b7706bf10ffe8208b98b136e0a2abd384b1462e3..fbaae47746a83d82cb29135007a7aa8d33b2e7c6 100644 (file)
@@ -1,9 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
- * AD7466/7/8 AD7476/5/7/8 (A) SPI ADC driver
+ * Analog Devices AD7466/7/8 AD7476/5/7/8 (A) SPI ADC driver
+ * TI ADC081S/ADC101S/ADC121S 8/10/12-bit SPI ADC driver
  *
  * Copyright 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
  */
 
 #include <linux/device.h>
@@ -56,6 +56,9 @@ enum ad7476_supported_device_ids {
        ID_AD7468,
        ID_AD7495,
        ID_AD7940,
+       ID_ADC081S,
+       ID_ADC101S,
+       ID_ADC121S,
 };
 
 static irqreturn_t ad7476_trigger_handler(int irq, void  *p)
@@ -147,6 +150,8 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
        },                                                      \
 }
 
+#define ADC081S_CHAN(bits) _AD7476_CHAN((bits), 12 - (bits), \
+               BIT(IIO_CHAN_INFO_RAW))
 #define AD7476_CHAN(bits) _AD7476_CHAN((bits), 13 - (bits), \
                BIT(IIO_CHAN_INFO_RAW))
 #define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \
@@ -192,6 +197,18 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
                .channel[0] = AD7940_CHAN(14),
                .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
        },
+       [ID_ADC081S] = {
+               .channel[0] = ADC081S_CHAN(8),
+               .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+       },
+       [ID_ADC101S] = {
+               .channel[0] = ADC081S_CHAN(10),
+               .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+       },
+       [ID_ADC121S] = {
+               .channel[0] = ADC081S_CHAN(12),
+               .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+       },
 };
 
 static const struct iio_info ad7476_info = {
@@ -294,6 +311,9 @@ static const struct spi_device_id ad7476_id[] = {
        {"ad7910", ID_AD7467},
        {"ad7920", ID_AD7466},
        {"ad7940", ID_AD7940},
+       {"adc081s", ID_ADC081S},
+       {"adc101s", ID_ADC101S},
+       {"adc121s", ID_ADC121S},
        {}
 };
 MODULE_DEVICE_TABLE(spi, ad7476_id);
index a30a97245e911089498f15447486c7685ced0d83..7cdb8bc8cde61c12ddbcba639e82e6e1e2b84de9 100644 (file)
 #define AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(x)    (((x) & BIT(0)) << 1)
 
 #define AXP20X_ADC_RATE_MASK                   GENMASK(7, 6)
+#define AXP813_V_I_ADC_RATE_MASK               GENMASK(5, 4)
+#define AXP813_ADC_RATE_MASK                   (AXP20X_ADC_RATE_MASK | AXP813_V_I_ADC_RATE_MASK)
 #define AXP20X_ADC_RATE_HZ(x)                  ((ilog2((x) / 25) << 6) & AXP20X_ADC_RATE_MASK)
 #define AXP22X_ADC_RATE_HZ(x)                  ((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK)
+#define AXP813_TS_GPIO0_ADC_RATE_HZ(x)         AXP20X_ADC_RATE_HZ(x)
+#define AXP813_V_I_ADC_RATE_HZ(x)              ((ilog2((x) / 100) << 4) & AXP813_V_I_ADC_RATE_MASK)
+#define AXP813_ADC_RATE_HZ(x)                  (AXP20X_ADC_RATE_HZ(x) | AXP813_V_I_ADC_RATE_HZ(x))
 
 #define AXP20X_ADC_CHANNEL(_channel, _name, _type, _reg)       \
        {                                                       \
@@ -95,6 +100,12 @@ enum axp22x_adc_channel_i {
        AXP22X_BATT_DISCHRG_I,
 };
 
+enum axp813_adc_channel_v {
+       AXP813_TS_IN = 0,
+       AXP813_GPIO0_V,
+       AXP813_BATT_V,
+};
+
 static struct iio_map axp20x_maps[] = {
        {
                .consumer_dev_name = "axp20x-usb-power-supply",
@@ -197,6 +208,25 @@ static const struct iio_chan_spec axp22x_adc_channels[] = {
                           AXP20X_BATT_DISCHRG_I_H),
 };
 
+static const struct iio_chan_spec axp813_adc_channels[] = {
+       {
+               .type = IIO_TEMP,
+               .address = AXP22X_PMIC_TEMP_H,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_SCALE) |
+                                     BIT(IIO_CHAN_INFO_OFFSET),
+               .datasheet_name = "pmic_temp",
+       },
+       AXP20X_ADC_CHANNEL(AXP813_GPIO0_V, "gpio0_v", IIO_VOLTAGE,
+                          AXP288_GP_ADC_H),
+       AXP20X_ADC_CHANNEL(AXP813_BATT_V, "batt_v", IIO_VOLTAGE,
+                          AXP20X_BATT_V_H),
+       AXP20X_ADC_CHANNEL(AXP22X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
+                          AXP20X_BATT_CHRG_I_H),
+       AXP20X_ADC_CHANNEL(AXP22X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
+                          AXP20X_BATT_DISCHRG_I_H),
+};
+
 static int axp20x_adc_raw(struct iio_dev *indio_dev,
                          struct iio_chan_spec const *chan, int *val)
 {
@@ -243,6 +273,18 @@ static int axp22x_adc_raw(struct iio_dev *indio_dev,
        return IIO_VAL_INT;
 }
 
+static int axp813_adc_raw(struct iio_dev *indio_dev,
+                         struct iio_chan_spec const *chan, int *val)
+{
+       struct axp20x_adc_iio *info = iio_priv(indio_dev);
+
+       *val = axp20x_read_variable_width(info->regmap, chan->address, 12);
+       if (*val < 0)
+               return *val;
+
+       return IIO_VAL_INT;
+}
+
 static int axp20x_adc_scale_voltage(int channel, int *val, int *val2)
 {
        switch (channel) {
@@ -273,6 +315,24 @@ static int axp20x_adc_scale_voltage(int channel, int *val, int *val2)
        }
 }
 
+static int axp813_adc_scale_voltage(int channel, int *val, int *val2)
+{
+       switch (channel) {
+       case AXP813_GPIO0_V:
+               *val = 0;
+               *val2 = 800000;
+               return IIO_VAL_INT_PLUS_MICRO;
+
+       case AXP813_BATT_V:
+               *val = 1;
+               *val2 = 100000;
+               return IIO_VAL_INT_PLUS_MICRO;
+
+       default:
+               return -EINVAL;
+       }
+}
+
 static int axp20x_adc_scale_current(int channel, int *val, int *val2)
 {
        switch (channel) {
@@ -342,6 +402,26 @@ static int axp22x_adc_scale(struct iio_chan_spec const *chan, int *val,
        }
 }
 
+static int axp813_adc_scale(struct iio_chan_spec const *chan, int *val,
+                           int *val2)
+{
+       switch (chan->type) {
+       case IIO_VOLTAGE:
+               return axp813_adc_scale_voltage(chan->channel, val, val2);
+
+       case IIO_CURRENT:
+               *val = 1;
+               return IIO_VAL_INT;
+
+       case IIO_TEMP:
+               *val = 100;
+               return IIO_VAL_INT;
+
+       default:
+               return -EINVAL;
+       }
+}
+
 static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
                                     int *val)
 {
@@ -425,6 +505,26 @@ static int axp22x_read_raw(struct iio_dev *indio_dev,
        }
 }
 
+static int axp813_read_raw(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *chan, int *val,
+                          int *val2, long mask)
+{
+       switch (mask) {
+       case IIO_CHAN_INFO_OFFSET:
+               *val = -2667;
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_SCALE:
+               return axp813_adc_scale(chan, val, val2);
+
+       case IIO_CHAN_INFO_RAW:
+               return axp813_adc_raw(indio_dev, chan, val);
+
+       default:
+               return -EINVAL;
+       }
+}
+
 static int axp20x_write_raw(struct iio_dev *indio_dev,
                            struct iio_chan_spec const *chan, int val, int val2,
                            long mask)
@@ -470,14 +570,29 @@ static const struct iio_info axp22x_adc_iio_info = {
        .read_raw = axp22x_read_raw,
 };
 
-static int axp20x_adc_rate(int rate)
+static const struct iio_info axp813_adc_iio_info = {
+       .read_raw = axp813_read_raw,
+};
+
+static int axp20x_adc_rate(struct axp20x_adc_iio *info, int rate)
+{
+       return regmap_update_bits(info->regmap, AXP20X_ADC_RATE,
+                                 AXP20X_ADC_RATE_MASK,
+                                 AXP20X_ADC_RATE_HZ(rate));
+}
+
+static int axp22x_adc_rate(struct axp20x_adc_iio *info, int rate)
 {
-       return AXP20X_ADC_RATE_HZ(rate);
+       return regmap_update_bits(info->regmap, AXP20X_ADC_RATE,
+                                 AXP20X_ADC_RATE_MASK,
+                                 AXP22X_ADC_RATE_HZ(rate));
 }
 
-static int axp22x_adc_rate(int rate)
+static int axp813_adc_rate(struct axp20x_adc_iio *info, int rate)
 {
-       return AXP22X_ADC_RATE_HZ(rate);
+       return regmap_update_bits(info->regmap, AXP813_ADC_RATE,
+                                AXP813_ADC_RATE_MASK,
+                                AXP813_ADC_RATE_HZ(rate));
 }
 
 struct axp_data {
@@ -485,7 +600,8 @@ struct axp_data {
        int                             num_channels;
        struct iio_chan_spec const      *channels;
        unsigned long                   adc_en1_mask;
-       int                             (*adc_rate)(int rate);
+       int                             (*adc_rate)(struct axp20x_adc_iio *info,
+                                                   int rate);
        bool                            adc_en2;
        struct iio_map                  *maps;
 };
@@ -510,9 +626,28 @@ static const struct axp_data axp22x_data = {
        .maps = axp22x_maps,
 };
 
+static const struct axp_data axp813_data = {
+       .iio_info = &axp813_adc_iio_info,
+       .num_channels = ARRAY_SIZE(axp813_adc_channels),
+       .channels = axp813_adc_channels,
+       .adc_en1_mask = AXP22X_ADC_EN1_MASK,
+       .adc_rate = axp813_adc_rate,
+       .adc_en2 = false,
+       .maps = axp22x_maps,
+};
+
+static const struct of_device_id axp20x_adc_of_match[] = {
+       { .compatible = "x-powers,axp209-adc", .data = (void *)&axp20x_data, },
+       { .compatible = "x-powers,axp221-adc", .data = (void *)&axp22x_data, },
+       { .compatible = "x-powers,axp813-adc", .data = (void *)&axp813_data, },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, axp20x_adc_of_match);
+
 static const struct platform_device_id axp20x_adc_id_match[] = {
        { .name = "axp20x-adc", .driver_data = (kernel_ulong_t)&axp20x_data, },
        { .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, },
+       { .name = "axp813-adc", .driver_data = (kernel_ulong_t)&axp813_data, },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(platform, axp20x_adc_id_match);
@@ -538,7 +673,16 @@ static int axp20x_probe(struct platform_device *pdev)
        indio_dev->dev.of_node = pdev->dev.of_node;
        indio_dev->modes = INDIO_DIRECT_MODE;
 
-       info->data = (struct axp_data *)platform_get_device_id(pdev)->driver_data;
+       if (!pdev->dev.of_node) {
+               const struct platform_device_id *id;
+
+               id = platform_get_device_id(pdev);
+               info->data = (struct axp_data *)id->driver_data;
+       } else {
+               struct device *dev = &pdev->dev;
+
+               info->data = (struct axp_data *)of_device_get_match_data(dev);
+       }
 
        indio_dev->name = platform_get_device_id(pdev)->name;
        indio_dev->info = info->data->iio_info;
@@ -554,8 +698,7 @@ static int axp20x_probe(struct platform_device *pdev)
                                   AXP20X_ADC_EN2_MASK, AXP20X_ADC_EN2_MASK);
 
        /* Configure ADCs rate */
-       regmap_update_bits(info->regmap, AXP20X_ADC_RATE, AXP20X_ADC_RATE_MASK,
-                          info->data->adc_rate(100));
+       info->data->adc_rate(info, 100);
 
        ret = iio_map_array_register(indio_dev, info->data->maps);
        if (ret < 0) {
@@ -602,6 +745,7 @@ static int axp20x_remove(struct platform_device *pdev)
 static struct platform_driver axp20x_adc_driver = {
        .driver = {
                .name = "axp20x-adc",
+               .of_match_table = of_match_ptr(axp20x_adc_of_match),
        },
        .id_table = axp20x_adc_id_match,
        .probe = axp20x_probe,
index 81c901507ad2432676bc0a9b6a6b811b26b677cd..5036c392cb2063be0fed9d3f96818347dd180659 100644 (file)
@@ -167,10 +167,6 @@ static int ep93xx_adc_probe(struct platform_device *pdev)
        priv = iio_priv(iiodev);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "Cannot obtain memory resource\n");
-               return -ENXIO;
-       }
        priv->base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(priv->base)) {
                dev_err(&pdev->dev, "Cannot map memory resource\n");
index 10fa7677ac4b98ec32589fda1adb763207785f30..3bbc9b9ddbfed2160ebfd9f50088bd0e321dad03 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * ti-adc161s626.c - Texas Instruments ADC161S626 1-channel differential ADC
  *
@@ -5,17 +6,8 @@
  *  adc141s626 - 14-bit ADC
  *  adc161s626 - 16-bit ADC
  *
- * Copyright (C) 2016 Matt Ranostay <mranostay@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Copyright (C) 2016-2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
  */
 
 #include <linux/module.h>
@@ -275,6 +267,6 @@ static struct spi_driver ti_adc_driver = {
 };
 module_spi_driver(ti_adc_driver);
 
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
 MODULE_DESCRIPTION("Texas Instruments ADC1x1S 1-channel differential ADC");
 MODULE_LICENSE("GPL");
index d9e5950ad24a729c73cb5511878118332b51d0e8..a0646ba2ad8873f7f3e7beb503727032dacbcc4e 100644 (file)
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * ams-iaq-core.c - Support for AMS iAQ-Core VOC sensors
  *
- * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
+ * Copyright (C) 2015, 2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
  */
 
 #include <linux/module.h>
@@ -194,6 +185,6 @@ static struct i2c_driver ams_iaqcore_driver = {
 };
 module_i2c_driver(ams_iaqcore_driver);
 
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
 MODULE_DESCRIPTION("AMS iAQ-Core VOC sensors");
 MODULE_LICENSE("GPL v2");
index 8c4e055800919aa6c784669a6e7833404079e3d6..abfc4bbc4cfc36ddef5edf9130bf83a8a91caab4 100644 (file)
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * atlas-ph-sensor.c - Support for Atlas Scientific OEM pH-SM sensor
  *
- * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Copyright (C) 2015-2018 Matt Ranostay
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
  */
 
 #include <linux/module.h>
@@ -689,6 +681,6 @@ static struct i2c_driver atlas_driver = {
 };
 module_i2c_driver(atlas_driver);
 
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
 MODULE_DESCRIPTION("Atlas Scientific pH-SM sensor");
 MODULE_LICENSE("GPL");
index fbe2431f5b81b25dcd14647ca656ae70c4925e7e..cfaf86b248d9b5f884c19589484bfd07b7afa29a 100644 (file)
@@ -32,7 +32,7 @@
 #define CCS811_ALG_RESULT_DATA 0x02
 #define CCS811_RAW_DATA                0x03
 #define CCS811_HW_ID           0x20
-#define CCS881_HW_ID_VALUE     0x81
+#define CCS811_HW_ID_VALUE     0x81
 #define CCS811_HW_VERSION      0x21
 #define CCS811_HW_VERSION_VALUE        0x10
 #define CCS811_HW_VERSION_MASK 0xF0
@@ -353,7 +353,7 @@ static int ccs811_probe(struct i2c_client *client,
        if (ret < 0)
                return ret;
 
-       if (ret != CCS881_HW_ID_VALUE) {
+       if (ret != CCS811_HW_ID_VALUE) {
                dev_err(&client->dev, "hardware id doesn't match CCS81x\n");
                return -ENODEV;
        }
index 9c9095ba42278dcd837a1a8d6a2a60fdeeb07c1f..415b39339d4ef66ef253be562bd0925f878f3a5c 100644 (file)
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * vz89x.c - Support for SGX Sensortech MiCS VZ89X VOC sensors
  *
- * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
+ * Copyright (C) 2015-2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
  */
 
 #include <linux/module.h>
@@ -419,6 +410,6 @@ static struct i2c_driver vz89x_driver = {
 };
 module_i2c_driver(vz89x_driver);
 
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
 MODULE_DESCRIPTION("SGX Sensortech MiCS VZ89X VOC sensors");
 MODULE_LICENSE("GPL v2");
index 91aef5df24a1afe07cd49855ad2388130ceee7e8..84010501762da09776bbf05a553845678dc62ca5 100644 (file)
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * max30100.c - Support for MAX30100 heart rate and pulse oximeter sensor
  *
- * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Copyright (C) 2015, 2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
  *
  * TODO: enable pulse length controls via device tree properties
  */
@@ -518,6 +510,6 @@ static struct i2c_driver max30100_driver = {
 };
 module_i2c_driver(max30100_driver);
 
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
 MODULE_DESCRIPTION("MAX30100 heart rate and pulse oximeter sensor");
 MODULE_LICENSE("GPL");
index 2c0fc9a400b8d3d799421eb5c03c472f2de2661f..1a0d458e4f4ec42a2edc7bdeb39970f26f8f8e95 100644 (file)
@@ -68,10 +68,12 @@ config HTS221
 config HTS221_I2C
        tristate
        depends on HTS221
+       select REGMAP_I2C
 
 config HTS221_SPI
        tristate
        depends on HTS221
+       select REGMAP_SPI
 
 config HTU21
        tristate "Measurement Specialties HTU21 humidity & temperature sensor"
index df6bab40d6fa5ffd7c6e843541416bfac454cd64..1a9f8f4ffb8877d6541eec3bee9ee2e334383b3d 100644 (file)
@@ -159,7 +159,7 @@ static int dht11_decode(struct dht11 *dht11, int offset)
        }
 
        dht11->timestamp = ktime_get_boot_ns();
-       if (hum_int < 20) {  /* DHT22 */
+       if (hum_int < 4) {  /* DHT22: 100000 = (3*256+232)*100 */
                dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) *
                                        ((temp_int & 0x80) ? -100 : 100);
                dht11->humidity = ((hum_int << 8) + hum_dec) * 100;
index d8438310b6d4d7a533506523611d01a589fdd961..066e05f920810c74afdac0b535046af455c67388 100644 (file)
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * hdc100x.c - Support for the TI HDC100x temperature + humidity sensors
  *
- * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Copyright (C) 2015, 2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
  *
  * Datasheets:
  * http://www.ti.com/product/HDC1000/datasheet
@@ -449,6 +441,6 @@ static struct i2c_driver hdc100x_driver = {
 };
 module_i2c_driver(hdc100x_driver);
 
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
 MODULE_DESCRIPTION("TI HDC100x humidity and temperature sensor driver");
 MODULE_LICENSE("GPL");
index c581af8c0f5d3f78cd0dd4461faee79404d3b99b..e41a3d83e95d367bf83f0fbda6ef278537a7515b 100644 (file)
 
 #include <linux/iio/iio.h>
 
-#define HTS221_RX_MAX_LENGTH   8
-#define HTS221_TX_MAX_LENGTH   8
-
 #define HTS221_DATA_SIZE       2
 
-struct hts221_transfer_buffer {
-       u8 rx_buf[HTS221_RX_MAX_LENGTH];
-       u8 tx_buf[HTS221_TX_MAX_LENGTH] ____cacheline_aligned;
-};
-
-struct hts221_transfer_function {
-       int (*read)(struct device *dev, u8 addr, int len, u8 *data);
-       int (*write)(struct device *dev, u8 addr, int len, u8 *data);
-};
-
 enum hts221_sensor_type {
        HTS221_SENSOR_H,
        HTS221_SENSOR_T,
@@ -44,8 +31,8 @@ struct hts221_sensor {
 struct hts221_hw {
        const char *name;
        struct device *dev;
+       struct regmap *regmap;
 
-       struct mutex lock;
        struct iio_trigger *trig;
        int irq;
 
@@ -53,16 +40,12 @@ struct hts221_hw {
 
        bool enabled;
        u8 odr;
-
-       const struct hts221_transfer_function *tf;
-       struct hts221_transfer_buffer tb;
 };
 
 extern const struct dev_pm_ops hts221_pm_ops;
 
-int hts221_write_with_mask(struct hts221_hw *hw, u8 addr, u8 mask, u8 val);
 int hts221_probe(struct device *dev, int irq, const char *name,
-                const struct hts221_transfer_function *tf_ops);
+                struct regmap *regmap);
 int hts221_set_enable(struct hts221_hw *hw, bool enable);
 int hts221_allocate_buffers(struct hts221_hw *hw);
 int hts221_allocate_trigger(struct hts221_hw *hw);
index e971ea425268a09cd21dc0005bd3452ef797d7c1..1a94b0b917210c04977783b005c6484f237d4d43 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/irqreturn.h>
+#include <linux/regmap.h>
+#include <linux/bitfield.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/trigger.h>
@@ -38,12 +40,10 @@ static int hts221_trig_set_state(struct iio_trigger *trig, bool state)
 {
        struct iio_dev *iio_dev = iio_trigger_get_drvdata(trig);
        struct hts221_hw *hw = iio_priv(iio_dev);
-       int err;
-
-       err = hts221_write_with_mask(hw, HTS221_REG_DRDY_EN_ADDR,
-                                    HTS221_REG_DRDY_EN_MASK, state);
 
-       return err < 0 ? err : 0;
+       return regmap_update_bits(hw->regmap, HTS221_REG_DRDY_EN_ADDR,
+                                 HTS221_REG_DRDY_EN_MASK,
+                                 FIELD_PREP(HTS221_REG_DRDY_EN_MASK, state));
 }
 
 static const struct iio_trigger_ops hts221_trigger_ops = {
@@ -53,15 +53,13 @@ static const struct iio_trigger_ops hts221_trigger_ops = {
 static irqreturn_t hts221_trigger_handler_thread(int irq, void *private)
 {
        struct hts221_hw *hw = private;
-       u8 status;
-       int err;
+       int err, status;
 
-       err = hw->tf->read(hw->dev, HTS221_REG_STATUS_ADDR, sizeof(status),
-                          &status);
+       err = regmap_read(hw->regmap, HTS221_REG_STATUS_ADDR, &status);
        if (err < 0)
                return IRQ_HANDLED;
 
-       /* 
+       /*
         * H_DA bit (humidity data available) is routed to DRDY line.
         * Humidity sample is computed after temperature one.
         * Here we can assume data channels are both available if H_DA bit
@@ -102,8 +100,10 @@ int hts221_allocate_trigger(struct hts221_hw *hw)
                break;
        }
 
-       err = hts221_write_with_mask(hw, HTS221_REG_DRDY_HL_ADDR,
-                                    HTS221_REG_DRDY_HL_MASK, irq_active_low);
+       err = regmap_update_bits(hw->regmap, HTS221_REG_DRDY_HL_ADDR,
+                                HTS221_REG_DRDY_HL_MASK,
+                                FIELD_PREP(HTS221_REG_DRDY_HL_MASK,
+                                           irq_active_low));
        if (err < 0)
                return err;
 
@@ -114,9 +114,10 @@ int hts221_allocate_trigger(struct hts221_hw *hw)
                open_drain = true;
        }
 
-       err = hts221_write_with_mask(hw, HTS221_REG_DRDY_PP_OD_ADDR,
-                                    HTS221_REG_DRDY_PP_OD_MASK,
-                                    open_drain);
+       err = regmap_update_bits(hw->regmap, HTS221_REG_DRDY_PP_OD_ADDR,
+                                HTS221_REG_DRDY_PP_OD_MASK,
+                                FIELD_PREP(HTS221_REG_DRDY_PP_OD_MASK,
+                                           open_drain));
        if (err < 0)
                return err;
 
@@ -171,15 +172,15 @@ static irqreturn_t hts221_buffer_handler_thread(int irq, void *p)
 
        /* humidity data */
        ch = &iio_dev->channels[HTS221_SENSOR_H];
-       err = hw->tf->read(hw->dev, ch->address, HTS221_DATA_SIZE,
-                          buffer);
+       err = regmap_bulk_read(hw->regmap, ch->address,
+                              buffer, HTS221_DATA_SIZE);
        if (err < 0)
                goto out;
 
        /* temperature data */
        ch = &iio_dev->channels[HTS221_SENSOR_T];
-       err = hw->tf->read(hw->dev, ch->address, HTS221_DATA_SIZE,
-                          buffer + HTS221_DATA_SIZE);
+       err = regmap_bulk_read(hw->regmap, ch->address,
+                              buffer + HTS221_DATA_SIZE, HTS221_DATA_SIZE);
        if (err < 0)
                goto out;
 
index d3f7904766bd3f477343c91d45d3280e8c23ac1c..166946d4978d84401ac8043a612e9050d465bf2a 100644 (file)
@@ -14,7 +14,8 @@
 #include <linux/iio/sysfs.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
-#include <asm/unaligned.h>
+#include <linux/regmap.h>
+#include <linux/bitfield.h>
 
 #include "hts221.h"
 
@@ -131,38 +132,11 @@ static const struct iio_chan_spec hts221_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(2),
 };
 
-int hts221_write_with_mask(struct hts221_hw *hw, u8 addr, u8 mask, u8 val)
-{
-       u8 data;
-       int err;
-
-       mutex_lock(&hw->lock);
-
-       err = hw->tf->read(hw->dev, addr, sizeof(data), &data);
-       if (err < 0) {
-               dev_err(hw->dev, "failed to read %02x register\n", addr);
-               goto unlock;
-       }
-
-       data = (data & ~mask) | ((val << __ffs(mask)) & mask);
-
-       err = hw->tf->write(hw->dev, addr, sizeof(data), &data);
-       if (err < 0)
-               dev_err(hw->dev, "failed to write %02x register\n", addr);
-
-unlock:
-       mutex_unlock(&hw->lock);
-
-       return err;
-}
-
 static int hts221_check_whoami(struct hts221_hw *hw)
 {
-       u8 data;
-       int err;
+       int err, data;
 
-       err = hw->tf->read(hw->dev, HTS221_REG_WHOAMI_ADDR, sizeof(data),
-                          &data);
+       err = regmap_read(hw->regmap, HTS221_REG_WHOAMI_ADDR, &data);
        if (err < 0) {
                dev_err(hw->dev, "failed to read whoami register\n");
                return err;
@@ -188,8 +162,10 @@ static int hts221_update_odr(struct hts221_hw *hw, u8 odr)
        if (i == ARRAY_SIZE(hts221_odr_table))
                return -EINVAL;
 
-       err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR,
-                                    HTS221_ODR_MASK, hts221_odr_table[i].val);
+       err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,
+                                HTS221_ODR_MASK,
+                                FIELD_PREP(HTS221_ODR_MASK,
+                                           hts221_odr_table[i].val));
        if (err < 0)
                return err;
 
@@ -202,8 +178,8 @@ static int hts221_update_avg(struct hts221_hw *hw,
                             enum hts221_sensor_type type,
                             u16 val)
 {
-       int i, err;
        const struct hts221_avg *avg = &hts221_avg_list[type];
+       int i, err, data;
 
        for (i = 0; i < HTS221_AVG_DEPTH; i++)
                if (avg->avg_avl[i] == val)
@@ -212,7 +188,9 @@ static int hts221_update_avg(struct hts221_hw *hw,
        if (i == HTS221_AVG_DEPTH)
                return -EINVAL;
 
-       err = hts221_write_with_mask(hw, avg->addr, avg->mask, i);
+       data = ((i << __ffs(avg->mask)) & avg->mask);
+       err = regmap_update_bits(hw->regmap, avg->addr,
+                                avg->mask, data);
        if (err < 0)
                return err;
 
@@ -274,8 +252,9 @@ int hts221_set_enable(struct hts221_hw *hw, bool enable)
 {
        int err;
 
-       err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR,
-                                    HTS221_ENABLE_MASK, enable);
+       err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,
+                                HTS221_ENABLE_MASK,
+                                FIELD_PREP(HTS221_ENABLE_MASK, enable));
        if (err < 0)
                return err;
 
@@ -286,38 +265,35 @@ int hts221_set_enable(struct hts221_hw *hw, bool enable)
 
 static int hts221_parse_temp_caldata(struct hts221_hw *hw)
 {
-       int err, *slope, *b_gen;
+       int err, *slope, *b_gen, cal0, cal1;
        s16 cal_x0, cal_x1, cal_y0, cal_y1;
-       u8 cal0, cal1;
+       __le16 val;
 
-       err = hw->tf->read(hw->dev, HTS221_REG_0T_CAL_Y_H,
-                          sizeof(cal0), &cal0);
+       err = regmap_read(hw->regmap, HTS221_REG_0T_CAL_Y_H, &cal0);
        if (err < 0)
                return err;
 
-       err = hw->tf->read(hw->dev, HTS221_REG_T1_T0_CAL_Y_H,
-                          sizeof(cal1), &cal1);
+       err = regmap_read(hw->regmap, HTS221_REG_T1_T0_CAL_Y_H, &cal1);
        if (err < 0)
                return err;
-       cal_y0 = (le16_to_cpu(cal1 & 0x3) << 8) | cal0;
+       cal_y0 = ((cal1 & 0x3) << 8) | cal0;
 
-       err = hw->tf->read(hw->dev, HTS221_REG_1T_CAL_Y_H,
-                          sizeof(cal0), &cal0);
+       err = regmap_read(hw->regmap, HTS221_REG_1T_CAL_Y_H, &cal0);
        if (err < 0)
                return err;
        cal_y1 = (((cal1 & 0xc) >> 2) << 8) | cal0;
 
-       err = hw->tf->read(hw->dev, HTS221_REG_0T_CAL_X_L, sizeof(cal_x0),
-                          (u8 *)&cal_x0);
+       err = regmap_bulk_read(hw->regmap, HTS221_REG_0T_CAL_X_L,
+                              &val, sizeof(val));
        if (err < 0)
                return err;
-       cal_x0 = le16_to_cpu(cal_x0);
+       cal_x0 = le16_to_cpu(val);
 
-       err = hw->tf->read(hw->dev, HTS221_REG_1T_CAL_X_L, sizeof(cal_x1),
-                          (u8 *)&cal_x1);
+       err = regmap_bulk_read(hw->regmap, HTS221_REG_1T_CAL_X_L,
+                              &val, sizeof(val));
        if (err < 0)
                return err;
-       cal_x1 = le16_to_cpu(cal_x1);
+       cal_x1 = le16_to_cpu(val);
 
        slope = &hw->sensors[HTS221_SENSOR_T].slope;
        b_gen = &hw->sensors[HTS221_SENSOR_T].b_gen;
@@ -332,33 +308,31 @@ static int hts221_parse_temp_caldata(struct hts221_hw *hw)
 
 static int hts221_parse_rh_caldata(struct hts221_hw *hw)
 {
-       int err, *slope, *b_gen;
+       int err, *slope, *b_gen, data;
        s16 cal_x0, cal_x1, cal_y0, cal_y1;
-       u8 data;
+       __le16 val;
 
-       err = hw->tf->read(hw->dev, HTS221_REG_0RH_CAL_Y_H, sizeof(data),
-                          &data);
+       err = regmap_read(hw->regmap, HTS221_REG_0RH_CAL_Y_H, &data);
        if (err < 0)
                return err;
        cal_y0 = data;
 
-       err = hw->tf->read(hw->dev, HTS221_REG_1RH_CAL_Y_H, sizeof(data),
-                          &data);
+       err = regmap_read(hw->regmap, HTS221_REG_1RH_CAL_Y_H, &data);
        if (err < 0)
                return err;
        cal_y1 = data;
 
-       err = hw->tf->read(hw->dev, HTS221_REG_0RH_CAL_X_H, sizeof(cal_x0),
-                          (u8 *)&cal_x0);
+       err = regmap_bulk_read(hw->regmap, HTS221_REG_0RH_CAL_X_H,
+                              &val, sizeof(val));
        if (err < 0)
                return err;
-       cal_x0 = le16_to_cpu(cal_x0);
+       cal_x0 = le16_to_cpu(val);
 
-       err = hw->tf->read(hw->dev, HTS221_REG_1RH_CAL_X_H, sizeof(cal_x1),
-                          (u8 *)&cal_x1);
+       err = regmap_bulk_read(hw->regmap, HTS221_REG_1RH_CAL_X_H,
+                              &val, sizeof(val));
        if (err < 0)
                return err;
-       cal_x1 = le16_to_cpu(cal_x1);
+       cal_x1 = le16_to_cpu(val);
 
        slope = &hw->sensors[HTS221_SENSOR_H].slope;
        b_gen = &hw->sensors[HTS221_SENSOR_H].b_gen;
@@ -431,7 +405,7 @@ static int hts221_get_sensor_offset(struct hts221_hw *hw,
 
 static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val)
 {
-       u8 data[HTS221_DATA_SIZE];
+       __le16 data;
        int err;
 
        err = hts221_set_enable(hw, true);
@@ -440,13 +414,13 @@ static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val)
 
        msleep(50);
 
-       err = hw->tf->read(hw->dev, addr, sizeof(data), data);
+       err = regmap_bulk_read(hw->regmap, addr, &data, sizeof(data));
        if (err < 0)
                return err;
 
        hts221_set_enable(hw, false);
 
-       *val = (s16)get_unaligned_le16(data);
+       *val = (s16)le16_to_cpu(data);
 
        return IIO_VAL_INT;
 }
@@ -582,7 +556,7 @@ static const struct iio_info hts221_info = {
 static const unsigned long hts221_scan_masks[] = {0x3, 0x0};
 
 int hts221_probe(struct device *dev, int irq, const char *name,
-                const struct hts221_transfer_function *tf_ops)
+                struct regmap *regmap)
 {
        struct iio_dev *iio_dev;
        struct hts221_hw *hw;
@@ -599,9 +573,7 @@ int hts221_probe(struct device *dev, int irq, const char *name,
        hw->name = name;
        hw->dev = dev;
        hw->irq = irq;
-       hw->tf = tf_ops;
-
-       mutex_init(&hw->lock);
+       hw->regmap = regmap;
 
        err = hts221_check_whoami(hw);
        if (err < 0)
@@ -616,8 +588,9 @@ int hts221_probe(struct device *dev, int irq, const char *name,
        iio_dev->info = &hts221_info;
 
        /* enable Block Data Update */
-       err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR,
-                                    HTS221_BDU_MASK, 1);
+       err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,
+                                HTS221_BDU_MASK,
+                                FIELD_PREP(HTS221_BDU_MASK, 1));
        if (err < 0)
                return err;
 
@@ -673,12 +646,10 @@ static int __maybe_unused hts221_suspend(struct device *dev)
 {
        struct iio_dev *iio_dev = dev_get_drvdata(dev);
        struct hts221_hw *hw = iio_priv(iio_dev);
-       int err;
 
-       err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR,
-                                    HTS221_ENABLE_MASK, false);
-
-       return err < 0 ? err : 0;
+       return regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,
+                                 HTS221_ENABLE_MASK,
+                                 FIELD_PREP(HTS221_ENABLE_MASK, false));
 }
 
 static int __maybe_unused hts221_resume(struct device *dev)
@@ -688,9 +659,10 @@ static int __maybe_unused hts221_resume(struct device *dev)
        int err = 0;
 
        if (hw->enabled)
-               err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR,
-                                            HTS221_ENABLE_MASK, true);
-
+               err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,
+                                        HTS221_ENABLE_MASK,
+                                        FIELD_PREP(HTS221_ENABLE_MASK,
+                                                   true));
        return err;
 }
 
index 2c97350a0f760dd46f3586a1fa124d65515b18cd..b5b3f408a658efe15e0f0b584233611291c2867b 100644 (file)
 #include <linux/acpi.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
-#include "hts221.h"
-
-#define I2C_AUTO_INCREMENT     0x80
-
-static int hts221_i2c_read(struct device *dev, u8 addr, int len, u8 *data)
-{
-       struct i2c_msg msg[2];
-       struct i2c_client *client = to_i2c_client(dev);
-
-       if (len > 1)
-               addr |= I2C_AUTO_INCREMENT;
-
-       msg[0].addr = client->addr;
-       msg[0].flags = client->flags;
-       msg[0].len = 1;
-       msg[0].buf = &addr;
-
-       msg[1].addr = client->addr;
-       msg[1].flags = client->flags | I2C_M_RD;
-       msg[1].len = len;
-       msg[1].buf = data;
-
-       return i2c_transfer(client->adapter, msg, 2);
-}
+#include <linux/regmap.h>
 
-static int hts221_i2c_write(struct device *dev, u8 addr, int len, u8 *data)
-{
-       u8 send[len + 1];
-       struct i2c_msg msg;
-       struct i2c_client *client = to_i2c_client(dev);
-
-       if (len > 1)
-               addr |= I2C_AUTO_INCREMENT;
-
-       send[0] = addr;
-       memcpy(&send[1], data, len * sizeof(u8));
-
-       msg.addr = client->addr;
-       msg.flags = client->flags;
-       msg.len = len + 1;
-       msg.buf = send;
+#include "hts221.h"
 
-       return i2c_transfer(client->adapter, &msg, 1);
-}
+#define HTS221_I2C_AUTO_INCREMENT      BIT(7)
 
-static const struct hts221_transfer_function hts221_transfer_fn = {
-       .read = hts221_i2c_read,
-       .write = hts221_i2c_write,
+static const struct regmap_config hts221_i2c_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .write_flag_mask = HTS221_I2C_AUTO_INCREMENT,
+       .read_flag_mask = HTS221_I2C_AUTO_INCREMENT,
 };
 
 static int hts221_i2c_probe(struct i2c_client *client,
                            const struct i2c_device_id *id)
 {
+       struct regmap *regmap;
+
+       regmap = devm_regmap_init_i2c(client, &hts221_i2c_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(&client->dev, "Failed to register i2c regmap %d\n",
+                       (int)PTR_ERR(regmap));
+               return PTR_ERR(regmap);
+       }
+
        return hts221_probe(&client->dev, client->irq,
-                           client->name, &hts221_transfer_fn);
+                           client->name, regmap);
 }
 
 static const struct acpi_device_id hts221_acpi_match[] = {
index 55b29b53b9d1b97861ab21b99f064561300b91ac..9c005f0370266d83dd4c6f81c4862f05043d62f8 100644 (file)
 #include <linux/module.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
-#include "hts221.h"
-
-#define SENSORS_SPI_READ       0x80
-#define SPI_AUTO_INCREMENT     0x40
-
-static int hts221_spi_read(struct device *dev, u8 addr, int len, u8 *data)
-{
-       int err;
-       struct spi_device *spi = to_spi_device(dev);
-       struct iio_dev *iio_dev = spi_get_drvdata(spi);
-       struct hts221_hw *hw = iio_priv(iio_dev);
-
-       struct spi_transfer xfers[] = {
-               {
-                       .tx_buf = hw->tb.tx_buf,
-                       .bits_per_word = 8,
-                       .len = 1,
-               },
-               {
-                       .rx_buf = hw->tb.rx_buf,
-                       .bits_per_word = 8,
-                       .len = len,
-               }
-       };
-
-       if (len > 1)
-               addr |= SPI_AUTO_INCREMENT;
-       hw->tb.tx_buf[0] = addr | SENSORS_SPI_READ;
-
-       err = spi_sync_transfer(spi, xfers,  ARRAY_SIZE(xfers));
-       if (err < 0)
-               return err;
-
-       memcpy(data, hw->tb.rx_buf, len * sizeof(u8));
-
-       return len;
-}
-
-static int hts221_spi_write(struct device *dev, u8 addr, int len, u8 *data)
-{
-       struct spi_device *spi = to_spi_device(dev);
-       struct iio_dev *iio_dev = spi_get_drvdata(spi);
-       struct hts221_hw *hw = iio_priv(iio_dev);
-
-       struct spi_transfer xfers = {
-               .tx_buf = hw->tb.tx_buf,
-               .bits_per_word = 8,
-               .len = len + 1,
-       };
-
-       if (len >= HTS221_TX_MAX_LENGTH)
-               return -ENOMEM;
+#include <linux/regmap.h>
 
-       if (len > 1)
-               addr |= SPI_AUTO_INCREMENT;
-       hw->tb.tx_buf[0] = addr;
-       memcpy(&hw->tb.tx_buf[1], data, len);
+#include "hts221.h"
 
-       return spi_sync_transfer(spi, &xfers, 1);
-}
+#define HTS221_SPI_READ                        BIT(7)
+#define HTS221_SPI_AUTO_INCREMENT      BIT(6)
 
-static const struct hts221_transfer_function hts221_transfer_fn = {
-       .read = hts221_spi_read,
-       .write = hts221_spi_write,
+static const struct regmap_config hts221_spi_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .write_flag_mask = HTS221_SPI_AUTO_INCREMENT,
+       .read_flag_mask = HTS221_SPI_READ | HTS221_SPI_AUTO_INCREMENT,
 };
 
 static int hts221_spi_probe(struct spi_device *spi)
 {
+       struct regmap *regmap;
+
+       regmap = devm_regmap_init_spi(spi, &hts221_spi_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(&spi->dev, "Failed to register spi regmap %d\n",
+                       (int)PTR_ERR(regmap));
+               return PTR_ERR(regmap);
+       }
+
        return hts221_probe(&spi->dev, spi->irq,
-                           spi->modalias, &hts221_transfer_fn);
+                           spi->modalias, regmap);
 }
 
 static const struct of_device_id hts221_spi_of_match[] = {
index 8fdd723afa050bdefd41b90e86c831300674bfa6..a3cc7cd97026585a58a49ecbe6ff4ccd60305c62 100644 (file)
@@ -27,7 +27,7 @@ enum st_lsm6dsx_hw_id {
        ST_LSM6DSX_MAX_ID,
 };
 
-#define ST_LSM6DSX_BUFF_SIZE           256
+#define ST_LSM6DSX_BUFF_SIZE           400
 #define ST_LSM6DSX_CHAN_SIZE           2
 #define ST_LSM6DSX_SAMPLE_SIZE         6
 #define ST_LSM6DSX_MAX_WORD_LEN                ((32 / ST_LSM6DSX_SAMPLE_SIZE) * \
@@ -57,6 +57,20 @@ struct st_lsm6dsx_fifo_ops {
        u8 th_wl;
 };
 
+/**
+ * struct st_lsm6dsx_hw_ts_settings - ST IMU hw timer settings
+ * @timer_en: Hw timer enable register info (addr + mask).
+ * @hr_timer: Hw timer resolution register info (addr + mask).
+ * @fifo_en: Hw timer FIFO enable register info (addr + mask).
+ * @decimator: Hw timer FIFO decimator register info (addr + mask).
+ */
+struct st_lsm6dsx_hw_ts_settings {
+       struct st_lsm6dsx_reg timer_en;
+       struct st_lsm6dsx_reg hr_timer;
+       struct st_lsm6dsx_reg fifo_en;
+       struct st_lsm6dsx_reg decimator;
+};
+
 /**
  * struct st_lsm6dsx_settings - ST IMU sensor settings
  * @wai: Sensor WhoAmI default value.
@@ -64,6 +78,7 @@ struct st_lsm6dsx_fifo_ops {
  * @id: List of hw id supported by the driver configuration.
  * @decimator: List of decimator register info (addr + mask).
  * @fifo_ops: Sensor hw FIFO parameters.
+ * @ts_settings: Hw timer related settings.
  */
 struct st_lsm6dsx_settings {
        u8 wai;
@@ -71,6 +86,7 @@ struct st_lsm6dsx_settings {
        enum st_lsm6dsx_hw_id id[ST_LSM6DSX_MAX_ID];
        struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID];
        struct st_lsm6dsx_fifo_ops fifo_ops;
+       struct st_lsm6dsx_hw_ts_settings ts_settings;
 };
 
 enum st_lsm6dsx_sensor_id {
@@ -94,8 +110,7 @@ enum st_lsm6dsx_fifo_mode {
  * @watermark: Sensor watermark level.
  * @sip: Number of samples in a given pattern.
  * @decimator: FIFO decimation factor.
- * @delta_ts: Delta time between two consecutive interrupts.
- * @ts: Latest timestamp from the interrupt handler.
+ * @ts_ref: Sensor timestamp reference for hw one.
  */
 struct st_lsm6dsx_sensor {
        char name[32];
@@ -108,9 +123,7 @@ struct st_lsm6dsx_sensor {
        u16 watermark;
        u8 sip;
        u8 decimator;
-
-       s64 delta_ts;
-       s64 ts;
+       s64 ts_ref;
 };
 
 /**
@@ -122,7 +135,8 @@ struct st_lsm6dsx_sensor {
  * @conf_lock: Mutex to prevent concurrent FIFO configuration update.
  * @fifo_mode: FIFO operating mode supported by the device.
  * @enable_mask: Enabled sensor bitmask.
- * @sip: Total number of samples (acc/gyro) in a given pattern.
+ * @ts_sip: Total number of timestamp samples in a given pattern.
+ * @sip: Total number of samples (acc/gyro/ts) in a given pattern.
  * @buff: Device read buffer.
  * @iio_devs: Pointers to acc/gyro iio_dev instances.
  * @settings: Pointer to the specific sensor settings in use.
@@ -137,6 +151,7 @@ struct st_lsm6dsx_hw {
 
        enum st_lsm6dsx_fifo_mode fifo_mode;
        u8 enable_mask;
+       u8 ts_sip;
        u8 sip;
 
        u8 *buff;
index 1d6aa9b1a4cf19a0f4d91c1fede63199b9a572b7..1045e025e92b8f14cb889ddf8ede58e109543a3c 100644 (file)
 #define ST_LSM6DSX_FIFO_ODR_MASK               GENMASK(6, 3)
 #define ST_LSM6DSX_FIFO_EMPTY_MASK             BIT(12)
 #define ST_LSM6DSX_REG_FIFO_OUTL_ADDR          0x3e
+#define ST_LSM6DSX_REG_TS_RESET_ADDR           0x42
 
 #define ST_LSM6DSX_MAX_FIFO_ODR_VAL            0x08
 
+#define ST_LSM6DSX_TS_SENSITIVITY              25000UL /* 25us */
+#define ST_LSM6DSX_TS_RESET_VAL                        0xaa
+
 struct st_lsm6dsx_decimator_entry {
        u8 decimator;
        u8 val;
@@ -98,9 +102,10 @@ static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw,
 
 static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
 {
+       u16 max_odr, min_odr, sip = 0, ts_sip = 0;
+       const struct st_lsm6dsx_reg *ts_dec_reg;
        struct st_lsm6dsx_sensor *sensor;
-       u16 max_odr, min_odr, sip = 0;
-       int err, i;
+       int err = 0, i;
        u8 data;
 
        st_lsm6dsx_get_max_min_odr(hw, &max_odr, &min_odr);
@@ -119,6 +124,7 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
                        sensor->decimator = 0;
                        data = 0;
                }
+               ts_sip = max_t(u16, ts_sip, sensor->sip);
 
                dec_reg = &hw->settings->decimator[sensor->id];
                if (dec_reg->addr) {
@@ -131,9 +137,23 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
                }
                sip += sensor->sip;
        }
-       hw->sip = sip;
+       hw->sip = sip + ts_sip;
+       hw->ts_sip = ts_sip;
 
-       return 0;
+       /*
+        * update hw ts decimator if necessary. Decimator for hw timestamp
+        * is always 1 or 0 in order to have a ts sample for each data
+        * sample in FIFO
+        */
+       ts_dec_reg = &hw->settings->ts_settings.decimator;
+       if (ts_dec_reg->addr) {
+               int val, ts_dec = !!hw->ts_sip;
+
+               val = ST_LSM6DSX_SHIFT_VAL(ts_dec, ts_dec_reg->mask);
+               err = regmap_update_bits(hw->regmap, ts_dec_reg->addr,
+                                        ts_dec_reg->mask, val);
+       }
+       return err;
 }
 
 int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
@@ -208,6 +228,28 @@ int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
                                 &wdata, sizeof(wdata));
 }
 
+static int st_lsm6dsx_reset_hw_ts(struct st_lsm6dsx_hw *hw)
+{
+       struct st_lsm6dsx_sensor *sensor;
+       int i, err;
+
+       /* reset hw ts counter */
+       err = regmap_write(hw->regmap, ST_LSM6DSX_REG_TS_RESET_ADDR,
+                          ST_LSM6DSX_TS_RESET_VAL);
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+               sensor = iio_priv(hw->iio_devs[i]);
+               /*
+                * store enable buffer timestamp as reference for
+                * hw timestamp
+                */
+               sensor->ts_ref = iio_get_time_ns(hw->iio_devs[i]);
+       }
+       return 0;
+}
+
 /*
  * Set max bulk read to ST_LSM6DSX_MAX_WORD_LEN in order to avoid
  * a kmalloc for each bus access
@@ -231,6 +273,8 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 *data,
        return 0;
 }
 
+#define ST_LSM6DSX_IIO_BUFF_SIZE       (ALIGN(ST_LSM6DSX_SAMPLE_SIZE, \
+                                              sizeof(s64)) + sizeof(s64))
 /**
  * st_lsm6dsx_read_fifo() - LSM6DS3-LSM6DS3H-LSM6DSL-LSM6DSM read FIFO routine
  * @hw: Pointer to instance of struct st_lsm6dsx_hw.
@@ -243,11 +287,13 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
 {
        u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE;
        u16 fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
-       int err, acc_sip, gyro_sip, read_len, samples, offset;
+       int err, acc_sip, gyro_sip, ts_sip, read_len, offset;
        struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor;
-       s64 acc_ts, acc_delta_ts, gyro_ts, gyro_delta_ts;
-       u8 iio_buff[ALIGN(ST_LSM6DSX_SAMPLE_SIZE, sizeof(s64)) + sizeof(s64)];
+       u8 gyro_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
+       u8 acc_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
+       bool reset_ts = false;
        __le16 fifo_status;
+       s64 ts = 0;
 
        err = regmap_bulk_read(hw->regmap,
                               hw->settings->fifo_ops.fifo_diff.addr,
@@ -260,23 +306,10 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
 
        fifo_len = (le16_to_cpu(fifo_status) & fifo_diff_mask) *
                   ST_LSM6DSX_CHAN_SIZE;
-       samples = fifo_len / ST_LSM6DSX_SAMPLE_SIZE;
        fifo_len = (fifo_len / pattern_len) * pattern_len;
 
-       /*
-        * compute delta timestamp between two consecutive samples
-        * in order to estimate queueing time of data generated
-        * by the sensor
-        */
        acc_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
-       acc_ts = acc_sensor->ts - acc_sensor->delta_ts;
-       acc_delta_ts = div_s64(acc_sensor->delta_ts * acc_sensor->decimator,
-                              samples);
-
        gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]);
-       gyro_ts = gyro_sensor->ts - gyro_sensor->delta_ts;
-       gyro_delta_ts = div_s64(gyro_sensor->delta_ts * gyro_sensor->decimator,
-                               samples);
 
        for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
                err = st_lsm6dsx_read_block(hw, hw->buff, pattern_len);
@@ -287,7 +320,7 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
                 * Data are written to the FIFO with a specific pattern
                 * depending on the configured ODRs. The first sequence of data
                 * stored in FIFO contains the data of all enabled sensors
-                * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated
+                * (e.g. Gx, Gy, Gz, Ax, Ay, Az, Ts), then data are repeated
                 * depending on the value of the decimation factor set for each
                 * sensor.
                 *
@@ -296,35 +329,65 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
                 *   - gyroscope ODR = 208Hz, accelerometer ODR = 104Hz
                 * Since the gyroscope ODR is twice the accelerometer one, the
                 * following pattern is repeated every 9 samples:
-                *   - Gx, Gy, Gz, Ax, Ay, Az, Gx, Gy, Gz
+                *   - Gx, Gy, Gz, Ax, Ay, Az, Ts, Gx, Gy, Gz, Ts, Gx, ..
                 */
                gyro_sip = gyro_sensor->sip;
                acc_sip = acc_sensor->sip;
+               ts_sip = hw->ts_sip;
                offset = 0;
 
                while (acc_sip > 0 || gyro_sip > 0) {
-                       if (gyro_sip-- > 0) {
-                               memcpy(iio_buff, &hw->buff[offset],
+                       if (gyro_sip > 0) {
+                               memcpy(gyro_buff, &hw->buff[offset],
                                       ST_LSM6DSX_SAMPLE_SIZE);
-                               iio_push_to_buffers_with_timestamp(
-                                       hw->iio_devs[ST_LSM6DSX_ID_GYRO],
-                                       iio_buff, gyro_ts);
                                offset += ST_LSM6DSX_SAMPLE_SIZE;
-                               gyro_ts += gyro_delta_ts;
                        }
-
-                       if (acc_sip-- > 0) {
-                               memcpy(iio_buff, &hw->buff[offset],
+                       if (acc_sip > 0) {
+                               memcpy(acc_buff, &hw->buff[offset],
                                       ST_LSM6DSX_SAMPLE_SIZE);
-                               iio_push_to_buffers_with_timestamp(
-                                       hw->iio_devs[ST_LSM6DSX_ID_ACC],
-                                       iio_buff, acc_ts);
                                offset += ST_LSM6DSX_SAMPLE_SIZE;
-                               acc_ts += acc_delta_ts;
                        }
+
+                       if (ts_sip-- > 0) {
+                               u8 data[ST_LSM6DSX_SAMPLE_SIZE];
+
+                               memcpy(data, &hw->buff[offset], sizeof(data));
+                               /*
+                                * hw timestamp is 3B long and it is stored
+                                * in FIFO using 6B as 4th FIFO data set
+                                * according to this schema:
+                                * B0 = ts[15:8], B1 = ts[23:16], B3 = ts[7:0]
+                                */
+                               ts = data[1] << 16 | data[0] << 8 | data[3];
+                               /*
+                                * check if hw timestamp engine is going to
+                                * reset (the sensor generates an interrupt
+                                * to signal the hw timestamp will reset in
+                                * 1.638s)
+                                */
+                               if (!reset_ts && ts >= 0xff0000)
+                                       reset_ts = true;
+                               ts *= ST_LSM6DSX_TS_SENSITIVITY;
+
+                               offset += ST_LSM6DSX_SAMPLE_SIZE;
+                       }
+
+                       if (gyro_sip-- > 0)
+                               iio_push_to_buffers_with_timestamp(
+                                       hw->iio_devs[ST_LSM6DSX_ID_GYRO],
+                                       gyro_buff, gyro_sensor->ts_ref + ts);
+                       if (acc_sip-- > 0)
+                               iio_push_to_buffers_with_timestamp(
+                                       hw->iio_devs[ST_LSM6DSX_ID_ACC],
+                                       acc_buff, acc_sensor->ts_ref + ts);
                }
        }
 
+       if (unlikely(reset_ts)) {
+               err = st_lsm6dsx_reset_hw_ts(hw);
+               if (err < 0)
+                       return err;
+       }
        return read_len;
 }
 
@@ -379,15 +442,12 @@ static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable)
                goto out;
 
        if (hw->enable_mask) {
-               err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT);
+               /* reset hw ts counter */
+               err = st_lsm6dsx_reset_hw_ts(hw);
                if (err < 0)
                        goto out;
 
-               /*
-                * store enable buffer timestamp as reference to compute
-                * first delta timestamp
-                */
-               sensor->ts = iio_get_time_ns(iio_dev);
+               err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT);
        }
 
 out:
@@ -399,25 +459,8 @@ out:
 static irqreturn_t st_lsm6dsx_handler_irq(int irq, void *private)
 {
        struct st_lsm6dsx_hw *hw = private;
-       struct st_lsm6dsx_sensor *sensor;
-       int i;
-
-       if (!hw->sip)
-               return IRQ_NONE;
-
-       for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
-               sensor = iio_priv(hw->iio_devs[i]);
-
-               if (sensor->sip > 0) {
-                       s64 timestamp;
-
-                       timestamp = iio_get_time_ns(hw->iio_devs[i]);
-                       sensor->delta_ts = timestamp - sensor->ts;
-                       sensor->ts = timestamp;
-               }
-       }
 
-       return IRQ_WAKE_THREAD;
+       return hw->sip > 0 ? IRQ_WAKE_THREAD : IRQ_NONE;
 }
 
 static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
index c2fa3239b9c64584ddf14eebb6b307d6b53f997d..8656d72ef4eecd47d8a00de5a747f5a7bd616f82 100644 (file)
@@ -181,6 +181,24 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
                        },
                        .th_wl = 3, /* 1LSB = 2B */
                },
+               .ts_settings = {
+                       .timer_en = {
+                               .addr = 0x58,
+                               .mask = BIT(7),
+                       },
+                       .hr_timer = {
+                               .addr = 0x5c,
+                               .mask = BIT(4),
+                       },
+                       .fifo_en = {
+                               .addr = 0x07,
+                               .mask = BIT(7),
+                       },
+                       .decimator = {
+                               .addr = 0x09,
+                               .mask = GENMASK(5, 3),
+                       },
+               },
        },
        {
                .wai = 0x69,
@@ -209,6 +227,24 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
                        },
                        .th_wl = 3, /* 1LSB = 2B */
                },
+               .ts_settings = {
+                       .timer_en = {
+                               .addr = 0x58,
+                               .mask = BIT(7),
+                       },
+                       .hr_timer = {
+                               .addr = 0x5c,
+                               .mask = BIT(4),
+                       },
+                       .fifo_en = {
+                               .addr = 0x07,
+                               .mask = BIT(7),
+                       },
+                       .decimator = {
+                               .addr = 0x09,
+                               .mask = GENMASK(5, 3),
+                       },
+               },
        },
        {
                .wai = 0x6a,
@@ -238,6 +274,24 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
                        },
                        .th_wl = 3, /* 1LSB = 2B */
                },
+               .ts_settings = {
+                       .timer_en = {
+                               .addr = 0x19,
+                               .mask = BIT(5),
+                       },
+                       .hr_timer = {
+                               .addr = 0x5c,
+                               .mask = BIT(4),
+                       },
+                       .fifo_en = {
+                               .addr = 0x07,
+                               .mask = BIT(7),
+                       },
+                       .decimator = {
+                               .addr = 0x09,
+                               .mask = GENMASK(5, 3),
+                       },
+               },
        },
 };
 
@@ -630,6 +684,44 @@ static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg)
        return err;
 }
 
+static int st_lsm6dsx_init_hw_timer(struct st_lsm6dsx_hw *hw)
+{
+       const struct st_lsm6dsx_hw_ts_settings *ts_settings;
+       int err, val;
+
+       ts_settings = &hw->settings->ts_settings;
+       /* enable hw timestamp generation if necessary */
+       if (ts_settings->timer_en.addr) {
+               val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->timer_en.mask);
+               err = regmap_update_bits(hw->regmap,
+                                        ts_settings->timer_en.addr,
+                                        ts_settings->timer_en.mask, val);
+               if (err < 0)
+                       return err;
+       }
+
+       /* enable high resolution for hw ts timer if necessary */
+       if (ts_settings->hr_timer.addr) {
+               val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->hr_timer.mask);
+               err = regmap_update_bits(hw->regmap,
+                                        ts_settings->hr_timer.addr,
+                                        ts_settings->hr_timer.mask, val);
+               if (err < 0)
+                       return err;
+       }
+
+       /* enable ts queueing in FIFO if necessary */
+       if (ts_settings->fifo_en.addr) {
+               val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->fifo_en.mask);
+               err = regmap_update_bits(hw->regmap,
+                                        ts_settings->fifo_en.addr,
+                                        ts_settings->fifo_en.mask, val);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
 static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
 {
        u8 drdy_int_reg;
@@ -654,10 +746,14 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
        if (err < 0)
                return err;
 
-       return regmap_update_bits(hw->regmap, drdy_int_reg,
-                                 ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK,
-                                 FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK,
-                                            1));
+       err = regmap_update_bits(hw->regmap, drdy_int_reg,
+                                ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK,
+                                FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK,
+                                           1));
+       if (err < 0)
+               return err;
+
+       return st_lsm6dsx_init_hw_timer(hw);
 }
 
 static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
index a8fa00e31c391df5061c29409e2114cf40a212dc..1f112ae15f3c37c9dfda80485a0a3f5a7feef683 100644 (file)
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * apds9960.c - Support for Avago APDS9960 gesture/RGB/ALS/proximity sensor
  *
- * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Copyright (C) 2015, 2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
  *
  * TODO: gesture + proximity calib offsets
  */
@@ -1141,6 +1133,6 @@ static struct i2c_driver apds9960_driver = {
 };
 module_i2c_driver(apds9960_driver);
 
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
 MODULE_DESCRIPTION("ADPS9960 Gesture/RGB/ALS/Proximity sensor");
 MODULE_LICENSE("GPL");
index 8bf282510be6e33cb759e1e7cd0f3186fec8c8e5..8daf6d1f4e054c0081d6a2759b752a49d91b1a4d 100644 (file)
@@ -5,6 +5,16 @@
 
 menu "Digital potentiometers"
 
+config AD5272
+       tristate "Analog Devices AD5272 and similar Digital Potentiometer driver"
+       depends on I2C
+       help
+         Say yes here to build support for the Analog Devices AD5272 and AD5274
+         digital potentiometer chip.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ad5272.
+
 config DS1803
        tristate "Maxim Integrated DS1803 Digital Potentiometer driver"
        depends on I2C
index 1afd1e70f8cc9982fa991c1b418e183df6be628c..dbc139cec3769b61920dbfd6e202b0afae0492e0 100644 (file)
@@ -4,6 +4,7 @@
 #
 
 # When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_AD5272) += ad5272.o
 obj-$(CONFIG_DS1803) += ds1803.o
 obj-$(CONFIG_MAX5481) += max5481.o
 obj-$(CONFIG_MAX5487) += max5487.o
diff --git a/drivers/iio/potentiometer/ad5272.c b/drivers/iio/potentiometer/ad5272.c
new file mode 100644 (file)
index 0000000..154f9a5
--- /dev/null
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Analog Devices AD5272 digital potentiometer driver
+ * Copyright (C) 2018 Phil Reid <preid@electromag.com.au>
+ *
+ * Datasheet: http://www.analog.com/media/en/technical-documentation/data-sheets/AD5272_5274.pdf
+ *
+ * DEVID       #Wipers #Positions      Resistor Opts (kOhm)    i2c address
+ * ad5272      1       1024            20, 50, 100             01011xx
+ * ad5274      1       256             20, 100                 01011xx
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+
+#define  AD5272_RDAC_WR  1
+#define  AD5272_RDAC_RD  2
+#define  AD5272_RESET    4
+#define  AD5272_CTL      7
+
+#define  AD5272_RDAC_WR_EN  BIT(1)
+
+struct ad5272_cfg {
+       int max_pos;
+       int kohms;
+       int shift;
+};
+
+enum ad5272_type {
+       AD5272_020,
+       AD5272_050,
+       AD5272_100,
+       AD5274_020,
+       AD5274_100,
+};
+
+static const struct ad5272_cfg ad5272_cfg[] = {
+       [AD5272_020] = { .max_pos = 1024, .kohms = 20 },
+       [AD5272_050] = { .max_pos = 1024, .kohms = 50 },
+       [AD5272_100] = { .max_pos = 1024, .kohms = 100 },
+       [AD5274_020] = { .max_pos = 256,  .kohms = 20,  .shift = 2 },
+       [AD5274_100] = { .max_pos = 256,  .kohms = 100, .shift = 2 },
+};
+
+struct ad5272_data {
+       struct i2c_client       *client;
+       struct mutex            lock;
+       const struct ad5272_cfg *cfg;
+       u8                      buf[2] ____cacheline_aligned;
+};
+
+static const struct iio_chan_spec ad5272_channel = {
+       .type = IIO_RESISTANCE,
+       .output = 1,
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+};
+
+static int ad5272_write(struct ad5272_data *data, int reg, int val)
+{
+       int ret;
+
+       data->buf[0] = (reg << 2) | ((val >> 8) & 0x3);
+       data->buf[1] = (u8)val;
+
+       mutex_lock(&data->lock);
+       ret = i2c_master_send(data->client, data->buf, sizeof(data->buf));
+       mutex_unlock(&data->lock);
+       return ret < 0 ? ret : 0;
+}
+
+static int ad5272_read(struct ad5272_data *data, int reg, int *val)
+{
+       int ret;
+
+       data->buf[0] = reg << 2;
+       data->buf[1] = 0;
+
+       mutex_lock(&data->lock);
+       ret = i2c_master_send(data->client, data->buf, sizeof(data->buf));
+       if (ret < 0)
+               goto error;
+
+       ret = i2c_master_recv(data->client, data->buf, sizeof(data->buf));
+       if (ret < 0)
+               goto error;
+
+       *val = ((data->buf[0] & 0x3) << 8) | data->buf[1];
+       ret = 0;
+error:
+       mutex_unlock(&data->lock);
+       return ret;
+}
+
+static int ad5272_read_raw(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *chan,
+                          int *val, int *val2, long mask)
+{
+       struct ad5272_data *data = iio_priv(indio_dev);
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW: {
+               ret = ad5272_read(data, AD5272_RDAC_RD, val);
+               *val = *val >> data->cfg->shift;
+               return ret ? ret : IIO_VAL_INT;
+       }
+       case IIO_CHAN_INFO_SCALE:
+               *val = 1000 * data->cfg->kohms;
+               *val2 = data->cfg->max_pos;
+               return IIO_VAL_FRACTIONAL;
+       }
+
+       return -EINVAL;
+}
+
+static int ad5272_write_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int val, int val2, long mask)
+{
+       struct ad5272_data *data = iio_priv(indio_dev);
+
+       if (mask != IIO_CHAN_INFO_RAW)
+               return -EINVAL;
+
+       if (val >= data->cfg->max_pos || val < 0 || val2)
+               return -EINVAL;
+
+       return ad5272_write(data, AD5272_RDAC_WR, val << data->cfg->shift);
+}
+
+static const struct iio_info ad5272_info = {
+       .read_raw = ad5272_read_raw,
+       .write_raw = ad5272_write_raw,
+};
+
+static int ad5272_reset(struct ad5272_data *data)
+{
+       struct gpio_desc *reset_gpio;
+
+       reset_gpio = devm_gpiod_get_optional(&data->client->dev, "reset",
+               GPIOD_OUT_LOW);
+       if (IS_ERR(reset_gpio))
+               return PTR_ERR(reset_gpio);
+
+       if (reset_gpio) {
+               udelay(1);
+               gpiod_set_value(reset_gpio, 1);
+       } else {
+               ad5272_write(data, AD5272_RESET, 0);
+       }
+       usleep_range(1000, 2000);
+
+       return 0;
+}
+
+static int ad5272_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct iio_dev *indio_dev;
+       struct ad5272_data *data;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, indio_dev);
+
+       data = iio_priv(indio_dev);
+       data->client = client;
+       mutex_init(&data->lock);
+       data->cfg = &ad5272_cfg[id->driver_data];
+
+       ret = ad5272_reset(data);
+       if (ret)
+               return ret;
+
+       ret = ad5272_write(data, AD5272_CTL, AD5272_RDAC_WR_EN);
+       if (ret < 0)
+               return -ENODEV;
+
+       indio_dev->dev.parent = dev;
+       indio_dev->info = &ad5272_info;
+       indio_dev->channels = &ad5272_channel;
+       indio_dev->num_channels = 1;
+       indio_dev->name = client->name;
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id ad5272_dt_ids[] = {
+       { .compatible = "adi,ad5272-020", .data = (void *)AD5272_020 },
+       { .compatible = "adi,ad5272-050", .data = (void *)AD5272_050 },
+       { .compatible = "adi,ad5272-100", .data = (void *)AD5272_100 },
+       { .compatible = "adi,ad5274-020", .data = (void *)AD5274_020 },
+       { .compatible = "adi,ad5274-100", .data = (void *)AD5274_100 },
+       {}
+};
+MODULE_DEVICE_TABLE(of, ad5272_dt_ids);
+#endif /* CONFIG_OF */
+
+static const struct i2c_device_id ad5272_id[] = {
+       { "ad5272-020", AD5272_020 },
+       { "ad5272-050", AD5272_050 },
+       { "ad5272-100", AD5272_100 },
+       { "ad5274-020", AD5274_020 },
+       { "ad5274-100", AD5274_100 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, ad5272_id);
+
+static struct i2c_driver ad5272_driver = {
+       .driver = {
+               .name   = "ad5272",
+               .of_match_table = of_match_ptr(ad5272_dt_ids),
+       },
+       .probe          = ad5272_probe,
+       .id_table       = ad5272_id,
+};
+
+module_i2c_driver(ad5272_driver);
+
+MODULE_AUTHOR("Phil Reid <preid@eletromag.com.au>");
+MODULE_DESCRIPTION("AD5272 digital potentiometer");
+MODULE_LICENSE("GPL v2");
index 93f9d4a8c9aa64002762799a216fe2e554cc5752..ca1cce58fe2036586892beccd5932aa621659736 100644 (file)
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * tpl0102.c - Support for Texas Instruments digital potentiometers
  *
- * Copyright (C) 2016 Matt Ranostay <mranostay@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Copyright (C) 2016, 2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
  *
  * TODO: enable/disable hi-z output control
  */
@@ -156,6 +148,6 @@ static struct i2c_driver tpl0102_driver = {
 
 module_i2c_driver(tpl0102_driver);
 
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
 MODULE_DESCRIPTION("TPL0102 digital potentiometer");
 MODULE_LICENSE("GPL");
index 007710991f1507cc4e52fabf2691b6b1b844b8a4..85714055cc74a1f25c58984e437f118ff1cc78a2 100644 (file)
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * lmp91000.c - Support for Texas Instruments digital potentiostats
  *
- * Copyright (C) 2016 Matt Ranostay <mranostay@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Copyright (C) 2016, 2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
  *
  * TODO: bias voltage + polarity control, and multiple chip support
  */
@@ -440,6 +432,6 @@ static struct i2c_driver lmp91000_driver = {
 };
 module_i2c_driver(lmp91000_driver);
 
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
 MODULE_DESCRIPTION("LMP91000 digital potentiostat");
 MODULE_LICENSE("GPL");
index ccda63c5b3c34191a3e8dc65e505ff3d11af7a64..ead9e9f8589487a60fac2dc90a602f9e8a0a410f 100644 (file)
@@ -63,7 +63,7 @@ struct ms5611_state {
 };
 
 int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
-                 const char* name, int type);
+                const char *name, int type);
 int ms5611_remove(struct iio_dev *indio_dev);
 
 #endif /* _MS5611_H */
index b6249af48014a4dfdbf7b9c876272c73935b3c20..f130388a16a0cbbcf72d1bb99a3bd46caa9382a8 100644 (file)
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * as3935.c - Support for AS3935 Franklin lightning sensor
  *
- * Copyright (C) 2014 Matt Ranostay <mranostay@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
+ * Copyright (C) 2014, 2017-2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
  */
 
 #include <linux/module.h>
@@ -502,6 +493,6 @@ static struct spi_driver as3935_driver = {
 };
 module_spi_driver(as3935_driver);
 
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
 MODULE_DESCRIPTION("AS3935 lightning sensor");
 MODULE_LICENSE("GPL");
index 4d56f67b24c6bc3cc8afd748e5b06d69fe77de89..47af54f14756bc6a124e98f9cbfd93792e9e5c8a 100644 (file)
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * pulsedlight-lidar-lite-v2.c - Support for PulsedLight LIDAR sensor
  *
- * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Copyright (C) 2015, 2017-2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
  *
  * TODO: interrupt mode, and signal strength reporting
  */
@@ -377,6 +369,6 @@ static struct i2c_driver lidar_driver = {
 };
 module_i2c_driver(lidar_driver);
 
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
 MODULE_DESCRIPTION("PulsedLight LIDAR sensor");
 MODULE_LICENSE("GPL");
index 5378976d6d27a0b7401f2e10949e161d28c2640d..82e4a62745e24e254af374d709a4292475878041 100644 (file)
@@ -43,6 +43,18 @@ config MLX90614
          This driver can also be built as a module. If so, the module will
          be called mlx90614.
 
+config MLX90632
+       tristate "MLX90632 contact-less infrared sensor with medical accuracy"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         If you say yes here you get support for the Melexis
+         MLX90632 contact-less infrared sensor with medical accuracy
+         connected with I2C.
+
+         This driver can also be built as a module. If so, the module will
+         be called mlx90632.
+
 config TMP006
        tristate "TMP006 infrared thermopile sensor"
        depends on I2C
index 34bd9023727b61279a3256c2fe27fd40fe744e65..34a31db0bb63633f808542d37cf96fb23047e9ee 100644 (file)
@@ -6,6 +6,7 @@
 obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o
 obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o
 obj-$(CONFIG_MLX90614) += mlx90614.o
+obj-$(CONFIG_MLX90632) += mlx90632.o
 obj-$(CONFIG_TMP006) += tmp006.o
 obj-$(CONFIG_TMP007) += tmp007.o
 obj-$(CONFIG_TSYS01) += tsys01.o
index e8b7e0b6c8ad0d114688467f7957e66ec4dc1b29..54e383231d1edef07abf150793656fa0cb9e92e5 100644 (file)
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * maxim_thermocouple.c  - Support for Maxim thermocouple chips
  *
- * Copyright (C) 2016 Matt Ranostay <mranostay@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Copyright (C) 2016-2018 Matt Ranostay
+ * Author: <matt.ranostay@konsulko.com>
  */
 
 #include <linux/module.h>
@@ -281,6 +273,6 @@ static struct spi_driver maxim_thermocouple_driver = {
 };
 module_spi_driver(maxim_thermocouple_driver);
 
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
 MODULE_DESCRIPTION("Maxim thermocouple sensors");
 MODULE_LICENSE("GPL");
diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c
new file mode 100644 (file)
index 0000000..d695ab9
--- /dev/null
@@ -0,0 +1,750 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mlx90632.c - Melexis MLX90632 contactless IR temperature sensor
+ *
+ * Copyright (c) 2017 Melexis <cmo@melexis.com>
+ *
+ * Driver for the Melexis MLX90632 I2C 16-bit IR thermopile sensor
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/math64.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+/* Memory sections addresses */
+#define MLX90632_ADDR_RAM      0x4000 /* Start address of ram */
+#define MLX90632_ADDR_EEPROM   0x2480 /* Start address of user eeprom */
+
+/* EEPROM addresses - used at startup */
+#define MLX90632_EE_CTRL       0x24d4 /* Control register initial value */
+#define MLX90632_EE_I2C_ADDR   0x24d5 /* I2C address register initial value */
+#define MLX90632_EE_VERSION    0x240b /* EEPROM version reg address */
+#define MLX90632_EE_P_R                0x240c /* P_R calibration register 32bit */
+#define MLX90632_EE_P_G                0x240e /* P_G calibration register 32bit */
+#define MLX90632_EE_P_T                0x2410 /* P_T calibration register 32bit */
+#define MLX90632_EE_P_O                0x2412 /* P_O calibration register 32bit */
+#define MLX90632_EE_Aa         0x2414 /* Aa calibration register 32bit */
+#define MLX90632_EE_Ab         0x2416 /* Ab calibration register 32bit */
+#define MLX90632_EE_Ba         0x2418 /* Ba calibration register 32bit */
+#define MLX90632_EE_Bb         0x241a /* Bb calibration register 32bit */
+#define MLX90632_EE_Ca         0x241c /* Ca calibration register 32bit */
+#define MLX90632_EE_Cb         0x241e /* Cb calibration register 32bit */
+#define MLX90632_EE_Da         0x2420 /* Da calibration register 32bit */
+#define MLX90632_EE_Db         0x2422 /* Db calibration register 32bit */
+#define MLX90632_EE_Ea         0x2424 /* Ea calibration register 32bit */
+#define MLX90632_EE_Eb         0x2426 /* Eb calibration register 32bit */
+#define MLX90632_EE_Fa         0x2428 /* Fa calibration register 32bit */
+#define MLX90632_EE_Fb         0x242a /* Fb calibration register 32bit */
+#define MLX90632_EE_Ga         0x242c /* Ga calibration register 32bit */
+
+#define MLX90632_EE_Gb         0x242e /* Gb calibration register 16bit */
+#define MLX90632_EE_Ka         0x242f /* Ka calibration register 16bit */
+
+#define MLX90632_EE_Ha         0x2481 /* Ha customer calib value reg 16bit */
+#define MLX90632_EE_Hb         0x2482 /* Hb customer calib value reg 16bit */
+
+/* Register addresses - volatile */
+#define MLX90632_REG_I2C_ADDR  0x3000 /* Chip I2C address register */
+
+/* Control register address - volatile */
+#define MLX90632_REG_CONTROL   0x3001 /* Control Register address */
+#define   MLX90632_CFG_PWR_MASK                GENMASK(2, 1) /* PowerMode Mask */
+/* PowerModes statuses */
+#define MLX90632_PWR_STATUS(ctrl_val) (ctrl_val << 1)
+#define MLX90632_PWR_STATUS_HALT MLX90632_PWR_STATUS(0) /* hold */
+#define MLX90632_PWR_STATUS_SLEEP_STEP MLX90632_PWR_STATUS(1) /* sleep step*/
+#define MLX90632_PWR_STATUS_STEP MLX90632_PWR_STATUS(2) /* step */
+#define MLX90632_PWR_STATUS_CONTINUOUS MLX90632_PWR_STATUS(3) /* continuous*/
+
+/* Device status register - volatile */
+#define MLX90632_REG_STATUS    0x3fff /* Device status register */
+#define   MLX90632_STAT_BUSY           BIT(10) /* Device busy indicator */
+#define   MLX90632_STAT_EE_BUSY                BIT(9) /* EEPROM busy indicator */
+#define   MLX90632_STAT_BRST           BIT(8) /* Brown out reset indicator */
+#define   MLX90632_STAT_CYCLE_POS      GENMASK(6, 2) /* Data position */
+#define   MLX90632_STAT_DATA_RDY       BIT(0) /* Data ready indicator */
+
+/* RAM_MEAS address-es for each channel */
+#define MLX90632_RAM_1(meas_num)       (MLX90632_ADDR_RAM + 3 * meas_num)
+#define MLX90632_RAM_2(meas_num)       (MLX90632_ADDR_RAM + 3 * meas_num + 1)
+#define MLX90632_RAM_3(meas_num)       (MLX90632_ADDR_RAM + 3 * meas_num + 2)
+
+/* Magic constants */
+#define MLX90632_ID_MEDICAL    0x0105 /* EEPROM DSPv5 Medical device id */
+#define MLX90632_ID_CONSUMER   0x0205 /* EEPROM DSPv5 Consumer device id */
+#define MLX90632_RESET_CMD     0x0006 /* Reset sensor (address or global) */
+#define MLX90632_REF_12                12LL /**< ResCtrlRef value of Ch 1 or Ch 2 */
+#define MLX90632_REF_3         12LL /**< ResCtrlRef value of Channel 3 */
+#define MLX90632_MAX_MEAS_NUM  31 /**< Maximum measurements in list */
+#define MLX90632_SLEEP_DELAY_MS 3000 /**< Autosleep delay */
+
+struct mlx90632_data {
+       struct i2c_client *client;
+       struct mutex lock; /* Multiple reads for single measurement */
+       struct regmap *regmap;
+       u16 emissivity;
+};
+
+static const struct regmap_range mlx90632_volatile_reg_range[] = {
+       regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL),
+       regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS),
+       regmap_reg_range(MLX90632_RAM_1(0),
+                        MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)),
+};
+
+static const struct regmap_access_table mlx90632_volatile_regs_tbl = {
+       .yes_ranges = mlx90632_volatile_reg_range,
+       .n_yes_ranges = ARRAY_SIZE(mlx90632_volatile_reg_range),
+};
+
+static const struct regmap_range mlx90632_read_reg_range[] = {
+       regmap_reg_range(MLX90632_EE_VERSION, MLX90632_EE_Ka),
+       regmap_reg_range(MLX90632_EE_CTRL, MLX90632_EE_I2C_ADDR),
+       regmap_reg_range(MLX90632_EE_Ha, MLX90632_EE_Hb),
+       regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL),
+       regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS),
+       regmap_reg_range(MLX90632_RAM_1(0),
+                        MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)),
+};
+
+static const struct regmap_access_table mlx90632_readable_regs_tbl = {
+       .yes_ranges = mlx90632_read_reg_range,
+       .n_yes_ranges = ARRAY_SIZE(mlx90632_read_reg_range),
+};
+
+static const struct regmap_range mlx90632_no_write_reg_range[] = {
+       regmap_reg_range(MLX90632_EE_VERSION, MLX90632_EE_Ka),
+       regmap_reg_range(MLX90632_RAM_1(0),
+                        MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)),
+};
+
+static const struct regmap_access_table mlx90632_writeable_regs_tbl = {
+       .no_ranges = mlx90632_no_write_reg_range,
+       .n_no_ranges = ARRAY_SIZE(mlx90632_no_write_reg_range),
+};
+
+static const struct regmap_config mlx90632_regmap = {
+       .reg_bits = 16,
+       .val_bits = 16,
+
+       .volatile_table = &mlx90632_volatile_regs_tbl,
+       .rd_table = &mlx90632_readable_regs_tbl,
+       .wr_table = &mlx90632_writeable_regs_tbl,
+
+       .use_single_rw = true,
+       .reg_format_endian = REGMAP_ENDIAN_BIG,
+       .val_format_endian = REGMAP_ENDIAN_BIG,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static s32 mlx90632_pwr_set_sleep_step(struct regmap *regmap)
+{
+       return regmap_update_bits(regmap, MLX90632_REG_CONTROL,
+                                 MLX90632_CFG_PWR_MASK,
+                                 MLX90632_PWR_STATUS_SLEEP_STEP);
+}
+
+static s32 mlx90632_pwr_continuous(struct regmap *regmap)
+{
+       return regmap_update_bits(regmap, MLX90632_REG_CONTROL,
+                                 MLX90632_CFG_PWR_MASK,
+                                 MLX90632_PWR_STATUS_CONTINUOUS);
+}
+
+/**
+ * mlx90632_perform_measurement - Trigger and retrieve current measurement cycle
+ * @*data: pointer to mlx90632_data object containing regmap information
+ *
+ * Perform a measurement and return latest measurement cycle position reported
+ * by sensor. This is a blocking function for 500ms, as that is default sensor
+ * refresh rate.
+ */
+static int mlx90632_perform_measurement(struct mlx90632_data *data)
+{
+       int ret, tries = 100;
+       unsigned int reg_status;
+
+       ret = regmap_update_bits(data->regmap, MLX90632_REG_STATUS,
+                                MLX90632_STAT_DATA_RDY, 0);
+       if (ret < 0)
+               return ret;
+
+       while (tries-- > 0) {
+               ret = regmap_read(data->regmap, MLX90632_REG_STATUS,
+                                 &reg_status);
+               if (ret < 0)
+                       return ret;
+               if (reg_status & MLX90632_STAT_DATA_RDY)
+                       break;
+               usleep_range(10000, 11000);
+       }
+
+       if (tries < 0) {
+               dev_err(&data->client->dev, "data not ready");
+               return -ETIMEDOUT;
+       }
+
+       return (reg_status & MLX90632_STAT_CYCLE_POS) >> 2;
+}
+
+static int mlx90632_channel_new_select(int perform_ret, uint8_t *channel_new,
+                                      uint8_t *channel_old)
+{
+       switch (perform_ret) {
+       case 1:
+               *channel_new = 1;
+               *channel_old = 2;
+               break;
+       case 2:
+               *channel_new = 2;
+               *channel_old = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int mlx90632_read_ambient_raw(struct regmap *regmap,
+                                    s16 *ambient_new_raw, s16 *ambient_old_raw)
+{
+       int ret;
+       unsigned int read_tmp;
+
+       ret = regmap_read(regmap, MLX90632_RAM_3(1), &read_tmp);
+       if (ret < 0)
+               return ret;
+       *ambient_new_raw = (s16)read_tmp;
+
+       ret = regmap_read(regmap, MLX90632_RAM_3(2), &read_tmp);
+       if (ret < 0)
+               return ret;
+       *ambient_old_raw = (s16)read_tmp;
+
+       return ret;
+}
+
+static int mlx90632_read_object_raw(struct regmap *regmap,
+                                   int perform_measurement_ret,
+                                   s16 *object_new_raw, s16 *object_old_raw)
+{
+       int ret;
+       unsigned int read_tmp;
+       s16 read;
+       u8 channel = 0;
+       u8 channel_old = 0;
+
+       ret = mlx90632_channel_new_select(perform_measurement_ret, &channel,
+                                         &channel_old);
+       if (ret != 0)
+               return ret;
+
+       ret = regmap_read(regmap, MLX90632_RAM_2(channel), &read_tmp);
+       if (ret < 0)
+               return ret;
+
+       read = (s16)read_tmp;
+
+       ret = regmap_read(regmap, MLX90632_RAM_1(channel), &read_tmp);
+       if (ret < 0)
+               return ret;
+       *object_new_raw = (read + (s16)read_tmp) / 2;
+
+       ret = regmap_read(regmap, MLX90632_RAM_2(channel_old), &read_tmp);
+       if (ret < 0)
+               return ret;
+       read = (s16)read_tmp;
+
+       ret = regmap_read(regmap, MLX90632_RAM_1(channel_old), &read_tmp);
+       if (ret < 0)
+               return ret;
+       *object_old_raw = (read + (s16)read_tmp) / 2;
+
+       return ret;
+}
+
+static int mlx90632_read_all_channel(struct mlx90632_data *data,
+                                    s16 *ambient_new_raw, s16 *ambient_old_raw,
+                                    s16 *object_new_raw, s16 *object_old_raw)
+{
+       s32 ret, measurement;
+
+       mutex_lock(&data->lock);
+       measurement = mlx90632_perform_measurement(data);
+       if (measurement < 0) {
+               ret = measurement;
+               goto read_unlock;
+       }
+       ret = mlx90632_read_ambient_raw(data->regmap, ambient_new_raw,
+                                       ambient_old_raw);
+       if (ret < 0)
+               goto read_unlock;
+
+       ret = mlx90632_read_object_raw(data->regmap, measurement,
+                                      object_new_raw, object_old_raw);
+read_unlock:
+       mutex_unlock(&data->lock);
+       return ret;
+}
+
+static int mlx90632_read_ee_register(struct regmap *regmap, u16 reg_lsb,
+                                    s32 *reg_value)
+{
+       s32 ret;
+       unsigned int read;
+       u32 value;
+
+       ret = regmap_read(regmap, reg_lsb, &read);
+       if (ret < 0)
+               return ret;
+
+       value = read;
+
+       ret = regmap_read(regmap, reg_lsb + 1, &read);
+       if (ret < 0)
+               return ret;
+
+       *reg_value = (read << 16) | (value & 0xffff);
+
+       return 0;
+}
+
+static s64 mlx90632_preprocess_temp_amb(s16 ambient_new_raw,
+                                       s16 ambient_old_raw, s16 Gb)
+{
+       s64 VR_Ta, kGb, tmp;
+
+       kGb = ((s64)Gb * 1000LL) >> 10ULL;
+       VR_Ta = (s64)ambient_old_raw * 1000000LL +
+               kGb * div64_s64(((s64)ambient_new_raw * 1000LL),
+                       (MLX90632_REF_3));
+       tmp = div64_s64(
+                        div64_s64(((s64)ambient_new_raw * 1000000000000LL),
+                                  (MLX90632_REF_3)), VR_Ta);
+       return div64_s64(tmp << 19ULL, 1000LL);
+}
+
+static s64 mlx90632_preprocess_temp_obj(s16 object_new_raw, s16 object_old_raw,
+                                       s16 ambient_new_raw,
+                                       s16 ambient_old_raw, s16 Ka)
+{
+       s64 VR_IR, kKa, tmp;
+
+       kKa = ((s64)Ka * 1000LL) >> 10ULL;
+       VR_IR = (s64)ambient_old_raw * 1000000LL +
+               kKa * div64_s64(((s64)ambient_new_raw * 1000LL),
+                       (MLX90632_REF_3));
+       tmp = div64_s64(
+                       div64_s64(((s64)((object_new_raw + object_old_raw) / 2)
+                                  * 1000000000000LL), (MLX90632_REF_12)),
+                       VR_IR);
+       return div64_s64((tmp << 19ULL), 1000LL);
+}
+
+static s32 mlx90632_calc_temp_ambient(s16 ambient_new_raw, s16 ambient_old_raw,
+                                     s32 P_T, s32 P_R, s32 P_G, s32 P_O,
+                                     s16 Gb)
+{
+       s64 Asub, Bsub, Ablock, Bblock, Cblock, AMB, sum;
+
+       AMB = mlx90632_preprocess_temp_amb(ambient_new_raw, ambient_old_raw,
+                                          Gb);
+       Asub = ((s64)P_T * 10000000000LL) >> 44ULL;
+       Bsub = AMB - (((s64)P_R * 1000LL) >> 8ULL);
+       Ablock = Asub * (Bsub * Bsub);
+       Bblock = (div64_s64(Bsub * 10000000LL, P_G)) << 20ULL;
+       Cblock = ((s64)P_O * 10000000000LL) >> 8ULL;
+
+       sum = div64_s64(Ablock, 1000000LL) + Bblock + Cblock;
+
+       return div64_s64(sum, 10000000LL);
+}
+
+static s32 mlx90632_calc_temp_object_iteration(s32 prev_object_temp, s64 object,
+                                              s64 TAdut, s32 Fa, s32 Fb,
+                                              s32 Ga, s16 Ha, s16 Hb,
+                                              u16 emissivity)
+{
+       s64 calcedKsTO, calcedKsTA, ir_Alpha, TAdut4, Alpha_corr;
+       s64 Ha_customer, Hb_customer;
+
+       Ha_customer = ((s64)Ha * 1000000LL) >> 14ULL;
+       Hb_customer = ((s64)Hb * 100) >> 10ULL;
+
+       calcedKsTO = ((s64)((s64)Ga * (prev_object_temp - 25 * 1000LL)
+                            * 1000LL)) >> 36LL;
+       calcedKsTA = ((s64)(Fb * (TAdut - 25 * 1000000LL))) >> 36LL;
+       Alpha_corr = div64_s64((((s64)(Fa * 10000000000LL) >> 46LL)
+                               * Ha_customer), 1000LL);
+       Alpha_corr *= ((s64)(1 * 1000000LL + calcedKsTO + calcedKsTA));
+       Alpha_corr = emissivity * div64_s64(Alpha_corr, 100000LL);
+       Alpha_corr = div64_s64(Alpha_corr, 1000LL);
+       ir_Alpha = div64_s64((s64)object * 10000000LL, Alpha_corr);
+       TAdut4 = (div64_s64(TAdut, 10000LL) + 27315) *
+               (div64_s64(TAdut, 10000LL) + 27315) *
+               (div64_s64(TAdut, 10000LL)  + 27315) *
+               (div64_s64(TAdut, 10000LL) + 27315);
+
+       return (int_sqrt64(int_sqrt64(ir_Alpha * 1000000000000LL + TAdut4))
+               - 27315 - Hb_customer) * 10;
+}
+
+static s32 mlx90632_calc_temp_object(s64 object, s64 ambient, s32 Ea, s32 Eb,
+                                    s32 Fa, s32 Fb, s32 Ga, s16 Ha, s16 Hb,
+                                    u16 tmp_emi)
+{
+       s64 kTA, kTA0, TAdut;
+       s64 temp = 25000;
+       s8 i;
+
+       kTA = (Ea * 1000LL) >> 16LL;
+       kTA0 = (Eb * 1000LL) >> 8LL;
+       TAdut = div64_s64(((ambient - kTA0) * 1000000LL), kTA) + 25 * 1000000LL;
+
+       /* Iterations of calculation as described in datasheet */
+       for (i = 0; i < 5; ++i) {
+               temp = mlx90632_calc_temp_object_iteration(temp, object, TAdut,
+                                                          Fa, Fb, Ga, Ha, Hb,
+                                                          tmp_emi);
+       }
+       return temp;
+}
+
+static int mlx90632_calc_object_dsp105(struct mlx90632_data *data, int *val)
+{
+       s32 ret;
+       s32 Ea, Eb, Fa, Fb, Ga;
+       unsigned int read_tmp;
+       s16 Ha, Hb, Gb, Ka;
+       s16 ambient_new_raw, ambient_old_raw, object_new_raw, object_old_raw;
+       s64 object, ambient;
+
+       ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Ea, &Ea);
+       if (ret < 0)
+               return ret;
+       ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Eb, &Eb);
+       if (ret < 0)
+               return ret;
+       ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Fa, &Fa);
+       if (ret < 0)
+               return ret;
+       ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Fb, &Fb);
+       if (ret < 0)
+               return ret;
+       ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Ga, &Ga);
+       if (ret < 0)
+               return ret;
+       ret = regmap_read(data->regmap, MLX90632_EE_Ha, &read_tmp);
+       if (ret < 0)
+               return ret;
+       Ha = (s16)read_tmp;
+       ret = regmap_read(data->regmap, MLX90632_EE_Hb, &read_tmp);
+       if (ret < 0)
+               return ret;
+       Hb = (s16)read_tmp;
+       ret = regmap_read(data->regmap, MLX90632_EE_Gb, &read_tmp);
+       if (ret < 0)
+               return ret;
+       Gb = (s16)read_tmp;
+       ret = regmap_read(data->regmap, MLX90632_EE_Ka, &read_tmp);
+       if (ret < 0)
+               return ret;
+       Ka = (s16)read_tmp;
+
+       ret = mlx90632_read_all_channel(data,
+                                       &ambient_new_raw, &ambient_old_raw,
+                                       &object_new_raw, &object_old_raw);
+       if (ret < 0)
+               return ret;
+
+       ambient = mlx90632_preprocess_temp_amb(ambient_new_raw,
+                                              ambient_old_raw, Gb);
+       object = mlx90632_preprocess_temp_obj(object_new_raw,
+                                             object_old_raw,
+                                             ambient_new_raw,
+                                             ambient_old_raw, Ka);
+
+       *val = mlx90632_calc_temp_object(object, ambient, Ea, Eb, Fa, Fb, Ga,
+                                        Ha, Hb, data->emissivity);
+       return 0;
+}
+
+static int mlx90632_calc_ambient_dsp105(struct mlx90632_data *data, int *val)
+{
+       s32 ret;
+       unsigned int read_tmp;
+       s32 PT, PR, PG, PO;
+       s16 Gb;
+       s16 ambient_new_raw, ambient_old_raw;
+
+       ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_R, &PR);
+       if (ret < 0)
+               return ret;
+       ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_G, &PG);
+       if (ret < 0)
+               return ret;
+       ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_T, &PT);
+       if (ret < 0)
+               return ret;
+       ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_O, &PO);
+       if (ret < 0)
+               return ret;
+       ret = regmap_read(data->regmap, MLX90632_EE_Gb, &read_tmp);
+       if (ret < 0)
+               return ret;
+       Gb = (s16)read_tmp;
+
+       ret = mlx90632_read_ambient_raw(data->regmap, &ambient_new_raw,
+                                       &ambient_old_raw);
+       *val = mlx90632_calc_temp_ambient(ambient_new_raw, ambient_old_raw,
+                                         PT, PR, PG, PO, Gb);
+       return ret;
+}
+
+static int mlx90632_read_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *channel, int *val,
+                            int *val2, long mask)
+{
+       struct mlx90632_data *data = iio_priv(indio_dev);
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_PROCESSED:
+               switch (channel->channel2) {
+               case IIO_MOD_TEMP_AMBIENT:
+                       ret = mlx90632_calc_ambient_dsp105(data, val);
+                       if (ret < 0)
+                               return ret;
+                       return IIO_VAL_INT;
+               case IIO_MOD_TEMP_OBJECT:
+                       ret = mlx90632_calc_object_dsp105(data, val);
+                       if (ret < 0)
+                               return ret;
+                       return IIO_VAL_INT;
+               default:
+                       return -EINVAL;
+               }
+       case IIO_CHAN_INFO_CALIBEMISSIVITY:
+               if (data->emissivity == 1000) {
+                       *val = 1;
+                       *val2 = 0;
+               } else {
+                       *val = 0;
+                       *val2 = data->emissivity * 1000;
+               }
+               return IIO_VAL_INT_PLUS_MICRO;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int mlx90632_write_raw(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *channel, int val,
+                             int val2, long mask)
+{
+       struct mlx90632_data *data = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_CALIBEMISSIVITY:
+               /* Confirm we are within 0 and 1.0 */
+               if (val < 0 || val2 < 0 || val > 1 ||
+                   (val == 1 && val2 != 0))
+                       return -EINVAL;
+               data->emissivity = val * 1000 + val2 / 1000;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct iio_chan_spec mlx90632_channels[] = {
+       {
+               .type = IIO_TEMP,
+               .modified = 1,
+               .channel2 = IIO_MOD_TEMP_AMBIENT,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+       },
+       {
+               .type = IIO_TEMP,
+               .modified = 1,
+               .channel2 = IIO_MOD_TEMP_OBJECT,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+                       BIT(IIO_CHAN_INFO_CALIBEMISSIVITY),
+       },
+};
+
+static const struct iio_info mlx90632_info = {
+       .read_raw = mlx90632_read_raw,
+       .write_raw = mlx90632_write_raw,
+};
+
+static int mlx90632_sleep(struct mlx90632_data *data)
+{
+       regcache_mark_dirty(data->regmap);
+
+       dev_dbg(&data->client->dev, "Requesting sleep");
+       return mlx90632_pwr_set_sleep_step(data->regmap);
+}
+
+static int mlx90632_wakeup(struct mlx90632_data *data)
+{
+       int ret;
+
+       ret = regcache_sync(data->regmap);
+       if (ret < 0) {
+               dev_err(&data->client->dev,
+                       "Failed to sync regmap registers: %d\n", ret);
+               return ret;
+       }
+
+       dev_dbg(&data->client->dev, "Requesting wake-up\n");
+       return mlx90632_pwr_continuous(data->regmap);
+}
+
+static int mlx90632_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       struct iio_dev *indio_dev;
+       struct mlx90632_data *mlx90632;
+       struct regmap *regmap;
+       int ret;
+       unsigned int read;
+
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*mlx90632));
+       if (!indio_dev) {
+               dev_err(&client->dev, "Failed to allocate device\n");
+               return -ENOMEM;
+       }
+
+       regmap = devm_regmap_init_i2c(client, &mlx90632_regmap);
+       if (IS_ERR(regmap)) {
+               ret = PTR_ERR(regmap);
+               dev_err(&client->dev, "Failed to allocate regmap: %d\n", ret);
+               return ret;
+       }
+
+       mlx90632 = iio_priv(indio_dev);
+       i2c_set_clientdata(client, indio_dev);
+       mlx90632->client = client;
+       mlx90632->regmap = regmap;
+
+       mutex_init(&mlx90632->lock);
+       indio_dev->dev.parent = &client->dev;
+       indio_dev->name = id->name;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->info = &mlx90632_info;
+       indio_dev->channels = mlx90632_channels;
+       indio_dev->num_channels = ARRAY_SIZE(mlx90632_channels);
+
+       ret = mlx90632_wakeup(mlx90632);
+       if (ret < 0) {
+               dev_err(&client->dev, "Wakeup failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_read(mlx90632->regmap, MLX90632_EE_VERSION, &read);
+       if (ret < 0) {
+               dev_err(&client->dev, "read of version failed: %d\n", ret);
+               return ret;
+       }
+       if (read == MLX90632_ID_MEDICAL) {
+               dev_dbg(&client->dev,
+                       "Detected Medical EEPROM calibration %x\n", read);
+       } else if (read == MLX90632_ID_CONSUMER) {
+               dev_dbg(&client->dev,
+                       "Detected Consumer EEPROM calibration %x\n", read);
+       } else {
+               dev_err(&client->dev,
+                       "EEPROM version mismatch %x (expected %x or %x)\n",
+                       read, MLX90632_ID_CONSUMER, MLX90632_ID_MEDICAL);
+               return -EPROTONOSUPPORT;
+       }
+
+       mlx90632->emissivity = 1000;
+
+       pm_runtime_disable(&client->dev);
+       ret = pm_runtime_set_active(&client->dev);
+       if (ret < 0) {
+               mlx90632_sleep(mlx90632);
+               return ret;
+       }
+       pm_runtime_enable(&client->dev);
+       pm_runtime_set_autosuspend_delay(&client->dev, MLX90632_SLEEP_DELAY_MS);
+       pm_runtime_use_autosuspend(&client->dev);
+
+       return iio_device_register(indio_dev);
+}
+
+static int mlx90632_remove(struct i2c_client *client)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(client);
+       struct mlx90632_data *data = iio_priv(indio_dev);
+
+       iio_device_unregister(indio_dev);
+
+       pm_runtime_disable(&client->dev);
+       pm_runtime_set_suspended(&client->dev);
+       pm_runtime_put_noidle(&client->dev);
+
+       mlx90632_sleep(data);
+
+       return 0;
+}
+
+static const struct i2c_device_id mlx90632_id[] = {
+       { "mlx90632", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mlx90632_id);
+
+static const struct of_device_id mlx90632_of_match[] = {
+       { .compatible = "melexis,mlx90632" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, mlx90632_of_match);
+
+static int __maybe_unused mlx90632_pm_suspend(struct device *dev)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+       struct mlx90632_data *data = iio_priv(indio_dev);
+
+       return mlx90632_sleep(data);
+}
+
+static int __maybe_unused mlx90632_pm_resume(struct device *dev)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+       struct mlx90632_data *data = iio_priv(indio_dev);
+
+       return mlx90632_wakeup(data);
+}
+
+static UNIVERSAL_DEV_PM_OPS(mlx90632_pm_ops, mlx90632_pm_suspend,
+                           mlx90632_pm_resume, NULL);
+
+static struct i2c_driver mlx90632_driver = {
+       .driver = {
+               .name   = "mlx90632",
+               .of_match_table = mlx90632_of_match,
+               .pm     = &mlx90632_pm_ops,
+       },
+       .probe = mlx90632_probe,
+       .remove = mlx90632_remove,
+       .id_table = mlx90632_id,
+};
+module_i2c_driver(mlx90632_driver);
+
+MODULE_AUTHOR("Crt Mori <cmo@melexis.com>");
+MODULE_DESCRIPTION("Melexis MLX90632 contactless Infra Red temperature sensor driver");
+MODULE_LICENSE("GPL v2");
index f01595593ce2d25558a51d47ec2eece33767f002..079a8410d664408b380cf3052a66635dcc67efd3 100644 (file)
@@ -290,8 +290,12 @@ static int ad7192_setup(struct ad7192_state *st,
        if (pdata->unipolar_en)
                st->conf |= AD7192_CONF_UNIPOLAR;
 
-       if (pdata->burnout_curr_en)
+       if (pdata->burnout_curr_en && pdata->buf_en && !pdata->chop_en) {
                st->conf |= AD7192_CONF_BURN;
+       } else if (pdata->burnout_curr_en) {
+               dev_warn(&st->sd.spi->dev,
+                        "Can't enable burnout currents: see CHOP or buffer\n");
+       }
 
        ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
        if (ret)
index 6ae78d8aa24f7eaeb5a3c9f1558d20a38d1fd882..2de81b53e786c92d1bfae9cb534e733e5798e33d 100644 (file)
  * @trig:              data ready trigger registered with iio
  * @tx:                        transmit buffer
  * @rx:                        receive buffer
- * @buf_lock:          mutex to protect tx and rx
+ * @buf_lock:          mutex to protect tx, rx, read and write frequency
  **/
 struct ade7758_state {
        struct spi_device       *us;
index 7b7ffe5ed18620a2b6e437b9bb8bd86cbc2180b2..4e0dbf5c570535d5435d45f81649bab921c918ad 100644 (file)
 #include "meter.h"
 #include "ade7758.h"
 
-int ade7758_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val)
+static int __ade7758_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val)
 {
-       int ret;
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct ade7758_state *st = iio_priv(indio_dev);
 
-       mutex_lock(&st->buf_lock);
        st->tx[0] = ADE7758_WRITE_REG(reg_address);
        st->tx[1] = val;
 
-       ret = spi_write(st->us, st->tx, 2);
+       return spi_write(st->us, st->tx, 2);
+}
+
+int ade7758_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct ade7758_state *st = iio_priv(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+       ret = __ade7758_spi_write_reg_8(dev, reg_address, val);
        mutex_unlock(&st->buf_lock);
 
        return ret;
@@ -91,7 +99,7 @@ static int ade7758_spi_write_reg_24(struct device *dev, u8 reg_address,
        return ret;
 }
 
-int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
+static int __ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
 {
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct ade7758_state *st = iio_priv(indio_dev);
@@ -111,7 +119,6 @@ int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
                },
        };
 
-       mutex_lock(&st->buf_lock);
        st->tx[0] = ADE7758_READ_REG(reg_address);
        st->tx[1] = 0;
 
@@ -124,7 +131,19 @@ int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
        *val = st->rx[0];
 
 error_ret:
+       return ret;
+}
+
+int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct ade7758_state *st = iio_priv(indio_dev);
+       int ret;
+
+       mutex_lock(&st->buf_lock);
+       ret = __ade7758_spi_read_reg_8(dev, reg_address, val);
        mutex_unlock(&st->buf_lock);
+
        return ret;
 }
 
@@ -484,6 +503,8 @@ static int ade7758_write_samp_freq(struct device *dev, int val)
 {
        int ret;
        u8 reg, t;
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct ade7758_state *st = iio_priv(indio_dev);
 
        switch (val) {
        case 26040:
@@ -499,20 +520,23 @@ static int ade7758_write_samp_freq(struct device *dev, int val)
                t = 3;
                break;
        default:
-               ret = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
 
-       ret = ade7758_spi_read_reg_8(dev, ADE7758_WAVMODE, &reg);
+       mutex_lock(&st->buf_lock);
+
+       ret = __ade7758_spi_read_reg_8(dev, ADE7758_WAVMODE, &reg);
        if (ret)
                goto out;
 
        reg &= ~(5 << 3);
        reg |= t << 5;
 
-       ret = ade7758_spi_write_reg_8(dev, ADE7758_WAVMODE, reg);
+       ret = __ade7758_spi_write_reg_8(dev, ADE7758_WAVMODE, reg);
 
 out:
+       mutex_unlock(&st->buf_lock);
+
        return ret;
 }
 
@@ -526,9 +550,9 @@ static int ade7758_read_raw(struct iio_dev *indio_dev,
 
        switch (mask) {
        case IIO_CHAN_INFO_SAMP_FREQ:
-               mutex_lock(&indio_dev->mlock);
+
                ret = ade7758_read_samp_freq(&indio_dev->dev, val);
-               mutex_unlock(&indio_dev->mlock);
+
                return ret;
        default:
                return -EINVAL;
@@ -547,9 +571,9 @@ static int ade7758_write_raw(struct iio_dev *indio_dev,
        case IIO_CHAN_INFO_SAMP_FREQ:
                if (val2)
                        return -EINVAL;
-               mutex_lock(&indio_dev->mlock);
+
                ret = ade7758_write_samp_freq(&indio_dev->dev, val);
-               mutex_unlock(&indio_dev->mlock);
+
                return ret;
        default:
                return -EINVAL;
index d99cf508d8d060aaeeb3db7af2088d6bf9faaebc..1decb2b8afab1414d561ab55c55580789f8a96c7 100644 (file)
@@ -72,8 +72,8 @@ struct ade7759_state {
 };
 
 static int ade7759_spi_write_reg_8(struct device *dev,
-               u8 reg_address,
-               u8 val)
+                                  u8 reg_address,
+                                  u8 val)
 {
        int ret;
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -91,8 +91,8 @@ static int ade7759_spi_write_reg_8(struct device *dev,
 
 /*Unlocked version of ade7759_spi_write_reg_16 function */
 static int __ade7759_spi_write_reg_16(struct device *dev,
-               u8 reg_address,
-               u16 value)
+                                     u8 reg_address,
+                                     u16 value)
 {
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct ade7759_state *st = iio_priv(indio_dev);
@@ -104,8 +104,8 @@ static int __ade7759_spi_write_reg_16(struct device *dev,
 }
 
 static int ade7759_spi_write_reg_16(struct device *dev,
-               u8 reg_address,
-               u16 value)
+                                   u8 reg_address,
+                                   u16 value)
 {
        int ret;
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -119,8 +119,8 @@ static int ade7759_spi_write_reg_16(struct device *dev,
 }
 
 static int ade7759_spi_read_reg_8(struct device *dev,
-               u8 reg_address,
-               u8 *val)
+                                 u8 reg_address,
+                                 u8 *val)
 {
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct ade7759_state *st = iio_priv(indio_dev);
@@ -128,8 +128,9 @@ static int ade7759_spi_read_reg_8(struct device *dev,
 
        ret = spi_w8r8(st->us, ADE7759_READ_REG(reg_address));
        if (ret < 0) {
-               dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
-                               reg_address);
+               dev_err(&st->us->dev,
+                       "problem when reading 8 bit register 0x%02X",
+                       reg_address);
                return ret;
        }
        *val = ret;
@@ -138,8 +139,8 @@ static int ade7759_spi_read_reg_8(struct device *dev,
 }
 
 static int ade7759_spi_read_reg_16(struct device *dev,
-               u8 reg_address,
-               u16 *val)
+                                  u8 reg_address,
+                                  u16 *val)
 {
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct ade7759_state *st = iio_priv(indio_dev);
@@ -158,8 +159,8 @@ static int ade7759_spi_read_reg_16(struct device *dev,
 }
 
 static int ade7759_spi_read_reg_40(struct device *dev,
-               u8 reg_address,
-               u64 *val)
+                                  u8 reg_address,
+                                  u64 *val)
 {
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct ade7759_state *st = iio_priv(indio_dev);
@@ -179,8 +180,9 @@ static int ade7759_spi_read_reg_40(struct device *dev,
 
        ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
        if (ret) {
-               dev_err(&st->us->dev, "problem when reading 40 bit register 0x%02X",
-                               reg_address);
+               dev_err(&st->us->dev,
+                       "problem when reading 40 bit register 0x%02X",
+                       reg_address);
                goto error_ret;
        }
        *val = ((u64)st->rx[1] << 32) | ((u64)st->rx[2] << 24) |
@@ -192,8 +194,8 @@ error_ret:
 }
 
 static ssize_t ade7759_read_8bit(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                struct device_attribute *attr,
+                                char *buf)
 {
        int ret;
        u8 val = 0;
@@ -207,8 +209,8 @@ static ssize_t ade7759_read_8bit(struct device *dev,
 }
 
 static ssize_t ade7759_read_16bit(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                 struct device_attribute *attr,
+                                 char *buf)
 {
        int ret;
        u16 val = 0;
@@ -222,8 +224,8 @@ static ssize_t ade7759_read_16bit(struct device *dev,
 }
 
 static ssize_t ade7759_read_40bit(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                 struct device_attribute *attr,
+                                 char *buf)
 {
        int ret;
        u64 val = 0;
@@ -237,9 +239,9 @@ static ssize_t ade7759_read_40bit(struct device *dev,
 }
 
 static ssize_t ade7759_write_8bit(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                 struct device_attribute *attr,
+                                 const char *buf,
+                                 size_t len)
 {
        struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
        int ret;
@@ -255,9 +257,9 @@ error_ret:
 }
 
 static ssize_t ade7759_write_16bit(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                  struct device_attribute *attr,
+                                  const char *buf,
+                                  size_t len)
 {
        struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
        int ret;
@@ -277,9 +279,7 @@ static int ade7759_reset(struct device *dev)
        int ret;
        u16 val;
 
-       ret = ade7759_spi_read_reg_16(dev,
-                       ADE7759_MODE,
-                       &val);
+       ret = ade7759_spi_read_reg_16(dev, ADE7759_MODE, &val);
        if (ret < 0)
                return ret;
 
@@ -365,9 +365,7 @@ static int ade7759_stop_device(struct device *dev)
        int ret;
        u16 val;
 
-       ret = ade7759_spi_read_reg_16(dev,
-                       ADE7759_MODE,
-                       &val);
+       ret = ade7759_spi_read_reg_16(dev, ADE7759_MODE, &val);
        if (ret < 0) {
                dev_err(dev, "unable to power down the device, error: %d\n",
                        ret);
@@ -404,16 +402,14 @@ err_ret:
 }
 
 static ssize_t ade7759_read_frequency(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                     struct device_attribute *attr,
+                                     char *buf)
 {
        int ret;
        u16 t;
        int sps;
 
-       ret = ade7759_spi_read_reg_16(dev,
-                       ADE7759_MODE,
-                       &t);
+       ret = ade7759_spi_read_reg_16(dev, ADE7759_MODE, &t);
        if (ret)
                return ret;
 
@@ -424,9 +420,9 @@ static ssize_t ade7759_read_frequency(struct device *dev,
 }
 
 static ssize_t ade7759_write_frequency(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                      struct device_attribute *attr,
+                                      const char *buf,
+                                      size_t len)
 {
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct ade7759_state *st = iio_priv(indio_dev);
index ce51455e2adf631229d21b43e6afb76b2496790c..2da80e079d56ef91cdf31ebadd9c7bc0ffc5a8d3 100644 (file)
@@ -479,6 +479,15 @@ extern int func_ptr_is_kernel_text(void *ptr);
 
 unsigned long int_sqrt(unsigned long);
 
+#if BITS_PER_LONG < 64
+u32 int_sqrt64(u64 x);
+#else
+static inline u32 int_sqrt64(u64 x)
+{
+       return (u32)int_sqrt(x);
+}
+#endif
+
 extern void bust_spinlocks(int yes);
 extern int oops_in_progress;           /* If set, an oops, panic(), BUG() or die() is in progress */
 extern int panic_timeout;
index 080798f17ece0d265d3fd0138993bebf74fdeb26..82bf7747b312be46f834125d52cdd5fd0109ca84 100644 (file)
@@ -266,6 +266,8 @@ enum axp20x_variants {
 #define AXP288_RT_BATT_V_H             0xa0
 #define AXP288_RT_BATT_V_L             0xa1
 
+#define AXP813_ADC_RATE                        0x85
+
 /* Fuel Gauge */
 #define AXP288_FG_RDC1_REG          0xba
 #define AXP288_FG_RDC0_REG          0xbb
index e2d329099bf7483d2f09f48ade59e834cd6b7555..14436f4ca6bd7f340971a4f85ded981a9c0b25dc 100644 (file)
@@ -38,3 +38,33 @@ unsigned long int_sqrt(unsigned long x)
        return y;
 }
 EXPORT_SYMBOL(int_sqrt);
+
+#if BITS_PER_LONG < 64
+/**
+ * int_sqrt64 - strongly typed int_sqrt function when minimum 64 bit input
+ * is expected.
+ * @x: 64bit integer of which to calculate the sqrt
+ */
+u32 int_sqrt64(u64 x)
+{
+       u64 b, m, y = 0;
+
+       if (x <= ULONG_MAX)
+               return int_sqrt((unsigned long) x);
+
+       m = 1ULL << (fls64(x) & ~1ULL);
+       while (m != 0) {
+               b = y + m;
+               y >>= 1;
+
+               if (x >= b) {
+                       x -= b;
+                       y += m;
+               }
+               m >>= 2;
+       }
+
+       return y;
+}
+EXPORT_SYMBOL(int_sqrt64);
+#endif