Re: [PATCH 1/2] iio: light: vcnl4000 add support for the VCNL4040 proximity and light sensor

2019-03-16 Thread Jonathan Cameron
On Fri, 15 Mar 2019 14:54:24 -0700
"Angus Ainslie (Purism)"  wrote:

> The VCNL4040 is almost identical to the VCNL4200 as far as register
> layout goes but just need to check a different ID register location.
> 
> This does change the initialization sequence of the VCNL4200 to use word
> writes instead of byte writes. The VCNL4200 datasheet says that word read
> and writes should be used to access the registers but I don't have a 4200
> to test with. The VCNL4040 doesn't initialize properly with the byte
> writes.
> 
> devicetree hooks were also added.
> 
> Signed-off-by: Angus Ainslie (Purism) 

Hi Angus,
A few things inline. Also.
1. Please break this up into a series. The word read thing (hopefully
after confirming it is fine on the older parts) should probably got in
as a fix for earlier kernels.  Hence needs to be in its own patch.
2. DT hooks should be in their own patch.
3. After the above we should have a patch adding the new device support.

Mostly good though. Hopefully we'll get confirmation the word change
is fine on all the sensors.  Peter?

Thanks,

Jonathan

> ---
>  drivers/iio/light/vcnl4000.c | 89 ++--
>  1 file changed, 76 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
> index 04fd0d4b6f19..6e1f02aa6696 100644
> --- a/drivers/iio/light/vcnl4000.c
> +++ b/drivers/iio/light/vcnl4000.c
> @@ -10,13 +10,14 @@
>   *
>   * IIO driver for:
>   *   VCNL4000/10/20 (7-bit I2C slave address 0x13)
> + *   VCNL4040 (7-bit I2C slave address 0x60)
>   *   VCNL4200 (7-bit I2C slave address 0x51)
>   *
>   * TODO:
>   *   allow to adjust IR current
>   *   proximity threshold and event handling
>   *   periodic ALS/proximity measurement (VCNL4010/20)
> - *   interrupts (VCNL4010/20, VCNL4200)
> + *   interrupts (VCNL4010/20/40, VCNL4200)
>   */
>  
>  #include 
> @@ -30,6 +31,7 @@
>  #define VCNL4000_DRV_NAME "vcnl4000"
>  #define VCNL4000_PROD_ID 0x01
>  #define VCNL4010_PROD_ID 0x02 /* for VCNL4020, VCNL4010 */
> +#define VCNL4040_PROD_ID 0x86
>  #define VCNL4200_PROD_ID 0x58
>  
>  #define VCNL4000_COMMAND 0x80 /* Command register */
> @@ -49,6 +51,8 @@
>  #define VCNL4200_AL_DATA 0x09 /* Ambient light data */
>  #define VCNL4200_DEV_ID  0x0e /* Device ID, slave address and 
> version */
>  
> +#define VCNL4040_DEV_ID  0x0c /* Device ID, slave address and 
> version */
> +
>  /* Bit masks for COMMAND register */
>  #define VCNL4000_AL_RDY  BIT(6) /* ALS data ready? */
>  #define VCNL4000_PS_RDY  BIT(5) /* proximity data ready? */
> @@ -58,6 +62,7 @@
>  enum vcnl4000_device_ids {
>   VCNL4000,
>   VCNL4010,
> + VCNL4040,
>   VCNL4200,
>  };
>  
> @@ -90,6 +95,7 @@ static const struct i2c_device_id vcnl4000_id[] = {
>   { "vcnl4000", VCNL4000 },
>   { "vcnl4010", VCNL4010 },
>   { "vcnl4020", VCNL4010 },
> + { "vcnl4040", VCNL4040 },
>   { "vcnl4200", VCNL4200 },
>   { }
>  };
> @@ -128,31 +134,56 @@ static int vcnl4000_init(struct vcnl4000_data *data)
>  
>  static int vcnl4200_init(struct vcnl4000_data *data)
>  {
> - int ret;
> + int ret, id;
>  
>   ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID);
>   if (ret < 0)
>   return ret;
>  
> - if ((ret & 0xff) != VCNL4200_PROD_ID)
> - return -ENODEV;
> + id = ret & 0xff;
> +
> + if (id != VCNL4200_PROD_ID) {
> + ret = i2c_smbus_read_word_data(data->client, VCNL4040_DEV_ID);
> + if (ret < 0)
> + return ret;
> +
> + id = ret & 0xff;
> +
> + if (id != VCNL4040_PROD_ID)
> + return -ENODEV;
> +
> + }
> +
> + dev_dbg(>client->dev, "device id 0x%x", id);
>  
>   data->rev = (ret >> 8) & 0xf;
>  
>   /* Set defaults and enable both channels */
> - ret = i2c_smbus_write_byte_data(data->client, VCNL4200_AL_CONF, 0x00);
> + ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, 0x00);
>   if (ret < 0)
>   return ret;
> - ret = i2c_smbus_write_byte_data(data->client, VCNL4200_PS_CONF1, 0x00);
> + ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, 0x00);
>   if (ret < 0)
>   return ret;
>  
> + switch (id) {
> + case VCNL4200_PROD_ID:
> + /* Integration time is 50ms, but the experiments */
> + /* show 54ms in total. */
> + data->vcnl4200_al.sampling_rate = ktime_set(0, 54000 * 1000);
> + data->vcnl4200_ps.sampling_rate = ktime_set(0, 4200 * 1000);
> + break;
> + case VCNL4040_PROD_ID:
> + /* Integration time is 80ms, add 10ms. */
> + data->vcnl4200_al.sampling_rate = ktime_set(0, 10 * 1000);
> + data->vcnl4200_ps.sampling_rate = ktime_set(0, 10 * 1000);
> + break;
> + }
> +
>   data->al_scale = 

[PATCH 1/2] iio: light: vcnl4000 add support for the VCNL4040 proximity and light sensor

2019-03-15 Thread Angus Ainslie (Purism)
The VCNL4040 is almost identical to the VCNL4200 as far as register
layout goes but just need to check a different ID register location.

This does change the initialization sequence of the VCNL4200 to use word
writes instead of byte writes. The VCNL4200 datasheet says that word read
and writes should be used to access the registers but I don't have a 4200
to test with. The VCNL4040 doesn't initialize properly with the byte
writes.

devicetree hooks were also added.

Signed-off-by: Angus Ainslie (Purism) 
---
 drivers/iio/light/vcnl4000.c | 89 ++--
 1 file changed, 76 insertions(+), 13 deletions(-)

diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index 04fd0d4b6f19..6e1f02aa6696 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -10,13 +10,14 @@
  *
  * IIO driver for:
  *   VCNL4000/10/20 (7-bit I2C slave address 0x13)
+ *   VCNL4040 (7-bit I2C slave address 0x60)
  *   VCNL4200 (7-bit I2C slave address 0x51)
  *
  * TODO:
  *   allow to adjust IR current
  *   proximity threshold and event handling
  *   periodic ALS/proximity measurement (VCNL4010/20)
- *   interrupts (VCNL4010/20, VCNL4200)
+ *   interrupts (VCNL4010/20/40, VCNL4200)
  */
 
 #include 
@@ -30,6 +31,7 @@
 #define VCNL4000_DRV_NAME "vcnl4000"
 #define VCNL4000_PROD_ID   0x01
 #define VCNL4010_PROD_ID   0x02 /* for VCNL4020, VCNL4010 */
+#define VCNL4040_PROD_ID   0x86
 #define VCNL4200_PROD_ID   0x58
 
 #define VCNL4000_COMMAND   0x80 /* Command register */
@@ -49,6 +51,8 @@
 #define VCNL4200_AL_DATA   0x09 /* Ambient light data */
 #define VCNL4200_DEV_ID0x0e /* Device ID, slave address and 
version */
 
+#define VCNL4040_DEV_ID0x0c /* Device ID, slave address and 
version */
+
 /* Bit masks for COMMAND register */
 #define VCNL4000_AL_RDYBIT(6) /* ALS data ready? */
 #define VCNL4000_PS_RDYBIT(5) /* proximity data ready? */
@@ -58,6 +62,7 @@
 enum vcnl4000_device_ids {
VCNL4000,
VCNL4010,
+   VCNL4040,
VCNL4200,
 };
 
@@ -90,6 +95,7 @@ static const struct i2c_device_id vcnl4000_id[] = {
{ "vcnl4000", VCNL4000 },
{ "vcnl4010", VCNL4010 },
{ "vcnl4020", VCNL4010 },
+   { "vcnl4040", VCNL4040 },
{ "vcnl4200", VCNL4200 },
{ }
 };
@@ -128,31 +134,56 @@ static int vcnl4000_init(struct vcnl4000_data *data)
 
 static int vcnl4200_init(struct vcnl4000_data *data)
 {
-   int ret;
+   int ret, id;
 
ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID);
if (ret < 0)
return ret;
 
-   if ((ret & 0xff) != VCNL4200_PROD_ID)
-   return -ENODEV;
+   id = ret & 0xff;
+
+   if (id != VCNL4200_PROD_ID) {
+   ret = i2c_smbus_read_word_data(data->client, VCNL4040_DEV_ID);
+   if (ret < 0)
+   return ret;
+
+   id = ret & 0xff;
+
+   if (id != VCNL4040_PROD_ID)
+   return -ENODEV;
+
+   }
+
+   dev_dbg(>client->dev, "device id 0x%x", id);
 
data->rev = (ret >> 8) & 0xf;
 
/* Set defaults and enable both channels */
-   ret = i2c_smbus_write_byte_data(data->client, VCNL4200_AL_CONF, 0x00);
+   ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, 0x00);
if (ret < 0)
return ret;
-   ret = i2c_smbus_write_byte_data(data->client, VCNL4200_PS_CONF1, 0x00);
+   ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, 0x00);
if (ret < 0)
return ret;
 
+   switch (id) {
+   case VCNL4200_PROD_ID:
+   /* Integration time is 50ms, but the experiments */
+   /* show 54ms in total. */
+   data->vcnl4200_al.sampling_rate = ktime_set(0, 54000 * 1000);
+   data->vcnl4200_ps.sampling_rate = ktime_set(0, 4200 * 1000);
+   break;
+   case VCNL4040_PROD_ID:
+   /* Integration time is 80ms, add 10ms. */
+   data->vcnl4200_al.sampling_rate = ktime_set(0, 10 * 1000);
+   data->vcnl4200_ps.sampling_rate = ktime_set(0, 10 * 1000);
+   break;
+   }
+
data->al_scale = 24000;
data->vcnl4200_al.reg = VCNL4200_AL_DATA;
data->vcnl4200_ps.reg = VCNL4200_PS_DATA;
-   /* Integration time is 50ms, but the experiments show 54ms in total. */
-   data->vcnl4200_al.sampling_rate = ktime_set(0, 54000 * 1000);
-   data->vcnl4200_ps.sampling_rate = ktime_set(0, 4200 * 1000);
+
data->vcnl4200_al.last_measurement = ktime_set(0, 0);
data->vcnl4200_ps.last_measurement = ktime_set(0, 0);
mutex_init(>vcnl4200_al.lock);
@@ -194,8 +225,11 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 
req_mask,
 
ret = i2c_smbus_read_i2c_block_data(data->client,
data_reg, sizeof(buf), (u8 *)