Re: [PATCH v7 2/4] i2c-acpi : exclude ARA address for smbus device

2018-01-14 Thread Marc CAPDEVILLE
> On Sat, 13 Jan 2018 14:37:03 +0100
> Marc CAPDEVILLE  wrote:
>> Somme ACPI enumerated devices are known to support smbus alert
protocol.
>> Theses devices may be miss-enumerated with the reserved smbus ARA address.
>> This is the case on Asus T100 tablet where cm3218 ambiant light sensor
expose two i2c serial bus connections, with the first one being the
alert
>> response address.
>> This patch make a match on known ACPI ids for which devices are smbus ARA
>> capable, then skip the connection if it has the reserved 0x0c address and
>> mark it with I2C_CLIENT_ALERT flag. So device is enumerated with the
correct address.
> I wonder if we are safe to always skip 0x0c address whether or not we
know the device supports ARA.  The exception may be for devices that do
support ARA but are rolling their own support the hard way...

The device is only flagged with I2C_CLIENT_ALERT if its ID is in the
i2c_acpi_alert_device_ids. IF a driver want to be enumerated with the
reserved Ox0c address, It just have to not put its Id in this table. But
this may break with registering the smbus_alert device as the address will
be marked as busy for this adapter.
> I suppose it's possible there are i2c devices (not smbus where the spec
says you must not use 0x0c for normal address IIRC) that use this
address.  Does anyone know of any?

I think this possible, but a such device can't share the bus with a smbus
alert capable device.
> Jonathan
>> Signed-off-by: Marc CAPDEVILLE 
>> ---
>>  drivers/i2c/i2c-core-acpi.c | 23 +--
>>  include/linux/i2c.h |  1 +
>>  2 files changed, 22 insertions(+), 2 deletions(-)
>> diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
index a9126b3cda61..5a8886f14329 100644
>> --- a/drivers/i2c/i2c-core-acpi.c
>> +++ b/drivers/i2c/i2c-core-acpi.c
>> @@ -59,8 +59,14 @@ static int i2c_acpi_fill_info(struct acpi_resource
*ares, void *data)
>>  if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
>>  return 1;
>> -if (lookup->index != -1 && lookup->n++ != lookup->index)
>> -return 1;
>> +if (lookup->index != -1) {
>> +if (lookup->n++ != lookup->index)
>> +return 1;
>> +} else {
>> +if (lookup->info->flags & I2C_CLIENT_ALERT &&
>> +sb->slave_address == 0x0c)
>> +return 1;
>> +}
>>  status = acpi_get_handle(lookup->device_handle,
>>   sb->resource_source.string_ptr,
>> @@ -85,6 +91,15 @@ static const struct acpi_device_id
>> i2c_acpi_ignored_device_ids[] = {
>>  {}
>>  };
>> +static const struct acpi_device_id i2c_acpi_alert_device_ids[] = { +
>> /*
>> + * Smbus alert capable device which may have the reserved ARA address
+* in their serial bus resources list.
>> + */
>> +{ "CPLM3218", 0 },
>> +{}
>> +};
>> +
>>  static int i2c_acpi_do_lookup(struct acpi_device *adev,
>>struct i2c_acpi_lookup *lookup)
>>  {
>> @@ -100,6 +115,10 @@ static int i2c_acpi_do_lookup(struct acpi_device
*adev,
>>  return -ENODEV;
>>  memset(info, 0, sizeof(*info));
>> +
>> +if (acpi_match_device_ids(adev, i2c_acpi_alert_device_ids) == 0)
+   info->flags |= I2C_CLIENT_ALERT;
>> +
>>  lookup->device_handle = acpi_device_handle(adev);
>>  /* Look up for I2cSerialBus resource */
>> diff --git a/include/linux/i2c.h b/include/linux/i2c.h
>> index 7592dce12923..b0d6f1333442 100644
>> --- a/include/linux/i2c.h
>> +++ b/include/linux/i2c.h
>> @@ -743,6 +743,7 @@ i2c_unlock_adapter(struct i2c_adapter *adapter)
>>  #define I2C_CLIENT_SLAVE0x20/* we are the slave */
>>  #define I2C_CLIENT_HOST_NOTIFY  0x40/* We want to use I2C host 
>> notify
>> */
>>  #define I2C_CLIENT_WAKE 0x80/* for board_info; true iff can 
>> wake */
>> +#define I2C_CLIENT_ALERT0x100   /* Client use SMBUS alert protocol */
>>  #define I2C_CLIENT_SCCB 0x9000  /* Use Omnivision SCCB protocol 
>> */
>>  /* Must match I2C_M_STOP|IGNORE_NAK */


-- 
Marc CAPDEVILLE






Re: [PATCH v7 3/4] iio : Add cm3218 smbus ARA and ACPI support

2018-01-14 Thread Marc CAPDEVILLE

> On Sat, 13 Jan 2018 14:37:04 +0100
> Marc CAPDEVILLE  wrote:
>
>> On asus T100, Capella cm3218 chip is implemented as ambiant light
>> sensor. This chip expose an smbus ARA protocol device on standard
>> address 0x0c. The chip is not functional before all alerts are
>> acknowledged.
>>
>> The driver call i2c_require_smbus_alert() to set the smbus alert
>> protocol driver on its adapter. If an interrupt resource is given,
>> we register this irq with the smbus alert driver.
>> If no irq is given, the driver call i2c_smbus_alert_event() to trigger
>> the alert process to clear the initial alert event before initializing
>> cm3218 registers.
>>
>> Signed-off-by: Marc CAPDEVILLE 
>
> Ultimately I think we can move most of the logic here into the i2c core,
> but that can be a job for another day.

This can be done in the core in i2c_device_probe(), but can we suppose
that client irq is the smbus alert line when the device is flagged with
I2C_CLIENT_ALERT and/or the driver define an alert callback ?
>
> I'm not sure there isn't a nasty mess with this device if we have
> a bus master created ara.  I raised it below.  Not sure there is
> much we can do about it though.

If the adapter has already created the smbus alert device, the
i2c_require_smbus_alert() do nothing. We just have to register an
additional handler for the irq line if it differ from the adapter one.
This is handle by i2c_smbus_alert_add_irq().
>
> Jonathan
>
>> ---
>>  drivers/iio/light/cm32181.c | 94
>> +++--
>>  1 file changed, 91 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
>> index aebf7dd071af..eae5b7cc6878 100644
>> --- a/drivers/iio/light/cm32181.c
>> +++ b/drivers/iio/light/cm32181.c
>> @@ -18,6 +18,9 @@
>>  #include 
>>  #include 
>>  #include 
>> +#include 
>> +#include 
>> +#include 
>>
>>  /* Registers Address */
>>  #define CM32181_REG_ADDR_CMD0x00
>> @@ -47,6 +50,9 @@
>>  #define CM32181_CALIBSCALE_RESOLUTION   1000
>>  #define MLUX_PER_LUX1000
>>
>> +#define CM32181_ID  0x81
>> +#define CM3218_ID   0x18
>> +
>>  static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = {
>>  CM32181_REG_ADDR_CMD,
>>  };
>> @@ -57,6 +63,7 @@ static const int als_it_value[] = {25000, 5,
>> 10, 20, 40,
>>
>>  struct cm32181_chip {
>>  struct i2c_client *client;
>> +int chip_id;
>>  struct mutex lock;
>>  u16 conf_regs[CM32181_CONF_REG_NUM];
>>  int calibscale;
>> @@ -81,7 +88,7 @@ static int cm32181_reg_init(struct cm32181_chip
>> *cm32181)
>>  return ret;
>>
>>  /* check device ID */
>> -if ((ret & 0xFF) != 0x81)
>> +if ((ret & 0xFF) != cm32181->chip_id)
>>  return -ENODEV;
>>
>>  /* Default Values */
>> @@ -297,12 +304,23 @@ static const struct iio_info cm32181_info = {
>>  .attrs  = &cm32181_attribute_group,
>>  };
>>
>> +static void cm3218_alert(struct i2c_client *client,
>> + enum i2c_alert_protocol type,
>> + unsigned int data)
>> +{
>> +/*
>> + * nothing to do for now.
>> + * This is just here to acknownledge the cm3218 alert.
>> + */
>> +}
>> +
>>  static int cm32181_probe(struct i2c_client *client,
>>  const struct i2c_device_id *id)
>>  {
>>  struct cm32181_chip *cm32181;
>>  struct iio_dev *indio_dev;
>>  int ret;
>> +const struct acpi_device_id *a_id;
>>
>>  indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*cm32181));
>>  if (!indio_dev) {
>> @@ -322,11 +340,55 @@ static int cm32181_probe(struct i2c_client
>> *client,
>>  indio_dev->name = id->name;
>>  indio_dev->modes = INDIO_DIRECT_MODE;
>>
>> +/* Lookup for chip ID from platform, ACPI or of device table */
>> +if (id) {
>> +cm32181->chip_id = id->driver_data;
>> +} else if (ACPI_COMPANION(&client->dev)) {
>> +a_id = acpi_match_device(client->dev.driver->acpi_match_table,
>> + &client->dev);
>> +if (!a_id)
>> +return -ENODEV;
>> +
>> +cm32181->chip_id = (int)a_id->driver_data;
>> +  

[PATCH v7 3/4] iio : Add cm3218 smbus ARA and ACPI support

2018-01-13 Thread Marc CAPDEVILLE
On asus T100, Capella cm3218 chip is implemented as ambiant light
sensor. This chip expose an smbus ARA protocol device on standard
address 0x0c. The chip is not functional before all alerts are
acknowledged.

The driver call i2c_require_smbus_alert() to set the smbus alert
protocol driver on its adapter. If an interrupt resource is given,
we register this irq with the smbus alert driver.
If no irq is given, the driver call i2c_smbus_alert_event() to trigger
the alert process to clear the initial alert event before initializing
cm3218 registers.

Signed-off-by: Marc CAPDEVILLE 
---
 drivers/iio/light/cm32181.c | 94 +++--
 1 file changed, 91 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index aebf7dd071af..eae5b7cc6878 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -18,6 +18,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 /* Registers Address */
 #define CM32181_REG_ADDR_CMD   0x00
@@ -47,6 +50,9 @@
 #define CM32181_CALIBSCALE_RESOLUTION  1000
 #define MLUX_PER_LUX   1000
 
+#define CM32181_ID 0x81
+#define CM3218_ID  0x18
+
 static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = {
CM32181_REG_ADDR_CMD,
 };
@@ -57,6 +63,7 @@ static const int als_it_value[] = {25000, 5, 10, 
20, 40,
 
 struct cm32181_chip {
struct i2c_client *client;
+   int chip_id;
struct mutex lock;
u16 conf_regs[CM32181_CONF_REG_NUM];
int calibscale;
@@ -81,7 +88,7 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
return ret;
 
/* check device ID */
-   if ((ret & 0xFF) != 0x81)
+   if ((ret & 0xFF) != cm32181->chip_id)
return -ENODEV;
 
/* Default Values */
@@ -297,12 +304,23 @@ static const struct iio_info cm32181_info = {
.attrs  = &cm32181_attribute_group,
 };
 
+static void cm3218_alert(struct i2c_client *client,
+enum i2c_alert_protocol type,
+unsigned int data)
+{
+   /*
+* nothing to do for now.
+* This is just here to acknownledge the cm3218 alert.
+*/
+}
+
 static int cm32181_probe(struct i2c_client *client,
const struct i2c_device_id *id)
 {
struct cm32181_chip *cm32181;
struct iio_dev *indio_dev;
int ret;
+   const struct acpi_device_id *a_id;
 
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*cm32181));
if (!indio_dev) {
@@ -322,11 +340,55 @@ static int cm32181_probe(struct i2c_client *client,
indio_dev->name = id->name;
indio_dev->modes = INDIO_DIRECT_MODE;
 
+   /* Lookup for chip ID from platform, ACPI or of device table */
+   if (id) {
+   cm32181->chip_id = id->driver_data;
+   } else if (ACPI_COMPANION(&client->dev)) {
+   a_id = acpi_match_device(client->dev.driver->acpi_match_table,
+&client->dev);
+   if (!a_id)
+   return -ENODEV;
+
+   cm32181->chip_id = (int)a_id->driver_data;
+   } else if (client->dev.of_node) {
+   cm32181->chip_id = (int)of_device_get_match_data(&client->dev);
+   if (!cm32181->chip_id)
+   return -ENODEV;
+   } else {
+   return -ENODEV;
+   }
+
+   if (cm32181->chip_id == CM3218_ID) {
+   /* cm3218 chip require an ARA device on his adapter */
+   ret = i2c_require_smbus_alert(client);
+   if (ret < 0)
+   return ret;
+
+   /* If irq is given, register it with the smbus alert driver */
+   if (client->irq > 0) {
+   ret = i2c_smbus_alert_add_irq(client, client->irq);
+   if (ret < 0)
+   return ret;
+   } else {
+   /*
+* if no irq is given, acknownledge initial ARA
+* event so cm32181_reg_init() will not fail.
+*/
+   ret = i2c_smbus_alert_event(client);
+   if (ret)
+   return ret;
+   }
+   }
+
ret = cm32181_reg_init(cm32181);
if (ret) {
dev_err(&client->dev,
"%s: register init failed\n",
__func__);
+
+   if (cm32181->chip_id == CM3218_ID && client->irq)
+   i2c_smbus_alert_free_irq(client, client->irq);
+
return ret;
}
 
@@ -335,32 +397,58 @@ static int

[PATCH v7 2/4] i2c-acpi : exclude ARA address for smbus device

2018-01-13 Thread Marc CAPDEVILLE
Somme ACPI enumerated devices are known to support smbus alert protocol.
Theses devices may be miss-enumerated with the reserved smbus ARA address.

This is the case on Asus T100 tablet where cm3218 ambiant light sensor
expose two i2c serial bus connections, with the first one being the alert
response address.

This patch make a match on known ACPI ids for which devices are smbus ARA
capable, then skip the connection if it has the reserved 0x0c address and
mark it with I2C_CLIENT_ALERT flag. So device is enumerated with the
correct address.

Signed-off-by: Marc CAPDEVILLE 
---
 drivers/i2c/i2c-core-acpi.c | 23 +--
 include/linux/i2c.h |  1 +
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
index a9126b3cda61..5a8886f14329 100644
--- a/drivers/i2c/i2c-core-acpi.c
+++ b/drivers/i2c/i2c-core-acpi.c
@@ -59,8 +59,14 @@ static int i2c_acpi_fill_info(struct acpi_resource *ares, 
void *data)
if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
return 1;
 
-   if (lookup->index != -1 && lookup->n++ != lookup->index)
-   return 1;
+   if (lookup->index != -1) {
+   if (lookup->n++ != lookup->index)
+   return 1;
+   } else {
+   if (lookup->info->flags & I2C_CLIENT_ALERT &&
+   sb->slave_address == 0x0c)
+   return 1;
+   }
 
status = acpi_get_handle(lookup->device_handle,
 sb->resource_source.string_ptr,
@@ -85,6 +91,15 @@ static const struct acpi_device_id 
i2c_acpi_ignored_device_ids[] = {
{}
 };
 
+static const struct acpi_device_id i2c_acpi_alert_device_ids[] = {
+   /*
+* Smbus alert capable device which may have the reserved ARA address
+* in their serial bus resources list.
+*/
+   { "CPLM3218", 0 },
+   {}
+};
+
 static int i2c_acpi_do_lookup(struct acpi_device *adev,
  struct i2c_acpi_lookup *lookup)
 {
@@ -100,6 +115,10 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev,
return -ENODEV;
 
memset(info, 0, sizeof(*info));
+
+   if (acpi_match_device_ids(adev, i2c_acpi_alert_device_ids) == 0)
+   info->flags |= I2C_CLIENT_ALERT;
+
lookup->device_handle = acpi_device_handle(adev);
 
/* Look up for I2cSerialBus resource */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 7592dce12923..b0d6f1333442 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -743,6 +743,7 @@ i2c_unlock_adapter(struct i2c_adapter *adapter)
 #define I2C_CLIENT_SLAVE   0x20/* we are the slave */
 #define I2C_CLIENT_HOST_NOTIFY 0x40/* We want to use I2C host notify */
 #define I2C_CLIENT_WAKE0x80/* for board_info; true iff can 
wake */
+#define I2C_CLIENT_ALERT   0x100   /* Client use SMBUS alert protocol */
 #define I2C_CLIENT_SCCB0x9000  /* Use Omnivision SCCB protocol 
*/
/* Must match I2C_M_STOP|IGNORE_NAK */
 
-- 
2.11.0



[PATCH v7 4/4] iio : cm32181 : cosmetic cleanup

2018-01-13 Thread Marc CAPDEVILLE
Somme cosmetic cleanup suggested by Peter Meerwald-Stadler.

Macro name :
   MLUX_PER_LUX => CM32181_MLUX_PER_LUX

Constante name :
   als_it_bits => cm32181_als_it_bits
   als_it_value => cm32181_als_it_value

Comment :
   Registers Address => Register Addresses

Suggested-by: Peter Meerwald-Stadler 
Signed-off-by: Marc CAPDEVILLE 
Acked-by: Jonathan Cameron 
---
 drivers/iio/light/cm32181.c | 26 +-
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index eae5b7cc6878..8fc01c8d4522 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -22,7 +22,7 @@
 #include 
 #include 
 
-/* Registers Address */
+/* Register Addresses */
 #define CM32181_REG_ADDR_CMD   0x00
 #define CM32181_REG_ADDR_ALS   0x04
 #define CM32181_REG_ADDR_STATUS0x06
@@ -48,7 +48,7 @@
 #define CM32181_MLUX_PER_BIT_BASE_IT   80  /* Based on IT=800ms */
 #defineCM32181_CALIBSCALE_DEFAULT  1000
 #define CM32181_CALIBSCALE_RESOLUTION  1000
-#define MLUX_PER_LUX   1000
+#define CM32181_MLUX_PER_LUX   1000
 
 #define CM32181_ID 0x81
 #define CM3218_ID  0x18
@@ -57,8 +57,8 @@ static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = {
CM32181_REG_ADDR_CMD,
 };
 
-static const int als_it_bits[] = {12, 8, 0, 1, 2, 3};
-static const int als_it_value[] = {25000, 5, 10, 20, 40,
+static const int cm32181_als_it_bits[] = {12, 8, 0, 1, 2, 3};
+static const int cm32181_als_it_value[] = {25000, 5, 10, 20, 
40,
80};
 
 struct cm32181_chip {
@@ -124,9 +124,9 @@ static int cm32181_read_als_it(struct cm32181_chip 
*cm32181, int *val2)
als_it = cm32181->conf_regs[CM32181_REG_ADDR_CMD];
als_it &= CM32181_CMD_ALS_IT_MASK;
als_it >>= CM32181_CMD_ALS_IT_SHIFT;
-   for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) {
-   if (als_it == als_it_bits[i]) {
-   *val2 = als_it_value[i];
+   for (i = 0; i < ARRAY_SIZE(cm32181_als_it_bits); i++) {
+   if (als_it == cm32181_als_it_bits[i]) {
+   *val2 = cm32181_als_it_value[i];
return IIO_VAL_INT_PLUS_MICRO;
}
}
@@ -149,14 +149,14 @@ static int cm32181_write_als_it(struct cm32181_chip 
*cm32181, int val)
u16 als_it;
int ret, i, n;
 
-   n = ARRAY_SIZE(als_it_value);
+   n = ARRAY_SIZE(cm32181_als_it_value);
for (i = 0; i < n; i++)
-   if (val <= als_it_value[i])
+   if (val <= cm32181_als_it_value[i])
break;
if (i >= n)
i = n - 1;
 
-   als_it = als_it_bits[i];
+   als_it = cm32181_als_it_bits[i];
als_it <<= CM32181_CMD_ALS_IT_SHIFT;
 
mutex_lock(&cm32181->lock);
@@ -202,7 +202,7 @@ static int cm32181_get_lux(struct cm32181_chip *cm32181)
lux *= ret;
lux *= cm32181->calibscale;
lux /= CM32181_CALIBSCALE_RESOLUTION;
-   lux /= MLUX_PER_LUX;
+   lux /= CM32181_MLUX_PER_LUX;
 
if (lux > 0x)
lux = 0x;
@@ -270,9 +270,9 @@ static ssize_t cm32181_get_it_available(struct device *dev,
 {
int i, n, len;
 
-   n = ARRAY_SIZE(als_it_value);
+   n = ARRAY_SIZE(cm32181_als_it_value);
for (i = 0, len = 0; i < n; i++)
-   len += sprintf(buf + len, "0.%06u ", als_it_value[i]);
+   len += sprintf(buf + len, "0.%06u ", cm32181_als_it_value[i]);
return len + sprintf(buf + len, "\n");
 }
 
-- 
2.11.0



[PATCH v7 1/4] i2c-smbus : Add client discovered ARA support

2018-01-13 Thread Marc CAPDEVILLE
This is from rfc by Alan Cox : https://patchwork.ozlabs.org/patch/381773

The idea is as follows (extract from above rfc) :
- If an adapter knows about its ARA and smbus alerts then the adapter
  creates its own interrupt handler as before

- If a client knows it needs smbus alerts it calls
  i2c_require_smbus_alert(). This ensures that there is an ARA handler
  registered and tells the client whether the adapter is handling it
  anyway or not.

- When the client learns that an ARA event has occurred it calls
  i2c_smbus_alert_event() which uses the existing ARA mechanism to kick
  things off.

In addition, if a client have an irq line to trigger smbus alert, client
driver register its irq with i2c_smbus_alert_add_irq() to the smbus alert
driver to use the generic alert interrupt handler. On detach, the client
must unregister its irq from the smbus alert driver with
i2c_smbus_alert_free_irq().

Signed-off-by: Marc CAPDEVILLE 
---
 drivers/i2c/i2c-core-smbus.c |  42 +++
 drivers/i2c/i2c-smbus.c  | 171 +--
 include/linux/i2c-smbus.h|  22 ++
 include/linux/i2c.h  |   2 +
 4 files changed, 232 insertions(+), 5 deletions(-)

diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c
index 1238c94fe5a1..0d84ac9669e9 100644
--- a/drivers/i2c/i2c-core-smbus.c
+++ b/drivers/i2c/i2c-core-smbus.c
@@ -659,6 +659,48 @@ struct i2c_client *i2c_setup_smbus_alert(struct 
i2c_adapter *adapter,
 }
 EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert);
 
+/**
+ * i2c_require_smbus_alert - Client discovered SMBus alert
+ * @client: client requiring ARA support
+ *
+ * When a client needs an ARA it calls this method. If the bus adapter
+ * supports ARA and already knows how to do so then it will already have
+ * configured for ARA and this is a no-op. If not then we set up an ARA
+ * on the adapter.
+ *
+ * Return:
+ * 0 if ARA support already registered
+ * 1 if call register a new smbus_alert device
+ * <0 on error
+ */
+int i2c_require_smbus_alert(struct i2c_client *client)
+{
+   struct i2c_adapter *adapter = client->adapter;
+   struct i2c_smbus_alert_setup setup;
+   struct i2c_client *ara;
+   int ret;
+
+   if (adapter->smbus_ara) {
+   /*
+* ARA is already known and handled by the adapter (ideal case)
+* or another client has specified ARA is needed
+*/
+   ret = 0;
+   } else {
+   /* First client requesting alert and no adapter has
+* has setup one
+*/
+   setup.irq = 0;
+   ara = i2c_setup_smbus_alert(adapter, &setup);
+   if (!ara)
+   return -ENODEV;
+   ret = 1;
+   }
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(i2c_require_smbus_alert);
+
 #if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_OF)
 int of_i2c_setup_smbus_alert(struct i2c_adapter *adapter)
 {
diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
index 5a1dd7f13bac..1699333ac950 100644
--- a/drivers/i2c/i2c-smbus.c
+++ b/drivers/i2c/i2c-smbus.c
@@ -25,9 +25,16 @@
 #include 
 #include 
 
+struct i2c_smbus_irq_usage {
+   struct list_headlist;
+   int irq;
+   int count;
+};
+
 struct i2c_smbus_alert {
struct work_struct  alert;
struct i2c_client   *ara;   /* Alert response address */
+   struct list_headirq_usage;  /* irq usage list */
 };
 
 struct alert_data {
@@ -126,6 +133,124 @@ static void smbalert_work(struct work_struct *work)
 
 }
 
+/**
+ * i2c_smbus_alert_add_irq - Add a new irq handler to ARA client
+ * @client: The client which want to add an smbus alert irq handler
+ * @irq: The irq number to be added to the smbus alert device
+ * return: 0 if irq handler already exist, 1 if a new handler has been
+ *registered, <0 on error
+ *
+ * This is used by the smbalert_probe and by smbus client to check if an
+ * irq handler already exist for that irq and if not register a new one
+ * Clients must free their irq with i2c_smbus_alert_free_irq() on driver
+ * detach.
+ */
+int i2c_smbus_alert_add_irq(struct i2c_client *client, int irq)
+{
+   int res;
+   struct i2c_smbus_irq_usage *irq_usage;
+   struct i2c_client *ara;
+   struct i2c_smbus_alert *alert;
+
+   ara = client->adapter->smbus_ara;
+   if (!ara)
+   return -EINVAL;
+
+   alert = i2c_get_clientdata(client->adapter->smbus_ara);
+   if (!alert)
+   return -EINVAL;
+
+   if (!irq)
+   return 0;
+
+   /* Check if handler exist for that irq */
+   list_for_each_entry(irq_usage, &alert->irq_usage, list)
+   if (irq_usage->irq == irq)
+   break;
+
+   if (irq_usage->irq == irq) {
+   irq_usage->coun

[PATCH v6 2/4] i2c-smbus : Add client discovered ARA support

2017-12-25 Thread Marc CAPDEVILLE
This is from rfc by Alan Cox : https://patchwork.ozlabs.org/patch/381773

The idea is as follows (extract from above rfc) :
- If an adapter knows about its ARA and smbus alerts then the adapter
  creates its own interrupt handler as before

- If a client knows it needs smbus alerts it calls
  i2c_require_smbus_alert(). This ensures that there is an ARA handler
  registered and tells the client whether the adapter is handling it
  anyway or not.

- When the client learns that an ARA event has occurred it calls
  i2c_smbus_alert_event() which uses the existing ARA mechanism to kick
  things off.

Suggested-by: Alan Cox 
Signed-off-by: Marc CAPDEVILLE 
---
 drivers/i2c/i2c-smbus.c   | 83 +++
 include/linux/i2c-smbus.h | 15 +
 2 files changed, 98 insertions(+)

diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
index 5a1dd7f13bac..e97fbafd10ef 100644
--- a/drivers/i2c/i2c-smbus.c
+++ b/drivers/i2c/i2c-smbus.c
@@ -161,6 +161,9 @@ static int smbalert_probe(struct i2c_client *ara,
}
 
i2c_set_clientdata(ara, alert);
+
+   ara->adapter->smbus_ara = ara;
+
dev_info(&adapter->dev, "supports SMBALERT#\n");
 
return 0;
@@ -172,6 +175,9 @@ static int smbalert_remove(struct i2c_client *ara)
struct i2c_smbus_alert *alert = i2c_get_clientdata(ara);
 
cancel_work_sync(&alert->alert);
+
+   ara->adapter->smbus_ara = NULL;
+
return 0;
 }
 
@@ -210,6 +216,83 @@ int i2c_handle_smbus_alert(struct i2c_client *ara)
 }
 EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert);
 
+/*
+ * i2c_require_smbus_alert - Client discovered SMBus alert
+ * @c: client requiring ARA
+ *
+ * When a client needs an ARA it calls this method. If the bus adapter
+ * supports ARA and already knows how to do so then it will already have
+ * configured for ARA and this is a no-op. If not then we set up an ARA
+ * on the adapter.
+ *
+ * We *cannot* simply register a new IRQ handler for this because we might
+ * have multiple GPIO interrupts to devices all of which trigger an ARA.
+ *
+ * Return:
+ * 0 if ara support already registered
+ * 1 if call register a new smbus_alert device
+ * <0 on error
+ */
+int i2c_require_smbus_alert(struct i2c_client *client)
+{
+   struct i2c_adapter *adapter = client->adapter;
+   struct i2c_smbus_alert_setup setup;
+   struct i2c_client *ara;
+
+   /* ARA is already known and handled by the adapter (ideal case)
+* or another client has specified ARA is needed
+*/
+   if (adapter->smbus_ara)
+   return 0;
+
+   /* Client driven, do not set up a new IRQ handler */
+   setup.irq = 0;
+
+   ara = i2c_setup_smbus_alert(adapter, &setup);
+   if (!ara)
+   return -ENODEV;
+
+   return 1;
+}
+EXPORT_SYMBOL_GPL(i2c_require_smbus_alert);
+
+/*
+ * i2c_smbus_alert_event
+ * @client: the client who known of a probable ara event
+ * Context: can't sleep
+ *
+ * Helper function to be called from an I2C device driver's interrupt
+ * handler. It will schedule the alert work, in turn calling the
+ * corresponding I2C device driver's alert function.
+ *
+ * It is assumed that client is an i2c client who previously call
+ * i2c_require_smbus_alert().
+ */
+int i2c_smbus_alert_event(struct i2c_client *client)
+{
+   struct i2c_adapter *adapter;
+   struct i2c_client *ara;
+   struct i2c_smbus_alert *alert;
+
+   if (!client)
+   return -EINVAL;
+
+   adapter = client->adapter;
+   if (!adapter)
+   return -EINVAL;
+
+   ara = adapter->smbus_ara;
+   if (!ara)
+   return -EINVAL;
+
+   alert = i2c_get_clientdata(ara);
+   if (!alert)
+   return -EINVAL;
+
+   return schedule_work(&alert->alert);
+}
+EXPORT_SYMBOL_GPL(i2c_smbus_alert_event);
+
 module_i2c_driver(smbalert_driver);
 
 MODULE_AUTHOR("Jean Delvare ");
diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h
index fb0e040b1abb..49f362fa6ac5 100644
--- a/include/linux/i2c-smbus.h
+++ b/include/linux/i2c-smbus.h
@@ -58,4 +58,19 @@ static inline int of_i2c_setup_smbus_alert(struct 
i2c_adapter *adap)
 }
 #endif
 
+#if IS_ENABLED(CONFIG_I2C_SMBUS)
+int i2c_require_smbus_alert(struct i2c_client *client);
+int i2c_smbus_alert_event(struct i2c_client *client);
+#else
+static inline int i2c_require_smbus_alert(struct i2c_client *client)
+{
+   return NULL;
+}
+
+static inline int i2c_smbus_alert_event(struct i2c_client *client)
+{
+   return NULL;
+}
+#endif
+
 #endif /* _LINUX_I2C_SMBUS_H */
-- 
2.11.0



[PATCH v6 4/4] iio : cm32181 : cosmetic cleanup

2017-12-25 Thread Marc CAPDEVILLE
Somme cosmetic cleanup suggested by Peter Meerwald-Stadler.

Macro name :
   MLUX_PER_LUX => CM32181_MLUX_PER_LUX

Constante name :
   als_it_bits => cm32181_als_it_bits
   als_it_value => cm32181_als_it_value

Comment :
   Registers Address => Register Addresses

Suggested-by:  Peter Meerwald-Stadler 
Signed-off-by: Marc CAPDEVILLE 
---
 drivers/iio/light/cm32181.c | 26 +-
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index 96c08755e6e3..3e6b244d5cd1 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -22,7 +22,7 @@
 #include 
 #include 
 
-/* Registers Address */
+/* Register Addresses */
 #define CM32181_REG_ADDR_CMD   0x00
 #define CM32181_REG_ADDR_ALS   0x04
 #define CM32181_REG_ADDR_STATUS0x06
@@ -48,7 +48,7 @@
 #define CM32181_MLUX_PER_BIT_BASE_IT   80  /* Based on IT=800ms */
 #defineCM32181_CALIBSCALE_DEFAULT  1000
 #define CM32181_CALIBSCALE_RESOLUTION  1000
-#define MLUX_PER_LUX   1000
+#define CM32181_MLUX_PER_LUX   1000
 
 #define CM32181_ID 0x81
 #define CM3218_ID  0x18
@@ -59,8 +59,8 @@ static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = {
CM32181_REG_ADDR_CMD,
 };
 
-static const int als_it_bits[] = {12, 8, 0, 1, 2, 3};
-static const int als_it_value[] = {25000, 5, 10, 20, 40,
+static const int cm32181_als_it_bits[] = {12, 8, 0, 1, 2, 3};
+static const int cm32181_als_it_value[] = {25000, 5, 10, 20, 
40,
80};
 
 struct cm32181_chip {
@@ -137,9 +137,9 @@ static int cm32181_read_als_it(struct cm32181_chip 
*cm32181, int *val2)
als_it = cm32181->conf_regs[CM32181_REG_ADDR_CMD];
als_it &= CM32181_CMD_ALS_IT_MASK;
als_it >>= CM32181_CMD_ALS_IT_SHIFT;
-   for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) {
-   if (als_it == als_it_bits[i]) {
-   *val2 = als_it_value[i];
+   for (i = 0; i < ARRAY_SIZE(cm32181_als_it_bits); i++) {
+   if (als_it == cm32181_als_it_bits[i]) {
+   *val2 = cm32181_als_it_value[i];
return IIO_VAL_INT_PLUS_MICRO;
}
}
@@ -162,14 +162,14 @@ static int cm32181_write_als_it(struct cm32181_chip 
*cm32181, int val)
u16 als_it;
int ret, i, n;
 
-   n = ARRAY_SIZE(als_it_value);
+   n = ARRAY_SIZE(cm32181_als_it_value);
for (i = 0; i < n; i++)
-   if (val <= als_it_value[i])
+   if (val <= cm32181_als_it_value[i])
break;
if (i >= n)
i = n - 1;
 
-   als_it = als_it_bits[i];
+   als_it = cm32181_als_it_bits[i];
als_it <<= CM32181_CMD_ALS_IT_SHIFT;
 
mutex_lock(&cm32181->lock);
@@ -215,7 +215,7 @@ static int cm32181_get_lux(struct cm32181_chip *cm32181)
lux *= ret;
lux *= cm32181->calibscale;
lux /= CM32181_CALIBSCALE_RESOLUTION;
-   lux /= MLUX_PER_LUX;
+   lux /= CM32181_MLUX_PER_LUX;
 
if (lux > 0x)
lux = 0x;
@@ -283,9 +283,9 @@ static ssize_t cm32181_get_it_available(struct device *dev,
 {
int i, n, len;
 
-   n = ARRAY_SIZE(als_it_value);
+   n = ARRAY_SIZE(cm32181_als_it_value);
for (i = 0, len = 0; i < n; i++)
-   len += sprintf(buf + len, "0.%06u ", als_it_value[i]);
+   len += sprintf(buf + len, "0.%06u ", cm32181_als_it_value[i]);
return len + sprintf(buf + len, "\n");
 }
 
-- 
2.11.0



[PATCH v6 1/4] i2c-core-acpi : Add i2c_acpi_set_connection

2017-12-25 Thread Marc CAPDEVILLE
Add a methode to allow clients to change their connection address on
same adapter.

On ACPI enumerated device, when a device support smbus alert protocol,
there are two acpi serial bus connection description. The order in which
connection is given is not well defined and devices may be enumerated
with the wrong address (the first one). So let the driver detect the
unsupported address and request i2c acpi core to choose the second one
at probing time.

Signed-off-by: Marc CAPDEVILLE 
---
 drivers/i2c/i2c-core-acpi.c | 50 +
 include/linux/i2c.h | 10 +
 2 files changed, 60 insertions(+)

diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
index a9126b3cda61..47bc0da12055 100644
--- a/drivers/i2c/i2c-core-acpi.c
+++ b/drivers/i2c/i2c-core-acpi.c
@@ -421,6 +421,56 @@ struct i2c_client *i2c_acpi_new_device(struct device *dev, 
int index,
 }
 EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
 
+int i2c_acpi_set_connection(struct i2c_client *client, int index)
+{
+   struct i2c_acpi_lookup lookup;
+   struct i2c_adapter *adapter;
+   struct acpi_device *adev;
+   struct i2c_board_info info;
+   LIST_HEAD(resource_list);
+   int ret;
+
+   if (!client)
+   return -ENODEV;
+
+   adev = ACPI_COMPANION(&client->dev);
+   if (!adev)
+   return -ENODEV;
+
+   memset(&info,  0, sizeof(info));
+   memset(&lookup, 0, sizeof(lookup));
+   lookup.info = &info;
+   lookup.device_handle = acpi_device_handle(adev);
+   lookup.index = index;
+
+   ret = acpi_dev_get_resources(adev, &resource_list,
+i2c_acpi_fill_info, &lookup);
+   acpi_dev_free_resource_list(&resource_list);
+
+   adapter = i2c_acpi_find_adapter_by_handle(lookup.adapter_handle);
+
+   if (ret < 0 || !info.addr)
+   return -EINVAL;
+
+   /* Only accept connection on same adapter */
+   if (adapter != client->adapter)
+   return -EINVAL;
+
+   ret = i2c_check_addr_validity(info.addr, info.flags);
+   if (ret) {
+   dev_err(&client->dev, "Invalid %d-bit I2C address 0x%02hx\n",
+   info.flags & I2C_CLIENT_TEN ? 10 : 7, info.addr);
+   return -EINVAL;
+   }
+
+   /* Set new address and flags */
+   client->addr = info.addr;
+   client->flags = info.flags;
+
+   return 0;
+}
+EXPORT_SYMBOL_GPL(i2c_acpi_set_connection);
+
 #ifdef CONFIG_ACPI_I2C_OPREGION
 static int acpi_gsb_i2c_read_bytes(struct i2c_client *client,
u8 cmd, u8 *data, u8 data_len)
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 0f774406fad0..618b453901da 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -595,6 +595,8 @@ struct i2c_adapter {
const struct i2c_adapter_quirks *quirks;
 
struct irq_domain *host_notify_domain;
+
+   struct i2c_client *smbus_ara;   /* ARA for SMBUS if present */
 };
 #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
 
@@ -839,16 +841,24 @@ static inline const struct of_device_id
 u32 i2c_acpi_find_bus_speed(struct device *dev);
 struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
   struct i2c_board_info *info);
+
+int i2c_acpi_set_connection(struct i2c_client *client, int index);
 #else
 static inline u32 i2c_acpi_find_bus_speed(struct device *dev)
 {
return 0;
 }
+
 static inline struct i2c_client *i2c_acpi_new_device(struct device *dev,
int index, struct i2c_board_info *info)
 {
return NULL;
 }
+
+static inline int i2c_acpi_set_connection(struct i2c_client *client, int index)
+{
+   return -EINVAL;
+}
 #endif /* CONFIG_ACPI */
 
 #endif /* _LINUX_I2C_H */
-- 
2.11.0



[PATCH v6 3/4] iio : Add cm3218 smbus ara and acpi support

2017-12-25 Thread Marc CAPDEVILLE
On asus T100, Capella cm3218 chip is implemented as ambiant light
sensor. This chip expose an smbus ARA protocol device on standard
address 0x0c. The chip is not functional before all alerts are
acknowledged.
On asus T100, this device is enumerated on ACPI bus and the description
give two I2C connection. The first is the connection to the ARA device
and the second gives the real address of the device.

So, on device probe,If the i2c address is the ARA address and the
device is enumerated via acpi, we change address of the device for
the one in the second acpi serial bus connection.
This free the ara address so we can register with the smbus_alert
driver.

If an interrupt resource is given, and a smbus_alert device was
found on the adapter, we request a treaded interrupt to
call i2c_smbus_alert_event to handle the alert.

In somme case, the treaded interrupt is not schedule before the driver
try to initialize chip registers. So if first registers access fail, we
call i2c_smbus_alert_event() to acknowledge initial alert, then retry
register access.

Signed-off-by: Marc CAPDEVILLE 
---
 drivers/iio/light/cm32181.c | 120 ++--
 1 file changed, 115 insertions(+), 5 deletions(-)

diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index aebf7dd071af..96c08755e6e3 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -18,6 +18,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 /* Registers Address */
 #define CM32181_REG_ADDR_CMD   0x00
@@ -47,6 +50,11 @@
 #define CM32181_CALIBSCALE_RESOLUTION  1000
 #define MLUX_PER_LUX   1000
 
+#define CM32181_ID 0x81
+#define CM3218_ID  0x18
+
+#define SMBUS_ARA_ADDR 0x0c
+
 static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = {
CM32181_REG_ADDR_CMD,
 };
@@ -57,6 +65,7 @@ static const int als_it_value[] = {25000, 5, 10, 
20, 40,
 
 struct cm32181_chip {
struct i2c_client *client;
+   int chip_id;
struct mutex lock;
u16 conf_regs[CM32181_CONF_REG_NUM];
int calibscale;
@@ -77,11 +86,22 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
s32 ret;
 
ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ID);
-   if (ret < 0)
-   return ret;
+   if (ret < 0) {
+   if (cm32181->chip_id == CM3218_ID) {
+   /*
+* On cm3218, smbus alert trigger after probing,
+* so poll for first alert here, then retry.
+*/
+   i2c_smbus_alert_event(client);
+   ret = i2c_smbus_read_word_data(client,
+  CM32181_REG_ADDR_ID);
+   } else {
+   return ret;
+   }
+   }
 
/* check device ID */
-   if ((ret & 0xFF) != 0x81)
+   if ((ret & 0xFF) != cm32181->chip_id)
return -ENODEV;
 
/* Default Values */
@@ -297,12 +317,36 @@ static const struct iio_info cm32181_info = {
.attrs  = &cm32181_attribute_group,
 };
 
+static void cm3218_alert(struct i2c_client *client,
+enum i2c_alert_protocol type,
+unsigned int data)
+{
+   /*
+* nothing to do for now.
+* This is just here to acknownledge the cm3218 alert.
+*/
+}
+
+static irqreturn_t cm32181_irq(int irq, void *d)
+{
+   struct cm32181_chip *cm32181 = d;
+
+   if (cm32181->chip_id == CM3218_ID) {
+   /* This is cm3218 chip irq, so handle the smbus alert */
+   i2c_smbus_alert_event(cm32181->client);
+   }
+
+   return IRQ_HANDLED;
+}
+
 static int cm32181_probe(struct i2c_client *client,
const struct i2c_device_id *id)
 {
struct cm32181_chip *cm32181;
struct iio_dev *indio_dev;
int ret;
+   const struct of_device_id *of_id;
+   const struct acpi_device_id *acpi_id;
 
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*cm32181));
if (!indio_dev) {
@@ -322,6 +366,61 @@ static int cm32181_probe(struct i2c_client *client,
indio_dev->name = id->name;
indio_dev->modes = INDIO_DIRECT_MODE;
 
+   /* Lookup for chip ID from platform, acpi or of device table */
+   if (id) {
+   cm32181->chip_id = id->driver_data;
+   } else if (ACPI_COMPANION(&client->dev)) {
+   acpi_id = 
acpi_match_device(client->dev.driver->acpi_match_table,
+   &client->dev);
+   if (!acpi_id)
+   return -ENODEV;
+
+   cm32181->chip_id = (kernel_ulong_t)acpi_id->driver_data;
+   } else if (client->dev.of_n

[PATCH v5 1/2] iio : Add cm3218 smbus ara and acpi support

2017-11-22 Thread Marc CAPDEVILLE
On asus T100, Capella cm3218 chip is implemented as ambiant light
sensor. This chip expose an smbus ARA protocol device on standard
address 0x0c. The chip is not functional before all alerts are
acknowledged.
On asus T100, this device is enumerated on ACPI bus and the description
give two I2C connection. The first is the connection to the ARA device
and the second gives the real address of the device.

So, on device probe,If the i2c address is the ARA address and the
device is enumerated via acpi, we lookup for the real address in
the ACPI resource list and create an i2c dummy device with that address.
If the client address is already the real one, we create an i2c dummy
device for the ara function.

if an interrupt resource is given, we request a treaded interrupt to
acknowledge the smbus alert for cm3218 chip.

Signed-off-by: Marc CAPDEVILLE 
---
v5 :
   - dont use smbus_alert driver anymore
   - implement threaded interrupt to acknowledge alert from cm3218
   - dont touch address in i2c_client structur
   - register new dummy i2c client for second address

v4 :
   - rework acpi i2c adress lookup due to bad commit being sent.

v3 :
   - rework acpi i2c adress lookup
   - comment style cleanup
   - add prefix cm32181_to constantes and macros

v2 :
   - cm3218 support always build
   - Cleanup of unneeded #if statement
   - Beter identifying chip in platform device, acpi and of_device

 drivers/iio/light/cm32181.c | 247 ++--
 1 file changed, 239 insertions(+), 8 deletions(-)

diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index d6fd0dace74f..9b412dbb3248 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -18,6 +18,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 /* Registers Address */
 #define CM32181_REG_ADDR_CMD   0x00
@@ -47,6 +50,11 @@
 #define CM32181_CALIBSCALE_RESOLUTION  1000
 #define MLUX_PER_LUX   1000
 
+#define CM32181_ID 0x81
+#define CM3218_ID  0x18
+
+#define CM3218_ARA_ADDR0x0c
+
 static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = {
CM32181_REG_ADDR_CMD,
 };
@@ -56,7 +64,9 @@ static const int als_it_value[] = {25000, 5, 10, 
20, 40,
80};
 
 struct cm32181_chip {
-   struct i2c_client *client;
+   int chip_id;
+   struct i2c_client *als;
+   struct i2c_client *ara;
struct mutex lock;
u16 conf_regs[CM32181_CONF_REG_NUM];
int calibscale;
@@ -72,7 +82,7 @@ struct cm32181_chip {
  */
 static int cm32181_reg_init(struct cm32181_chip *cm32181)
 {
-   struct i2c_client *client = cm32181->client;
+   struct i2c_client *client = cm32181->als;
int i;
s32 ret;
 
@@ -81,7 +91,7 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
return ret;
 
/* check device ID */
-   if ((ret & 0xFF) != 0x81)
+   if ((ret & 0xFF) != cm32181->chip_id)
return -ENODEV;
 
/* Default Values */
@@ -138,7 +148,7 @@ static int cm32181_read_als_it(struct cm32181_chip 
*cm32181, int *val2)
  */
 static int cm32181_write_als_it(struct cm32181_chip *cm32181, int val)
 {
-   struct i2c_client *client = cm32181->client;
+   struct i2c_client *client = cm32181->als;
u16 als_it;
int ret, i, n;
 
@@ -175,7 +185,7 @@ static int cm32181_write_als_it(struct cm32181_chip 
*cm32181, int val)
  */
 static int cm32181_get_lux(struct cm32181_chip *cm32181)
 {
-   struct i2c_client *client = cm32181->client;
+   struct i2c_client *client = cm32181->als;
int ret;
int als_it;
unsigned long lux;
@@ -298,12 +308,107 @@ static const struct iio_info cm32181_info = {
.attrs  = &cm32181_attribute_group,
 };
 
+static irqreturn_t cm32181_irq(int irq, void *d)
+{
+   struct cm32181_chip *cm32181 = d;
+   int ret;
+
+   if (cm32181->chip_id == CM3218_ID) {
+   /* this is cm3218 chip, so this irq is from the ara device.
+* so acknowledge it
+*/
+   ret = i2c_smbus_read_byte(cm32181->ara);
+   }
+
+   return IRQ_HANDLED;
+}
+
+#if defined(CONFIG_ACPI)
+/*
+ * Look acpi resources for an i2c address other than smbus ara on same adapter.
+ * When address is found, set client structur then terminate walking acpi
+ * resources.
+ */
+static unsigned int cm3218_acpi_find_i2c_address(struct acpi_resource *ares,
+void *data)
+{
+   struct data_S {
+   struct i2c_client *client;
+   unsigned short als_address;
+   } *pdata = data;
+   struct acpi_resource_i2c_serialbus *sb;
+   acpi_status status;
+   acpi_handle adapter_handle;
+
+   if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+   return AE_OK;

[PATCH v5 2/2] iio : cm32181 : cosmetic cleanup

2017-11-22 Thread Marc CAPDEVILLE
Somme cosmetic cleanup suggested by Peter Meerwald-Stadler.

Macro name :
   MLUX_PER_LUX => CM32181_MLUX_PER_LUX

Constante name :
   als_it_bits => cm32181_als_it_bits
   als_it_value => cm32181_als_it_value

Comment :
   Registers Address => Register Addresses

Signed-off-by: Marc CAPDEVILLE 
---
 drivers/iio/light/cm32181.c | 26 +-
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index 9b412dbb3248..253e3a79429e 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -22,7 +22,7 @@
 #include 
 #include 
 
-/* Registers Address */
+/* Register Addresses */
 #define CM32181_REG_ADDR_CMD   0x00
 #define CM32181_REG_ADDR_ALS   0x04
 #define CM32181_REG_ADDR_STATUS0x06
@@ -48,7 +48,7 @@
 #define CM32181_MLUX_PER_BIT_BASE_IT   80  /* Based on IT=800ms */
 #defineCM32181_CALIBSCALE_DEFAULT  1000
 #define CM32181_CALIBSCALE_RESOLUTION  1000
-#define MLUX_PER_LUX   1000
+#define CM32181_MLUX_PER_LUX   1000
 
 #define CM32181_ID 0x81
 #define CM3218_ID  0x18
@@ -59,8 +59,8 @@ static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = {
CM32181_REG_ADDR_CMD,
 };
 
-static const int als_it_bits[] = {12, 8, 0, 1, 2, 3};
-static const int als_it_value[] = {25000, 5, 10, 20, 40,
+static const int cm32181_als_it_bits[] = {12, 8, 0, 1, 2, 3};
+static const int cm32181_als_it_value[] = {25000, 5, 10, 20, 
40,
80};
 
 struct cm32181_chip {
@@ -127,9 +127,9 @@ static int cm32181_read_als_it(struct cm32181_chip 
*cm32181, int *val2)
als_it = cm32181->conf_regs[CM32181_REG_ADDR_CMD];
als_it &= CM32181_CMD_ALS_IT_MASK;
als_it >>= CM32181_CMD_ALS_IT_SHIFT;
-   for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) {
-   if (als_it == als_it_bits[i]) {
-   *val2 = als_it_value[i];
+   for (i = 0; i < ARRAY_SIZE(cm32181_als_it_bits); i++) {
+   if (als_it == cm32181_als_it_bits[i]) {
+   *val2 = cm32181_als_it_value[i];
return IIO_VAL_INT_PLUS_MICRO;
}
}
@@ -152,14 +152,14 @@ static int cm32181_write_als_it(struct cm32181_chip 
*cm32181, int val)
u16 als_it;
int ret, i, n;
 
-   n = ARRAY_SIZE(als_it_value);
+   n = ARRAY_SIZE(cm32181_als_it_value);
for (i = 0; i < n; i++)
-   if (val <= als_it_value[i])
+   if (val <= cm32181_als_it_value[i])
break;
if (i >= n)
i = n - 1;
 
-   als_it = als_it_bits[i];
+   als_it = cm32181_als_it_bits[i];
als_it <<= CM32181_CMD_ALS_IT_SHIFT;
 
mutex_lock(&cm32181->lock);
@@ -205,7 +205,7 @@ static int cm32181_get_lux(struct cm32181_chip *cm32181)
lux *= ret;
lux *= cm32181->calibscale;
lux /= CM32181_CALIBSCALE_RESOLUTION;
-   lux /= MLUX_PER_LUX;
+   lux /= CM32181_MLUX_PER_LUX;
 
if (lux > 0x)
lux = 0x;
@@ -273,9 +273,9 @@ static ssize_t cm32181_get_it_available(struct device *dev,
 {
int i, n, len;
 
-   n = ARRAY_SIZE(als_it_value);
+   n = ARRAY_SIZE(cm32181_als_it_value);
for (i = 0, len = 0; i < n; i++)
-   len += sprintf(buf + len, "0.%06u ", als_it_value[i]);
+   len += sprintf(buf + len, "0.%06u ", cm32181_als_it_value[i]);
return len + sprintf(buf + len, "\n");
 }
 
-- 
2.11.0



[PATCH v4] iio : Add cm3218 smbus ara and acpi support

2017-10-27 Thread Marc CAPDEVILLE
On asus T100, Capella cm3218 chip is implemented as ambiant light
sensor. This chip expose an smbus ARA protocol device on standard
address 0x0c. The chip is not functional before all alerts are
acknowledged.
On asus T100, this device is enumerated on ACPI bus and the description
give tow I2C connection. The first is the connection to the ARA device
and the second gives the real address of the device.

So, on device probe,If the i2c address is the ARA address and the
device is enumerated via acpi, we lookup for the real address in
the ACPI resource list and change it in the client structure.
if an interrupt resource is given, and only for cm3218 chip,
we declare an smbus_alert device.

Signed-off-by: Marc CAPDEVILLE 
---
v4 :
   - rework acpi i2c adress lookup due to bad commit being sent.

v3 :
   - rework acpi i2c adress lookup
   - comment style cleanup
   - add prefix cm32181_to constantes and macros

v2 :
   - cm3218 support always build
   - Cleanup of unneeded #if statement
   - Beter identifying chip in platform device, acpi and of_device

 drivers/iio/light/cm32181.c | 202 
 1 file changed, 185 insertions(+), 17 deletions(-)

diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index d6fd0dace74f..f1a7495e851b 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -18,8 +18,12 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
 
-/* Registers Address */
+/* Registers Addresses */
 #define CM32181_REG_ADDR_CMD   0x00
 #define CM32181_REG_ADDR_ALS   0x04
 #define CM32181_REG_ADDR_STATUS0x06
@@ -45,18 +49,25 @@
 #define CM32181_MLUX_PER_BIT_BASE_IT   80  /* Based on IT=800ms */
 #defineCM32181_CALIBSCALE_DEFAULT  1000
 #define CM32181_CALIBSCALE_RESOLUTION  1000
-#define MLUX_PER_LUX   1000
+#define CM32181_MLUX_PER_LUX   1000
+
+#define CM32181_ID 0x81
+#define CM3218_ID  0x18
+
+#define CM3218_ARA_ADDR0x0c
 
 static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = {
CM32181_REG_ADDR_CMD,
 };
 
-static const int als_it_bits[] = {12, 8, 0, 1, 2, 3};
-static const int als_it_value[] = {25000, 5, 10, 20, 40,
+static const int cm32181_als_it_bits[] = {12, 8, 0, 1, 2, 3};
+static const int cm32181_als_it_value[] = {25000, 5, 10, 20, 
40,
80};
 
 struct cm32181_chip {
struct i2c_client *client;
+   int chip_id;
+   struct i2c_client *ara;
struct mutex lock;
u16 conf_regs[CM32181_CONF_REG_NUM];
int calibscale;
@@ -81,7 +92,7 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
return ret;
 
/* check device ID */
-   if ((ret & 0xFF) != 0x81)
+   if ((ret & 0xFF) != cm32181->chip_id)
return -ENODEV;
 
/* Default Values */
@@ -103,7 +114,7 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
 /**
  *  cm32181_read_als_it() - Get sensor integration time (ms)
  *  @cm32181:  pointer of struct cm32181
- *  @val2: pointer of int to load the als_it value.
+ *  @val2: pointer of int to load the cm32181_als_it value.
  *
  *  Report the current integartion time by millisecond.
  *
@@ -117,9 +128,9 @@ static int cm32181_read_als_it(struct cm32181_chip 
*cm32181, int *val2)
als_it = cm32181->conf_regs[CM32181_REG_ADDR_CMD];
als_it &= CM32181_CMD_ALS_IT_MASK;
als_it >>= CM32181_CMD_ALS_IT_SHIFT;
-   for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) {
-   if (als_it == als_it_bits[i]) {
-   *val2 = als_it_value[i];
+   for (i = 0; i < ARRAY_SIZE(cm32181_als_it_bits); i++) {
+   if (als_it == cm32181_als_it_bits[i]) {
+   *val2 = cm32181_als_it_value[i];
return IIO_VAL_INT_PLUS_MICRO;
}
}
@@ -142,14 +153,14 @@ static int cm32181_write_als_it(struct cm32181_chip 
*cm32181, int val)
u16 als_it;
int ret, i, n;
 
-   n = ARRAY_SIZE(als_it_value);
+   n = ARRAY_SIZE(cm32181_als_it_value);
for (i = 0; i < n; i++)
-   if (val <= als_it_value[i])
+   if (val <= cm32181_als_it_value[i])
break;
if (i >= n)
i = n - 1;
 
-   als_it = als_it_bits[i];
+   als_it = cm32181_als_it_bits[i];
als_it <<= CM32181_CMD_ALS_IT_SHIFT;
 
mutex_lock(&cm32181->lock);
@@ -195,7 +206,7 @@ static int cm32181_get_lux(struct cm32181_chip *cm32181)
lux *= ret;
lux *= cm32181->calibscale;
lux /= CM32181_CALIBSCALE_RESOLUTION;
-   lux /= MLUX_PER_LUX;
+   lux /= CM32181_MLUX_PER_LUX;
 
if (lux > 0x)
lux = 0x;
@@ -263,9 +274,9 @@ static ssize_t cm3

[PATCH v3] iio : Add cm3218 smbus ara and acpi support

2017-10-27 Thread Marc CAPDEVILLE
I'm sorry, this patch is not functionnal.
I'll resubmit in v4 soon.

I apologize for the inconvenience.



[PATCH v3] iio : Add cm3218 smbus ara and acpi support

2017-10-27 Thread Marc CAPDEVILLE
On asus T100, Capella cm3218 chip is implemented as ambiant light
sensor. This chip expose an smbus ARA protocol device on standard
address 0x0c. The chip is not functional before all alerts are
acknowledged.
On asus T100, this device is enumerated on ACPI bus and the description
give tow I2C connection. The first is the connection to the ARA device
and the second gives the real address of the device.

So, on device probe,If the i2c address is the ARA address and the
device is enumerated via acpi, we lookup for the real address in
the ACPI resource list and change it in the client structure.
if an interrupt resource is given, and only for cm3218 chip,
we declare an smbus_alert device.

Signed-off-by: Marc CAPDEVILLE 
---

Thanks to all for your review.

It seems that capellamicro.com  mailhost timeout when sending to Kevin.

v3 :
   - rework acpi i2c adress lookup
   - comment style cleanup
   - add prefix cm32181_to constantes and macros

v2 :
   - cm3218 support always build
   - Cleanup of unneeded #if statement
   - Beter identifying chip in platform device, acpi and of_device

 drivers/iio/light/cm32181.c | 202 
 1 file changed, 185 insertions(+), 17 deletions(-)

diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index d6fd0dace74f..f1a7495e851b 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -18,8 +18,12 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
 
-/* Registers Address */
+/* Registers Addresses */
 #define CM32181_REG_ADDR_CMD   0x00
 #define CM32181_REG_ADDR_ALS   0x04
 #define CM32181_REG_ADDR_STATUS0x06
@@ -45,18 +49,25 @@
 #define CM32181_MLUX_PER_BIT_BASE_IT   80  /* Based on IT=800ms */
 #defineCM32181_CALIBSCALE_DEFAULT  1000
 #define CM32181_CALIBSCALE_RESOLUTION  1000
-#define MLUX_PER_LUX   1000
+#define CM32181_MLUX_PER_LUX   1000
+
+#define CM32181_ID 0x81
+#define CM3218_ID  0x18
+
+#define CM3218_ARA_ADDR0x0c
 
 static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = {
CM32181_REG_ADDR_CMD,
 };
 
-static const int als_it_bits[] = {12, 8, 0, 1, 2, 3};
-static const int als_it_value[] = {25000, 5, 10, 20, 40,
+static const int cm32181_als_it_bits[] = {12, 8, 0, 1, 2, 3};
+static const int cm32181_als_it_value[] = {25000, 5, 10, 20, 
40,
80};
 
 struct cm32181_chip {
struct i2c_client *client;
+   int chip_id;
+   struct i2c_client *ara;
struct mutex lock;
u16 conf_regs[CM32181_CONF_REG_NUM];
int calibscale;
@@ -81,7 +92,7 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
return ret;
 
/* check device ID */
-   if ((ret & 0xFF) != 0x81)
+   if ((ret & 0xFF) != cm32181->chip_id)
return -ENODEV;
 
/* Default Values */
@@ -103,7 +114,7 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
 /**
  *  cm32181_read_als_it() - Get sensor integration time (ms)
  *  @cm32181:  pointer of struct cm32181
- *  @val2: pointer of int to load the als_it value.
+ *  @val2: pointer of int to load the cm32181_als_it value.
  *
  *  Report the current integartion time by millisecond.
  *
@@ -117,9 +128,9 @@ static int cm32181_read_als_it(struct cm32181_chip 
*cm32181, int *val2)
als_it = cm32181->conf_regs[CM32181_REG_ADDR_CMD];
als_it &= CM32181_CMD_ALS_IT_MASK;
als_it >>= CM32181_CMD_ALS_IT_SHIFT;
-   for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) {
-   if (als_it == als_it_bits[i]) {
-   *val2 = als_it_value[i];
+   for (i = 0; i < ARRAY_SIZE(cm32181_als_it_bits); i++) {
+   if (als_it == cm32181_als_it_bits[i]) {
+   *val2 = cm32181_als_it_value[i];
return IIO_VAL_INT_PLUS_MICRO;
}
}
@@ -142,14 +153,14 @@ static int cm32181_write_als_it(struct cm32181_chip 
*cm32181, int val)
u16 als_it;
int ret, i, n;
 
-   n = ARRAY_SIZE(als_it_value);
+   n = ARRAY_SIZE(cm32181_als_it_value);
for (i = 0; i < n; i++)
-   if (val <= als_it_value[i])
+   if (val <= cm32181_als_it_value[i])
break;
if (i >= n)
i = n - 1;
 
-   als_it = als_it_bits[i];
+   als_it = cm32181_als_it_bits[i];
als_it <<= CM32181_CMD_ALS_IT_SHIFT;
 
mutex_lock(&cm32181->lock);
@@ -195,7 +206,7 @@ static int cm32181_get_lux(struct cm32181_chip *cm32181)
lux *= ret;
lux *= cm32181->calibscale;
lux /= CM32181_CALIBSCALE_RESOLUTION;
-   lux /= MLUX_PER_LUX;
+   lux /= CM32181_MLUX_PER_LUX;
 
if (lux > 0x)
lux = 0x;
@@ -2

[PATCH v2] iio : Add cm3218 smbus ara and acpi support

2017-10-25 Thread Marc CAPDEVILLE
On asus T100, Capella cm3218 chip is implemented as ambiant light
sensor. This chip expose an smbus ARA protocol device on standard
address 0x0c. The chip is not functional before all alerts are
acknowledged.
On asus T100, this device is enumerated on ACPI bus and the description
give tow I2C connection. The first is the connection to the ARA device
and the second gives the real address of the device.

So, on device probe,If the i2c address is the ARA address and the
device is enumerated via acpi, we lookup for the real address in
the ACPI resource list and change it in the client structure.
if an interrupt resource is given, and only for cm3218 chip,
we declare an smbus_alert device.

Signed-off-by: Marc CAPDEVILLE 
---
v2 : 
   - cm3218 support always build
   - Cleanup of unneeded #if statement
   - Beter identifying chip in platform device, acpi and of_device

 drivers/iio/light/cm32181.c | 165 +++-
 1 file changed, 162 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index d6fd0da..7bc97ff 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -18,6 +18,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 /* Registers Address */
 #define CM32181_REG_ADDR_CMD   0x00
@@ -47,6 +50,11 @@
 #define CM32181_CALIBSCALE_RESOLUTION  1000
 #define MLUX_PER_LUX   1000
 
+#define CM32181_ID 0x81
+#define CM3218_ID  0x18
+
+#define CM3218_ARA_ADDR0x0c
+
 static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = {
CM32181_REG_ADDR_CMD,
 };
@@ -57,6 +65,8 @@ static const int als_it_value[] = {25000, 5, 10, 
20, 40,
 
 struct cm32181_chip {
struct i2c_client *client;
+   int chip_id;
+   struct i2c_client *ara;
struct mutex lock;
u16 conf_regs[CM32181_CONF_REG_NUM];
int calibscale;
@@ -81,7 +91,7 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
return ret;
 
/* check device ID */
-   if ((ret & 0xFF) != 0x81)
+   if ((ret & 0xFF) != cm32181->chip_id)
return -ENODEV;
 
/* Default Values */
@@ -298,12 +308,81 @@ static const struct iio_info cm32181_info = {
.attrs  = &cm32181_attribute_group,
 };
 
+#if defined(CONFIG_ACPI)
+/* Parse acpi resources for a second i2c address on same adapter
+ */
+static int cm3218_get_i2c_address(struct acpi_resource *ares, void *data)
+{
+   struct i2c_client *client = data;
+   struct acpi_resource_i2c_serialbus *sb;
+   acpi_status status;
+   acpi_handle adapter_handle;
+
+   if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+   return 1;
+
+   sb = &ares->data.i2c_serial_bus;
+   if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
+   return 1;
+
+   status = acpi_get_handle(ACPI_HANDLE(&client->dev),
+sb->resource_source.string_ptr,
+&adapter_handle);
+   if (!ACPI_SUCCESS(status))
+   return 1;
+
+   if (adapter_handle != ACPI_HANDLE(&client->adapter->dev))
+   return 1;
+
+   if (sb->slave_address == CM3218_ARA_ADDR)
+   return 1;
+
+   client->addr = sb->slave_address;
+   client->flags &= ~I2C_CLIENT_TEN;
+   if (sb->access_mode == ACPI_I2C_10BIT_MODE)
+   client->flags |= I2C_CLIENT_TEN;
+
+   return -1;
+}
+
+/* Walk through acpi resources to find second i2c connection
+ */
+static int cm3218_acpi_get_address(struct i2c_client *client)
+{
+   int ret;
+   struct acpi_device *adev;
+   LIST_HEAD(ares);
+
+   adev = ACPI_COMPANION(&client->dev);
+   if (!adev)
+   return -ENODEV;
+
+   ret = acpi_dev_get_resources(adev,
+&ares,
+cm3218_get_i2c_address,
+client);
+   acpi_dev_free_resource_list(&ares);
+   if (ret < 0)
+   return -ENODEV;
+
+   return 0;
+}
+#else
+static inline int cm3218_acpi_get_address(struct i2c_client *client)
+{
+   return -ENODEV;
+}
+#endif
+
 static int cm32181_probe(struct i2c_client *client,
const struct i2c_device_id *id)
 {
struct cm32181_chip *cm32181;
struct iio_dev *indio_dev;
int ret;
+   struct i2c_smbus_alert_setup ara_setup;
+   const struct of_device_id *of_id;
+   const struct acpi_device_id *acpi_id;
 
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*cm32181));
if (!indio_dev) {
@@ -323,11 +402,65 @@ static int cm32181_probe(struct i2c_client *client,
indio_dev->name = id->name;
indio_dev->modes =

[PATCH] iio : Add cm3218 smbus ara and acpi support

2017-10-19 Thread Marc CAPDEVILLE
On asus T100, Capella cm3218 chip is implemented as ambiant light
sensor. This chip expose an smbus ARA protocol device on standard
address 0x0c. The chip is not functional before all alerts are
acknowledged.
On asus T100, this device is enumerated on ACPI bus and the description
give tow I2C connection. The first is the connection to the ARA device
and the second gives the real address of the device.

So, on device probe, if an interrupt resource is given, we declare an
smbus_alert device, and if the i2c address is the ARA address, we lookup
for the second in the ACPI resource list and change it in the client
structur.

Signed-off-by: Marc CAPDEVILLE 
---
 drivers/iio/light/Kconfig   |  19 +++
 drivers/iio/light/cm32181.c | 119 
 2 files changed, 138 insertions(+)

diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 2356ed9..6b1dacc 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -94,6 +94,25 @@ config CM32181
 To compile this driver as a module, choose M here:
 the module will be called cm32181.
 
+if CM32181
+config CM3218
+   depends on CM32181
+   depends on I2C_SMBUS
+   bool "Support for smbus ara protocol on cm3218 chip"
+   help
+Say Y here if you want to support Capella cm3218
+ambiant light sensor with smbus ARA protocol.
+
+config CM3218_ACPI
+   depends on CM3218
+   depends on ACPI
+   bool "Support for second address on acpi enumerated cm3218"
+   help
+Say Y here if you want to support Capella cm3218
+ambiant light sensor enumerated on ACPI.
+
+endif #CM32181
+
 config CM3232
depends on I2C
tristate "CM3232 ambient light sensor"
diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index d6fd0da..9b69177 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -18,6 +18,12 @@
 #include 
 #include 
 #include 
+#if defined(CONFIG_I2C_SMBUS) && defined(CONFIG_CM3218)
+#include 
+#if  defined(CONFIG_ACPI) && defined(CONFIG_CM3218_ACPI)
+#include 
+#endif
+#endif
 
 /* Registers Address */
 #define CM32181_REG_ADDR_CMD   0x00
@@ -47,6 +53,10 @@
 #define CM32181_CALIBSCALE_RESOLUTION  1000
 #define MLUX_PER_LUX   1000
 
+#if defined(CONFIG_I2C_SMBUS) && defined(CONFIG_CM3218)
+#define CM3218_ARA_ADDR0x0c
+#endif
+
 static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = {
CM32181_REG_ADDR_CMD,
 };
@@ -57,6 +67,9 @@ static const int als_it_value[] = {25000, 5, 10, 
20, 40,
 
 struct cm32181_chip {
struct i2c_client *client;
+#if  defined(CONFIG_I2C_SMBUS) && defined(CONFIG_CM3218)
+   struct i2c_client *ara;
+#endif
struct mutex lock;
u16 conf_regs[CM32181_CONF_REG_NUM];
int calibscale;
@@ -81,7 +94,11 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
return ret;
 
/* check device ID */
+#ifdef CONFIG_CM3218
+   if ((ret & 0xFF) != 0x81 && (ret & 0xFF) != 0x18)
+#else
if ((ret & 0xFF) != 0x81)
+#endif
return -ENODEV;
 
/* Default Values */
@@ -298,12 +315,59 @@ static const struct iio_info cm32181_info = {
.attrs  = &cm32181_attribute_group,
 };
 
+#if defined(CONFIG_ACPI) && defined(CONFIG_CM3218_ACPI)
+static int cm3218_get_i2c_client(struct acpi_resource *ares, void *data)
+{
+   struct i2c_client *client = data;
+   struct acpi_resource_i2c_serialbus *sb;
+   acpi_status status;
+   acpi_handle adapter_handle;
+   acpi_handle client_adapter_handle;
+
+   if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+   return 1;
+
+   sb = &ares->data.i2c_serial_bus;
+   if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
+   return 1;
+
+   status = 
acpi_get_handle(acpi_device_handle(ACPI_COMPANION(&client->dev)),
+sb->resource_source.string_ptr,
+&adapter_handle);
+   if (!ACPI_SUCCESS(status))
+   return 1;
+
+   client_adapter_handle = 
acpi_device_handle(ACPI_COMPANION(&client->adapter->dev));
+
+   if (adapter_handle != client_adapter_handle)
+   return 1;
+
+   if (sb->slave_address == client->addr)
+   return 1;
+
+   client->addr = sb->slave_address;
+   client->flags &= ~I2C_CLIENT_TEN;
+   if (sb->access_mode == ACPI_I2C_10BIT_MODE)
+   client->flags |= I2C_CLIENT_TEN;
+
+   return -1;
+}
+#endif
+
 static int cm32181_probe(struct i2c_client *client,
const struct i2c_device_id *id)
 {
struct cm32181_chip *cm32181;
struct iio_dev *indio_dev;
int ret;
+#if defined(CONFIG_