Re: [PATCH v3 2/3] hwmon: ltc2992: Add support for GPIOs.

2020-12-04 Thread Guenter Roeck
On Thu, Dec 03, 2020 at 09:11:54AM +0200, alexandru.tach...@analog.com wrote:
> From: Alexandru Tachici 
> 
> LTC2992 has 4 open-drain GPIOS. This patch exports to user
> space the 4 GPIOs using the GPIO driver Linux API.
> 
> Signed-off-by: Alexandru Tachici 

Applied.

Thanks,
Guenter

> ---
>  drivers/hwmon/Kconfig   |   1 +
>  drivers/hwmon/ltc2992.c | 160 +++-
>  2 files changed, 160 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index bf9e387270d6..8a8eb42fb1ec 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -861,6 +861,7 @@ config SENSORS_LTC2990
>  config SENSORS_LTC2992
>   tristate "Linear Technology LTC2992"
>   depends on I2C
> + depends on GPIOLIB
>   help
> If you say yes here you get support for Linear Technology LTC2992
> I2C System Monitor. The LTC2992 measures current, voltage, and
> diff --git a/drivers/hwmon/ltc2992.c b/drivers/hwmon/ltc2992.c
> index c11d585a9600..69dbb5aa5dc2 100644
> --- a/drivers/hwmon/ltc2992.c
> +++ b/drivers/hwmon/ltc2992.c
> @@ -8,6 +8,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -54,6 +55,9 @@
>  #define LTC2992_G4_MAX_THRESH0x74
>  #define LTC2992_G4_MIN_THRESH0x76
>  #define LTC2992_FAULT3   0x92
> +#define LTC2992_GPIO_STATUS  0x95
> +#define LTC2992_GPIO_IO_CTRL 0x96
> +#define LTC2992_GPIO_CTRL0x97
>  
>  #define LTC2992_POWER(x) (LTC2992_POWER1 + ((x) * 0x32))
>  #define LTC2992_POWER_MAX(x) (LTC2992_POWER1_MAX + ((x) * 0x32))
> @@ -96,8 +100,18 @@
>  #define LTC2992_VADC_UV_LSB  25000
>  #define LTC2992_VADC_GPIO_UV_LSB 500
>  
> +#define LTC2992_GPIO_NR  4
> +#define LTC2992_GPIO1_BIT7
> +#define LTC2992_GPIO2_BIT6
> +#define LTC2992_GPIO3_BIT0
> +#define LTC2992_GPIO4_BIT6
> +#define LTC2992_GPIO_BIT(x)  (LTC2992_GPIO_NR - (x) - 1)
> +
>  struct ltc2992_state {
>   struct i2c_client   *client;
> + struct gpio_chipgc;
> + struct mutexgpio_mutex; /* lock for gpio access */
> + const char  *gpio_names[LTC2992_GPIO_NR];
>   struct regmap   *regmap;
>   u32 r_sense_uohm[2];
>  };
> @@ -111,6 +125,8 @@ struct ltc2992_gpio_regs {
>   u8  alarm;
>   u8  min_alarm_msk;
>   u8  max_alarm_msk;
> + u8  ctrl;
> + u8  ctrl_bit;
>  };
>  
>  static const struct ltc2992_gpio_regs ltc2992_gpio_addr_map[] = {
> @@ -123,6 +139,8 @@ static const struct ltc2992_gpio_regs 
> ltc2992_gpio_addr_map[] = {
>   .alarm = LTC2992_FAULT1,
>   .min_alarm_msk = LTC2992_GPIO1_FAULT_MSK(0),
>   .max_alarm_msk = LTC2992_GPIO1_FAULT_MSK(1),
> + .ctrl = LTC2992_GPIO_IO_CTRL,
> + .ctrl_bit = LTC2992_GPIO1_BIT,
>   },
>   {
>   .data = LTC2992_G2,
> @@ -133,6 +151,8 @@ static const struct ltc2992_gpio_regs 
> ltc2992_gpio_addr_map[] = {
>   .alarm = LTC2992_FAULT2,
>   .min_alarm_msk = LTC2992_GPIO2_FAULT_MSK(0),
>   .max_alarm_msk = LTC2992_GPIO2_FAULT_MSK(1),
> + .ctrl = LTC2992_GPIO_IO_CTRL,
> + .ctrl_bit = LTC2992_GPIO2_BIT,
>   },
>   {
>   .data = LTC2992_G3,
> @@ -143,6 +163,8 @@ static const struct ltc2992_gpio_regs 
> ltc2992_gpio_addr_map[] = {
>   .alarm = LTC2992_FAULT3,
>   .min_alarm_msk = LTC2992_GPIO3_FAULT_MSK(0),
>   .max_alarm_msk = LTC2992_GPIO3_FAULT_MSK(1),
> + .ctrl = LTC2992_GPIO_IO_CTRL,
> + .ctrl_bit = LTC2992_GPIO3_BIT,
>   },
>   {
>   .data = LTC2992_G4,
> @@ -153,14 +175,20 @@ static const struct ltc2992_gpio_regs 
> ltc2992_gpio_addr_map[] = {
>   .alarm = LTC2992_FAULT3,
>   .min_alarm_msk = LTC2992_GPIO4_FAULT_MSK(0),
>   .max_alarm_msk = LTC2992_GPIO4_FAULT_MSK(1),
> + .ctrl = LTC2992_GPIO_CTRL,
> + .ctrl_bit = LTC2992_GPIO4_BIT,
>   },
>  };
>  
> +static const char *ltc2992_gpio_names[LTC2992_GPIO_NR] = {
> + "GPIO1", "GPIO2", "GPIO3", "GPIO4",
> +};
> +
>  static int ltc2992_read_reg(struct ltc2992_state *st, u8 addr, const u8 
> reg_len)
>  {
>   u8 regvals[4];
> - int ret;
>   int val;
> + int ret;
>   int i;
>  
>   ret = regmap_bulk_read(st->regmap, addr, regvals, reg_len);
> @@ -185,6 +213,132 @@ static int ltc2992_write_reg(struct ltc2992_state *st, 
> u8 addr, const u8 reg_len
>   return regmap_bulk_write(st->regmap, addr, regvals, reg_len);
>  }
>  
> +static int ltc2992_gpio_get(struct gpio_chip *chip, unsigned int offset)
> +{
> + struct ltc2992_state *st = gpiochip_get_data(chip);
> + unsigned long 

[PATCH v3 2/3] hwmon: ltc2992: Add support for GPIOs.

2020-12-02 Thread alexandru.tachici
From: Alexandru Tachici 

LTC2992 has 4 open-drain GPIOS. This patch exports to user
space the 4 GPIOs using the GPIO driver Linux API.

Signed-off-by: Alexandru Tachici 
---
 drivers/hwmon/Kconfig   |   1 +
 drivers/hwmon/ltc2992.c | 160 +++-
 2 files changed, 160 insertions(+), 1 deletion(-)

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index bf9e387270d6..8a8eb42fb1ec 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -861,6 +861,7 @@ config SENSORS_LTC2990
 config SENSORS_LTC2992
tristate "Linear Technology LTC2992"
depends on I2C
+   depends on GPIOLIB
help
  If you say yes here you get support for Linear Technology LTC2992
  I2C System Monitor. The LTC2992 measures current, voltage, and
diff --git a/drivers/hwmon/ltc2992.c b/drivers/hwmon/ltc2992.c
index c11d585a9600..69dbb5aa5dc2 100644
--- a/drivers/hwmon/ltc2992.c
+++ b/drivers/hwmon/ltc2992.c
@@ -8,6 +8,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -54,6 +55,9 @@
 #define LTC2992_G4_MAX_THRESH  0x74
 #define LTC2992_G4_MIN_THRESH  0x76
 #define LTC2992_FAULT3 0x92
+#define LTC2992_GPIO_STATUS0x95
+#define LTC2992_GPIO_IO_CTRL   0x96
+#define LTC2992_GPIO_CTRL  0x97
 
 #define LTC2992_POWER(x)   (LTC2992_POWER1 + ((x) * 0x32))
 #define LTC2992_POWER_MAX(x)   (LTC2992_POWER1_MAX + ((x) * 0x32))
@@ -96,8 +100,18 @@
 #define LTC2992_VADC_UV_LSB25000
 #define LTC2992_VADC_GPIO_UV_LSB   500
 
+#define LTC2992_GPIO_NR4
+#define LTC2992_GPIO1_BIT  7
+#define LTC2992_GPIO2_BIT  6
+#define LTC2992_GPIO3_BIT  0
+#define LTC2992_GPIO4_BIT  6
+#define LTC2992_GPIO_BIT(x)(LTC2992_GPIO_NR - (x) - 1)
+
 struct ltc2992_state {
struct i2c_client   *client;
+   struct gpio_chipgc;
+   struct mutexgpio_mutex; /* lock for gpio access */
+   const char  *gpio_names[LTC2992_GPIO_NR];
struct regmap   *regmap;
u32 r_sense_uohm[2];
 };
@@ -111,6 +125,8 @@ struct ltc2992_gpio_regs {
u8  alarm;
u8  min_alarm_msk;
u8  max_alarm_msk;
+   u8  ctrl;
+   u8  ctrl_bit;
 };
 
 static const struct ltc2992_gpio_regs ltc2992_gpio_addr_map[] = {
@@ -123,6 +139,8 @@ static const struct ltc2992_gpio_regs 
ltc2992_gpio_addr_map[] = {
.alarm = LTC2992_FAULT1,
.min_alarm_msk = LTC2992_GPIO1_FAULT_MSK(0),
.max_alarm_msk = LTC2992_GPIO1_FAULT_MSK(1),
+   .ctrl = LTC2992_GPIO_IO_CTRL,
+   .ctrl_bit = LTC2992_GPIO1_BIT,
},
{
.data = LTC2992_G2,
@@ -133,6 +151,8 @@ static const struct ltc2992_gpio_regs 
ltc2992_gpio_addr_map[] = {
.alarm = LTC2992_FAULT2,
.min_alarm_msk = LTC2992_GPIO2_FAULT_MSK(0),
.max_alarm_msk = LTC2992_GPIO2_FAULT_MSK(1),
+   .ctrl = LTC2992_GPIO_IO_CTRL,
+   .ctrl_bit = LTC2992_GPIO2_BIT,
},
{
.data = LTC2992_G3,
@@ -143,6 +163,8 @@ static const struct ltc2992_gpio_regs 
ltc2992_gpio_addr_map[] = {
.alarm = LTC2992_FAULT3,
.min_alarm_msk = LTC2992_GPIO3_FAULT_MSK(0),
.max_alarm_msk = LTC2992_GPIO3_FAULT_MSK(1),
+   .ctrl = LTC2992_GPIO_IO_CTRL,
+   .ctrl_bit = LTC2992_GPIO3_BIT,
},
{
.data = LTC2992_G4,
@@ -153,14 +175,20 @@ static const struct ltc2992_gpio_regs 
ltc2992_gpio_addr_map[] = {
.alarm = LTC2992_FAULT3,
.min_alarm_msk = LTC2992_GPIO4_FAULT_MSK(0),
.max_alarm_msk = LTC2992_GPIO4_FAULT_MSK(1),
+   .ctrl = LTC2992_GPIO_CTRL,
+   .ctrl_bit = LTC2992_GPIO4_BIT,
},
 };
 
+static const char *ltc2992_gpio_names[LTC2992_GPIO_NR] = {
+   "GPIO1", "GPIO2", "GPIO3", "GPIO4",
+};
+
 static int ltc2992_read_reg(struct ltc2992_state *st, u8 addr, const u8 
reg_len)
 {
u8 regvals[4];
-   int ret;
int val;
+   int ret;
int i;
 
ret = regmap_bulk_read(st->regmap, addr, regvals, reg_len);
@@ -185,6 +213,132 @@ static int ltc2992_write_reg(struct ltc2992_state *st, u8 
addr, const u8 reg_len
return regmap_bulk_write(st->regmap, addr, regvals, reg_len);
 }
 
+static int ltc2992_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+   struct ltc2992_state *st = gpiochip_get_data(chip);
+   unsigned long gpio_status;
+   int reg;
+
+   mutex_lock(>gpio_mutex);
+   reg = ltc2992_read_reg(st, LTC2992_GPIO_STATUS, 1);
+   mutex_unlock(>gpio_mutex);
+
+   if (reg < 0)
+   return reg;
+
+   gpio_status = reg;
+
+   return