Re: [PATCH v2 08/12] iio: imu: inv_icm42600: add device interrupt

2020-05-31 Thread Jonathan Cameron
On Wed, 27 May 2020 20:57:07 +0200
Jean-Baptiste Maneyrol  wrote:

> Add INT1 interrupt support. Support interrupt edge and level,
> active high or low. Push-pull or open-drain configurations.
> 
> Interrupt will be used to read data from the FIFO.
> 
> Signed-off-by: Jean-Baptiste Maneyrol 

Some nitpicks inline - all cases where a blank line would slightly
help readability.

J

> ---
>  drivers/iio/imu/inv_icm42600/inv_icm42600.h   |  2 +-
>  .../iio/imu/inv_icm42600/inv_icm42600_core.c  | 96 ++-
>  .../iio/imu/inv_icm42600/inv_icm42600_i2c.c   |  3 +-
>  .../iio/imu/inv_icm42600/inv_icm42600_spi.c   |  3 +-
>  4 files changed, 100 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h 
> b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
> index c534acae0308..43749f56426c 100644
> --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h
> +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
> @@ -372,7 +372,7 @@ int inv_icm42600_set_temp_conf(struct inv_icm42600_state 
> *st, bool enable,
>  int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
>unsigned int writeval, unsigned int *readval);
>  
> -int inv_icm42600_core_probe(struct regmap *regmap, int chip,
> +int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
>   inv_icm42600_bus_setup bus_setup);
>  
>  int inv_icm42600_gyro_init(struct inv_icm42600_state *st);
> diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c 
> b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
> index e7f7835aca9b..246c1eb52231 100644
> --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
> +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
> @@ -9,8 +9,11 @@
>  #include 
>  #include 
>  #include 
> +#include 
> +#include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  
> @@ -409,6 +412,79 @@ static int inv_icm42600_setup(struct inv_icm42600_state 
> *st,
>   return inv_icm42600_set_conf(st, hw->conf);
>  }
>  
> +static irqreturn_t inv_icm42600_irq_handler(int irq, void *_data)
> +{
> + struct inv_icm42600_state *st = _data;
> + struct device *dev = regmap_get_device(st->map);
> + unsigned int status;
> + int ret;
> +
> + mutex_lock(>lock);
> +
> + ret = regmap_read(st->map, INV_ICM42600_REG_INT_STATUS, );
> + if (ret)
> + goto out_unlock;
> +
> + /* FIFO full */
> + if (status & INV_ICM42600_INT_STATUS_FIFO_FULL)
> + dev_warn(dev, "FIFO full data lost!\n");
> +
> +out_unlock:
> + mutex_unlock(>lock);
> + return IRQ_HANDLED;
> +}
> +
> +/**
> + * inv_icm42600_irq_init() - initialize int pin and interrupt handler
> + * @st:  driver internal state
> + * @irq: irq number
> + * @irq_type:irq trigger type
> + * @open_drain:  true if irq is open drain, false for push-pull
> + *
> + * Returns 0 on success, a negative error code otherwise.
> + */
> +static int inv_icm42600_irq_init(struct inv_icm42600_state *st, int irq,
> +  int irq_type, bool open_drain)
> +{
> + struct device *dev = regmap_get_device(st->map);
> + unsigned int val;
> + int ret;
> +
> + /* configure INT1 interrupt: default is active low on edge */
> + switch (irq_type) {
> + case IRQF_TRIGGER_RISING:
> + case IRQF_TRIGGER_HIGH:
> + val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_HIGH;
> + break;
> + default:
> + val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_LOW;
> + break;
> + }

blank line here

> + switch (irq_type) {
> + case IRQF_TRIGGER_LOW:
> + case IRQF_TRIGGER_HIGH:
> + val |= INV_ICM42600_INT_CONFIG_INT1_LATCHED;
> + break;
> + default:
> + break;
> + }

blank line here.

> + if (!open_drain)
> + val |= INV_ICM42600_INT_CONFIG_INT1_PUSH_PULL;

blank line here

> + ret = regmap_write(st->map, INV_ICM42600_REG_INT_CONFIG, val);
> + if (ret)
> + return ret;
> +
> + /* Deassert async reset for proper INT pin operation (cf datasheet) */
> + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_CONFIG1,
> +  INV_ICM42600_INT_CONFIG1_ASYNC_RESET, 0);
> + if (ret)
> + return ret;
> +
> + return devm_request_threaded_irq(dev, irq, NULL,
> +  inv_icm42600_irq_handler, irq_type,
> +  "inv_icm42600", st);
> +}
> +
>  static int inv_icm42600_enable_regulator_vddio(struct inv_icm42600_state *st)
>  {
>   int ret;
> @@ -453,11 +529,14 @@ static void inv_icm42600_disable_pm(void *_data)
>   pm_runtime_disable(dev);
>  }
>  
> -int inv_icm42600_core_probe(struct regmap *regmap, int chip,
> +int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
>   inv_icm42600_bus_setup bus_setup)
>  {
>   

[PATCH v2 08/12] iio: imu: inv_icm42600: add device interrupt

2020-05-27 Thread Jean-Baptiste Maneyrol
Add INT1 interrupt support. Support interrupt edge and level,
active high or low. Push-pull or open-drain configurations.

Interrupt will be used to read data from the FIFO.

Signed-off-by: Jean-Baptiste Maneyrol 
---
 drivers/iio/imu/inv_icm42600/inv_icm42600.h   |  2 +-
 .../iio/imu/inv_icm42600/inv_icm42600_core.c  | 96 ++-
 .../iio/imu/inv_icm42600/inv_icm42600_i2c.c   |  3 +-
 .../iio/imu/inv_icm42600/inv_icm42600_spi.c   |  3 +-
 4 files changed, 100 insertions(+), 4 deletions(-)

diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h 
b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
index c534acae0308..43749f56426c 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
@@ -372,7 +372,7 @@ int inv_icm42600_set_temp_conf(struct inv_icm42600_state 
*st, bool enable,
 int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
 unsigned int writeval, unsigned int *readval);
 
-int inv_icm42600_core_probe(struct regmap *regmap, int chip,
+int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
inv_icm42600_bus_setup bus_setup);
 
 int inv_icm42600_gyro_init(struct inv_icm42600_state *st);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c 
b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
index e7f7835aca9b..246c1eb52231 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
@@ -9,8 +9,11 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -409,6 +412,79 @@ static int inv_icm42600_setup(struct inv_icm42600_state 
*st,
return inv_icm42600_set_conf(st, hw->conf);
 }
 
+static irqreturn_t inv_icm42600_irq_handler(int irq, void *_data)
+{
+   struct inv_icm42600_state *st = _data;
+   struct device *dev = regmap_get_device(st->map);
+   unsigned int status;
+   int ret;
+
+   mutex_lock(>lock);
+
+   ret = regmap_read(st->map, INV_ICM42600_REG_INT_STATUS, );
+   if (ret)
+   goto out_unlock;
+
+   /* FIFO full */
+   if (status & INV_ICM42600_INT_STATUS_FIFO_FULL)
+   dev_warn(dev, "FIFO full data lost!\n");
+
+out_unlock:
+   mutex_unlock(>lock);
+   return IRQ_HANDLED;
+}
+
+/**
+ * inv_icm42600_irq_init() - initialize int pin and interrupt handler
+ * @st:driver internal state
+ * @irq:   irq number
+ * @irq_type:  irq trigger type
+ * @open_drain:true if irq is open drain, false for push-pull
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+static int inv_icm42600_irq_init(struct inv_icm42600_state *st, int irq,
+int irq_type, bool open_drain)
+{
+   struct device *dev = regmap_get_device(st->map);
+   unsigned int val;
+   int ret;
+
+   /* configure INT1 interrupt: default is active low on edge */
+   switch (irq_type) {
+   case IRQF_TRIGGER_RISING:
+   case IRQF_TRIGGER_HIGH:
+   val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_HIGH;
+   break;
+   default:
+   val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_LOW;
+   break;
+   }
+   switch (irq_type) {
+   case IRQF_TRIGGER_LOW:
+   case IRQF_TRIGGER_HIGH:
+   val |= INV_ICM42600_INT_CONFIG_INT1_LATCHED;
+   break;
+   default:
+   break;
+   }
+   if (!open_drain)
+   val |= INV_ICM42600_INT_CONFIG_INT1_PUSH_PULL;
+   ret = regmap_write(st->map, INV_ICM42600_REG_INT_CONFIG, val);
+   if (ret)
+   return ret;
+
+   /* Deassert async reset for proper INT pin operation (cf datasheet) */
+   ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_CONFIG1,
+INV_ICM42600_INT_CONFIG1_ASYNC_RESET, 0);
+   if (ret)
+   return ret;
+
+   return devm_request_threaded_irq(dev, irq, NULL,
+inv_icm42600_irq_handler, irq_type,
+"inv_icm42600", st);
+}
+
 static int inv_icm42600_enable_regulator_vddio(struct inv_icm42600_state *st)
 {
int ret;
@@ -453,11 +529,14 @@ static void inv_icm42600_disable_pm(void *_data)
pm_runtime_disable(dev);
 }
 
-int inv_icm42600_core_probe(struct regmap *regmap, int chip,
+int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
inv_icm42600_bus_setup bus_setup)
 {
struct device *dev = regmap_get_device(regmap);
struct inv_icm42600_state *st;
+   struct irq_data *irq_desc;
+   int irq_type;
+   bool open_drain;
int ret;
 
if (chip < 0 || chip >= INV_CHIP_NB) {
@@ -465,6 +544,17 @@ int inv_icm42600_core_probe(struct regmap *regmap, int 
chip,
return -ENODEV;
}
 
+   /*