Skip to contentSkip to conversation

GPIO driver for Maxim MAX3191x

PATCH New Lukas Wunner 8 participants 26 messages Aug 21, 2017 – Oct 12, 2017 2 messages not in the archive

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover GPIO driver for Maxim MAX3191x

GPIO driver for Maxim MAX31910, MAX31911, MAX31912, MAX31913, MAX31953 and MAX31963 industrial serializer, a daisy-chainable chip to make 8 digital 24V inputs available via SPI. Supports CRC checksums to guard against electromagnetic interference, as well as undervoltage and overtemperature detection.

The chip is used by the "Revolution Pi" family of open source PLCs based on the Raspberry Pi (https://revolution.kunbus.com/).

In a typical SCADA system, all input signals are read periodically, say, every 5 or 10 ms, and stored in a so-called "process image". To make this perform well with serializers, add a ->get_multiple callback to struct gpio_chip, add corresponding consumer functions and wire it up with linehandle_ioctl().

Thanks,

Lukas

Lukas Wunner (4):
bitops: Introduce assign_bit()
gpio: Introduce ->get_multiple callback
dt-bindings: gpio: max3191x: Document new driver
gpio: Add driver for Maxim MAX3191x industrial serializer

 .../devicetree/bindings/gpio/gpio-max3191x.txt     |  37 ++
 drivers/gpio/Kconfig                               |  10 +
 drivers/gpio/Makefile                              |   1 +
 drivers/gpio/gpio-max3191x.c                       | 482 +++++++++++++++++++++
 drivers/gpio/gpiolib.c                             | 181 +++++++-
 drivers/gpio/gpiolib.h                             |   4 +
 drivers/md/dm-mpath.c                              |   8 -
 include/linux/bitops.h                             |  24 +
 include/linux/gpio/consumer.h                      |  44 ++
 include/linux/gpio/driver.h                        |   5 +
 10 files changed, 777 insertions(+), 19 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/gpio/gpio-max3191x.txt
 create mode 100644 drivers/gpio/gpio-max3191x.c
Signature · 6 lines
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#1 lore raw

PATCH 1/4 bitops: Introduce assign_bit()

A common idiom is to assign a value to a bit with:

    if (value)
        set_bit(nr, addr);
    else
        clear_bit(nr, addr);

Likewise common is the one-line expression variant:

    value ? set_bit(nr, addr) : clear_bit(nr, addr);

Commit 9a8ac3ae682e ("dm mpath: cleanup QUEUE_IF_NO_PATH bit manipulation by introducing assign_bit()") introduced assign_bit() to the md subsystem for brevity.

Make it available to others, in particular gpiolib and the upcoming driver for Maxim MAX3191x industrial serializer chips.

Cc Bart Van Assche <[email protected]>
Cc Alasdair Kergon <[email protected]>
Cc Mike Snitzer <[email protected]>
---
 drivers/md/dm-mpath.c  |  8 --------
 include/linux/bitops.h | 24 ++++++++++++++++++++++++
 2 files changed, 24 insertions(+), 8 deletions(-)
drivers/md/dm-mpath.c +0 -8
index 0e8ab5bb3575..c79c113b7e7d 100644
@@ -638,14 +638,6 @@ static void process_queued_bios(struct work_struct *work)
 	blk_finish_plug(&plug);
 }
 
-static void assign_bit(bool value, long nr, unsigned long *addr)
-{
-	if (value)
-		set_bit(nr, addr);
-	else
-		clear_bit(nr, addr);
-}
-
 /*
  * If we run out of usable paths, should we queue I/O or error it?
  */
include/linux/bitops.h +24 -0
index a83c822c35c2..097af36887c0 100644
@@ -226,6 +226,30 @@ static inline unsigned long __ffs64(u64 word)
 	return __ffs((unsigned long)word);
 }
 
+/**
+ * assign_bit - Assign value to a bit in memory
+ * @value: the value to assign
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ */
+static __always_inline void assign_bit(bool value, long nr,
+				       volatile unsigned long *addr)
+{
+	if (value)
+		set_bit(nr, addr);
+	else
+		clear_bit(nr, addr);
+}
+
+static __always_inline void __assign_bit(bool value, long nr,
+					 volatile unsigned long *addr)
+{
+	if (value)
+		__set_bit(nr, addr);
+	else
+		__clear_bit(nr, addr);
+}
+
 #ifdef __KERNEL__
 
 #ifndef set_mask_bits
Signature · 1 line
2.11.0
#2 lore raw

Re: [PATCH 1/4] bitops: Introduce assign_bit()

Quoted 5 lines · Lukas Wunner
[ ... ]
Cc Bart Van Assche <[email protected]>
Cc Alasdair Kergon <[email protected]>
Cc Mike Snitzer <[email protected]>

This Cc-list is incomplete. Previous <linux/bitops.h> patches went in through Andrew Morton's tree so I think an ack from Andrew Morton is needed before this patch can be sent to Linus Torvalds. Please also Cc other frequent contributors to this header file, e.g. Ingo Molnar and Peter Zijlstra. Please also consider to Cc the LKML for this patch or even for the entire series.

Quoted 13 lines
include/linux/bitops.h +13 -0
+/**
+ * assign_bit - Assign value to a bit in memory
+ * @value: the value to assign
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ */
+static __always_inline void assign_bit(bool value, long nr,
+				       volatile unsigned long *addr)
+{
+	if (value)
+		set_bit(nr, addr);
+	else
+		clear_bit(nr, addr);

include/linux/bitops.h static inline unsigned long __ffs64(u64 word) · line 251

Quoted 10 lines
include/linux/bitops.h +10 -0
+}
+
+static __always_inline void __assign_bit(bool value, long nr,
+					 volatile unsigned long *addr)
+{
+	if (value)
+		__set_bit(nr, addr);
+	else
+		__clear_bit(nr, addr);
+}

Why has __always_inline been specified? What makes you think that you know better than the compiler whether or not these functions should be inlined?

Thanks,

Bart.

#3 lore raw

Re: [PATCH 1/4] bitops: Introduce assign_bit()

Quoted 6 lines · Bart Van Assche
Quoted 4 lines · Lukas Wunner
Cc Bart Van Assche <[email protected]>
Cc Alasdair Kergon <[email protected]>
Cc Mike Snitzer <[email protected]>
Quoted 6 lines

This Cc-list is incomplete. Previous <linux/bitops.h> patches went in through Andrew Morton's tree so I think an ack from Andrew Morton is needed before this patch can be sent to Linus Torvalds. Please also Cc other frequent contributors to this header file, e.g. Ingo Molnar and Peter Zijlstra. Please also consider to Cc the LKML for this patch or even for the entire series.

Fair enough, adding more folks to cc. Does anyone have objections or comments to the below patch and to merging it through linux-gpio?

It's part of this series:
https://www.spinics.net/lists/linux-gpio/msg25067.html

Looking at the mnemonics of x86 and arm I couldn't find one which would avoid the jump and be faster/shorter than the inline functions below, so putting this in include/linux/bitops.h (rather than arch/*/include/asm/) seemed appropriate. Can anyone imagine doing the same quicker with inline assembly?

Quoted 5 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+static __always_inline void assign_bit(bool value, long nr,
+				       volatile unsigned long *addr)

Why has __always_inline been specified? What makes you think that you know better than the compiler whether or not these functions should be inlined?

I carried this over from existing functions, see e.g. commit 1a1d48a4a8fd ("linux/bitmap: Force inlining of bitmap weight functions").

Thanks,

Lukas

-- >8 --
Subject: [PATCH 1/4] bitops: Introduce assign_bit()

A common idiom is to assign a value to a bit with:

    if (value)
        set_bit(nr, addr);
    else
        clear_bit(nr, addr);

Likewise common is the one-line expression variant:

    value ? set_bit(nr, addr) : clear_bit(nr, addr);

Commit 9a8ac3ae682e ("dm mpath: cleanup QUEUE_IF_NO_PATH bit manipulation by introducing assign_bit()") introduced assign_bit() to the md subsystem for brevity.

Make it available to others, in particular gpiolib and the upcoming driver for Maxim MAX3191x industrial serializer chips.

Cc Bart Van Assche <[email protected]>
Cc Alasdair Kergon <[email protected]>
Cc Mike Snitzer <[email protected]>
---
 drivers/md/dm-mpath.c  |  8 --------
 include/linux/bitops.h | 24 ++++++++++++++++++++++++
 2 files changed, 24 insertions(+), 8 deletions(-)
drivers/md/dm-mpath.c +0 -8
index 0e8ab5bb3575..c79c113b7e7d 100644
@@ -638,14 +638,6 @@ static void process_queued_bios(struct work_struct *work)
 	blk_finish_plug(&plug);
 }
 
-static void assign_bit(bool value, long nr, unsigned long *addr)
-{
-	if (value)
-		set_bit(nr, addr);
-	else
-		clear_bit(nr, addr);
-}
-
 /*
  * If we run out of usable paths, should we queue I/O or error it?
  */
include/linux/bitops.h +24 -0
index a83c822c35c2..097af36887c0 100644
@@ -226,6 +226,30 @@ static inline unsigned long __ffs64(u64 word)
 	return __ffs((unsigned long)word);
 }
 
+/**
+ * assign_bit - Assign value to a bit in memory
+ * @value: the value to assign
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ */
+static __always_inline void assign_bit(bool value, long nr,
+				       volatile unsigned long *addr)
+{
+	if (value)
+		set_bit(nr, addr);
+	else
+		clear_bit(nr, addr);
+}
+
+static __always_inline void __assign_bit(bool value, long nr,
+					 volatile unsigned long *addr)
+{
+	if (value)
+		__set_bit(nr, addr);
+	else
+		__clear_bit(nr, addr);
+}
+
 #ifdef __KERNEL__
 
 #ifndef set_mask_bits
Signature · 1 line
2.11.0
#4 lore raw

Re: [PATCH 1/4] bitops: Introduce assign_bit()

Quoted 22 lines · Lukas Wunner
include/linux/bitops.h +14 -0
index a83c822c35c2..097af36887c0 100644
@@ -226,6 +226,30 @@ static inline unsigned long __ffs64(u64 word)
 	return __ffs((unsigned long)word);
 }
 
+/**
+ * assign_bit - Assign value to a bit in memory
+ * @value: the value to assign
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ */
+static __always_inline void assign_bit(bool value, long nr,
+				       volatile unsigned long *addr)
+{
+	if (value)
+		set_bit(nr, addr);
+	else
+		clear_bit(nr, addr);
+}

include/linux/bitops.h static inline unsigned long __ffs64(u64 word) · line 252

Quoted 10 lines
include/linux/bitops.h +10 -0
+
+static __always_inline void __assign_bit(bool value, long nr,
+					 volatile unsigned long *addr)
+{
+	if (value)
+		__set_bit(nr, addr);
+	else
+		__clear_bit(nr, addr);
+}
+

I dislike the argument order, in C you naturally write: dst = src. So I would have expected:

	assign_bit(nr, addr, val);

but we have quite a few of these backwards functions in the kernel (like most of the atomic_t family) and I didn't check to see if the existing bitops are part of that 'tradition'.

#5 lore raw

Re: [PATCH 1/4] bitops: Introduce assign_bit()

Quoted 37 lines · Peter Zijlstra
Quoted 22 lines · Lukas Wunner
include/linux/bitops.h +14 -0
index a83c822c35c2..097af36887c0 100644
@@ -226,6 +226,30 @@ static inline unsigned long __ffs64(u64 word)
 	return __ffs((unsigned long)word);
 }
 
+/**
+ * assign_bit - Assign value to a bit in memory
+ * @value: the value to assign
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ */
+static __always_inline void assign_bit(bool value, long nr,
+				       volatile unsigned long *addr)
+{
+	if (value)
+		set_bit(nr, addr);
+	else
+		clear_bit(nr, addr);
+}

include/linux/bitops.h static inline unsigned long __ffs64(u64 word) · line 252

Quoted 10 lines
include/linux/bitops.h +10 -0
+
+static __always_inline void __assign_bit(bool value, long nr,
+					 volatile unsigned long *addr)
+{
+	if (value)
+		__set_bit(nr, addr);
+	else
+		__clear_bit(nr, addr);
+}
+

I dislike the argument order, in C you naturally write: dst = src. So I would have expected:

Quoted 5 lines
	assign_bit(nr, addr, val);

but we have quite a few of these backwards functions in the kernel (like most of the atomic_t family) and I didn't check to see if the existing bitops are part of that 'tradition'.

The functions in include/linux/bitmap.h do follow the dst-then-src pattern. I carried over the argument order from Bart's function to minimize the impact on the md subsystem, but will be happy to respin with the order you're suggesting. Will wait a bit though to see if there are further comments.

Thanks,

Lukas

#6 lore raw

Re: [PATCH 1/4] bitops: Introduce assign_bit()

In reply to Lukas Wunner
Quoted 15 lines · Lukas Wunner

A common idiom is to assign a value to a bit with:

    if (value)
        set_bit(nr, addr);
    else
        clear_bit(nr, addr);

Likewise common is the one-line expression variant:

    value ? set_bit(nr, addr) : clear_bit(nr, addr);

Commit 9a8ac3ae682e ("dm mpath: cleanup QUEUE_IF_NO_PATH bit manipulation by introducing assign_bit()") introduced assign_bit() to the md subsystem for brevity.

Quoted 7 lines

Make it available to others, in particular gpiolib and the upcoming driver for Maxim MAX3191x industrial serializer chips.

Cc Bart Van Assche <[email protected]>
Cc Alasdair Kergon <[email protected]>
Cc Mike Snitzer <[email protected]>

Looks reasonable.

Quoted 7 lines
include/linux/bitops.h +7 -0
+static __always_inline void assign_bit(bool value, long nr,
+                                      volatile unsigned long *addr)
+{
+       if (value)
+               set_bit(nr, addr);
+       else
+               clear_bit(nr, addr);

include/linux/bitops.h static inline unsigned long __ffs64(u64 word) · line 251

Quoted 10 lines
include/linux/bitops.h +10 -0
+}
+
+static __always_inline void __assign_bit(bool value, long nr,
+                                        volatile unsigned long *addr)
+{
+       if (value)
+               __set_bit(nr, addr);
+       else
+               __clear_bit(nr, addr);
+}

What I have never understood is the semantic difference between bitop_foo() and __bitop_foo().

And I even use them quite a lot.

Can someone explain when I use the bitop_foo() and when I use the __bitop_foo(). I am asking so I can understand patch 2/4 in this series.

I guess this is why I generally detest the __annotation, since it is so unspecific and unclear, but that is not something I expect you to solve in this patch.

Yours,
Linus Walleij

#7 lore raw

Re: [PATCH 1/4] bitops: Introduce assign_bit()

Quoted 3 lines · Linus Walleij

Can someone explain when I use the bitop_foo() and when I use the __bitop_foo(). I am asking so I can understand patch 2/4 in this series.

That's easy. From Documentation/core-api/atomic_ops.rst:

----------------------------------------------------------------------
Finally, there are non-atomic versions of the bitmask operations provided. They are used in contexts where some other higher-level SMP locking scheme is being used to protect the bitmask, and thus less expensive non-atomic operations may be used in the implementation. They have names similar to the above bitmask operation interfaces, except that two underscores are prefixed to the interface name. ::

	void __set_bit(unsigned long nr, volatile unsigned long *addr);
	void __clear_bit(unsigned long nr, volatile unsigned long *addr);
	void __change_bit(unsigned long nr, volatile unsigned long *addr);
	int __test_and_set_bit(unsigned long nr, volatile unsigned long *addr);
	int __test_and_clear_bit(unsigned long nr, volatile unsigned long *addr);
	int __test_and_change_bit(unsigned long nr, volatile unsigned long *addr);

These non-atomic variants also do not require any special memory barrier semantics.
----------------------------------------------------------------------

Bart.

#8 lore raw

Re: [PATCH 1/4] bitops: Introduce assign_bit()

Quoted 22 lines · Bart Van Assche
Quoted 3 lines · Linus Walleij

Can someone explain when I use the bitop_foo() and when I use the __bitop_foo(). I am asking so I can understand patch 2/4 in this series.

That's easy. From Documentation/core-api/atomic_ops.rst:

----------------------------------------------------------------------
Finally, there are non-atomic versions of the bitmask operations provided. They are used in contexts where some other higher-level SMP locking scheme is being used to protect the bitmask, and thus less expensive non-atomic operations may be used in the implementation. They have names similar to the above bitmask operation interfaces, except that two underscores are prefixed to the interface name. ::

        void __set_bit(unsigned long nr, volatile unsigned long *addr);
        void __clear_bit(unsigned long nr, volatile unsigned long *addr);
        void __change_bit(unsigned long nr, volatile unsigned long *addr);
        int __test_and_set_bit(unsigned long nr, volatile unsigned long *addr);
        int __test_and_clear_bit(unsigned long nr, volatile unsigned long *addr);
        int __test_and_change_bit(unsigned long nr, volatile unsigned long *addr);
Quoted 2 lines

These non-atomic variants also do not require any special memory barrier semantics.

All right that makes sense.

On Rusty Russell's API ladder
http://sweng.the-davies.net/Home/rustys-api-design-manifesto
this scores 3/10 "read the documentation and you will get it right".

We could raise it to 6-7 by renaming them all set_bit_nonatomic() etc (or even set_bit_na()), I almost feel like sending a script to Torvalds to do that after the merge window, but I fear some people would beat me up for it.

Yours,
Linus Walleij

#9 lore raw

PATCH 2/4 gpio: Introduce ->get_multiple callback

In reply to Lukas Wunner

SPI-attached GPIO controllers typically read out all inputs in one go. If callers desire the values of multipe inputs, ideally a single readout should take place to return the desired values. However the current driver API only offers a ->get callback but no ->get_multiple (unlike ->set_multiple, which is present). Thus, to read multiple inputs, a full readout needs to be performed for every single value (barring driver-internal caching), which is inefficient.

In fact, the lack of a ->get_multiple callback has been bemoaned repeatedly by the gpio subsystem maintainer:
http://www.spinics.net/lists/linux-gpio/msg10571.html
http://www.spinics.net/lists/devicetree/msg121734.html

Introduce the missing callback. Add corresponding consumer functions such as gpiod_get_array_value(). Amend linehandle_ioctl() to take advantage of the newly added infrastructure.

---
 drivers/gpio/gpiolib.c        | 181 +++++++++++++++++++++++++++++++++++++++---
 drivers/gpio/gpiolib.h        |   4 +
 include/linux/gpio/consumer.h |  44 ++++++++++
 include/linux/gpio/driver.h   |   5 ++
 4 files changed, 223 insertions(+), 11 deletions(-)
drivers/gpio/gpiolib.c +170 -11
index 18bba1748a35..ea02916df0ad 100644
@@ -365,28 +365,28 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
 	struct linehandle_state *lh = filep->private_data;
 	void __user *ip = (void __user *)arg;
 	struct gpiohandle_data ghd;
+	int vals[GPIOHANDLES_MAX];
 	int i;
 
 	if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
-		int val;
+		/* TODO: check if descriptors are really input */
+		int ret = gpiod_get_array_value_complex(false,
+							true,
+							lh->numdescs,
+			     (const struct gpio_desc **)lh->descs,
+							vals);
+		if (ret)
+			return ret;
 
 		memset(&ghd, 0, sizeof(ghd));
-
-		/* TODO: check if descriptors are really input */
-		for (i = 0; i < lh->numdescs; i++) {
-			val = gpiod_get_value_cansleep(lh->descs[i]);
-			if (val < 0)
-				return val;
-			ghd.values[i] = val;
-		}
+		for (i = 0; i < lh->numdescs; i++)
+			ghd.values[i] = vals[i];
 
 		if (copy_to_user(ip, &ghd, sizeof(ghd)))
 			return -EFAULT;
 
 		return 0;
 	} else if (cmd == GPIOHANDLE_SET_LINE_VALUES_IOCTL) {
-		int vals[GPIOHANDLES_MAX];
-
 		/* TODO: check if descriptors are really output */
 		if (copy_from_user(&ghd, ip, sizeof(ghd)))
 			return -EFAULT;
@@ -2473,6 +2473,71 @@ static int _gpiod_get_raw_value(const struct gpio_desc *desc)
 	return value;
 }
 
+static int gpio_chip_get_multiple(struct gpio_chip *chip,
+				  unsigned long *mask, unsigned long *bits)
+{
+	if (chip->get_multiple) {
+		return chip->get_multiple(chip, mask, bits);
+	} else if (chip->get) {
+		int i, value;
+
+		for_each_set_bit(i, mask, chip->ngpio) {
+			value = chip->get(chip, i);
+			if (value < 0)
+				return value;
+			__assign_bit(value, i, bits);
+		}
+		return 0;
+	}
+	return -EIO;
+}
+
+int gpiod_get_array_value_complex(bool raw, bool can_sleep,
+				  unsigned int array_size,
+				  const struct gpio_desc **desc_array,
+				  int *value_array)
+{
+	int i = 0;
+
+	while (i < array_size) {
+		struct gpio_chip *chip = desc_array[i]->gdev->chip;
+		unsigned long mask[BITS_TO_LONGS(chip->ngpio)];
+		unsigned long bits[BITS_TO_LONGS(chip->ngpio)];
+		int first, j, ret;
+
+		if (!can_sleep)
+			WARN_ON(chip->can_sleep);
+
+		/* collect all inputs belonging to the same chip */
+		first = i;
+		memset(mask, 0, sizeof(mask));
+		do {
+			const struct gpio_desc *desc = desc_array[i];
+			int hwgpio = gpio_chip_hwgpio(desc);
+
+			__set_bit(hwgpio, mask);
+			i++;
+		} while ((i < array_size) &&
+			 (desc_array[i]->gdev->chip == chip));
+
+		ret = gpio_chip_get_multiple(chip, mask, bits);
+		if (ret)
+			return ret;
+
+		for (j = first; j < i; j++) {
+			const struct gpio_desc *desc = desc_array[j];
+			int hwgpio = gpio_chip_hwgpio(desc);
+			int value = test_bit(hwgpio, bits);
+
+			if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags))
+				value = !value;
+			value_array[j] = value;
+			trace_gpio_value(desc_to_gpio(desc), 1, value);
+		}
+	}
+	return 0;
+}
+
 /**
  * gpiod_get_raw_value() - return a gpio's raw value
  * @desc: gpio whose value will be returned
@@ -2521,6 +2586,53 @@ int gpiod_get_value(const struct gpio_desc *desc)
 }
 EXPORT_SYMBOL_GPL(gpiod_get_value);
 
+/**
+ * gpiod_get_raw_array_value() - read raw values from an array of GPIOs
+ * @array_size: number of elements in the descriptor / value arrays
+ * @desc_array: array of GPIO descriptors whose values will be read
+ * @value_array: array to store the read values
+ *
+ * Read the raw values of the GPIOs, i.e. the values of the physical lines
+ * without regard for their ACTIVE_LOW status.  Return 0 in case of success,
+ * else an error code.
+ *
+ * This function should be called from contexts where we cannot sleep,
+ * and it will complain if the GPIO chip functions potentially sleep.
+ */
+int gpiod_get_raw_array_value(unsigned int array_size,
+			      const struct gpio_desc **desc_array,
+			      int *value_array)
+{
+	if (!desc_array)
+		return -EINVAL;
+	return gpiod_get_array_value_complex(true, false, array_size,
+					     desc_array, value_array);
+}
+EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value);
+
+/**
+ * gpiod_get_array_value() - read values from an array of GPIOs
+ * @array_size: number of elements in the descriptor / value arrays
+ * @desc_array: array of GPIO descriptors whose values will be read
+ * @value_array: array to store the read values
+ *
+ * Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
+ * into account.  Return 0 in case of success, else an error code.
+ *
+ * This function should be called from contexts where we cannot sleep,
+ * and it will complain if the GPIO chip functions potentially sleep.
+ */
+int gpiod_get_array_value(unsigned int array_size,
+			  const struct gpio_desc **desc_array,
+			  int *value_array)
+{
+	if (!desc_array)
+		return -EINVAL;
+	return gpiod_get_array_value_complex(false, false, array_size,
+					     desc_array, value_array);
+}
+EXPORT_SYMBOL_GPL(gpiod_get_array_value);
+
 /*
  *  _gpio_set_open_drain_value() - Set the open drain gpio's value.
  * @desc: gpio descriptor whose state need to be set.
@@ -2950,6 +3062,53 @@ int gpiod_get_value_cansleep(const struct gpio_desc *desc)
 EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep);
 
 /**
+ * gpiod_get_raw_array_value_cansleep() - read raw values from an array of GPIOs
+ * @array_size: number of elements in the descriptor / value arrays
+ * @desc_array: array of GPIO descriptors whose values will be read
+ * @value_array: array to store the read values
+ *
+ * Read the raw values of the GPIOs, i.e. the values of the physical lines
+ * without regard for their ACTIVE_LOW status.  Return 0 in case of success,
+ * else an error code.
+ *
+ * This function is to be called from contexts that can sleep.
+ */
+int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
+				       const struct gpio_desc **desc_array,
+				       int *value_array)
+{
+	might_sleep_if(extra_checks);
+	if (!desc_array)
+		return -EINVAL;
+	return gpiod_get_array_value_complex(true, true, array_size,
+					     desc_array, value_array);
+}
+EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep);
+
+/**
+ * gpiod_get_array_value_cansleep() - read values from an array of GPIOs
+ * @array_size: number of elements in the descriptor / value arrays
+ * @desc_array: array of GPIO descriptors whose values will be read
+ * @value_array: array to store the read values
+ *
+ * Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
+ * into account.  Return 0 in case of success, else an error code.
+ *
+ * This function is to be called from contexts that can sleep.
+ */
+int gpiod_get_array_value_cansleep(unsigned int array_size,
+				   const struct gpio_desc **desc_array,
+				   int *value_array)
+{
+	might_sleep_if(extra_checks);
+	if (!desc_array)
+		return -EINVAL;
+	return gpiod_get_array_value_complex(false, true, array_size,
+					     desc_array, value_array);
+}
+EXPORT_SYMBOL_GPL(gpiod_get_array_value_cansleep);
+
+/**
  * gpiod_set_raw_value_cansleep() - assign a gpio's raw value
  * @desc: gpio whose value will be assigned
  * @value: value to assign
drivers/gpio/gpiolib.h +4 -0
index d003ccb12781..fe75ed71c90f 100644
@@ -180,6 +180,10 @@ static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
 #endif
 
 struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum);
+int gpiod_get_array_value_complex(bool raw, bool can_sleep,
+				  unsigned int array_size,
+				  const struct gpio_desc **desc_array,
+				  int *value_array);
 void gpiod_set_array_value_complex(bool raw, bool can_sleep,
 				   unsigned int array_size,
 				   struct gpio_desc **desc_array,
include/linux/gpio/consumer.h +44 -0

89 lines not on this page · raw message

include/linux/gpio/driver.h +5 -0
index c97f8325e8bf..f793530a8a1a 100644
@@ -35,6 +35,8 @@ struct module;
  * @direction_input: configures signal "offset" as input, or returns error
  * @direction_output: configures signal "offset" as output, or returns error
  * @get: returns value for signal "offset", 0=low, 1=high, or negative error
+ * @get_multiple: reads values for multiple signals defined by "mask" and
+ *	stores them in "bits", returns 0 on success or negative error
  * @set: assigns output value for signal "offset"
  * @set_multiple: assigns output values for multiple signals defined by "mask"
  * @set_config: optional hook for all kinds of settings. Uses the same
@@ -126,6 +128,9 @@ struct gpio_chip {
 						unsigned offset, int value);
 	int			(*get)(struct gpio_chip *chip,
 						unsigned offset);
+	int			(*get_multiple)(struct gpio_chip *chip,
+						unsigned long *mask,
+						unsigned long *bits);
 	void			(*set)(struct gpio_chip *chip,
 						unsigned offset, int value);
 	void			(*set_multiple)(struct gpio_chip *chip,
Signature · 1 line
2.11.0
#10 lore raw

Re: [PATCH 2/4] gpio: Introduce ->get_multiple callback

Quoted 13 lines · Lukas Wunner

SPI-attached GPIO controllers typically read out all inputs in one go. If callers desire the values of multipe inputs, ideally a single readout should take place to return the desired values. However the current driver API only offers a ->get callback but no ->get_multiple (unlike ->set_multiple, which is present). Thus, to read multiple inputs, a full readout needs to be performed for every single value (barring driver-internal caching), which is inefficient.

In fact, the lack of a ->get_multiple callback has been bemoaned repeatedly by the gpio subsystem maintainer:
http://www.spinics.net/lists/linux-gpio/msg10571.html
http://www.spinics.net/lists/devicetree/msg121734.html

Quoted 5 lines

Introduce the missing callback. Add corresponding consumer functions such as gpiod_get_array_value(). Amend linehandle_ioctl() to take advantage of the newly added infrastructure.

Lean, mean, and clean and introducing the interface that I've been missing for some time. Good work!

Let's hope we can merge this early for v4.15 once v4.14-rc1 is out and pile some drivers supporting it on top of it too.

I am only worried on how to get __assign_bit() into place in time, or whether I should carry that patch in the GPIO tree simply? We *could* add a local version of it and then switch it over with a follow-up patch...

Could you please patch
Documentation/gpio/consumer.txt
to mention the new functions as well?

Maybe we should have a section in Documentation/gpio/driver.txt, that doc is a bit incomplete right now.

Yours,
Linus Walleij

#11 lore raw

Re: [PATCH 2/4] gpio: Introduce ->get_multiple callback

Quoted 14 lines · Linus Walleij
Quoted 13 lines · Lukas Wunner

SPI-attached GPIO controllers typically read out all inputs in one go. If callers desire the values of multipe inputs, ideally a single readout should take place to return the desired values. However the current driver API only offers a ->get callback but no ->get_multiple (unlike ->set_multiple, which is present). Thus, to read multiple inputs, a full readout needs to be performed for every single value (barring driver-internal caching), which is inefficient.

In fact, the lack of a ->get_multiple callback has been bemoaned repeatedly by the gpio subsystem maintainer:
http://www.spinics.net/lists/linux-gpio/msg10571.html
http://www.spinics.net/lists/devicetree/msg121734.html

Quoted 7 lines
Quoted 3 lines

Introduce the missing callback. Add corresponding consumer functions such as gpiod_get_array_value(). Amend linehandle_ioctl() to take advantage of the newly added infrastructure.

Could you please patch
Documentation/gpio/consumer.txt
to mention the new functions as well?

Missed that, will fix in v2. There is an oddity in that document in that it claims gpiod_get_value() / gpiod_set_value() do not return errors. The kerneldoc in gpiolib.c and driver.h says otherwise, it allows the get functions to return a negative errno. Now what?

Here are the two occurrences of the false claim in consumer.txt:

It should be checked, since the get/set calls don't return errors and since misconfiguration is possible.

The get/set calls do not return errors because "invalid GPIO" should have been reported earlier from gpiod_direction_*().

At least with SPI-attached GPIO controllers, the transmission is never guaranteed to succeed, so errors can occur both for input and output GPIOs. The MAX3191x is input-only and does pass SPI errors back to the caller. Output drivers such as gpio-74x164.c silently ignore SPI errors, which is arguably a problem.

Quoted 2 lines

Maybe we should have a section in Documentation/gpio/driver.txt, that doc is a bit incomplete right now.

First time I've seen that file. :-) I used the kerneldoc as guidance when writing the gpio-max3191x.c driver and found it sufficient, so I'm not sure how driver.txt could be expanded?

Thanks!

Lukas

#12 lore raw

Re: [PATCH 2/4] gpio: Introduce ->get_multiple callback

Quoted 19 lines · Lukas Wunner
Quoted 18 lines · Linus Walleij
Quoted 16 lines · Lukas Wunner

SPI-attached GPIO controllers typically read out all inputs in one go. If callers desire the values of multipe inputs, ideally a single readout should take place to return the desired values. However the current driver API only offers a ->get callback but no ->get_multiple (unlike ->set_multiple, which is present). Thus, to read multiple inputs, a full readout needs to be performed for every single value (barring driver-internal caching), which is inefficient.

In fact, the lack of a ->get_multiple callback has been bemoaned repeatedly by the gpio subsystem maintainer:
http://www.spinics.net/lists/linux-gpio/msg10571.html
http://www.spinics.net/lists/devicetree/msg121734.html

Introduce the missing callback. Add corresponding consumer functions such as gpiod_get_array_value(). Amend linehandle_ioctl() to take advantage of the newly added infrastructure.

Quoted 8 lines
Quoted 3 lines

Could you please patch
Documentation/gpio/consumer.txt
to mention the new functions as well?

Missed that, will fix in v2. There is an oddity in that document in that it claims gpiod_get_value() / gpiod_set_value() do not return errors. The kerneldoc in gpiolib.c and driver.h says otherwise, it allows the get functions to return a negative errno. Now what?

Probably errors in the documentation.

Feel free to correct it.

Quoted 5 lines

At least with SPI-attached GPIO controllers, the transmission is never guaranteed to succeed, so errors can occur both for input and output GPIOs. The MAX3191x is input-only and does pass SPI errors back to the caller. Output drivers such as gpio-74x164.c silently ignore SPI errors, which is arguably a problem.

This has historical reasons.

Quoted 6 lines
Quoted 2 lines

Maybe we should have a section in Documentation/gpio/driver.txt, that doc is a bit incomplete right now.

First time I've seen that file. :-) I used the kerneldoc as guidance when writing the gpio-max3191x.c driver and found it sufficient, so I'm not sure how driver.txt could be expanded?

Don't worry about it if you feel it's superfluous.

Yours,
Linus Walleij

#13 lore raw

Re: [PATCH 2/4] gpio: Introduce ->get_multiple callback

Quoted 8 lines · Linus Walleij
Quoted 5 lines · Lukas Wunner

At least with SPI-attached GPIO controllers, the transmission is never guaranteed to succeed, so errors can occur both for input and output GPIOs. The MAX3191x is input-only and does pass SPI errors back to the caller. Output drivers such as gpio-74x164.c silently ignore SPI errors, which is arguably a problem.

This has historical reasons.

Would you generally be open for allowing errors to be returned from the set functions as well? The Revolution Pi uses SPI-attached digital outputs and knowing if access to them fails would be useful.

For consumers, switching the return value from void to int shouldn't cause any fallout. They just don't check the return value initially. However the ->set and ->set_multiple callbacks in all the GPIO drivers would need to be changed, that's where the real work is.

Thanks,

Lukas

#14 lore raw

Re: [PATCH 2/4] gpio: Introduce ->get_multiple callback

Quoted 8 lines · Lukas Wunner
Quoted 7 lines · Linus Walleij
Quoted 5 lines · Lukas Wunner

At least with SPI-attached GPIO controllers, the transmission is never guaranteed to succeed, so errors can occur both for input and output GPIOs. The MAX3191x is input-only and does pass SPI errors back to the caller. Output drivers such as gpio-74x164.c silently ignore SPI errors, which is arguably a problem.

Quoted 4 lines
Quoted 1 line

This has historical reasons.

Would you generally be open for allowing errors to be returned from the set functions as well?

Yes if we can make a series fixing the fallout.

Quoted 2 lines

The Revolution Pi uses SPI-attached
digital outputs and knowing if access to them fails would be useful.

True.

Quoted 2 lines

For consumers, switching the return value from void to int shouldn't cause any fallout. They just don't check the return value initially.

Indeed.

Quoted 2 lines

However the ->set and ->set_multiple callbacks in all the GPIO drivers would need to be changed, that's where the real work is.

Yeah :/

But there are not so many of them, luckily.

Yours,
Linus Walleij

#15 lore raw

Re: [PATCH 2/4] gpio: Introduce ->get_multiple callback

In reply to Lukas Wunner

Hi Linus,

one question popped up regarding this patch that I'd like to clarify before reposting a revised series:

Quoted 7 lines · Lukas Wunner

SPI-attached GPIO controllers typically read out all inputs in one go. If callers desire the values of multipe inputs, ideally a single readout should take place to return the desired values. However the current driver API only offers a ->get callback but no ->get_multiple (unlike ->set_multiple, which is present). Thus, to read multiple inputs, a full readout needs to be performed for every single value (barring driver-internal caching), which is inefficient.

[...]

Quoted 3 lines

Introduce the missing callback. Add corresponding consumer functions such as gpiod_get_array_value(). Amend linehandle_ioctl() to take advantage of the newly added infrastructure.

[...]

Quoted 7 lines
drivers/gpio/gpiolib.c +1 -0
@@ -365,28 +365,28 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
 	struct linehandle_state *lh = filep->private_data;
 	void __user *ip = (void __user *)arg;
 	struct gpiohandle_data ghd;
+	int vals[GPIOHANDLES_MAX];

drivers/gpio/gpiolib.c static long linehandle_ioctl(struct file *filep, unsigned int cmd, · line 377

Quoted 10 lines
drivers/gpio/gpiolib.c +6 -1
 	int i;
 
 	if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
-		int val;
+		/* TODO: check if descriptors are really input */
+		int ret = gpiod_get_array_value_complex(false,
+							true,
+							lh->numdescs,
+			     (const struct gpio_desc **)lh->descs,
+							vals);

I've designed the function signature of

gpiod_get_array_value_complex()
gpiod_get_raw_array_value()
gpiod_get_array_value()
gpiod_get_raw_array_value_cansleep()
gpiod_get_array_value_cansleep()

such that a "const struct gpio_desc **" argument is passed in (the point being the const). This was done to enforce const-correctness and for consistency with the family of functions to read a single GPIO, such as gpiod_get_value() which take a "const struct gpio_desc *".

However after actually using the newly introduced functions in a driver, I've discovered that the const keyword is mostly just an annoyance in this
case: When acquiring GPIOs with gpiod_get_array(), the resulting struct gpio_desc ** is not const. Thus, a cast is necessary whenever feeding the result of gpiod_get_array() to gpiod_get_array_value(), which may well be the most common use case. (It's probably less common that folks construct the array by hand.) A cast is also already necessary for the invocation of gpiod_get_array_value_complex() quoted above.

So I'm wondering if the const keyword does more harm than good in this case. Let me know what you think.

Thanks,

Lukas

#16 lore raw

Re: [PATCH 2/4] gpio: Introduce ->get_multiple callback

Quoted 2 lines · Lukas Wunner

So I'm wondering if the const keyword does more harm than good in this case. Let me know what you think.

I've had similar experiences.

I'm not very sensitive about it, do whatever makes most sense to you.

What is important is that we get get_mutiple() in place.

Yours,
Linus Walleij

#17 lore raw

Re: [PATCH 2/4] gpio: Introduce ->get_multiple callback

Quoted 9 lines · Linus Walleij
Quoted 2 lines · Lukas Wunner

So I'm wondering if the const keyword does more harm than good in this case. Let me know what you think.

I've had similar experiences.

I'm not very sensitive about it, do whatever makes most sense to you.

What is important is that we get get_mutiple() in place.

Yes. My apologies for the delay.

I've dropped the const qualifier, the rationale for the compiler error it triggers is given in:

http://c-faq.com/ansi/constmismatch.html

Briefly, it is legal to pass a pointer to non-const if the function signature specifies const, but not for a pointer-to-pointer, i.e. a second level of indirection. The error is supposed to "help" the developer keep the const promises but I don't find it helpful at all. It necessitates a cast unless a const struct gpio_desc ** is passed in. When would that be the case in reality? Only if the array is statically declared, but usually the gpio_desc structs are obtained at runtime, so the the cast would likely *always* be needed.

Thanks,

Lukas

#18 lore raw

PATCH 3/4 dt-bindings: gpio: max3191x: Document new driver

In reply to Lukas Wunner

Add device tree bindings for Maxim MAX3191x industrial serializer.

Cc Mathias Duckeck <[email protected]>
---
 .../devicetree/bindings/gpio/gpio-max3191x.txt     | 37 ++++++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/gpio-max3191x.txt
Documentation/devicetree/bindings/gpio/gpio-max3191x.txt new file +37 -0
new file mode 100644
index 000000000000..18182ecaa199
@@ -0,0 +1,37 @@
+GPIO driver for Maxim MAX3191x industrial serializer
+
+Required properties:
+ - compatible:		"maxim,max31910", "maxim,max31911", "maxim,max31912",
+			"maxim,max31913", "maxim,max31953", "maxim,max31963"
+ - gpio-controller:	Marks the device node as a GPIO controller.
+ - #gpio-cells: 	Should be two. For consumer use see gpio.txt.
+
+Optional properties:
+ - maxim,nchips:	Number of chips in the daisy-chain (default is 1).
+ - modesel-gpios:	GPIO pins to configure modesel of each chip.
+			The number of GPIOs must be equal to "maxim,nchips".
+ - fault-gpios: 	GPIO pins to read undervoltage fault of each chip.
+ - db0-gpios:		GPIO pins to configure debounce of each chip.
+ - db1-gpios:		GPIO pins to configure debounce of each chip.
+ - maxim,modesel:	Mode to use if hardwired (and thus not selectable
+			through GPIOs): 0 for 16-bit mode, 1 for 8-bit mode.
+ - maxim,no-vcc24v:	Boolean, whether the chips are powered through 5VOUT
+			instead of VCC24V.
+
+For other required and optional properties of SPI slave nodes please refer to
+../spi/spi-bus.txt.
+
+Example:
+	gpio@0 {
+		compatible = "maxim,max31913";
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		modesel-gpios = <&gpio2 23>;
+		fault-gpios   = <&gpio2 24 GPIO_ACTIVE_LOW>;
+		db0-gpios     = <&gpio2 25>;
+		db1-gpios     = <&gpio2 26>;
+
+		reg = <0>;
+		spi-max-frequency = <25000000>;
+	};
Signature · 1 line
2.11.0
maintainer
#19 lore raw

Re: [PATCH 3/4] dt-bindings: gpio: max3191x: Document new driver

Quoted 15 lines · Lukas Wunner

Add device tree bindings for Maxim MAX3191x industrial serializer.

Cc Mathias Duckeck <[email protected]>
---
 .../devicetree/bindings/gpio/gpio-max3191x.txt     | 37 ++++++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/gpio-max3191x.txt
Documentation/devicetree/bindings/gpio/gpio-max3191x.txt new file +0 -0
new file mode 100644
index 000000000000..18182ecaa199

Documentation/devicetree/bindings/gpio/gpio-max3191x.txt line 5

Quoted 5 lines
Documentation/devicetree/bindings/gpio/gpio-max3191x.txt new file +5 -0
@@ -0,0 +1,37 @@
+GPIO driver for Maxim MAX3191x industrial serializer
+
+Required properties:
+ - compatible:		"maxim,max31910", "maxim,max31911", "maxim,max31912",
+			"maxim,max31913", "maxim,max31953", "maxim,max31963"

One valid combination per line please.

Documentation/devicetree/bindings/gpio/gpio-max3191x.txt line 15

Quoted 10 lines
Documentation/devicetree/bindings/gpio/gpio-max3191x.txt new file +10 -0
+ - gpio-controller:	Marks the device node as a GPIO controller.
+ - #gpio-cells: 	Should be two. For consumer use see gpio.txt.
+
+Optional properties:
+ - maxim,nchips:	Number of chips in the daisy-chain (default is 1).
+ - modesel-gpios:	GPIO pins to configure modesel of each chip.
+			The number of GPIOs must be equal to "maxim,nchips".
+ - fault-gpios: 	GPIO pins to read undervoltage fault of each chip.
+ - db0-gpios:		GPIO pins to configure debounce of each chip.
+ - db1-gpios:		GPIO pins to configure debounce of each chip.

Perhaps an array db-gpios with 2 entries.

These gpios all need a vendor prefix.

Documentation/devicetree/bindings/gpio/gpio-max3191x.txt line 17

Quoted 2 lines
Documentation/devicetree/bindings/gpio/gpio-max3191x.txt new file +2 -0
+ - maxim,modesel:	Mode to use if hardwired (and thus not selectable
+			through GPIOs): 0 for 16-bit mode, 1 for 8-bit mode.

Make this a boolean and define the default when not present (and modesel-gpios not present).

Documentation/devicetree/bindings/gpio/gpio-max3191x.txt line 19

Quoted 2 lines
Documentation/devicetree/bindings/gpio/gpio-max3191x.txt new file +2 -0
+ - maxim,no-vcc24v:	Boolean, whether the chips are powered through 5VOUT
+			instead of VCC24V.

Use the regulator binding here?

Quoted 6 lines
Documentation/devicetree/bindings/gpio/gpio-max3191x.txt new file +6 -0
+
+For other required and optional properties of SPI slave nodes please refer to
+../spi/spi-bus.txt.
+
+Example:
+	gpio@0 {

Documentation/devicetree/bindings/gpio/gpio-max3191x.txt line 35

Quoted 10 lines
Documentation/devicetree/bindings/gpio/gpio-max3191x.txt new file +10 -0
+		compatible = "maxim,max31913";
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		modesel-gpios = <&gpio2 23>;
+		fault-gpios   = <&gpio2 24 GPIO_ACTIVE_LOW>;
+		db0-gpios     = <&gpio2 25>;
+		db1-gpios     = <&gpio2 26>;
+
+		reg = <0>;

reg usually comes after compatible. Also, reg needs to be documented above.

Quoted 9 lines
Documentation/devicetree/bindings/gpio/gpio-max3191x.txt new file +2 -0
+		spi-max-frequency = <25000000>;
+	};
Signature · 6 lines
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#20 lore raw

Re: [PATCH 3/4] dt-bindings: gpio: max3191x: Document new driver

Thanks Rob for the helpful review!

Quoted 8 lines · Rob Herring

Documentation/devicetree/bindings/gpio/gpio-max3191x.txt line 15

Quoted 5 lines · Lukas Wunner

+ - modesel-gpios: GPIO pins to configure modesel of each chip.

Documentation/devicetree/bindings/gpio/gpio-max3191x.txt new file +4 -0
+			The number of GPIOs must be equal to "maxim,nchips".
+ - fault-gpios: 	GPIO pins to read undervoltage fault of each chip.
+ - db0-gpios:	GPIO pins to configure debounce of each chip.
+ - db1-gpios:	GPIO pins to configure debounce of each chip.

Perhaps an array db-gpios with 2 entries.

Each of the db0-gpios and db1-gpios is already an array with one pin for each chip in the daisy-chain.

So it would have to be a two-dimensional array, which AFAICS is not supported by the devicetree spec, or is it?

However I realize that for clarity I should amend fault-gpios, db0-gpios and db1-gpios with the same text as modesel-gpios:
The number of GPIOs must be equal to "maxim,nchips".

Quoted 4 lines

Review

Quoted 2 lines

+ - maxim,no-vcc24v:Boolean, whether the chips are powered through

(quoted diff) +1 -0
+			5VOUT instead of VCC24V.

Use the regulator binding here?

I'd have to look at the regulator's current voltage to determine through which pin the chips in the daisy-chain are powered (5VOUT or VCC24V).

But if the regulator is generating 5V I couldn't discern if it's a faulting 24V supply or a non-faulting 5V supply.

So a boolean does seem necessary, however I realize now that "no-vcc24v" is misleading, I've changed it to "maxim,ignore-undervoltage" for clarity:

- maxim,ignore-undervoltage:
Boolean, whether to ignore undervoltage alarms signaled by the "maxim,fault-gpios" and by the status byte (in 16-bit mode). Use this if the chips are powered through 5VOUT instead of VCC24V, in which case they will constantly signal undervoltage.

Thanks,

Lukas
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 20170823094438.GA12416-JFq808J9C/[email protected]

#22 lore raw

Re: [PATCH 3/4] dt-bindings: gpio: max3191x: Document new driver

Quoted 10 lines · Lukas Wunner

Thanks Rob for the helpful review!

Quoted 7 lines · Rob Herring
Quoted 5 lines · Lukas Wunner
+ - modesel-gpios:  GPIO pins to configure modesel of each chip.
+                   The number of GPIOs must be equal to "maxim,nchips".
+ - fault-gpios:    GPIO pins to read undervoltage fault of each chip.
+ - db0-gpios:      GPIO pins to configure debounce of each chip.
+ - db1-gpios:      GPIO pins to configure debounce of each chip.
Quoted 4 lines
Quoted 1 line

Perhaps an array db-gpios with 2 entries.

Each of the db0-gpios and db1-gpios is already an array with one pin for each chip in the daisy-chain.

Okay.

Quoted 2 lines

So it would have to be a two-dimensional array, which AFAICS is not supported by the devicetree spec, or is it?

Not in the sense that the dimensions are encoded into the property, but the binding doc can define that. You know one dimension is 2, so you could figure out the other. But it's fine as is.

Quoted 3 lines

However I realize that for clarity I should amend fault-gpios, db0-gpios and db1-gpios with the same text as modesel-gpios:
The number of GPIOs must be equal to "maxim,nchips".

Really, this binding should be 1 node per chip instead, but I don't know how you would describe that. You'd need a parent node with reg for the chipselect, and then child nodes for each chip.

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

+ - maxim,no-vcc24v:Boolean, whether the chips are powered through
+ 5VOUT instead of VCC24V.

Use the regulator binding here?

I'd have to look at the regulator's current voltage to determine through which pin the chips in the daisy-chain are powered (5VOUT or VCC24V).

No, the supply properties should correspond to the power pins/rails. So it would be whichever property is present that tells you if 5V or 24V is hooked up.

Quoted 6 lines

But if the regulator is generating 5V I couldn't discern if it's a faulting 24V supply or a non-faulting 5V supply.

So a boolean does seem necessary, however I realize now that "no-vcc24v" is misleading, I've changed it to "maxim,ignore-undervoltage" for clarity:

Quoted 6 lines

- maxim,ignore-undervoltage:
Boolean, whether to ignore undervoltage alarms signaled by the "maxim,fault-gpios" and by the status byte (in 16-bit mode). Use this if the chips are powered through 5VOUT instead of VCC24V, in which case they will constantly signal undervoltage.

But I'm not that concerned with a single property like this if you feel strongly about it and want to avoid the complexity of the regulator binding.

Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#23 lore raw

Re: [PATCH 3/4] dt-bindings: gpio: max3191x: Document new driver

In reply to Rob Herring

Hi Rob,

sorry to bother you again, one more question popped up regarding the MAX3191x DT bindings:

Quoted 2 lines · Rob Herring
Quoted 1 line · Lukas Wunner

Add device tree bindings for Maxim MAX3191x industrial serializer.

[snip]

Quoted 2 lines
Quoted 2 lines

+Optional properties:
+ - maxim,nchips: Number of chips in the daisy-chain (default is 1).

Many I/O chips are daisy-chainable, so I've been wondering if a common property should be introduced?

The existing gpio-74x164.c uses "registers-number" to convey the number of chips in the daisy chain. (Sans vendor prefix, multiple vendors sell compatible versions of this chip.)

gpio-pisosr.c takes a different approach and calculates the number of chips in the daisy-chain by taking the common "ngpios" property (Documentation/devicetree/bindings/gpio/gpio.txt) and dividing it by 8 (which assumes that each chip has 8 inputs).

Thanks,

Lukas

#24 lore raw

Re: [PATCH 3/4] dt-bindings: gpio: max3191x: Document new driver

Hi Rob,

gentle ping on this question:

Quoted 27 lines · Lukas Wunner

Hi Rob,

sorry to bother you again, one more question popped up regarding the MAX3191x DT bindings:

Quoted 2 lines · Rob Herring
Quoted 1 line · Lukas Wunner

Add device tree bindings for Maxim MAX3191x industrial serializer.

[snip]

Quoted 2 lines
Quoted 2 lines

+Optional properties:
+ - maxim,nchips: Number of chips in the daisy-chain (default is 1).

Many I/O chips are daisy-chainable, so I've been wondering if a common property should be introduced?

The existing gpio-74x164.c uses "registers-number" to convey the number of chips in the daisy chain. (Sans vendor prefix, multiple vendors sell compatible versions of this chip.)

gpio-pisosr.c takes a different approach and calculates the number of chips in the daisy-chain by taking the common "ngpios" property (Documentation/devicetree/bindings/gpio/gpio.txt) and dividing it by 8 (which assumes that each chip has 8 inputs).

Thanks,

Lukas

#25 lore raw

PATCH 4/4 gpio: Add driver for Maxim MAX3191x industrial serializer

In reply to Lukas Wunner

The driver was developed for and tested with the MAX31913 built into the Revolution Pi by KUNBUS, but should work with all members of the MAX3191x family:

MAX31910: low power
MAX31911: LED drivers
MAX31912: LED drivers + 2nd voltage monitor + low power
MAX31913: LED drivers + 2nd voltage monitor
MAX31953: LED drivers + 2nd voltage monitor + isolation
MAX31963: LED drivers + 2nd voltage monitor + isolation + buck regulator

They are similar to but more versatile than the TI SN65HVS880/2/3/5 supported by gpio-pisosr.c as they clock out a CRC checksum to guard against electromagnetic interference, as well as undervoltage and overtemperature indicator bits. If these features are not needed they can be disabled by pulling the "modesel" pin high and then gpio-pisosr.c can be used instead of the present driver.

Cc Mathias Duckeck <[email protected]>
---
 drivers/gpio/Kconfig         |  10 +
 drivers/gpio/Makefile        |   1 +
 drivers/gpio/gpio-max3191x.c | 482 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 493 insertions(+)
 create mode 100644 drivers/gpio/gpio-max3191x.c
drivers/gpio/Kconfig +10 -0
index fc9b75c9e3ba..c42e5e75353f 100644
@@ -1246,6 +1246,16 @@ config GPIO_74X164
 	  shift registers. This driver can be used to provide access
 	  to more gpio outputs.
 
+config GPIO_MAX3191X
+	tristate "Maxim MAX3191x industrial serializer"
+	select CRC8
+	help
+	  GPIO driver for Maxim MAX31910, MAX31911, MAX31912, MAX31913,
+	  MAX31953 and MAX31963 industrial serializer, a daisy-chainable
+	  chip to make 8 digital 24V inputs available via SPI.  Supports
+	  CRC checksums to guard against electromagnetic interference,
+	  as well as undervoltage and overtemperature detection.
+
 config GPIO_MAX7301
 	tristate "Maxim MAX7301 GPIO expander"
 	select GPIO_MAX730X
drivers/gpio/Makefile +1 -0
index 37f2029218cb..f1482ee7fd23 100644
@@ -69,6 +69,7 @@ obj-$(CONFIG_ARCH_LPC32XX)	+= gpio-lpc32xx.o
 obj-$(CONFIG_GPIO_LP873X)	+= gpio-lp873x.o
 obj-$(CONFIG_GPIO_LP87565)	+= gpio-lp87565.o
 obj-$(CONFIG_GPIO_LYNXPOINT)	+= gpio-lynxpoint.o
+obj-$(CONFIG_GPIO_MAX3191X)	+= gpio-max3191x.o
 obj-$(CONFIG_GPIO_MAX730X)	+= gpio-max730x.o
 obj-$(CONFIG_GPIO_MAX7300)	+= gpio-max7300.o
 obj-$(CONFIG_GPIO_MAX7301)	+= gpio-max7301.o
drivers/gpio/gpio-max3191x.c new file +482 -0

482 lines not on this page · raw message

Signature · 1 line
2.11.0

A message that is not in the archive (sent off-list or not yet received): df530ae703fcfdf52d27a1b6d19b6d1a4724b103.1503319573.git.lukas-JFq808J9C/[email protected]

#27 lore raw

Re: [PATCH 4/4] gpio: Add driver for Maxim MAX3191x industrial serializer

Quoted 18 lines · Lukas Wunner

The driver was developed for and tested with the MAX31913 built into the Revolution Pi by KUNBUS, but should work with all members of the MAX3191x family:

MAX31910: low power
MAX31911: LED drivers
MAX31912: LED drivers + 2nd voltage monitor + low power
MAX31913: LED drivers + 2nd voltage monitor
MAX31953: LED drivers + 2nd voltage monitor + isolation
MAX31963: LED drivers + 2nd voltage monitor + isolation + buck regulator

They are similar to but more versatile than the TI SN65HVS880/2/3/5 supported by gpio-pisosr.c as they clock out a CRC checksum to guard against electromagnetic interference, as well as undervoltage and overtemperature indicator bits. If these features are not needed they can be disabled by pulling the "modesel" pin high and then gpio-pisosr.c can be used instead of the present driver.

Quoted 2 lines
Cc Mathias Duckeck <m.duckeck-XB/[email protected]>

This looks like a fine piece of driver.

We just need to get the infrastructure in place and I can merge it.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html