From: Guenter Roeck <linux@roeck-us.net>
To: alexandru.tachici@analog.com
Cc: linux-hwmon@vger.kernel.org, linux-kernel@vger.kernel.org,
devicetree@vger.kernel.org, robh+dt@kernel.org
Subject: Re: [PATCH 2/3] hwmon: ltc2992: Add support for GPIOs.
Date: Sun, 8 Nov 2020 09:33:13 -0800 [thread overview]
Message-ID: <20201108173313.GA31165@roeck-us.net> (raw)
In-Reply-To: <20201029094911.79173-3-alexandru.tachici@analog.com>
On Thu, Oct 29, 2020 at 11:49:10AM +0200, alexandru.tachici@analog.com wrote:
> From: Alexandru Tachici <alexandru.tachici@analog.com>
>
> 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 <alexandru.tachici@analog.com>
> Reported-by: kernel test robot <lkp@intel.com>
Please fix the problem reported by 0-day and resubmit.
Thanks,
Guenter
> ---
> drivers/hwmon/Kconfig | 1 +
> drivers/hwmon/ltc2992.c | 160 ++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 161 insertions(+)
>
> 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 940d92b4a1d0..3fe6d34cdade 100644
> --- a/drivers/hwmon/ltc2992.c
> +++ b/drivers/hwmon/ltc2992.c
> @@ -9,6 +9,7 @@
> #include <linux/bitops.h>
> #include <linux/bits.h>
> #include <linux/err.h>
> +#include <linux/gpio/driver.h>
> #include <linux/hwmon.h>
> #include <linux/hwmon-sysfs.h>
> #include <linux/i2c.h>
> @@ -56,6 +57,9 @@
> #define LTC2992_G4_MAX_THRESH 0x74
> #define LTC2992_G4_MIN_THRESH 0x76
> #define LTC2992_FAULT3 0x92
> +#define LTC2992_GPIO_STATUS 0x95
> +#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))
> @@ -95,8 +99,18 @@
> #define LTC2992_VADC_UV_LSB 25000
> #define LTC2992_VADC_GPIO_UV_LSB 500
>
> +#define LTC2992_GPIO_NR 4
> +#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_chip gc;
> + struct mutex gpio_mutex; /* lock for gpio access */
> + const char *gpio_names[LTC2992_GPIO_NR];
> struct regmap *regmap;
> u32 r_sense_uohm[2];
> };
> @@ -109,6 +123,8 @@ struct ltc2992_gpio_regs {
> u8 min_thresh;
> u8 alarm;
> u8 alarm_msk;
> + u8 ctrl;
> + u8 ctrl_bit;
> };
>
> static const struct ltc2992_gpio_regs ltc2992_gpio_addr_map[] = {
> @@ -120,6 +136,8 @@ static const struct ltc2992_gpio_regs ltc2992_gpio_addr_map[] = {
> .min_thresh = LTC2992_G1_MIN_THRESH,
> .alarm = LTC2992_FAULT1,
> .alarm_msk = LTC2992_GPIO1_FAULT_MSK,
> + .ctrl = LTC2992_GPIO_IO_CTRL,
> + .ctrl_bit = LTC2992_GPIO1_BIT,
> },
> {
> .data = LTC2992_G2,
> @@ -129,6 +147,8 @@ static const struct ltc2992_gpio_regs ltc2992_gpio_addr_map[] = {
> .min_thresh = LTC2992_G2_MIN_THRESH,
> .alarm = LTC2992_FAULT2,
> .alarm_msk = LTC2992_GPIO2_FAULT_MSK,
> + .ctrl = LTC2992_GPIO_IO_CTRL,
> + .ctrl_bit = LTC2992_GPIO2_BIT,
> },
> {
> .data = LTC2992_G3,
> @@ -138,6 +158,8 @@ static const struct ltc2992_gpio_regs ltc2992_gpio_addr_map[] = {
> .min_thresh = LTC2992_G3_MIN_THRESH,
> .alarm = LTC2992_FAULT3,
> .alarm_msk = LTC2992_GPIO3_FAULT_MSK,
> + .ctrl = LTC2992_GPIO_IO_CTRL,
> + .ctrl_bit = LTC2992_GPIO3_BIT,
> },
> {
> .data = LTC2992_G4,
> @@ -147,9 +169,15 @@ static const struct ltc2992_gpio_regs ltc2992_gpio_addr_map[] = {
> .min_thresh = LTC2992_G4_MIN_THRESH,
> .alarm = LTC2992_FAULT3,
> .alarm_msk = LTC2992_GPIO4_FAULT_MSK,
> + .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, u32 *val)
> {
> u8 regvals[4];
> @@ -178,6 +206,134 @@ 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;
> + u32 reg;
> + int ret;
> +
> + mutex_lock(&st->gpio_mutex);
> + ret = ltc2992_read_reg(st, LTC2992_GPIO_STATUS, 1, ®);
> + mutex_unlock(&st->gpio_mutex);
> +
> + if (ret < 0)
> + return ret;
> +
> + gpio_status = reg;
> +
> + return !test_bit(LTC2992_GPIO_BIT(offset), &gpio_status);
> +}
> +
> +static int ltc2992_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
> + unsigned long *bits)
> +{
> + struct ltc2992_state *st = gpiochip_get_data(chip);
> + unsigned long gpio_status;
> + unsigned int gpio_nr;
> + u32 reg;
> + int ret;
> +
> + mutex_lock(&st->gpio_mutex);
> + ret = ltc2992_read_reg(st, LTC2992_GPIO_STATUS, 1, ®);
> + mutex_unlock(&st->gpio_mutex);
> +
> + if (ret < 0)
> + return ret;
> +
> + gpio_status = reg;
> +
> + gpio_nr = 0;
> + for_each_set_bit_from(gpio_nr, mask, LTC2992_GPIO_NR) {
> + if (test_bit(LTC2992_GPIO_BIT(gpio_nr), &gpio_status))
> + set_bit(gpio_nr, bits);
> + }
> +
> + return 0;
> +}
> +
> +static void ltc2992_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
> +{
> + struct ltc2992_state *st = gpiochip_get_data(chip);
> + unsigned long gpio_ctrl;
> + u32 reg_val;
> + int ret;
> +
> + mutex_lock(&st->gpio_mutex);
> + ret = ltc2992_read_reg(st, ltc2992_gpio_addr_map[offset].ctrl, 1, ®_val);
> + if (ret < 0) {
> + mutex_unlock(&st->gpio_mutex);
> + return;
> + }
> +
> + gpio_ctrl = reg_val;
> + assign_bit(ltc2992_gpio_addr_map[offset].ctrl_bit, &gpio_ctrl, value);
> +
> + ltc2992_write_reg(st, ltc2992_gpio_addr_map[offset].ctrl, 1, gpio_ctrl);
> + mutex_unlock(&st->gpio_mutex);
> +}
> +
> +void ltc2992_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits)
> +{
> + struct ltc2992_state *st = gpiochip_get_data(chip);
> + unsigned long gpio_ctrl_io = 0;
> + unsigned long gpio_ctrl = 0;
> + unsigned int gpio_nr;
> +
> + for_each_set_bit(gpio_nr, mask, LTC2992_GPIO_NR) {
> + if (gpio_nr < 3)
> + assign_bit(ltc2992_gpio_addr_map[gpio_nr].ctrl_bit, &gpio_ctrl_io, true);
> +
> + if (gpio_nr == 3)
> + assign_bit(ltc2992_gpio_addr_map[gpio_nr].ctrl_bit, &gpio_ctrl, true);
> + }
> +
> + mutex_lock(&st->gpio_mutex);
> + ltc2992_write_reg(st, LTC2992_GPIO_IO_CTRL, 1, gpio_ctrl_io);
> + ltc2992_write_reg(st, LTC2992_GPIO_CTRL, 1, gpio_ctrl);
> + mutex_unlock(&st->gpio_mutex);
> +}
> +
> +static int ltc2992_config_gpio(struct ltc2992_state *st)
> +{
> + const char *name = dev_name(&st->client->dev);
> + char *gpio_name;
> + int ret;
> + int i;
> +
> + ret = ltc2992_write_reg(st, LTC2992_GPIO_IO_CTRL, 1, 0);
> + if (ret < 0)
> + return ret;
> +
> + mutex_init(&st->gpio_mutex);
> +
> + for (i = 0; i < ARRAY_SIZE(st->gpio_names); i++) {
> + gpio_name = devm_kasprintf(&st->client->dev, GFP_KERNEL, "ltc2992-%x-%s",
> + st->client->addr, ltc2992_gpio_names[i]);
> + if (!gpio_name)
> + return -ENOMEM;
> +
> + st->gpio_names[i] = gpio_name;
> + }
> +
> + st->gc.label = name;
> + st->gc.parent = &st->client->dev;
> + st->gc.owner = THIS_MODULE;
> + st->gc.base = -1;
> + st->gc.names = st->gpio_names;
> + st->gc.ngpio = ARRAY_SIZE(st->gpio_names);
> + st->gc.get = ltc2992_gpio_get;
> + st->gc.get_multiple = ltc2992_gpio_get_multiple;
> + st->gc.set = ltc2992_gpio_set;
> + st->gc.set_multiple = ltc2992_gpio_set_multiple;
> +
> + ret = devm_gpiochip_add_data(&st->client->dev, &st->gc, st);
> + if (ret)
> + dev_err(&st->client->dev, "GPIO registering failed (%d)\n", ret);
> +
> + return ret;
> +}
> +
> static umode_t ltc2992_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,
> int channel)
> {
> @@ -701,6 +857,10 @@ static int ltc2992_i2c_probe(struct i2c_client *client, const struct i2c_device_
> if (ret < 0)
> return ret;
>
> + ret = ltc2992_config_gpio(st);
> + if (ret < 0)
> + return ret;
> +
> hwmon_dev = devm_hwmon_device_register_with_info(&client->dev, client->name, st,
> <c2992_chip_info, NULL);
>
next prev parent reply other threads:[~2020-11-08 17:33 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-10-29 9:49 [PATCH 0/3] hwmon: ltc2992: Add support alexandru.tachici
2020-10-29 9:49 ` [PATCH 1/3] " alexandru.tachici
2020-11-04 5:54 ` Guenter Roeck
2020-10-29 9:49 ` [PATCH 2/3] hwmon: ltc2992: Add support for GPIOs alexandru.tachici
2020-10-30 8:15 ` kernel test robot
2020-10-30 8:15 ` kernel test robot
2020-11-01 18:32 ` kernel test robot
2020-11-01 18:32 ` kernel test robot
2020-11-08 17:33 ` Guenter Roeck [this message]
2020-10-29 9:49 ` [PATCH 3/3] dt-binding: hwmon: Add documentation for ltc2992 alexandru.tachici
2020-10-29 15:36 ` Rob Herring
2020-10-29 15:37 ` Rob Herring
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201108173313.GA31165@roeck-us.net \
--to=linux@roeck-us.net \
--cc=alexandru.tachici@analog.com \
--cc=devicetree@vger.kernel.org \
--cc=linux-hwmon@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=robh+dt@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.