diff mbox series

[v2,1/5] dt-bindings: iio: temperature: melexis,mlx90614: Document MLX90615 support

Message ID 20230507184649.39290-1-marex@denx.de
State Superseded, archived
Headers show
Series [v2,1/5] dt-bindings: iio: temperature: melexis,mlx90614: Document MLX90615 support | expand

Checks

Context Check Description
robh/checkpatch success
robh/patch-applied success
robh/dtbs-check warning build log
robh/dt-meta-schema success

Commit Message

Marek Vasut May 7, 2023, 6:46 p.m. UTC
Document support for MLX90615 Infra Red Thermometer, which seems to
be the predecesor of MLX90614 . There are significant differences in
the register layout compared to MLX90614, but the functionality of
the device is virtually identical.

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Signed-off-by: Marek Vasut <marex@denx.de>
---
Cc: Crt Mori <cmo@melexis.com>
Cc: Jonathan Cameron <jic23@kernel.org>
Cc: Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>
Cc: Lars-Peter Clausen <lars@metafoo.de>
Cc: Marek Vasut <marex@denx.de>
Cc: Peter Meerwald <pmeerw@pmeerw.net>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: devicetree@vger.kernel.org
Cc: linux-iio@vger.kernel.org
---
V2: - Add spaces to subject tags
    - Add AB from Krzysztof
---
 .../bindings/iio/temperature/melexis,mlx90614.yaml          | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

Comments

Crt Mori May 8, 2023, 9:48 a.m. UTC | #1
Acked-by: Crt Mori <cmo@melexis.com>

(also tested that existing dts's work without any modification).

On Sun, 7 May 2023 at 20:47, Marek Vasut <marex@denx.de> wrote:
>
> Document support for MLX90615 Infra Red Thermometer, which seems to
> be the predecesor of MLX90614 . There are significant differences in
> the register layout compared to MLX90614, but the functionality of
> the device is virtually identical.
>
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> Signed-off-by: Marek Vasut <marex@denx.de>
> ---
> Cc: Crt Mori <cmo@melexis.com>
> Cc: Jonathan Cameron <jic23@kernel.org>
> Cc: Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>
> Cc: Lars-Peter Clausen <lars@metafoo.de>
> Cc: Marek Vasut <marex@denx.de>
> Cc: Peter Meerwald <pmeerw@pmeerw.net>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: devicetree@vger.kernel.org
> Cc: linux-iio@vger.kernel.org
> ---
> V2: - Add spaces to subject tags
>     - Add AB from Krzysztof
> ---
>  .../bindings/iio/temperature/melexis,mlx90614.yaml          | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/iio/temperature/melexis,mlx90614.yaml b/Documentation/devicetree/bindings/iio/temperature/melexis,mlx90614.yaml
> index d6965a0c1cf30..654d31f65d360 100644
> --- a/Documentation/devicetree/bindings/iio/temperature/melexis,mlx90614.yaml
> +++ b/Documentation/devicetree/bindings/iio/temperature/melexis,mlx90614.yaml
> @@ -4,7 +4,7 @@
>  $id: http://devicetree.org/schemas/iio/temperature/melexis,mlx90614.yaml#
>  $schema: http://devicetree.org/meta-schemas/core.yaml#
>
> -title: Melexis MLX90614 contactless IR temperature sensor
> +title: Melexis MLX90614/MLX90615 contactless IR temperature sensor
>
>  maintainers:
>    - Peter Meerwald <pmeerw@pmeerw.net>
> @@ -15,7 +15,9 @@ description: |
>
>  properties:
>    compatible:
> -    const: melexis,mlx90614
> +    enum:
> +      - melexis,mlx90614
> +      - melexis,mlx90615
>
>    reg:
>      maxItems: 1
> --
> 2.39.2
>
Crt Mori May 8, 2023, 9:48 a.m. UTC | #2
Acked-by: Crt Mori <cmo@melexis.com>

On Sun, 7 May 2023 at 20:47, Marek Vasut <marex@denx.de> wrote:
>
> Sort the headers alphabetically. No functional change.
>
> Signed-off-by: Marek Vasut <marex@denx.de>
> ---
> Cc: Crt Mori <cmo@melexis.com>
> Cc: Jonathan Cameron <jic23@kernel.org>
> Cc: Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>
> Cc: Lars-Peter Clausen <lars@metafoo.de>
> Cc: Marek Vasut <marex@denx.de>
> Cc: Peter Meerwald <pmeerw@pmeerw.net>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: devicetree@vger.kernel.org
> Cc: linux-iio@vger.kernel.org
> ---
> V2: New patch
> ---
>  drivers/iio/temperature/mlx90614.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c
> index 909fadb623491..bd92b24918253 100644
> --- a/drivers/iio/temperature/mlx90614.c
> +++ b/drivers/iio/temperature/mlx90614.c
> @@ -19,12 +19,12 @@
>   * the "wakeup" GPIO is not given, power management will be disabled.
>   */
>
> +#include <linux/delay.h>
>  #include <linux/err.h>
> +#include <linux/gpio/consumer.h>
>  #include <linux/i2c.h>
> -#include <linux/module.h>
> -#include <linux/delay.h>
>  #include <linux/jiffies.h>
> -#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
>  #include <linux/pm_runtime.h>
>
>  #include <linux/iio/iio.h>
> --
> 2.39.2
>
Crt Mori May 8, 2023, 9:51 a.m. UTC | #3
I was retaining these macros in case future development would need
them. Since 90614 already has successor in 90632, I can agree to their
removal.

Acked-by: Crt Mori <cmo@melexis.com>

On Sun, 7 May 2023 at 20:47, Marek Vasut <marex@denx.de> wrote:
>
> To simplify addition of support for new parts, drop unused register macros.
> No functional change.
>
> Signed-off-by: Marek Vasut <marex@denx.de>
> ---
> Cc: Crt Mori <cmo@melexis.com>
> Cc: Jonathan Cameron <jic23@kernel.org>
> Cc: Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>
> Cc: Lars-Peter Clausen <lars@metafoo.de>
> Cc: Marek Vasut <marex@denx.de>
> Cc: Peter Meerwald <pmeerw@pmeerw.net>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: devicetree@vger.kernel.org
> Cc: linux-iio@vger.kernel.org
> ---
> V2: New patch
> ---
>  drivers/iio/temperature/mlx90614.c | 4 ----
>  1 file changed, 4 deletions(-)
>
> diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c
> index bd92b24918253..b0f69a7b05abc 100644
> --- a/drivers/iio/temperature/mlx90614.c
> +++ b/drivers/iio/temperature/mlx90614.c
> @@ -35,8 +35,6 @@
>  #define MLX90614_OP_SLEEP      0xff
>
>  /* RAM offsets with 16-bit data, MSB first */
> -#define MLX90614_RAW1  (MLX90614_OP_RAM | 0x04) /* raw data IR channel 1 */
> -#define MLX90614_RAW2  (MLX90614_OP_RAM | 0x05) /* raw data IR channel 2 */
>  #define MLX90614_TA    (MLX90614_OP_RAM | 0x06) /* ambient temperature */
>  #define MLX90614_TOBJ1 (MLX90614_OP_RAM | 0x07) /* object 1 temperature */
>  #define MLX90614_TOBJ2 (MLX90614_OP_RAM | 0x08) /* object 2 temperature */
> @@ -52,8 +50,6 @@
>  #define MLX90614_CONFIG_DUAL_MASK (1 << MLX90614_CONFIG_DUAL_SHIFT)
>  #define MLX90614_CONFIG_FIR_SHIFT 8 /* FIR coefficient */
>  #define MLX90614_CONFIG_FIR_MASK (0x7 << MLX90614_CONFIG_FIR_SHIFT)
> -#define MLX90614_CONFIG_GAIN_SHIFT 11 /* gain */
> -#define MLX90614_CONFIG_GAIN_MASK (0x7 << MLX90614_CONFIG_GAIN_SHIFT)
>
>  /* Timings (in ms) */
>  #define MLX90614_TIMING_EEPROM 20 /* time for EEPROM write/erase to complete */
> --
> 2.39.2
>
Crt Mori May 8, 2023, 10:06 a.m. UTC | #4
I did some basic tests with this patch to ensure that 90614 still
reports data and that frequency can also be adjusted (and read back)
along with emissivity changes and reported values. I all works.

Thanks for your improvement of the driver.

Acked-by: Crt Mori <cmo@melexis.com> (not sure if reviewed by is
expected here as maintainer)
Tested-by: Crt Mori <cmo@melexis.com>

On Sun, 7 May 2023 at 20:47, Marek Vasut <marex@denx.de> wrote:
>
> Factor out all the differences between MLX90614 and other similar chips
> into a structure which describes the chip and allows abstracting out the
> differences from the driver code. No functional change.
>
> This patch moves all the RAM and EEPROM IO opcodes into the descriptor
> structure and combines them, instead of combining the opcode and offset
> in macros.
>
> Signed-off-by: Marek Vasut <marex@denx.de>
> ---
> Cc: Crt Mori <cmo@melexis.com>
> Cc: Jonathan Cameron <jic23@kernel.org>
> Cc: Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>
> Cc: Lars-Peter Clausen <lars@metafoo.de>
> Cc: Marek Vasut <marex@denx.de>
> Cc: Peter Meerwald <pmeerw@pmeerw.net>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: devicetree@vger.kernel.org
> Cc: linux-iio@vger.kernel.org
> ---
> V2: New patch
> ---
>  drivers/iio/temperature/mlx90614.c | 183 +++++++++++++++++++----------
>  1 file changed, 124 insertions(+), 59 deletions(-)
>
> diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c
> index b0f69a7b05abc..d6d2a5afaf8c0 100644
> --- a/drivers/iio/temperature/mlx90614.c
> +++ b/drivers/iio/temperature/mlx90614.c
> @@ -25,6 +25,7 @@
>  #include <linux/i2c.h>
>  #include <linux/jiffies.h>
>  #include <linux/module.h>
> +#include <linux/of_device.h>
>  #include <linux/pm_runtime.h>
>
>  #include <linux/iio/iio.h>
> @@ -34,15 +35,6 @@
>  #define MLX90614_OP_EEPROM     0x20
>  #define MLX90614_OP_SLEEP      0xff
>
> -/* RAM offsets with 16-bit data, MSB first */
> -#define MLX90614_TA    (MLX90614_OP_RAM | 0x06) /* ambient temperature */
> -#define MLX90614_TOBJ1 (MLX90614_OP_RAM | 0x07) /* object 1 temperature */
> -#define MLX90614_TOBJ2 (MLX90614_OP_RAM | 0x08) /* object 2 temperature */
> -
> -/* EEPROM offsets with 16-bit data, MSB first */
> -#define MLX90614_EMISSIVITY    (MLX90614_OP_EEPROM | 0x04) /* emissivity correction coefficient */
> -#define MLX90614_CONFIG                (MLX90614_OP_EEPROM | 0x05) /* configuration register */
> -
>  /* Control bits in configuration register */
>  #define MLX90614_CONFIG_IIR_SHIFT 0 /* IIR coefficient */
>  #define MLX90614_CONFIG_IIR_MASK (0x7 << MLX90614_CONFIG_IIR_SHIFT)
> @@ -62,30 +54,45 @@
>  #define MLX90614_CONST_OFFSET_DEC -13657 /* decimal part of the Kelvin offset */
>  #define MLX90614_CONST_OFFSET_REM 500000 /* remainder of offset (273.15*50) */
>  #define MLX90614_CONST_SCALE 20 /* Scale in milliKelvin (0.02 * 1000) */
> -#define MLX90614_CONST_RAW_EMISSIVITY_MAX 65535 /* max value for emissivity */
> -#define MLX90614_CONST_EMISSIVITY_RESOLUTION 15259 /* 1/65535 ~ 0.000015259 */
>  #define MLX90614_CONST_FIR 0x7 /* Fixed value for FIR part of low pass filter */
>
> +/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */
> +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
> +#define field_prep(_mask, _val)        (((_val) << (ffs(_mask) - 1)) & (_mask))
> +
> +struct mlx_chip_info {
> +       /* EEPROM offsets with 16-bit data, MSB first */
> +       /* emissivity correction coefficient */
> +       u8                      op_eeprom_emissivity;
> +       u8                      op_eeprom_config1;
> +       /* RAM offsets with 16-bit data, MSB first */
> +       /* ambient temperature */
> +       u8                      op_ram_ta;
> +       /* object 1 temperature */
> +       u8                      op_ram_tobj1;
> +       /* object 2 temperature */
> +       u8                      op_ram_tobj2;
> +       u8                      op_sleep;
> +       /* support for two input channels (MLX90614 only) */
> +       u8                      dual_channel;
> +       u8                      wakeup_delay_ms;
> +       u16                     emissivity_max;
> +       u16                     emissivity_res;
> +       u16                     fir_config_mask;
> +       u16                     iir_config_mask;
> +       int                     iir_valid_offset;
> +       u16                     iir_values[8];
> +       int                     iir_freqs[8][2];
> +};
> +
>  struct mlx90614_data {
>         struct i2c_client *client;
>         struct mutex lock; /* for EEPROM access only */
>         struct gpio_desc *wakeup_gpio; /* NULL to disable sleep/wake-up */
> +       const struct mlx_chip_info *chip_info; /* Chip hardware details */
>         unsigned long ready_timestamp; /* in jiffies */
>  };
>
> -/* Bandwidth values for IIR filtering */
> -static const int mlx90614_iir_values[] = {77, 31, 20, 15, 723, 153, 110, 86};
> -static const int mlx90614_freqs[][2] = {
> -       {0, 150000},
> -       {0, 200000},
> -       {0, 310000},
> -       {0, 770000},
> -       {0, 860000},
> -       {1, 100000},
> -       {1, 530000},
> -       {7, 230000}
> -};
> -
>  /*
>   * Erase an address and write word.
>   * The mutex must be locked before calling.
> @@ -125,21 +132,26 @@ static s32 mlx90614_write_word(const struct i2c_client *client, u8 command,
>  }
>
>  /*
> - * Find the IIR value inside mlx90614_iir_values array and return its position
> + * Find the IIR value inside iir_values array and return its position
>   * which is equivalent to the bit value in sensor register
>   */
>  static inline s32 mlx90614_iir_search(const struct i2c_client *client,
>                                       int value)
>  {
> +       struct iio_dev *indio_dev = i2c_get_clientdata(client);
> +       struct mlx90614_data *data = iio_priv(indio_dev);
> +       const struct mlx_chip_info *chip_info = data->chip_info;
>         int i;
>         s32 ret;
>
> -       for (i = 0; i < ARRAY_SIZE(mlx90614_iir_values); ++i) {
> -               if (value == mlx90614_iir_values[i])
> +       for (i = chip_info->iir_valid_offset;
> +            i < ARRAY_SIZE(chip_info->iir_values);
> +            i++) {
> +               if (value == chip_info->iir_values[i])
>                         break;
>         }
>
> -       if (i == ARRAY_SIZE(mlx90614_iir_values))
> +       if (i == ARRAY_SIZE(chip_info->iir_values))
>                 return -EINVAL;
>
>         /*
> @@ -147,17 +159,21 @@ static inline s32 mlx90614_iir_search(const struct i2c_client *client,
>          * we must read them before we actually write
>          * changes
>          */
> -       ret = i2c_smbus_read_word_data(client, MLX90614_CONFIG);
> +       ret = i2c_smbus_read_word_data(client, chip_info->op_eeprom_config1);
>         if (ret < 0)
>                 return ret;
>
> -       ret &= ~MLX90614_CONFIG_FIR_MASK;
> -       ret |= MLX90614_CONST_FIR << MLX90614_CONFIG_FIR_SHIFT;
> -       ret &= ~MLX90614_CONFIG_IIR_MASK;
> -       ret |= i << MLX90614_CONFIG_IIR_SHIFT;
> +       /* Modify FIR on parts which have configurable FIR filter */
> +       if (chip_info->fir_config_mask) {
> +               ret &= ~chip_info->fir_config_mask;
> +               ret |= field_prep(chip_info->fir_config_mask, MLX90614_CONST_FIR);
> +       }
> +
> +       ret &= ~chip_info->iir_config_mask;
> +       ret |= field_prep(chip_info->iir_config_mask, i);
>
>         /* Write changed values */
> -       ret = mlx90614_write_word(client, MLX90614_CONFIG, ret);
> +       ret = mlx90614_write_word(client, chip_info->op_eeprom_config1, ret);
>         return ret;
>  }
>
> @@ -217,22 +233,26 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
>                             int *val2, long mask)
>  {
>         struct mlx90614_data *data = iio_priv(indio_dev);
> -       u8 cmd;
> +       const struct mlx_chip_info *chip_info = data->chip_info;
> +       u8 cmd, idx;
>         s32 ret;
>
>         switch (mask) {
>         case IIO_CHAN_INFO_RAW: /* 0.02K / LSB */
>                 switch (channel->channel2) {
>                 case IIO_MOD_TEMP_AMBIENT:
> -                       cmd = MLX90614_TA;
> +                       cmd = chip_info->op_ram_ta;
>                         break;
>                 case IIO_MOD_TEMP_OBJECT:
> +                       if (chip_info->dual_channel && channel->channel)
> +                               return -EINVAL;
> +
>                         switch (channel->channel) {
>                         case 0:
> -                               cmd = MLX90614_TOBJ1;
> +                               cmd = chip_info->op_ram_tobj1;
>                                 break;
>                         case 1:
> -                               cmd = MLX90614_TOBJ2;
> +                               cmd = chip_info->op_ram_tobj2;
>                                 break;
>                         default:
>                                 return -EINVAL;
> @@ -264,26 +284,26 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
>         case IIO_CHAN_INFO_SCALE:
>                 *val = MLX90614_CONST_SCALE;
>                 return IIO_VAL_INT;
> -       case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */
> +       case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/emissivity_max / LSB */
>                 ret = mlx90614_power_get(data, false);
>                 if (ret < 0)
>                         return ret;
>
>                 mutex_lock(&data->lock);
>                 ret = i2c_smbus_read_word_data(data->client,
> -                                              MLX90614_EMISSIVITY);
> +                                              chip_info->op_eeprom_emissivity);
>                 mutex_unlock(&data->lock);
>                 mlx90614_power_put(data);
>
>                 if (ret < 0)
>                         return ret;
>
> -               if (ret == MLX90614_CONST_RAW_EMISSIVITY_MAX) {
> +               if (ret == chip_info->emissivity_max) {
>                         *val = 1;
>                         *val2 = 0;
>                 } else {
>                         *val = 0;
> -                       *val2 = ret * MLX90614_CONST_EMISSIVITY_RESOLUTION;
> +                       *val2 = ret * chip_info->emissivity_res;
>                 }
>                 return IIO_VAL_INT_PLUS_NANO;
>         case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* IIR setting with
> @@ -293,16 +313,19 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
>                         return ret;
>
>                 mutex_lock(&data->lock);
> -               ret = i2c_smbus_read_word_data(data->client, MLX90614_CONFIG);
> +               ret = i2c_smbus_read_word_data(data->client,
> +                                              chip_info->op_eeprom_config1);
>                 mutex_unlock(&data->lock);
>                 mlx90614_power_put(data);
>
>                 if (ret < 0)
>                         return ret;
>
> -               *val = mlx90614_iir_values[ret & MLX90614_CONFIG_IIR_MASK] / 100;
> -               *val2 = (mlx90614_iir_values[ret & MLX90614_CONFIG_IIR_MASK] % 100) *
> -                       10000;
> +               idx = field_get(chip_info->iir_config_mask, ret) -
> +                     chip_info->iir_valid_offset;
> +
> +               *val = chip_info->iir_values[idx] / 100;
> +               *val2 = (chip_info->iir_values[idx] % 100) * 10000;
>                 return IIO_VAL_INT_PLUS_MICRO;
>         default:
>                 return -EINVAL;
> @@ -314,22 +337,23 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev,
>                              int val2, long mask)
>  {
>         struct mlx90614_data *data = iio_priv(indio_dev);
> +       const struct mlx_chip_info *chip_info = data->chip_info;
>         s32 ret;
>
>         switch (mask) {
> -       case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */
> +       case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/emissivity_max / LSB */
>                 if (val < 0 || val2 < 0 || val > 1 || (val == 1 && val2 != 0))
>                         return -EINVAL;
> -               val = val * MLX90614_CONST_RAW_EMISSIVITY_MAX +
> -                       val2 / MLX90614_CONST_EMISSIVITY_RESOLUTION;
> +               val = val * chip_info->emissivity_max +
> +                     val2 / chip_info->emissivity_res;
>
>                 ret = mlx90614_power_get(data, false);
>                 if (ret < 0)
>                         return ret;
>
>                 mutex_lock(&data->lock);
> -               ret = mlx90614_write_word(data->client, MLX90614_EMISSIVITY,
> -                                         val);
> +               ret = mlx90614_write_word(data->client,
> +                                         chip_info->op_eeprom_emissivity, val);
>                 mutex_unlock(&data->lock);
>                 mlx90614_power_put(data);
>
> @@ -373,11 +397,15 @@ static int mlx90614_read_avail(struct iio_dev *indio_dev,
>                                const int **vals, int *type, int *length,
>                                long mask)
>  {
> +       struct mlx90614_data *data = iio_priv(indio_dev);
> +       const struct mlx_chip_info *chip_info = data->chip_info;
> +
>         switch (mask) {
>         case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
> -               *vals = (int *)mlx90614_freqs;
> +               *vals = (int *)chip_info->iir_freqs;
>                 *type = IIO_VAL_INT_PLUS_MICRO;
> -               *length = 2 * ARRAY_SIZE(mlx90614_freqs);
> +               *length = 2 * (ARRAY_SIZE(chip_info->iir_freqs) -
> +                              chip_info->iir_valid_offset);
>                 return IIO_AVAIL_LIST;
>         default:
>                 return -EINVAL;
> @@ -431,6 +459,7 @@ static const struct iio_info mlx90614_info = {
>  #ifdef CONFIG_PM
>  static int mlx90614_sleep(struct mlx90614_data *data)
>  {
> +       const struct mlx_chip_info *chip_info = data->chip_info;
>         s32 ret;
>
>         if (!data->wakeup_gpio) {
> @@ -443,7 +472,7 @@ static int mlx90614_sleep(struct mlx90614_data *data)
>         mutex_lock(&data->lock);
>         ret = i2c_smbus_xfer(data->client->adapter, data->client->addr,
>                              data->client->flags | I2C_CLIENT_PEC,
> -                            I2C_SMBUS_WRITE, MLX90614_OP_SLEEP,
> +                            I2C_SMBUS_WRITE, chip_info->op_sleep,
>                              I2C_SMBUS_BYTE, NULL);
>         mutex_unlock(&data->lock);
>
> @@ -452,6 +481,8 @@ static int mlx90614_sleep(struct mlx90614_data *data)
>
>  static int mlx90614_wakeup(struct mlx90614_data *data)
>  {
> +       const struct mlx_chip_info *chip_info = data->chip_info;
> +
>         if (!data->wakeup_gpio) {
>                 dev_dbg(&data->client->dev, "Wake-up disabled");
>                 return -ENOSYS;
> @@ -461,7 +492,7 @@ static int mlx90614_wakeup(struct mlx90614_data *data)
>
>         i2c_lock_bus(data->client->adapter, I2C_LOCK_ROOT_ADAPTER);
>         gpiod_direction_output(data->wakeup_gpio, 0);
> -       msleep(MLX90614_TIMING_WAKEUP);
> +       msleep(chip_info->wakeup_delay_ms);
>         gpiod_direction_input(data->wakeup_gpio);
>         i2c_unlock_bus(data->client->adapter, I2C_LOCK_ROOT_ADAPTER);
>
> @@ -474,7 +505,7 @@ static int mlx90614_wakeup(struct mlx90614_data *data)
>          * If the read fails, the controller will probably be reset so that
>          * further reads will work.
>          */
> -       i2c_smbus_read_word_data(data->client, MLX90614_CONFIG);
> +       i2c_smbus_read_word_data(data->client, chip_info->op_eeprom_config1);
>
>         return 0;
>  }
> @@ -523,9 +554,15 @@ static inline struct gpio_desc *mlx90614_probe_wakeup(struct i2c_client *client)
>  /* Return 0 for single sensor, 1 for dual sensor, <0 on error. */
>  static int mlx90614_probe_num_ir_sensors(struct i2c_client *client)
>  {
> +       struct iio_dev *indio_dev = i2c_get_clientdata(client);
> +       struct mlx90614_data *data = iio_priv(indio_dev);
> +       const struct mlx_chip_info *chip_info = data->chip_info;
>         s32 ret;
>
> -       ret = i2c_smbus_read_word_data(client, MLX90614_CONFIG);
> +       if (chip_info->dual_channel)
> +               return 0;
> +
> +       ret = i2c_smbus_read_word_data(client, chip_info->op_eeprom_config1);
>
>         if (ret < 0)
>                 return ret;
> @@ -552,6 +589,7 @@ static int mlx90614_probe(struct i2c_client *client)
>         data->client = client;
>         mutex_init(&data->lock);
>         data->wakeup_gpio = mlx90614_probe_wakeup(client);
> +       data->chip_info = device_get_match_data(&client->dev);
>
>         mlx90614_wakeup(data);
>
> @@ -601,14 +639,41 @@ static void mlx90614_remove(struct i2c_client *client)
>         }
>  }
>
> +static const struct mlx_chip_info mlx90614_chip_info = {
> +       .op_eeprom_emissivity           = MLX90614_OP_EEPROM | 0x04,
> +       .op_eeprom_config1              = MLX90614_OP_EEPROM | 0x05,
> +       .op_ram_ta                      = MLX90614_OP_RAM | 0x06,
> +       .op_ram_tobj1                   = MLX90614_OP_RAM | 0x07,
> +       .op_ram_tobj2                   = MLX90614_OP_RAM | 0x08,
> +       .op_sleep                       = MLX90614_OP_SLEEP,
> +       .dual_channel                   = true,
> +       .wakeup_delay_ms                = MLX90614_TIMING_WAKEUP,
> +       .emissivity_max                 = 65535,
> +       .emissivity_res                 = 1000000000 / 65535,
> +       .fir_config_mask                = MLX90614_CONFIG_FIR_MASK,
> +       .iir_config_mask                = MLX90614_CONFIG_IIR_MASK,
> +       .iir_valid_offset               = 0,
> +       .iir_values                     = { 77, 31, 20, 15, 723, 153, 110, 86 },
> +       .iir_freqs                      = {
> +               { 0, 150000 },  /* 13% ~= 0.15 Hz */
> +               { 0, 200000 },  /* 17% ~= 0.20 Hz */
> +               { 0, 310000 },  /* 25% ~= 0.31 Hz */
> +               { 0, 770000 },  /* 50% ~= 0.77 Hz */
> +               { 0, 860000 },  /* 57% ~= 0.86 Hz */
> +               { 1, 100000 },  /* 67% ~= 1.10 Hz */
> +               { 1, 530000 },  /* 80% ~= 1.53 Hz */
> +               { 7, 230000 }   /* 100% ~= 7.23 Hz */
> +       },
> +};
> +
>  static const struct i2c_device_id mlx90614_id[] = {
> -       { "mlx90614", 0 },
> +       { "mlx90614", .driver_data = (kernel_ulong_t)&mlx90614_chip_info },
>         { }
>  };
>  MODULE_DEVICE_TABLE(i2c, mlx90614_id);
>
>  static const struct of_device_id mlx90614_of_match[] = {
> -       { .compatible = "melexis,mlx90614" },
> +       { .compatible = "melexis,mlx90614", .data = &mlx90614_chip_info },
>         { }
>  };
>  MODULE_DEVICE_TABLE(of, mlx90614_of_match);
> --
> 2.39.2
>
Crt Mori May 8, 2023, 10:10 a.m. UTC | #5
On Sun, 7 May 2023 at 20:47, Marek Vasut <marex@denx.de> wrote:
>
> Add support for MLX90615 Infra Red Thermometer, which seems to be
> the predecesor of MLX90614 . There are significant differences in
> the register layout compared to MLX90614, but the functionality
> of the device is virtually identical.
>
> The following differences have been identified:
> - RAM/EEPROM/SLEEP access opcodes are different
> - RAM/EEPROM registers are at different offsets
> - EEPROM emissivity and configuration registers are at different offsets
> - EEPROM configuration register bits are shuffled around
> - EEPROM emissivity settings are 14 bit on MLX90615 , 16 bit on MLX90614
> - MLX90615 can only ever support one sensor, MLX90614 could support two
> - FIR filter is set to fixed settings on MLX90615
> - IIR filter coefficients are different
>
> This patch fills in the MLX90615 specific description and quirk handling.
>
> Signed-off-by: Marek Vasut <marex@denx.de>
> ---
> NOTE: The IIR coefficients need to be checked
> ---
> Cc: Crt Mori <cmo@melexis.com>
> Cc: Jonathan Cameron <jic23@kernel.org>
> Cc: Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>
> Cc: Lars-Peter Clausen <lars@metafoo.de>
> Cc: Marek Vasut <marex@denx.de>
> Cc: Peter Meerwald <pmeerw@pmeerw.net>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: devicetree@vger.kernel.org
> Cc: linux-iio@vger.kernel.org
> ---
> V2: Split the patch up into cleanups, abstraction and MLX90615 addition
> ---
>  drivers/iio/temperature/mlx90614.c | 49 +++++++++++++++++++++++++++---
>  1 file changed, 45 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c
> index d6d2a5afaf8c0..5bcd323921db5 100644
> --- a/drivers/iio/temperature/mlx90614.c
> +++ b/drivers/iio/temperature/mlx90614.c
> @@ -1,12 +1,15 @@
>  // SPDX-License-Identifier: GPL-2.0-only
>  /*
> - * mlx90614.c - Support for Melexis MLX90614 contactless IR temperature sensor
> + * mlx90614.c - Support for Melexis MLX90614/MLX90615 contactless IR temperature sensor
>   *
>   * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
>   * Copyright (c) 2015 Essensium NV
>   * Copyright (c) 2015 Melexis
>   *
> - * Driver for the Melexis MLX90614 I2C 16-bit IR thermopile sensor
> + * Driver for the Melexis MLX90614/MLX90615 I2C 16-bit IR thermopile sensor
> + *
> + * MLX90614 - 17-bit ADC + MLX90302 DSP
> + * MLX90615 - 16-bit ADC + MLX90325 DSP
>   *
>   * (7-bit I2C slave address 0x5a, 100KHz bus speed only!)
>   *
> @@ -35,6 +38,10 @@
>  #define MLX90614_OP_EEPROM     0x20
>  #define MLX90614_OP_SLEEP      0xff
>
> +#define MLX90615_OP_EEPROM     0x10
> +#define MLX90615_OP_RAM                0x20
> +#define MLX90615_OP_SLEEP      0xc6
> +
>  /* Control bits in configuration register */
>  #define MLX90614_CONFIG_IIR_SHIFT 0 /* IIR coefficient */
>  #define MLX90614_CONFIG_IIR_MASK (0x7 << MLX90614_CONFIG_IIR_SHIFT)
> @@ -43,11 +50,16 @@
>  #define MLX90614_CONFIG_FIR_SHIFT 8 /* FIR coefficient */
>  #define MLX90614_CONFIG_FIR_MASK (0x7 << MLX90614_CONFIG_FIR_SHIFT)
>
> +#define MLX90615_CONFIG_IIR_SHIFT 12 /* IIR coefficient */
> +#define MLX90615_CONFIG_IIR_MASK (0x7 << MLX90615_CONFIG_IIR_SHIFT)
> +
>  /* Timings (in ms) */
>  #define MLX90614_TIMING_EEPROM 20 /* time for EEPROM write/erase to complete */
>  #define MLX90614_TIMING_WAKEUP 34 /* time to hold SDA low for wake-up */
>  #define MLX90614_TIMING_STARTUP 250 /* time before first data after wake-up */
>
> +#define MLX90615_TIMING_WAKEUP 22 /* time to hold SCL low for wake-up */
> +
>  #define MLX90614_AUTOSLEEP_DELAY 5000 /* default autosleep delay */
>
>  /* Magic constants */
> @@ -306,8 +318,8 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
>                         *val2 = ret * chip_info->emissivity_res;
>                 }
>                 return IIO_VAL_INT_PLUS_NANO;
> -       case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* IIR setting with
> -                                                            FIR = 1024 */
> +       /* IIR setting with FIR=1024 (MLX90614) or FIR=65536 (MLX90615) */
> +       case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
>                 ret = mlx90614_power_get(data, false);
>                 if (ret < 0)
>                         return ret;
> @@ -666,14 +678,43 @@ static const struct mlx_chip_info mlx90614_chip_info = {
>         },
>  };
>
> +static const struct mlx_chip_info mlx90615_chip_info = {
> +       .op_eeprom_emissivity           = MLX90615_OP_EEPROM | 0x03,
> +       .op_eeprom_config1              = MLX90615_OP_EEPROM | 0x02,
> +       .op_ram_ta                      = MLX90615_OP_RAM | 0x06,
> +       .op_ram_tobj1                   = MLX90615_OP_RAM | 0x07,
> +       .op_ram_tobj2                   = MLX90615_OP_RAM | 0x08,
> +       .op_sleep                       = MLX90615_OP_SLEEP,
> +       .dual_channel                   = false,
> +       .wakeup_delay_ms                = MLX90615_TIMING_WAKEUP,
> +       .emissivity_max                 = 16383,
> +       .emissivity_res                 = 1000000000 / 16383,
This makes me wonder if we could just drop the emissivity_res and have
it calculate it using emissivity_max, since both chips will do it.

> +       .fir_config_mask                = 0,    /* MLX90615 FIR is fixed */
> +       .iir_config_mask                = MLX90615_CONFIG_IIR_MASK,
> +       /* IIR value 0 is FORBIDDEN COMBINATION on MLX90615 */
> +       .iir_valid_offset               = 1,
> +       .iir_values                     = { 723, 77, 42, 31, 28, 20, 18 },
> +       .iir_freqs                      = {
> +               { 0, 180000 },  /* 14% ~= 0.18 Hz */
> +               { 0, 200000 },  /* 17% ~= 0.20 Hz */
> +               { 0, 280000 },  /* 20% ~= 0.28 Hz */
> +               { 0, 310000 },  /* 25% ~= 0.31 Hz */
> +               { 0, 420000 },  /* 33% ~= 0.42 Hz */
> +               { 0, 770000 },  /* 50% ~= 0.77 Hz */
> +               { 7, 230000 },  /* 100% ~= 7.23 Hz */
> +       },
> +};
> +
>  static const struct i2c_device_id mlx90614_id[] = {
>         { "mlx90614", .driver_data = (kernel_ulong_t)&mlx90614_chip_info },
> +       { "mlx90615", .driver_data = (kernel_ulong_t)&mlx90615_chip_info },
>         { }
>  };
>  MODULE_DEVICE_TABLE(i2c, mlx90614_id);
>
>  static const struct of_device_id mlx90614_of_match[] = {
>         { .compatible = "melexis,mlx90614", .data = &mlx90614_chip_info },
> +       { .compatible = "melexis,mlx90615", .data = &mlx90615_chip_info },
>         { }
>  };
>  MODULE_DEVICE_TABLE(of, mlx90614_of_match);
> --
> 2.39.2
>
Marek Vasut May 8, 2023, 11:32 a.m. UTC | #6
On 5/8/23 12:10, Crt Mori wrote:

[...]

>> @@ -666,14 +678,43 @@ static const struct mlx_chip_info mlx90614_chip_info = {
>>          },
>>   };
>>
>> +static const struct mlx_chip_info mlx90615_chip_info = {
>> +       .op_eeprom_emissivity           = MLX90615_OP_EEPROM | 0x03,
>> +       .op_eeprom_config1              = MLX90615_OP_EEPROM | 0x02,
>> +       .op_ram_ta                      = MLX90615_OP_RAM | 0x06,
>> +       .op_ram_tobj1                   = MLX90615_OP_RAM | 0x07,
>> +       .op_ram_tobj2                   = MLX90615_OP_RAM | 0x08,
>> +       .op_sleep                       = MLX90615_OP_SLEEP,
>> +       .dual_channel                   = false,
>> +       .wakeup_delay_ms                = MLX90615_TIMING_WAKEUP,
>> +       .emissivity_max                 = 16383,
>> +       .emissivity_res                 = 1000 000 000 / 16383,
> This makes me wonder if we could just drop the emissivity_res and have
> it calculate it using emissivity_max, since both chips will do it.

We can do that (i.e. change done locally now).

>> +       .fir_config_mask                = 0,    /* MLX90615 FIR is fixed */
>> +       .iir_config_mask                = MLX90615_CONFIG_IIR_MASK,
>> +       /* IIR value 0 is FORBIDDEN COMBINATION on MLX90615 */
>> +       .iir_valid_offset               = 1,
>> +       .iir_values                     = { 723, 77, 42, 31, 28, 20, 18 },
>> +       .iir_freqs                      = {
>> +               { 0, 180000 },  /* 14% ~= 0.18 Hz */
>> +               { 0, 200000 },  /* 17% ~= 0.20 Hz */
>> +               { 0, 280000 },  /* 20% ~= 0.28 Hz */
>> +               { 0, 310000 },  /* 25% ~= 0.31 Hz */
>> +               { 0, 420000 },  /* 33% ~= 0.42 Hz */
>> +               { 0, 770000 },  /* 50% ~= 0.77 Hz */
>> +               { 7, 230000 },  /* 100% ~= 7.23 Hz */

Before I send a V3, can you please double-check these ^ IIR coefficients 
? I approximated those, but I suspect my approximation might not be 
accurate.

[...]
Crt Mori May 10, 2023, 7:33 a.m. UTC | #7
On Mon, 8 May 2023 at 13:32, Marek Vasut <marex@denx.de> wrote:
>
> On 5/8/23 12:10, Crt Mori wrote:
>
> [...]
>
> >> @@ -666,14 +678,43 @@ static const struct mlx_chip_info mlx90614_chip_info = {
> >>          },
> >>   };
> >>
> >> +static const struct mlx_chip_info mlx90615_chip_info = {
> >> +       .op_eeprom_emissivity           = MLX90615_OP_EEPROM | 0x03,
> >> +       .op_eeprom_config1              = MLX90615_OP_EEPROM | 0x02,
> >> +       .op_ram_ta                      = MLX90615_OP_RAM | 0x06,
> >> +       .op_ram_tobj1                   = MLX90615_OP_RAM | 0x07,
> >> +       .op_ram_tobj2                   = MLX90615_OP_RAM | 0x08,
> >> +       .op_sleep                       = MLX90615_OP_SLEEP,
> >> +       .dual_channel                   = false,
> >> +       .wakeup_delay_ms                = MLX90615_TIMING_WAKEUP,
> >> +       .emissivity_max                 = 16383,
> >> +       .emissivity_res                 = 1000 000 000 / 16383,
> > This makes me wonder if we could just drop the emissivity_res and have
> > it calculate it using emissivity_max, since both chips will do it.
>
> We can do that (i.e. change done locally now).
>
> >> +       .fir_config_mask                = 0,    /* MLX90615 FIR is fixed */
> >> +       .iir_config_mask                = MLX90615_CONFIG_IIR_MASK,
> >> +       /* IIR value 0 is FORBIDDEN COMBINATION on MLX90615 */
> >> +       .iir_valid_offset               = 1,
> >> +       .iir_values                     = { 723, 77, 42, 31, 28, 20, 18 },
> >> +       .iir_freqs                      = {
> >> +               { 0, 180000 },  /* 14% ~= 0.18 Hz */
> >> +               { 0, 200000 },  /* 17% ~= 0.20 Hz */
> >> +               { 0, 280000 },  /* 20% ~= 0.28 Hz */
> >> +               { 0, 310000 },  /* 25% ~= 0.31 Hz */
> >> +               { 0, 420000 },  /* 33% ~= 0.42 Hz */
> >> +               { 0, 770000 },  /* 50% ~= 0.77 Hz */
> >> +               { 7, 230000 },  /* 100% ~= 7.23 Hz */
>
> Before I send a V3, can you please double-check these ^ IIR coefficients
> ? I approximated those, but I suspect my approximation might not be
> accurate.
>
I have reached out to the developer for the 90615 and here is his message:

0b0000 - Forbidden value
0b0001 - 100% - settling time = refresh rate = 205ms (around 5Hz)
0b0010 - 50% - settling time = 2050ms (around 0.5Hz)
0b0011 - 33% - settling time = 36900ms (around 0.3Hz)
0b0100 - 25% - settling time = 5125ms (around 0.2Hz)
0b0101 - 20% - settling time = 6355ms (around 0.15Hz)
0b0110 - 17% - settling time = 7790ms (around 0.13Hz)
0b0111 - 14% - settling time = 9225ms (around 0.1Hz)

It does differ to yours, so what was your source?
> [...]
Marek Vasut May 10, 2023, 4:25 p.m. UTC | #8
On 5/10/23 09:33, Crt Mori wrote:
> On Mon, 8 May 2023 at 13:32, Marek Vasut <marex@denx.de> wrote:
>>
>> On 5/8/23 12:10, Crt Mori wrote:
>>
>> [...]
>>
>>>> @@ -666,14 +678,43 @@ static const struct mlx_chip_info mlx90614_chip_info = {
>>>>           },
>>>>    };
>>>>
>>>> +static const struct mlx_chip_info mlx90615_chip_info = {
>>>> +       .op_eeprom_emissivity           = MLX90615_OP_EEPROM | 0x03,
>>>> +       .op_eeprom_config1              = MLX90615_OP_EEPROM | 0x02,
>>>> +       .op_ram_ta                      = MLX90615_OP_RAM | 0x06,
>>>> +       .op_ram_tobj1                   = MLX90615_OP_RAM | 0x07,
>>>> +       .op_ram_tobj2                   = MLX90615_OP_RAM | 0x08,
>>>> +       .op_sleep                       = MLX90615_OP_SLEEP,
>>>> +       .dual_channel                   = false,
>>>> +       .wakeup_delay_ms                = MLX90615_TIMING_WAKEUP,
>>>> +       .emissivity_max                 = 16383,
>>>> +       .emissivity_res                 = 1000 000 000 / 16383,
>>> This makes me wonder if we could just drop the emissivity_res and have
>>> it calculate it using emissivity_max, since both chips will do it.
>>
>> We can do that (i.e. change done locally now).
>>
>>>> +       .fir_config_mask                = 0,    /* MLX90615 FIR is fixed */
>>>> +       .iir_config_mask                = MLX90615_CONFIG_IIR_MASK,
>>>> +       /* IIR value 0 is FORBIDDEN COMBINATION on MLX90615 */
>>>> +       .iir_valid_offset               = 1,
>>>> +       .iir_values                     = { 723, 77, 42, 31, 28, 20, 18 },
>>>> +       .iir_freqs                      = {
>>>> +               { 0, 180000 },  /* 14% ~= 0.18 Hz */
>>>> +               { 0, 200000 },  /* 17% ~= 0.20 Hz */
>>>> +               { 0, 280000 },  /* 20% ~= 0.28 Hz */
>>>> +               { 0, 310000 },  /* 25% ~= 0.31 Hz */
>>>> +               { 0, 420000 },  /* 33% ~= 0.42 Hz */
>>>> +               { 0, 770000 },  /* 50% ~= 0.77 Hz */
>>>> +               { 7, 230000 },  /* 100% ~= 7.23 Hz */
>>
>> Before I send a V3, can you please double-check these ^ IIR coefficients
>> ? I approximated those, but I suspect my approximation might not be
>> accurate.
>>
> I have reached out to the developer for the 90615 and here is his message:
> 
> 0b0000 - Forbidden value
> 0b0001 - 100% - settling time = refresh rate = 205ms (around 5Hz)
> 0b0010 - 50% - settling time = 2050ms (around 0.5Hz)
> 0b0011 - 33% - settling time = 36900ms (around 0.3Hz)
> 0b0100 - 25% - settling time = 5125ms (around 0.2Hz)
> 0b0101 - 20% - settling time = 6355ms (around 0.15Hz)
> 0b0110 - 17% - settling time = 7790ms (around 0.13Hz)
> 0b0111 - 14% - settling time = 9225ms (around 0.1Hz)
> 
> It does differ to yours, so what was your source?

Approximation, really ... clearly they were wrong, so thanks for checking !

Fixed in V3.
diff mbox series

Patch

diff --git a/Documentation/devicetree/bindings/iio/temperature/melexis,mlx90614.yaml b/Documentation/devicetree/bindings/iio/temperature/melexis,mlx90614.yaml
index d6965a0c1cf30..654d31f65d360 100644
--- a/Documentation/devicetree/bindings/iio/temperature/melexis,mlx90614.yaml
+++ b/Documentation/devicetree/bindings/iio/temperature/melexis,mlx90614.yaml
@@ -4,7 +4,7 @@ 
 $id: http://devicetree.org/schemas/iio/temperature/melexis,mlx90614.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Melexis MLX90614 contactless IR temperature sensor
+title: Melexis MLX90614/MLX90615 contactless IR temperature sensor
 
 maintainers:
   - Peter Meerwald <pmeerw@pmeerw.net>
@@ -15,7 +15,9 @@  description: |
 
 properties:
   compatible:
-    const: melexis,mlx90614
+    enum:
+      - melexis,mlx90614
+      - melexis,mlx90615
 
   reg:
     maxItems: 1