All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/9] mux controller abstraction and iio/i2c muxes
@ 2016-11-30  8:16 ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:16 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc

Hi!

v5 -> v6 changes
- fix stupidity in mux_chip_priv, mux_gpio_remove and adg792a_remove.
- change the devicetree bindings for the iio-mux to use a list of strings
  (channels property) instead of a list children.

v4 -> v5 changes
- remove support for fancier dt layouts and go back to the phandle
  approach from v2 and before, killing the horrible non-working
  refcounting crap from v4 and avoiding a bunch of life-time issues
  in v3.
- introduce the concept of a mux-chip, that can hold one or more
  mux-controllers (inspired by the pwm subsystem).
- add dt #mux-control-cells property needed to get to the desired
  mux controller if a mux chip provides more than one.
- take away the option to build the mux-core as a module.
- if the mux controller has an idle state, make sure the mux controller
  is set up in the idle state initially (when it should be idle).
- do not use a variable length array on the stack in mux_gpio_set to
  temporarily store the gpio state, preallocate space instead.
- fix resource leak on one failure path in mux_gpio_probe.
- driver for Analog Devices ADG792A/G, literally the first mux chip
  I found on the Internet with an i2c interface (that was not a
  dedicated i2c multiplexer like PCA9547) which I used to verify
  that the abstractions in the mux core are up to the task. Untested,
  just proof of concept that at least looks pretty and compiles...
- various touch-ups.

v3 -> v4 changes
- rebased onto next-20161122 (depends on recent _available iio changes).
- added support for having the mux-controller in a child node of a
  mux-consumer if it is a sole consumer, to hopefully even further satisfy
  the complaint from Rob (and later Lars-Peter) about dt complexity.
- the above came at the cost of some rather horrible refcounting code,
  please review and suggest how it should be done...
- changed to register a device class instead of a bus.
- pass in the parent device into mux_control_alloc and require less
  work from mux-control drivers.
- changed device names from mux:control%d to mux%d
- move kernel-doc from mux-core.c to mux.h (and add some bits).
- give the gpio driver a chance to update all mux pins at once.
- factor out iio ext_info lookup into new helper function. /Lars-Peter
- use an unsigned type for the iio ext_info count. /Lars-Peter
- unified "brag strings" in the file headers.

v2 -> v3 changes
- have the mux-controller in the parent node of any mux-controller consumer,
  to hopefully satisfy complaint from Rob about dt complexity.
- improve commit message of the mux subsystem commit, making it more
  general, as requested by Jonathan.
- remove priv member from struct mux_control and calculate it on the
  fly. /Jonathan
- make the function comments in mux-core.c kernel doc. /Jonathan
- add devm_mux_control_* to Documentation/driver.model/devres.txt. /Jonathan
- add common dt bindings for mux-controllers, refer to them from the
  mux-gpio bindings. /Rob
- clarify how the gpio pins map to the mux state. /Rob
- separate CONFIG_ variables for the mux core and the mux gpio driver.
- improve Kconfig help texts.
- make CONFIG_MUX_GPIO depend on CONFIG_GPIOLIB.
- keep track of the number of mux states in the mux core.
- since the iio channel number is used as mux state, it was possible
  to drop the state member from the mux_child struct.
- cleanup dt bindings for i2c-mux-simple, it had some of copy-paste
  problems from ots origin (i2c-mux-gpio).
- select the mux control subsystem in config for the i2c-mux-simple driver.
- add entries to MAINTAINERS and my sign-off, I'm now satisfied and know
  nothing in this to be ashamed of.

v1 -> v2 changes
- fixup export of mux_control_put reported by kbuild
- drop devicetree iio-ext-info property as noted by Lars-Peter,
  and replace the functionality by exposing all ext_info
  attributes of the parent channel for each of the muxed
  channels. A cache on top of that and each muxed channel
  gets its own view of the ext_info of the parent channel.
- implement idle-state for muxes
- clear out the cache on failure in order to force a mux
  update on the following use
- cleanup the probe of i2c-mux-simple driver
- fix a bug in the i2c-mux-simple driver, where failure in
  the selection of the mux caused a deadlock when the mux
  was later unconditionally deselected.

I have a piece of hardware that is using the same 3 GPIO pins
to control four 8-way muxes. Three of them control ADC lines
to an ADS1015 chip with an iio driver, and the last one
controls the SDA line of an i2c bus. We have some deployed
code to handle this, but you do not want to see it or ever
hear about it. I'm not sure why I even mention it. Anyway,
the situation has nagged me to no end for quite some time.

So, after first getting more intimate with the i2c muxing code
and later discovering the drivers/iio/inkern.c file and
writing a couple of drivers making use of it, I came up with
what I think is an acceptable solution; add a generic mux
controller driver (and subsystem) that is shared between all
instances, and combine that with an iio mux driver and a new
generic i2c mux driver. The new i2c mux I called "simple"
since it is only hooking the i2c muxing and the new mux
controller (much like the alsa simple card driver does for ASoC).

One thing that I would like to do, but don't see a solution
for, is to move the mux control code that is present in
various drivers in drivers/i2c/muxes to this new minimalistic
muxing subsystem, thus converting all present i2c muxes (but
perhaps not gates and arbitrators) to be i2c-mux-simple muxes.

I'm using an rwsem to lock a mux, but that isn't really a
perfect fit. Is there a better locking primitive that I don't
know about that fits better? I had a mutex at one point, but
that didn't allow any concurrent accesses at all. At least
the rwsem allows concurrent access as long as all users
agree on the mux state, but I suspect that the rwsem will
degrade to the mutex situation pretty quickly if there is
any contention.

Also, the "mux" name feels a bit ambitious, there are many muxes
in the world, and this tiny bit of code is probably not good
enough to be a nice fit for all...

Cheers,
Peter

Peter Rosin (9):
  dt-bindings: document devicetree bindings for mux-controllers and
    mux-gpio
  misc: minimal mux subsystem and gpio-based mux controller
  iio: inkern: api for manipulating ext_info of iio channels
  dt-bindings: iio: iio-mux: document iio-mux bindings
  iio: multiplexer: new iio category and iio-mux driver
  dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
  i2c: i2c-mux-simple: new driver
  dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G
    mux
  misc: mux-adg792a: add mux controller driver for ADG792A/G

 .../devicetree/bindings/i2c/i2c-mux-simple.txt     |  81 ++++
 .../bindings/iio/multiplexer/iio-mux.txt           |  40 ++
 .../devicetree/bindings/misc/mux-adg792a.txt       |  64 +++
 .../devicetree/bindings/misc/mux-controller.txt    | 127 ++++++
 .../devicetree/bindings/misc/mux-gpio.txt          |  68 +++
 Documentation/driver-model/devres.txt              |   6 +-
 MAINTAINERS                                        |  14 +
 drivers/i2c/muxes/Kconfig                          |  13 +
 drivers/i2c/muxes/Makefile                         |   1 +
 drivers/i2c/muxes/i2c-mux-simple.c                 | 179 ++++++++
 drivers/iio/Kconfig                                |   1 +
 drivers/iio/Makefile                               |   1 +
 drivers/iio/inkern.c                               |  60 +++
 drivers/iio/multiplexer/Kconfig                    |  18 +
 drivers/iio/multiplexer/Makefile                   |   6 +
 drivers/iio/multiplexer/iio-mux.c                  | 456 +++++++++++++++++++++
 drivers/misc/Kconfig                               |  42 ++
 drivers/misc/Makefile                              |   3 +
 drivers/misc/mux-adg792a.c                         | 154 +++++++
 drivers/misc/mux-core.c                            | 311 ++++++++++++++
 drivers/misc/mux-gpio.c                            | 138 +++++++
 include/linux/iio/consumer.h                       |  37 ++
 include/linux/mux.h                                | 197 +++++++++
 23 files changed, 2016 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-simple.txt
 create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
 create mode 100644 Documentation/devicetree/bindings/misc/mux-adg792a.txt
 create mode 100644 Documentation/devicetree/bindings/misc/mux-controller.txt
 create mode 100644 Documentation/devicetree/bindings/misc/mux-gpio.txt
 create mode 100644 drivers/i2c/muxes/i2c-mux-simple.c
 create mode 100644 drivers/iio/multiplexer/Kconfig
 create mode 100644 drivers/iio/multiplexer/Makefile
 create mode 100644 drivers/iio/multiplexer/iio-mux.c
 create mode 100644 drivers/misc/mux-adg792a.c
 create mode 100644 drivers/misc/mux-core.c
 create mode 100644 drivers/misc/mux-gpio.c
 create mode 100644 include/linux/mux.h

-- 
2.1.4

^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH v6 0/9] mux controller abstraction and iio/i2c muxes
@ 2016-11-30  8:16 ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:16 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc

Hi!

v5 -> v6 changes
- fix stupidity in mux_chip_priv, mux_gpio_remove and adg792a_remove.
- change the devicetree bindings for the iio-mux to use a list of strings
  (channels property) instead of a list children.

v4 -> v5 changes
- remove support for fancier dt layouts and go back to the phandle
  approach from v2 and before, killing the horrible non-working
  refcounting crap from v4 and avoiding a bunch of life-time issues
  in v3.
- introduce the concept of a mux-chip, that can hold one or more
  mux-controllers (inspired by the pwm subsystem).
- add dt #mux-control-cells property needed to get to the desired
  mux controller if a mux chip provides more than one.
- take away the option to build the mux-core as a module.
- if the mux controller has an idle state, make sure the mux controller
  is set up in the idle state initially (when it should be idle).
- do not use a variable length array on the stack in mux_gpio_set to
  temporarily store the gpio state, preallocate space instead.
- fix resource leak on one failure path in mux_gpio_probe.
- driver for Analog Devices ADG792A/G, literally the first mux chip
  I found on the Internet with an i2c interface (that was not a
  dedicated i2c multiplexer like PCA9547) which I used to verify
  that the abstractions in the mux core are up to the task. Untested,
  just proof of concept that at least looks pretty and compiles...
- various touch-ups.

v3 -> v4 changes
- rebased onto next-20161122 (depends on recent _available iio changes).
- added support for having the mux-controller in a child node of a
  mux-consumer if it is a sole consumer, to hopefully even further satisfy
  the complaint from Rob (and later Lars-Peter) about dt complexity.
- the above came at the cost of some rather horrible refcounting code,
  please review and suggest how it should be done...
- changed to register a device class instead of a bus.
- pass in the parent device into mux_control_alloc and require less
  work from mux-control drivers.
- changed device names from mux:control%d to mux%d
- move kernel-doc from mux-core.c to mux.h (and add some bits).
- give the gpio driver a chance to update all mux pins at once.
- factor out iio ext_info lookup into new helper function. /Lars-Peter
- use an unsigned type for the iio ext_info count. /Lars-Peter
- unified "brag strings" in the file headers.

v2 -> v3 changes
- have the mux-controller in the parent node of any mux-controller consumer,
  to hopefully satisfy complaint from Rob about dt complexity.
- improve commit message of the mux subsystem commit, making it more
  general, as requested by Jonathan.
- remove priv member from struct mux_control and calculate it on the
  fly. /Jonathan
- make the function comments in mux-core.c kernel doc. /Jonathan
- add devm_mux_control_* to Documentation/driver.model/devres.txt. /Jonathan
- add common dt bindings for mux-controllers, refer to them from the
  mux-gpio bindings. /Rob
- clarify how the gpio pins map to the mux state. /Rob
- separate CONFIG_ variables for the mux core and the mux gpio driver.
- improve Kconfig help texts.
- make CONFIG_MUX_GPIO depend on CONFIG_GPIOLIB.
- keep track of the number of mux states in the mux core.
- since the iio channel number is used as mux state, it was possible
  to drop the state member from the mux_child struct.
- cleanup dt bindings for i2c-mux-simple, it had some of copy-paste
  problems from ots origin (i2c-mux-gpio).
- select the mux control subsystem in config for the i2c-mux-simple driver.
- add entries to MAINTAINERS and my sign-off, I'm now satisfied and know
  nothing in this to be ashamed of.

v1 -> v2 changes
- fixup export of mux_control_put reported by kbuild
- drop devicetree iio-ext-info property as noted by Lars-Peter,
  and replace the functionality by exposing all ext_info
  attributes of the parent channel for each of the muxed
  channels. A cache on top of that and each muxed channel
  gets its own view of the ext_info of the parent channel.
- implement idle-state for muxes
- clear out the cache on failure in order to force a mux
  update on the following use
- cleanup the probe of i2c-mux-simple driver
- fix a bug in the i2c-mux-simple driver, where failure in
  the selection of the mux caused a deadlock when the mux
  was later unconditionally deselected.

I have a piece of hardware that is using the same 3 GPIO pins
to control four 8-way muxes. Three of them control ADC lines
to an ADS1015 chip with an iio driver, and the last one
controls the SDA line of an i2c bus. We have some deployed
code to handle this, but you do not want to see it or ever
hear about it. I'm not sure why I even mention it. Anyway,
the situation has nagged me to no end for quite some time.

So, after first getting more intimate with the i2c muxing code
and later discovering the drivers/iio/inkern.c file and
writing a couple of drivers making use of it, I came up with
what I think is an acceptable solution; add a generic mux
controller driver (and subsystem) that is shared between all
instances, and combine that with an iio mux driver and a new
generic i2c mux driver. The new i2c mux I called "simple"
since it is only hooking the i2c muxing and the new mux
controller (much like the alsa simple card driver does for ASoC).

One thing that I would like to do, but don't see a solution
for, is to move the mux control code that is present in
various drivers in drivers/i2c/muxes to this new minimalistic
muxing subsystem, thus converting all present i2c muxes (but
perhaps not gates and arbitrators) to be i2c-mux-simple muxes.

I'm using an rwsem to lock a mux, but that isn't really a
perfect fit. Is there a better locking primitive that I don't
know about that fits better? I had a mutex at one point, but
that didn't allow any concurrent accesses at all. At least
the rwsem allows concurrent access as long as all users
agree on the mux state, but I suspect that the rwsem will
degrade to the mutex situation pretty quickly if there is
any contention.

Also, the "mux" name feels a bit ambitious, there are many muxes
in the world, and this tiny bit of code is probably not good
enough to be a nice fit for all...

Cheers,
Peter

Peter Rosin (9):
  dt-bindings: document devicetree bindings for mux-controllers and
    mux-gpio
  misc: minimal mux subsystem and gpio-based mux controller
  iio: inkern: api for manipulating ext_info of iio channels
  dt-bindings: iio: iio-mux: document iio-mux bindings
  iio: multiplexer: new iio category and iio-mux driver
  dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
  i2c: i2c-mux-simple: new driver
  dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G
    mux
  misc: mux-adg792a: add mux controller driver for ADG792A/G

 .../devicetree/bindings/i2c/i2c-mux-simple.txt     |  81 ++++
 .../bindings/iio/multiplexer/iio-mux.txt           |  40 ++
 .../devicetree/bindings/misc/mux-adg792a.txt       |  64 +++
 .../devicetree/bindings/misc/mux-controller.txt    | 127 ++++++
 .../devicetree/bindings/misc/mux-gpio.txt          |  68 +++
 Documentation/driver-model/devres.txt              |   6 +-
 MAINTAINERS                                        |  14 +
 drivers/i2c/muxes/Kconfig                          |  13 +
 drivers/i2c/muxes/Makefile                         |   1 +
 drivers/i2c/muxes/i2c-mux-simple.c                 | 179 ++++++++
 drivers/iio/Kconfig                                |   1 +
 drivers/iio/Makefile                               |   1 +
 drivers/iio/inkern.c                               |  60 +++
 drivers/iio/multiplexer/Kconfig                    |  18 +
 drivers/iio/multiplexer/Makefile                   |   6 +
 drivers/iio/multiplexer/iio-mux.c                  | 456 +++++++++++++++++++++
 drivers/misc/Kconfig                               |  42 ++
 drivers/misc/Makefile                              |   3 +
 drivers/misc/mux-adg792a.c                         | 154 +++++++
 drivers/misc/mux-core.c                            | 311 ++++++++++++++
 drivers/misc/mux-gpio.c                            | 138 +++++++
 include/linux/iio/consumer.h                       |  37 ++
 include/linux/mux.h                                | 197 +++++++++
 23 files changed, 2016 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-simple.txt
 create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
 create mode 100644 Documentation/devicetree/bindings/misc/mux-adg792a.txt
 create mode 100644 Documentation/devicetree/bindings/misc/mux-controller.txt
 create mode 100644 Documentation/devicetree/bindings/misc/mux-gpio.txt
 create mode 100644 drivers/i2c/muxes/i2c-mux-simple.c
 create mode 100644 drivers/iio/multiplexer/Kconfig
 create mode 100644 drivers/iio/multiplexer/Makefile
 create mode 100644 drivers/iio/multiplexer/iio-mux.c
 create mode 100644 drivers/misc/mux-adg792a.c
 create mode 100644 drivers/misc/mux-core.c
 create mode 100644 drivers/misc/mux-gpio.c
 create mode 100644 include/linux/mux.h

-- 
2.1.4

^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH v6 1/9] dt-bindings: document devicetree bindings for mux-controllers and mux-gpio
@ 2016-11-30  8:16   ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:16 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../devicetree/bindings/misc/mux-controller.txt    | 127 +++++++++++++++++++++
 .../devicetree/bindings/misc/mux-gpio.txt          |  68 +++++++++++
 MAINTAINERS                                        |   5 +
 3 files changed, 200 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/misc/mux-controller.txt
 create mode 100644 Documentation/devicetree/bindings/misc/mux-gpio.txt

diff --git a/Documentation/devicetree/bindings/misc/mux-controller.txt b/Documentation/devicetree/bindings/misc/mux-controller.txt
new file mode 100644
index 000000000000..19c36b73173e
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/mux-controller.txt
@@ -0,0 +1,127 @@
+Common multiplexer controller bindings
+======================================
+
+A multiplexer (or mux) controller will have one, or several, consumer devices
+that uses the mux controller. Thus, a mux controller can possibly control
+several parallel multiplexers, presumably there will be at least one
+multiplexer needed by each consumer..
+
+A mux controller provides a number of states to its consumers, and the state
+space is a simple zero-based enumeration. I.e. 0-1 for a 2-way multiplexer,
+0-7 for an 8-way multiplexer, etc.
+
+
+Consumers
+---------
+
+Mux controller consumers should specify a list of mux controllers that they
+want to use with a property containing a 'mux-ctrl-list':
+
+	mux-ctrl-list ::= <single-mux-ctrl> [mux-ctrl-list]
+	single-mux-ctrl ::= <mux-ctrl-phandle> [mux-ctrl-specifier]
+	mux-ctrl-phandle : phandle to mux controller node
+	mux-ctrl-specifier : array of #mux-control-cells specifying the
+			     given mux controller (controller specific)
+
+Mux controller properties should be named "mux-controls". The exact meaning of
+each mux controller property must be documented in the device tree binding for
+each consumer. An optional property "mux-control-names" may contain a list of
+strings to label each of the mux controllers listed in the "mux-controls"
+property.
+
+Drivers for devices that use more than a single mux controller can use the
+"mux-control-names" property to map the name of the mux controller requested by
+the mux_control_get() call to an index into the list given by the
+"mux-controls" property.
+
+mux-ctrl-specifier typically encodes the chip-relative mux controller number.
+If the mux controller chip only provides a single mux controller, the
+mux-ctrl-specifier can typically be left out.
+
+Example:
+
+	/* One consumer of a 2-way mux controller (one GPIO-line) */
+	mux: mux-controller {
+		compatible = "mux-gpio";
+		#mux-control-cells = <0>;
+
+		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>;
+	};
+
+	adc-mux {
+		compatible = "iio-mux";
+		io-channels = <&adc 0>;
+		io-channel-names = "parent";
+		mux-controls = <&mux>;
+		mux-control-names = "adc";
+
+		channels = "sync", "in";
+	};
+
+Note that in the example above, specifying the "mux-control-names" is redundant
+because there is only one mux controller in the list.
+
+	/*
+	 * Two consumers (one for an ADC line and one for an i2c bus) of
+	 * parallel 4-way multiplexers controlled by the same two GPIO-lines.
+	 */
+	mux: mux-controller {
+		compatible = "mux-gpio";
+		#mux-control-cells = <0>;
+
+		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
+			    <&pioA 1 GPIO_ACTIVE_HIGH>;
+	};
+
+	adc-mux {
+		compatible = "iio-mux";
+		io-channels = <&adc 0>;
+		io-channel-names = "parent";
+		mux-controls = <&mux>;
+
+		channels = "sync-1", "in", "out", "sync-2";
+	};
+
+	i2c-mux {
+		compatible = "i2c-mux-simple,mux-locked";
+		i2c-parent = <&i2c1>;
+		mux-controls = <&mux>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c@0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ssd1307: oled@3c {
+				/* ... */
+			};
+		};
+
+		i2c@3 {
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pca9555: pca9555@20 {
+				/* ... */
+			};
+		};
+	};
+
+
+Mux controller nodes
+--------------------
+
+Mux controller nodes must specify the number of cells used for the
+specifier using the '#mux-control-cells' property.
+
+An example mux controller might look like this:
+
+	mux: adg792a@50 {
+		compatible = "adi,adg792a";
+		reg = <0x50>;
+		#mux-control-cells = <1>;
+	};
diff --git a/Documentation/devicetree/bindings/misc/mux-gpio.txt b/Documentation/devicetree/bindings/misc/mux-gpio.txt
new file mode 100644
index 000000000000..2ff814f082c8
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/mux-gpio.txt
@@ -0,0 +1,68 @@
+GPIO-based multiplexer controller bindings
+
+Define what GPIO pins are used to control a multiplexer. Or several
+multiplexers, if the same pins control more than one multiplexer.
+
+Required properties:
+- compatible : "mux-gpio"
+- mux-gpios : list of gpios used to control the multiplexer, least
+	      significant bit first.
+- #mux-control-cells : <0>
+* Standard mux-controller bindings as decribed in mux-controller.txt
+
+Optional properties:
+- idle-state : if present, the state the mux will have when idle.
+
+The multiplexer state is defined as the number represented by the
+multiplexer GPIO pins, where the first pin is the least significant
+bit. An active pin is a binary 1, an inactive pin is a binary 0.
+
+Example:
+
+	mux: mux-controller {
+		compatible = "mux-gpio";
+		#mux-control-cells = <0>;
+
+		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
+			    <&pioA 1 GPIO_ACTIVE_HIGH>;
+	};
+
+	adc-mux {
+		compatible = "iio-mux";
+		io-channels = <&adc 0>;
+		io-channel-names = "parent";
+
+		mux-controls = <&mux>;
+
+		channels = "sync-1", "in", "out", "sync-2";
+	};
+
+	i2c-mux {
+		compatible = "i2c-mux-simple,mux-locked";
+		i2c-parent = <&i2c1>;
+
+		mux-controls = <&mux>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c@0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ssd1307: oled@3c {
+				/* ... */
+			};
+		};
+
+		i2c@3 {
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pca9555: pca9555@20 {
+				/* ... */
+			};
+		};
+	};
diff --git a/MAINTAINERS b/MAINTAINERS
index d8eb3843dbd4..3d4d0efc2b64 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8403,6 +8403,11 @@ S:	Orphan
 F:	drivers/mmc/host/mmc_spi.c
 F:	include/linux/spi/mmc_spi.h
 
+MULTIPLEXER SUBSYSTEM
+M:	Peter Rosin <peda@axentia.se>
+S:	Maintained
+F:	Documentation/devicetree/bindings/misc/mux-*
+
 MULTISOUND SOUND DRIVER
 M:	Andrew Veliath <andrewtv@usa.net>
 S:	Maintained
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 1/9] dt-bindings: document devicetree bindings for mux-controllers and mux-gpio
@ 2016-11-30  8:16   ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:16 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
---
 .../devicetree/bindings/misc/mux-controller.txt    | 127 +++++++++++++++++++++
 .../devicetree/bindings/misc/mux-gpio.txt          |  68 +++++++++++
 MAINTAINERS                                        |   5 +
 3 files changed, 200 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/misc/mux-controller.txt
 create mode 100644 Documentation/devicetree/bindings/misc/mux-gpio.txt

diff --git a/Documentation/devicetree/bindings/misc/mux-controller.txt b/Documentation/devicetree/bindings/misc/mux-controller.txt
new file mode 100644
index 000000000000..19c36b73173e
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/mux-controller.txt
@@ -0,0 +1,127 @@
+Common multiplexer controller bindings
+======================================
+
+A multiplexer (or mux) controller will have one, or several, consumer devices
+that uses the mux controller. Thus, a mux controller can possibly control
+several parallel multiplexers, presumably there will be at least one
+multiplexer needed by each consumer..
+
+A mux controller provides a number of states to its consumers, and the state
+space is a simple zero-based enumeration. I.e. 0-1 for a 2-way multiplexer,
+0-7 for an 8-way multiplexer, etc.
+
+
+Consumers
+---------
+
+Mux controller consumers should specify a list of mux controllers that they
+want to use with a property containing a 'mux-ctrl-list':
+
+	mux-ctrl-list ::= <single-mux-ctrl> [mux-ctrl-list]
+	single-mux-ctrl ::= <mux-ctrl-phandle> [mux-ctrl-specifier]
+	mux-ctrl-phandle : phandle to mux controller node
+	mux-ctrl-specifier : array of #mux-control-cells specifying the
+			     given mux controller (controller specific)
+
+Mux controller properties should be named "mux-controls". The exact meaning of
+each mux controller property must be documented in the device tree binding for
+each consumer. An optional property "mux-control-names" may contain a list of
+strings to label each of the mux controllers listed in the "mux-controls"
+property.
+
+Drivers for devices that use more than a single mux controller can use the
+"mux-control-names" property to map the name of the mux controller requested by
+the mux_control_get() call to an index into the list given by the
+"mux-controls" property.
+
+mux-ctrl-specifier typically encodes the chip-relative mux controller number.
+If the mux controller chip only provides a single mux controller, the
+mux-ctrl-specifier can typically be left out.
+
+Example:
+
+	/* One consumer of a 2-way mux controller (one GPIO-line) */
+	mux: mux-controller {
+		compatible = "mux-gpio";
+		#mux-control-cells = <0>;
+
+		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>;
+	};
+
+	adc-mux {
+		compatible = "iio-mux";
+		io-channels = <&adc 0>;
+		io-channel-names = "parent";
+		mux-controls = <&mux>;
+		mux-control-names = "adc";
+
+		channels = "sync", "in";
+	};
+
+Note that in the example above, specifying the "mux-control-names" is redundant
+because there is only one mux controller in the list.
+
+	/*
+	 * Two consumers (one for an ADC line and one for an i2c bus) of
+	 * parallel 4-way multiplexers controlled by the same two GPIO-lines.
+	 */
+	mux: mux-controller {
+		compatible = "mux-gpio";
+		#mux-control-cells = <0>;
+
+		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
+			    <&pioA 1 GPIO_ACTIVE_HIGH>;
+	};
+
+	adc-mux {
+		compatible = "iio-mux";
+		io-channels = <&adc 0>;
+		io-channel-names = "parent";
+		mux-controls = <&mux>;
+
+		channels = "sync-1", "in", "out", "sync-2";
+	};
+
+	i2c-mux {
+		compatible = "i2c-mux-simple,mux-locked";
+		i2c-parent = <&i2c1>;
+		mux-controls = <&mux>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c@0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ssd1307: oled@3c {
+				/* ... */
+			};
+		};
+
+		i2c@3 {
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pca9555: pca9555@20 {
+				/* ... */
+			};
+		};
+	};
+
+
+Mux controller nodes
+--------------------
+
+Mux controller nodes must specify the number of cells used for the
+specifier using the '#mux-control-cells' property.
+
+An example mux controller might look like this:
+
+	mux: adg792a@50 {
+		compatible = "adi,adg792a";
+		reg = <0x50>;
+		#mux-control-cells = <1>;
+	};
diff --git a/Documentation/devicetree/bindings/misc/mux-gpio.txt b/Documentation/devicetree/bindings/misc/mux-gpio.txt
new file mode 100644
index 000000000000..2ff814f082c8
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/mux-gpio.txt
@@ -0,0 +1,68 @@
+GPIO-based multiplexer controller bindings
+
+Define what GPIO pins are used to control a multiplexer. Or several
+multiplexers, if the same pins control more than one multiplexer.
+
+Required properties:
+- compatible : "mux-gpio"
+- mux-gpios : list of gpios used to control the multiplexer, least
+	      significant bit first.
+- #mux-control-cells : <0>
+* Standard mux-controller bindings as decribed in mux-controller.txt
+
+Optional properties:
+- idle-state : if present, the state the mux will have when idle.
+
+The multiplexer state is defined as the number represented by the
+multiplexer GPIO pins, where the first pin is the least significant
+bit. An active pin is a binary 1, an inactive pin is a binary 0.
+
+Example:
+
+	mux: mux-controller {
+		compatible = "mux-gpio";
+		#mux-control-cells = <0>;
+
+		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
+			    <&pioA 1 GPIO_ACTIVE_HIGH>;
+	};
+
+	adc-mux {
+		compatible = "iio-mux";
+		io-channels = <&adc 0>;
+		io-channel-names = "parent";
+
+		mux-controls = <&mux>;
+
+		channels = "sync-1", "in", "out", "sync-2";
+	};
+
+	i2c-mux {
+		compatible = "i2c-mux-simple,mux-locked";
+		i2c-parent = <&i2c1>;
+
+		mux-controls = <&mux>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c@0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ssd1307: oled@3c {
+				/* ... */
+			};
+		};
+
+		i2c@3 {
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pca9555: pca9555@20 {
+				/* ... */
+			};
+		};
+	};
diff --git a/MAINTAINERS b/MAINTAINERS
index d8eb3843dbd4..3d4d0efc2b64 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8403,6 +8403,11 @@ S:	Orphan
 F:	drivers/mmc/host/mmc_spi.c
 F:	include/linux/spi/mmc_spi.h
 
+MULTIPLEXER SUBSYSTEM
+M:	Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
+S:	Maintained
+F:	Documentation/devicetree/bindings/misc/mux-*
+
 MULTISOUND SOUND DRIVER
 M:	Andrew Veliath <andrewtv-Jdbf3xiKgS8@public.gmane.org>
 S:	Maintained
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 2/9] misc: minimal mux subsystem and gpio-based mux controller
  2016-11-30  8:16 ` Peter Rosin
@ 2016-11-30  8:16   ` Peter Rosin
  -1 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:16 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc

Add a new minimalistic subsystem that handles multiplexer controllers.
When multiplexers are used in various places in the kernel, and the
same multiplexer controller can be used for several independent things,
there should be one place to implement support for said multiplexer
controller.

A single multiplexer controller can also be used to control several
parallel multiplexers, that are in turn used by different subsystems
in the kernel, leading to a need to coordinate multiplexer accesses.
The multiplexer subsystem handles this coordination.

This new mux controller subsystem initially comes with a single backend
driver that controls gpio based multiplexers. Even though not needed by
this initial driver, the mux controller subsystem is prepared to handle
chips with multiple (independent) mux controllers.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 Documentation/driver-model/devres.txt |   6 +-
 MAINTAINERS                           |   2 +
 drivers/misc/Kconfig                  |  30 ++++
 drivers/misc/Makefile                 |   2 +
 drivers/misc/mux-core.c               | 311 ++++++++++++++++++++++++++++++++++
 drivers/misc/mux-gpio.c               | 138 +++++++++++++++
 include/linux/mux.h                   | 197 +++++++++++++++++++++
 7 files changed, 685 insertions(+), 1 deletion(-)
 create mode 100644 drivers/misc/mux-core.c
 create mode 100644 drivers/misc/mux-gpio.c
 create mode 100644 include/linux/mux.h

diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index ca9d1eb46bc0..d64ede85b61b 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -330,7 +330,11 @@ MEM
   devm_kzalloc()
 
 MFD
- devm_mfd_add_devices()
+  devm_mfd_add_devices()
+
+MUX
+  devm_mux_control_get()
+  devm_mux_control_put()
 
 PER-CPU MEM
   devm_alloc_percpu()
diff --git a/MAINTAINERS b/MAINTAINERS
index 3d4d0efc2b64..dc7498682752 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8407,6 +8407,8 @@ MULTIPLEXER SUBSYSTEM
 M:	Peter Rosin <peda@axentia.se>
 S:	Maintained
 F:	Documentation/devicetree/bindings/misc/mux-*
+F:	include/linux/mux.h
+F:	drivers/misc/mux-*
 
 MULTISOUND SOUND DRIVER
 M:	Andrew Veliath <andrewtv@usa.net>
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 64971baf11fa..2ce675e410c5 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -766,6 +766,36 @@ config PANEL_BOOT_MESSAGE
 	  An empty message will only clear the display at driver init time. Any other
 	  printf()-formatted message is valid with newline and escape codes.
 
+menuconfig MULTIPLEXER
+	bool "Multiplexer subsystem"
+	help
+	  Multiplexer controller subsystem. Multiplexers are used in a
+	  variety of settings, and this subsystem abstracts their use
+	  so that the rest of the kernel sees a common interface. When
+	  multiple parallel multiplexers are controlled by one single
+	  multiplexer controller, this subsystem also coordinates the
+	  multiplexer accesses.
+
+	  If unsure, say no.
+
+if MULTIPLEXER
+
+config MUX_GPIO
+	tristate "GPIO-controlled Multiplexer"
+	depends on OF && GPIOLIB
+	help
+	  GPIO-controlled Multiplexer controller.
+
+	  The driver builds a single multiplexer controller using a number
+	  of gpio pins. For N pins, there will be 2^N possible multiplexer
+	  states. The GPIO pins can be connected (by the hardware) to several
+	  multiplexers, which in that case will be operated in parallel.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called mux-gpio.
+
+endif
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 31983366090a..0befa2bba762 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -53,6 +53,8 @@ obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
 obj-$(CONFIG_CXL_BASE)		+= cxl/
 obj-$(CONFIG_PANEL)             += panel.o
+obj-$(CONFIG_MULTIPLEXER)      	+= mux-core.o
+obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
 
 lkdtm-$(CONFIG_LKDTM)		+= lkdtm_core.o
 lkdtm-$(CONFIG_LKDTM)		+= lkdtm_bugs.o
diff --git a/drivers/misc/mux-core.c b/drivers/misc/mux-core.c
new file mode 100644
index 000000000000..cccaa7261a6e
--- /dev/null
+++ b/drivers/misc/mux-core.c
@@ -0,0 +1,311 @@
+/*
+ * Multiplexer subsystem
+ *
+ * Copyright (C) 2016 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) "mux-core: " fmt
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/idr.h>
+#include <linux/module.h>
+#include <linux/mux.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+
+static struct class mux_class = {
+	.name = "mux",
+	.owner = THIS_MODULE,
+};
+
+static int __init mux_init(void)
+{
+	return class_register(&mux_class);
+}
+
+static DEFINE_IDA(mux_ida);
+
+static void mux_chip_release(struct device *dev)
+{
+	struct mux_chip *mux_chip = to_mux_chip(dev);
+
+	ida_simple_remove(&mux_ida, mux_chip->id);
+	kfree(mux_chip);
+}
+
+static struct device_type mux_type = {
+	.name = "mux-chip",
+	.release = mux_chip_release,
+};
+
+struct mux_chip *mux_chip_alloc(struct device *dev,
+				unsigned int controllers, size_t sizeof_priv)
+{
+	struct mux_chip *mux_chip;
+	int i;
+
+	if (!dev || !controllers)
+		return NULL;
+
+	mux_chip = kzalloc(sizeof(*mux_chip) +
+			   controllers * sizeof(*mux_chip->mux) +
+			   sizeof_priv, GFP_KERNEL);
+	if (!mux_chip)
+		return NULL;
+
+	mux_chip->mux = (struct mux_control *)(mux_chip + 1);
+	mux_chip->dev.class = &mux_class;
+	mux_chip->dev.type = &mux_type;
+	mux_chip->dev.parent = dev;
+	mux_chip->dev.of_node = dev->of_node;
+	dev_set_drvdata(&mux_chip->dev, mux_chip);
+
+	mux_chip->id = ida_simple_get(&mux_ida, 0, 0, GFP_KERNEL);
+	if (mux_chip->id < 0) {
+		pr_err("muxchipX failed to get a device id\n");
+		kfree(mux_chip);
+		return NULL;
+	}
+	dev_set_name(&mux_chip->dev, "muxchip%d", mux_chip->id);
+
+	mux_chip->controllers = controllers;
+	for (i = 0; i < controllers; ++i) {
+		struct mux_control *mux = &mux_chip->mux[i];
+
+		mux->chip = mux_chip;
+		init_rwsem(&mux->lock);
+		mux->cached_state = -1;
+		mux->idle_state = -1;
+	}
+
+	device_initialize(&mux_chip->dev);
+
+	return mux_chip;
+}
+EXPORT_SYMBOL_GPL(mux_chip_alloc);
+
+static int mux_control_set(struct mux_control *mux, int state)
+{
+	int ret = mux->chip->ops->set(mux, state);
+
+	mux->cached_state = ret < 0 ? -1 : state;
+
+	return ret;
+}
+
+int mux_chip_register(struct mux_chip *mux_chip)
+{
+	int i;
+	int ret;
+
+	for (i = 0; i < mux_chip->controllers; ++i) {
+		struct mux_control *mux = &mux_chip->mux[i];
+
+		if (mux->idle_state == mux->cached_state)
+			continue;
+
+		ret = mux_control_set(mux, mux->idle_state);
+		if (ret < 0)
+			return ret;
+	}
+
+	return device_add(&mux_chip->dev);
+}
+EXPORT_SYMBOL_GPL(mux_chip_register);
+
+void mux_chip_unregister(struct mux_chip *mux_chip)
+{
+	device_del(&mux_chip->dev);
+}
+EXPORT_SYMBOL_GPL(mux_chip_unregister);
+
+void mux_chip_free(struct mux_chip *mux_chip)
+{
+	if (!mux_chip)
+		return;
+	put_device(&mux_chip->dev);
+}
+EXPORT_SYMBOL_GPL(mux_chip_free);
+
+int mux_control_select(struct mux_control *mux, int state)
+{
+	int ret;
+
+	if (down_read_trylock(&mux->lock)) {
+		if (mux->cached_state == state)
+			return 0;
+
+		/* Sigh, the mux needs updating... */
+		up_read(&mux->lock);
+	}
+
+	/* ...or it's just contended. */
+	down_write(&mux->lock);
+
+	if (mux->cached_state == state) {
+		/*
+		 * Hmmm, someone else changed the mux to my liking.
+		 * That makes me wonder how long I waited for nothing?
+		 */
+		downgrade_write(&mux->lock);
+		return 0;
+	}
+
+	ret = mux_control_set(mux, state);
+	if (ret < 0) {
+		if (mux->idle_state != -1)
+			mux_control_set(mux, mux->idle_state);
+
+		up_write(&mux->lock);
+		return ret;
+	}
+
+	downgrade_write(&mux->lock);
+
+	return 1;
+}
+EXPORT_SYMBOL_GPL(mux_control_select);
+
+int mux_control_deselect(struct mux_control *mux)
+{
+	int ret = 0;
+
+	if (mux->idle_state != -1 && mux->cached_state != mux->idle_state)
+		ret = mux_control_set(mux, mux->idle_state);
+
+	up_read(&mux->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(mux_control_deselect);
+
+static int of_dev_node_match(struct device *dev, const void *data)
+{
+	return dev->of_node == data;
+}
+
+static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
+{
+	struct device *dev;
+
+	dev = class_find_device(&mux_class, NULL, np, of_dev_node_match);
+
+	return dev ? to_mux_chip(dev) : NULL;
+}
+
+struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
+{
+	struct device_node *np = dev->of_node;
+	struct of_phandle_args args;
+	struct mux_chip *mux_chip;
+	unsigned int controller;
+	int index = 0;
+	int ret;
+
+	if (mux_name) {
+		index = of_property_match_string(np, "mux-control-names",
+						 mux_name);
+		if (index < 0)
+			return ERR_PTR(index);
+	}
+
+	ret = of_parse_phandle_with_args(np,
+					 "mux-controls", "#mux-control-cells",
+					 index, &args);
+	if (ret) {
+		dev_err(dev, "%s: failed to get mux-control %s(%i)\n",
+			np->full_name, mux_name ?: "", index);
+		return ERR_PTR(ret);
+	}
+
+	mux_chip = of_find_mux_chip_by_node(args.np);
+	of_node_put(args.np);
+	if (!mux_chip)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	if (args.args_count > 1 ||
+	    (!args.args_count && (mux_chip->controllers > 1))) {
+		dev_err(dev, "%s: wrong #mux-control-cells for %s\n",
+			np->full_name, args.np->full_name);
+		return ERR_PTR(-EINVAL);
+	}
+
+	controller = 0;
+	if (args.args_count)
+		controller = args.args[0];
+
+	if (controller >= mux_chip->controllers)
+		return ERR_PTR(-EINVAL);
+
+	get_device(&mux_chip->dev);
+	return &mux_chip->mux[controller];
+}
+EXPORT_SYMBOL_GPL(mux_control_get);
+
+void mux_control_put(struct mux_control *mux)
+{
+	put_device(&mux->chip->dev);
+}
+EXPORT_SYMBOL_GPL(mux_control_put);
+
+static void devm_mux_control_release(struct device *dev, void *res)
+{
+	struct mux_control *mux = *(struct mux_control **)res;
+
+	mux_control_put(mux);
+}
+
+struct mux_control *devm_mux_control_get(struct device *dev,
+					 const char *mux_name)
+{
+	struct mux_control **ptr, *mux;
+
+	ptr = devres_alloc(devm_mux_control_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	mux = mux_control_get(dev, mux_name);
+	if (IS_ERR(mux)) {
+		devres_free(ptr);
+		return mux;
+	}
+
+	*ptr = mux;
+	devres_add(dev, ptr);
+
+	return mux;
+}
+EXPORT_SYMBOL_GPL(devm_mux_control_get);
+
+static int devm_mux_control_match(struct device *dev, void *res, void *data)
+{
+	struct mux_control **r = res;
+
+	if (!r || !*r) {
+		WARN_ON(!r || !*r);
+		return 0;
+	}
+
+	return *r == data;
+}
+
+void devm_mux_control_put(struct device *dev, struct mux_control *mux)
+{
+	WARN_ON(devres_release(dev, devm_mux_control_release,
+			       devm_mux_control_match, mux));
+}
+EXPORT_SYMBOL_GPL(devm_mux_control_put);
+
+subsys_initcall(mux_init);
+
+MODULE_DESCRIPTION("Multiplexer subsystem");
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mux-gpio.c b/drivers/misc/mux-gpio.c
new file mode 100644
index 000000000000..a107a9b96854
--- /dev/null
+++ b/drivers/misc/mux-gpio.c
@@ -0,0 +1,138 @@
+/*
+ * GPIO-controlled multiplexer driver
+ *
+ * Copyright (C) 2016 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/mux.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+struct mux_gpio {
+	struct gpio_descs *gpios;
+	int *val;
+};
+
+static int mux_gpio_set(struct mux_control *mux, int state)
+{
+	struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip);
+	int i;
+
+	for (i = 0; i < mux_gpio->gpios->ndescs; i++)
+		mux_gpio->val[i] = (state >> i) & 1;
+
+	gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs,
+				       mux_gpio->gpios->desc,
+				       mux_gpio->val);
+
+	return 0;
+}
+
+static const struct mux_control_ops mux_gpio_ops = {
+	.set = mux_gpio_set,
+};
+
+static const struct of_device_id mux_gpio_dt_ids[] = {
+	{ .compatible = "mux-gpio", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mux_gpio_dt_ids);
+
+static int mux_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = pdev->dev.of_node;
+	struct mux_chip *mux_chip;
+	struct mux_gpio *mux_gpio;
+	int pins;
+	u32 idle_state;
+	int ret;
+
+	if (!np)
+		return -ENODEV;
+
+	pins = gpiod_count(dev, "mux");
+	if (pins < 0)
+		return pins;
+
+	mux_chip = mux_chip_alloc(dev, 1, sizeof(*mux_gpio) +
+				  pins * sizeof(*mux_gpio->val));
+	if (!mux_chip)
+		return -ENOMEM;
+
+	mux_gpio = mux_chip_priv(mux_chip);
+	mux_gpio->val = (int *)(mux_gpio + 1);
+	mux_chip->ops = &mux_gpio_ops;
+
+	platform_set_drvdata(pdev, mux_chip);
+
+	mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW);
+	if (IS_ERR(mux_gpio->gpios)) {
+		ret = PTR_ERR(mux_gpio->gpios);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "failed to get gpios\n");
+		goto free_mux_chip;
+	}
+	WARN_ON(pins != mux_gpio->gpios->ndescs);
+	mux_chip->mux->states = 1 << pins;
+
+	ret = of_property_read_u32(np, "idle-state", &idle_state);
+	if (ret >= 0) {
+		if (idle_state >= mux_chip->mux->states) {
+			dev_err(dev, "invalid idle-state %u\n", idle_state);
+			ret = -EINVAL;
+			goto free_mux_chip;
+		}
+
+		mux_chip->mux->idle_state = idle_state;
+	}
+
+	ret = mux_chip_register(mux_chip);
+	if (ret < 0) {
+		dev_err(dev, "failed to register mux-chip\n");
+		goto free_mux_chip;
+	}
+
+	dev_info(dev, "%u-way mux-controller registered\n",
+		 mux_chip->mux->states);
+
+	return 0;
+
+free_mux_chip:
+	mux_chip_free(mux_chip);
+	return ret;
+}
+
+static int mux_gpio_remove(struct platform_device *pdev)
+{
+	struct mux_chip *mux_chip = platform_get_drvdata(pdev);
+
+	mux_chip_unregister(mux_chip);
+	mux_chip_free(mux_chip);
+
+	return 0;
+}
+
+static struct platform_driver mux_gpio_driver = {
+	.driver = {
+		.name = "mux-gpio",
+		.of_match_table	= of_match_ptr(mux_gpio_dt_ids),
+	},
+	.probe = mux_gpio_probe,
+	.remove = mux_gpio_remove,
+};
+module_platform_driver(mux_gpio_driver);
+
+MODULE_DESCRIPTION("GPIO-controlled multiplexer driver");
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mux.h b/include/linux/mux.h
new file mode 100644
index 000000000000..88d607b7fde7
--- /dev/null
+++ b/include/linux/mux.h
@@ -0,0 +1,197 @@
+/*
+ * mux.h - definitions for the multiplexer interface
+ *
+ * Copyright (C) 2016 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_MUX_H
+#define _LINUX_MUX_H
+
+#include <linux/device.h>
+#include <linux/rwsem.h>
+
+struct mux_chip;
+struct mux_control;
+struct platform_device;
+
+struct mux_control_ops {
+	int (*set)(struct mux_control *mux, int state);
+};
+
+/**
+ * struct mux_control - Represents a mux controller.
+ * @lock:		Protects the mux controller state.
+ * @chip:		The mux chip that is handling this mux controller.
+ * @states:		The number of mux controller states.
+ * @cached_state:	The current mux controller state, or -1 if none.
+ * @idle_state:		The mux controller state to use when inactive, or -1
+ *			for none.
+ */
+struct mux_control {
+	struct rw_semaphore lock; /* protects the state of the mux */
+
+	struct mux_chip *chip;
+
+	unsigned int states;
+	int cached_state;
+	int idle_state;
+};
+
+/**
+ * struct mux_chip -	Represents a chip holding mux controllers.
+ * @controllers:	Number of mux controllers handled by the chip.
+ * @mux:		Array of mux controllers that is handled.
+ * @dev:		Device structure.
+ * @id:			Used to identify the device internally.
+ * @ops:		Mux controller operations.
+ */
+struct mux_chip {
+	unsigned int controllers;
+	struct mux_control *mux;
+	struct device dev;
+	int id;
+
+	const struct mux_control_ops *ops;
+};
+
+#define to_mux_chip(x) container_of((x), struct mux_chip, dev)
+
+/**
+ * mux_chip_priv() - Get the extra memory reserved by mux_chip_alloc().
+ * @mux_chip: The mux-chip to get the private memory from.
+ *
+ * Return: Pointer to the private memory reserved by the allocator.
+ */
+static inline void *mux_chip_priv(struct mux_chip *mux_chip)
+{
+	return &mux_chip->mux[mux_chip->controllers];
+}
+
+/**
+ * mux_chip_alloc() - Allocate a mux-chip.
+ * @dev: The parent device implementing the mux interface.
+ * @controllers: The number of mux controllers to allocate for this chip.
+ * @sizeof_priv: Size of extra memory area for private use by the caller.
+ *
+ * Return: A pointer to the new mux-chip, NULL on failure.
+ */
+struct mux_chip *mux_chip_alloc(struct device *dev,
+				unsigned int controllers, size_t sizeof_priv);
+
+/**
+ * mux_chip_register() - Register a mux-chip, thus readying the controllers
+ *			 for use.
+ * @mux_chip: The mux-chip to register.
+ *
+ * Do not retry registration of the same mux-chip on failure. You should
+ * instead put it away with mux_chip_free() and allocate a new one, if you
+ * for some reason would like to retry registration.
+ *
+ * Return: Zero on success or a negative errno on error.
+ */
+int mux_chip_register(struct mux_chip *mux_chip);
+
+/**
+ * mux_chip_unregister() - Take the mux-chip off-line.
+ * @mux_chip: The mux-chip to unregister.
+ *
+ * mux_chip_unregister() reverses the effects of mux_chip_register().
+ * But not completely, you should not try to call mux_chip_register()
+ * on a mux-chip that has been registered before.
+ */
+void mux_chip_unregister(struct mux_chip *mux_chip);
+
+/**
+ * mux_chip_free() - Free the mux-chip for good.
+ * @mux_chip: The mux-chip to free.
+ *
+ * mux_chip_free() reverses the effects of mux_chip_alloc().
+ */
+void mux_chip_free(struct mux_chip *mux_chip);
+
+/**
+ * mux_control_select() - Select the given multiplexer state.
+ * @mux: The mux-control to request a change of state from.
+ * @state: The new requested state.
+ *
+ * Make sure to call mux_control_deselect() when the operation is complete and
+ * the mux-control is free for others to use, but do not call
+ * mux_control_deselect() if mux_control_select() fails.
+ *
+ * Return: 0 if the requested state was already active, or 1 it the
+ * mux-control state was changed to the requested state. Or a negavive
+ * errno on error.
+ *
+ * Note that the difference in return value of zero or one is of
+ * questionable value; especially if the mux-control has several independent
+ * consumers, which is something the consumers should perhaps not be making
+ * assumptions about.
+ */
+int mux_control_select(struct mux_control *mux, int state);
+
+/**
+ * mux_control_deselect() - Deselect the previously selected multiplexer state.
+ * @mux: The mux-control to deselect.
+ *
+ * Return: 0 on success and a negative errno on error. An error can only
+ * occur if the mux has an idle state. Note that even if an error occurs, the
+ * mux-control is unlocked for others to access.
+ */
+int mux_control_deselect(struct mux_control *mux);
+
+/**
+ * mux_control_get_index() - Get the index of the given mux controller
+ * @mux: The mux-control to the the index for.
+ *
+ * Return: The index of the mux controller within the mux chip the mux
+ * controller is a part of.
+ */
+static inline unsigned int mux_control_get_index(struct mux_control *mux)
+{
+	return mux - mux->chip->mux;
+}
+
+/**
+ * mux_control_get() - Get the mux-control for a device.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *mux_control_get(struct device *dev, const char *mux_name);
+
+/**
+ * mux_control_put() - Put away the mux-control for good.
+ * @mux: The mux-control to put away.
+ *
+ * mux_control_put() reverses the effects of mux_control_get().
+ */
+void mux_control_put(struct mux_control *mux);
+
+/**
+ * devm_mux_control_get() - Get the mux-control for a device, with resource
+ *			    management.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *devm_mux_control_get(struct device *dev,
+					 const char *mux_name);
+
+/**
+ * devm_mux_control_put() - Resource-managed version mux_control_put().
+ * @dev: The device that originally got the mux-control.
+ * @mux: The mux-control to put away.
+ *
+ * Note that you do not normally need to call this function.
+ */
+void devm_mux_control_put(struct device *dev, struct mux_control *mux);
+
+#endif /* _LINUX_MUX_H */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 2/9] misc: minimal mux subsystem and gpio-based mux controller
@ 2016-11-30  8:16   ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:16 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc

Add a new minimalistic subsystem that handles multiplexer controllers.
When multiplexers are used in various places in the kernel, and the
same multiplexer controller can be used for several independent things,
there should be one place to implement support for said multiplexer
controller.

A single multiplexer controller can also be used to control several
parallel multiplexers, that are in turn used by different subsystems
in the kernel, leading to a need to coordinate multiplexer accesses.
The multiplexer subsystem handles this coordination.

This new mux controller subsystem initially comes with a single backend
driver that controls gpio based multiplexers. Even though not needed by
this initial driver, the mux controller subsystem is prepared to handle
chips with multiple (independent) mux controllers.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 Documentation/driver-model/devres.txt |   6 +-
 MAINTAINERS                           |   2 +
 drivers/misc/Kconfig                  |  30 ++++
 drivers/misc/Makefile                 |   2 +
 drivers/misc/mux-core.c               | 311 ++++++++++++++++++++++++++++++++++
 drivers/misc/mux-gpio.c               | 138 +++++++++++++++
 include/linux/mux.h                   | 197 +++++++++++++++++++++
 7 files changed, 685 insertions(+), 1 deletion(-)
 create mode 100644 drivers/misc/mux-core.c
 create mode 100644 drivers/misc/mux-gpio.c
 create mode 100644 include/linux/mux.h

diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index ca9d1eb46bc0..d64ede85b61b 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -330,7 +330,11 @@ MEM
   devm_kzalloc()
 
 MFD
- devm_mfd_add_devices()
+  devm_mfd_add_devices()
+
+MUX
+  devm_mux_control_get()
+  devm_mux_control_put()
 
 PER-CPU MEM
   devm_alloc_percpu()
diff --git a/MAINTAINERS b/MAINTAINERS
index 3d4d0efc2b64..dc7498682752 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8407,6 +8407,8 @@ MULTIPLEXER SUBSYSTEM
 M:	Peter Rosin <peda@axentia.se>
 S:	Maintained
 F:	Documentation/devicetree/bindings/misc/mux-*
+F:	include/linux/mux.h
+F:	drivers/misc/mux-*
 
 MULTISOUND SOUND DRIVER
 M:	Andrew Veliath <andrewtv@usa.net>
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 64971baf11fa..2ce675e410c5 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -766,6 +766,36 @@ config PANEL_BOOT_MESSAGE
 	  An empty message will only clear the display at driver init time. Any other
 	  printf()-formatted message is valid with newline and escape codes.
 
+menuconfig MULTIPLEXER
+	bool "Multiplexer subsystem"
+	help
+	  Multiplexer controller subsystem. Multiplexers are used in a
+	  variety of settings, and this subsystem abstracts their use
+	  so that the rest of the kernel sees a common interface. When
+	  multiple parallel multiplexers are controlled by one single
+	  multiplexer controller, this subsystem also coordinates the
+	  multiplexer accesses.
+
+	  If unsure, say no.
+
+if MULTIPLEXER
+
+config MUX_GPIO
+	tristate "GPIO-controlled Multiplexer"
+	depends on OF && GPIOLIB
+	help
+	  GPIO-controlled Multiplexer controller.
+
+	  The driver builds a single multiplexer controller using a number
+	  of gpio pins. For N pins, there will be 2^N possible multiplexer
+	  states. The GPIO pins can be connected (by the hardware) to several
+	  multiplexers, which in that case will be operated in parallel.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called mux-gpio.
+
+endif
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 31983366090a..0befa2bba762 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -53,6 +53,8 @@ obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
 obj-$(CONFIG_CXL_BASE)		+= cxl/
 obj-$(CONFIG_PANEL)             += panel.o
+obj-$(CONFIG_MULTIPLEXER)      	+= mux-core.o
+obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
 
 lkdtm-$(CONFIG_LKDTM)		+= lkdtm_core.o
 lkdtm-$(CONFIG_LKDTM)		+= lkdtm_bugs.o
diff --git a/drivers/misc/mux-core.c b/drivers/misc/mux-core.c
new file mode 100644
index 000000000000..cccaa7261a6e
--- /dev/null
+++ b/drivers/misc/mux-core.c
@@ -0,0 +1,311 @@
+/*
+ * Multiplexer subsystem
+ *
+ * Copyright (C) 2016 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) "mux-core: " fmt
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/idr.h>
+#include <linux/module.h>
+#include <linux/mux.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+
+static struct class mux_class = {
+	.name = "mux",
+	.owner = THIS_MODULE,
+};
+
+static int __init mux_init(void)
+{
+	return class_register(&mux_class);
+}
+
+static DEFINE_IDA(mux_ida);
+
+static void mux_chip_release(struct device *dev)
+{
+	struct mux_chip *mux_chip = to_mux_chip(dev);
+
+	ida_simple_remove(&mux_ida, mux_chip->id);
+	kfree(mux_chip);
+}
+
+static struct device_type mux_type = {
+	.name = "mux-chip",
+	.release = mux_chip_release,
+};
+
+struct mux_chip *mux_chip_alloc(struct device *dev,
+				unsigned int controllers, size_t sizeof_priv)
+{
+	struct mux_chip *mux_chip;
+	int i;
+
+	if (!dev || !controllers)
+		return NULL;
+
+	mux_chip = kzalloc(sizeof(*mux_chip) +
+			   controllers * sizeof(*mux_chip->mux) +
+			   sizeof_priv, GFP_KERNEL);
+	if (!mux_chip)
+		return NULL;
+
+	mux_chip->mux = (struct mux_control *)(mux_chip + 1);
+	mux_chip->dev.class = &mux_class;
+	mux_chip->dev.type = &mux_type;
+	mux_chip->dev.parent = dev;
+	mux_chip->dev.of_node = dev->of_node;
+	dev_set_drvdata(&mux_chip->dev, mux_chip);
+
+	mux_chip->id = ida_simple_get(&mux_ida, 0, 0, GFP_KERNEL);
+	if (mux_chip->id < 0) {
+		pr_err("muxchipX failed to get a device id\n");
+		kfree(mux_chip);
+		return NULL;
+	}
+	dev_set_name(&mux_chip->dev, "muxchip%d", mux_chip->id);
+
+	mux_chip->controllers = controllers;
+	for (i = 0; i < controllers; ++i) {
+		struct mux_control *mux = &mux_chip->mux[i];
+
+		mux->chip = mux_chip;
+		init_rwsem(&mux->lock);
+		mux->cached_state = -1;
+		mux->idle_state = -1;
+	}
+
+	device_initialize(&mux_chip->dev);
+
+	return mux_chip;
+}
+EXPORT_SYMBOL_GPL(mux_chip_alloc);
+
+static int mux_control_set(struct mux_control *mux, int state)
+{
+	int ret = mux->chip->ops->set(mux, state);
+
+	mux->cached_state = ret < 0 ? -1 : state;
+
+	return ret;
+}
+
+int mux_chip_register(struct mux_chip *mux_chip)
+{
+	int i;
+	int ret;
+
+	for (i = 0; i < mux_chip->controllers; ++i) {
+		struct mux_control *mux = &mux_chip->mux[i];
+
+		if (mux->idle_state == mux->cached_state)
+			continue;
+
+		ret = mux_control_set(mux, mux->idle_state);
+		if (ret < 0)
+			return ret;
+	}
+
+	return device_add(&mux_chip->dev);
+}
+EXPORT_SYMBOL_GPL(mux_chip_register);
+
+void mux_chip_unregister(struct mux_chip *mux_chip)
+{
+	device_del(&mux_chip->dev);
+}
+EXPORT_SYMBOL_GPL(mux_chip_unregister);
+
+void mux_chip_free(struct mux_chip *mux_chip)
+{
+	if (!mux_chip)
+		return;
+	put_device(&mux_chip->dev);
+}
+EXPORT_SYMBOL_GPL(mux_chip_free);
+
+int mux_control_select(struct mux_control *mux, int state)
+{
+	int ret;
+
+	if (down_read_trylock(&mux->lock)) {
+		if (mux->cached_state == state)
+			return 0;
+
+		/* Sigh, the mux needs updating... */
+		up_read(&mux->lock);
+	}
+
+	/* ...or it's just contended. */
+	down_write(&mux->lock);
+
+	if (mux->cached_state == state) {
+		/*
+		 * Hmmm, someone else changed the mux to my liking.
+		 * That makes me wonder how long I waited for nothing?
+		 */
+		downgrade_write(&mux->lock);
+		return 0;
+	}
+
+	ret = mux_control_set(mux, state);
+	if (ret < 0) {
+		if (mux->idle_state != -1)
+			mux_control_set(mux, mux->idle_state);
+
+		up_write(&mux->lock);
+		return ret;
+	}
+
+	downgrade_write(&mux->lock);
+
+	return 1;
+}
+EXPORT_SYMBOL_GPL(mux_control_select);
+
+int mux_control_deselect(struct mux_control *mux)
+{
+	int ret = 0;
+
+	if (mux->idle_state != -1 && mux->cached_state != mux->idle_state)
+		ret = mux_control_set(mux, mux->idle_state);
+
+	up_read(&mux->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(mux_control_deselect);
+
+static int of_dev_node_match(struct device *dev, const void *data)
+{
+	return dev->of_node == data;
+}
+
+static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
+{
+	struct device *dev;
+
+	dev = class_find_device(&mux_class, NULL, np, of_dev_node_match);
+
+	return dev ? to_mux_chip(dev) : NULL;
+}
+
+struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
+{
+	struct device_node *np = dev->of_node;
+	struct of_phandle_args args;
+	struct mux_chip *mux_chip;
+	unsigned int controller;
+	int index = 0;
+	int ret;
+
+	if (mux_name) {
+		index = of_property_match_string(np, "mux-control-names",
+						 mux_name);
+		if (index < 0)
+			return ERR_PTR(index);
+	}
+
+	ret = of_parse_phandle_with_args(np,
+					 "mux-controls", "#mux-control-cells",
+					 index, &args);
+	if (ret) {
+		dev_err(dev, "%s: failed to get mux-control %s(%i)\n",
+			np->full_name, mux_name ?: "", index);
+		return ERR_PTR(ret);
+	}
+
+	mux_chip = of_find_mux_chip_by_node(args.np);
+	of_node_put(args.np);
+	if (!mux_chip)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	if (args.args_count > 1 ||
+	    (!args.args_count && (mux_chip->controllers > 1))) {
+		dev_err(dev, "%s: wrong #mux-control-cells for %s\n",
+			np->full_name, args.np->full_name);
+		return ERR_PTR(-EINVAL);
+	}
+
+	controller = 0;
+	if (args.args_count)
+		controller = args.args[0];
+
+	if (controller >= mux_chip->controllers)
+		return ERR_PTR(-EINVAL);
+
+	get_device(&mux_chip->dev);
+	return &mux_chip->mux[controller];
+}
+EXPORT_SYMBOL_GPL(mux_control_get);
+
+void mux_control_put(struct mux_control *mux)
+{
+	put_device(&mux->chip->dev);
+}
+EXPORT_SYMBOL_GPL(mux_control_put);
+
+static void devm_mux_control_release(struct device *dev, void *res)
+{
+	struct mux_control *mux = *(struct mux_control **)res;
+
+	mux_control_put(mux);
+}
+
+struct mux_control *devm_mux_control_get(struct device *dev,
+					 const char *mux_name)
+{
+	struct mux_control **ptr, *mux;
+
+	ptr = devres_alloc(devm_mux_control_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	mux = mux_control_get(dev, mux_name);
+	if (IS_ERR(mux)) {
+		devres_free(ptr);
+		return mux;
+	}
+
+	*ptr = mux;
+	devres_add(dev, ptr);
+
+	return mux;
+}
+EXPORT_SYMBOL_GPL(devm_mux_control_get);
+
+static int devm_mux_control_match(struct device *dev, void *res, void *data)
+{
+	struct mux_control **r = res;
+
+	if (!r || !*r) {
+		WARN_ON(!r || !*r);
+		return 0;
+	}
+
+	return *r == data;
+}
+
+void devm_mux_control_put(struct device *dev, struct mux_control *mux)
+{
+	WARN_ON(devres_release(dev, devm_mux_control_release,
+			       devm_mux_control_match, mux));
+}
+EXPORT_SYMBOL_GPL(devm_mux_control_put);
+
+subsys_initcall(mux_init);
+
+MODULE_DESCRIPTION("Multiplexer subsystem");
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mux-gpio.c b/drivers/misc/mux-gpio.c
new file mode 100644
index 000000000000..a107a9b96854
--- /dev/null
+++ b/drivers/misc/mux-gpio.c
@@ -0,0 +1,138 @@
+/*
+ * GPIO-controlled multiplexer driver
+ *
+ * Copyright (C) 2016 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/mux.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+struct mux_gpio {
+	struct gpio_descs *gpios;
+	int *val;
+};
+
+static int mux_gpio_set(struct mux_control *mux, int state)
+{
+	struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip);
+	int i;
+
+	for (i = 0; i < mux_gpio->gpios->ndescs; i++)
+		mux_gpio->val[i] = (state >> i) & 1;
+
+	gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs,
+				       mux_gpio->gpios->desc,
+				       mux_gpio->val);
+
+	return 0;
+}
+
+static const struct mux_control_ops mux_gpio_ops = {
+	.set = mux_gpio_set,
+};
+
+static const struct of_device_id mux_gpio_dt_ids[] = {
+	{ .compatible = "mux-gpio", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mux_gpio_dt_ids);
+
+static int mux_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = pdev->dev.of_node;
+	struct mux_chip *mux_chip;
+	struct mux_gpio *mux_gpio;
+	int pins;
+	u32 idle_state;
+	int ret;
+
+	if (!np)
+		return -ENODEV;
+
+	pins = gpiod_count(dev, "mux");
+	if (pins < 0)
+		return pins;
+
+	mux_chip = mux_chip_alloc(dev, 1, sizeof(*mux_gpio) +
+				  pins * sizeof(*mux_gpio->val));
+	if (!mux_chip)
+		return -ENOMEM;
+
+	mux_gpio = mux_chip_priv(mux_chip);
+	mux_gpio->val = (int *)(mux_gpio + 1);
+	mux_chip->ops = &mux_gpio_ops;
+
+	platform_set_drvdata(pdev, mux_chip);
+
+	mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW);
+	if (IS_ERR(mux_gpio->gpios)) {
+		ret = PTR_ERR(mux_gpio->gpios);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "failed to get gpios\n");
+		goto free_mux_chip;
+	}
+	WARN_ON(pins != mux_gpio->gpios->ndescs);
+	mux_chip->mux->states = 1 << pins;
+
+	ret = of_property_read_u32(np, "idle-state", &idle_state);
+	if (ret >= 0) {
+		if (idle_state >= mux_chip->mux->states) {
+			dev_err(dev, "invalid idle-state %u\n", idle_state);
+			ret = -EINVAL;
+			goto free_mux_chip;
+		}
+
+		mux_chip->mux->idle_state = idle_state;
+	}
+
+	ret = mux_chip_register(mux_chip);
+	if (ret < 0) {
+		dev_err(dev, "failed to register mux-chip\n");
+		goto free_mux_chip;
+	}
+
+	dev_info(dev, "%u-way mux-controller registered\n",
+		 mux_chip->mux->states);
+
+	return 0;
+
+free_mux_chip:
+	mux_chip_free(mux_chip);
+	return ret;
+}
+
+static int mux_gpio_remove(struct platform_device *pdev)
+{
+	struct mux_chip *mux_chip = platform_get_drvdata(pdev);
+
+	mux_chip_unregister(mux_chip);
+	mux_chip_free(mux_chip);
+
+	return 0;
+}
+
+static struct platform_driver mux_gpio_driver = {
+	.driver = {
+		.name = "mux-gpio",
+		.of_match_table	= of_match_ptr(mux_gpio_dt_ids),
+	},
+	.probe = mux_gpio_probe,
+	.remove = mux_gpio_remove,
+};
+module_platform_driver(mux_gpio_driver);
+
+MODULE_DESCRIPTION("GPIO-controlled multiplexer driver");
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mux.h b/include/linux/mux.h
new file mode 100644
index 000000000000..88d607b7fde7
--- /dev/null
+++ b/include/linux/mux.h
@@ -0,0 +1,197 @@
+/*
+ * mux.h - definitions for the multiplexer interface
+ *
+ * Copyright (C) 2016 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_MUX_H
+#define _LINUX_MUX_H
+
+#include <linux/device.h>
+#include <linux/rwsem.h>
+
+struct mux_chip;
+struct mux_control;
+struct platform_device;
+
+struct mux_control_ops {
+	int (*set)(struct mux_control *mux, int state);
+};
+
+/**
+ * struct mux_control - Represents a mux controller.
+ * @lock:		Protects the mux controller state.
+ * @chip:		The mux chip that is handling this mux controller.
+ * @states:		The number of mux controller states.
+ * @cached_state:	The current mux controller state, or -1 if none.
+ * @idle_state:		The mux controller state to use when inactive, or -1
+ *			for none.
+ */
+struct mux_control {
+	struct rw_semaphore lock; /* protects the state of the mux */
+
+	struct mux_chip *chip;
+
+	unsigned int states;
+	int cached_state;
+	int idle_state;
+};
+
+/**
+ * struct mux_chip -	Represents a chip holding mux controllers.
+ * @controllers:	Number of mux controllers handled by the chip.
+ * @mux:		Array of mux controllers that is handled.
+ * @dev:		Device structure.
+ * @id:			Used to identify the device internally.
+ * @ops:		Mux controller operations.
+ */
+struct mux_chip {
+	unsigned int controllers;
+	struct mux_control *mux;
+	struct device dev;
+	int id;
+
+	const struct mux_control_ops *ops;
+};
+
+#define to_mux_chip(x) container_of((x), struct mux_chip, dev)
+
+/**
+ * mux_chip_priv() - Get the extra memory reserved by mux_chip_alloc().
+ * @mux_chip: The mux-chip to get the private memory from.
+ *
+ * Return: Pointer to the private memory reserved by the allocator.
+ */
+static inline void *mux_chip_priv(struct mux_chip *mux_chip)
+{
+	return &mux_chip->mux[mux_chip->controllers];
+}
+
+/**
+ * mux_chip_alloc() - Allocate a mux-chip.
+ * @dev: The parent device implementing the mux interface.
+ * @controllers: The number of mux controllers to allocate for this chip.
+ * @sizeof_priv: Size of extra memory area for private use by the caller.
+ *
+ * Return: A pointer to the new mux-chip, NULL on failure.
+ */
+struct mux_chip *mux_chip_alloc(struct device *dev,
+				unsigned int controllers, size_t sizeof_priv);
+
+/**
+ * mux_chip_register() - Register a mux-chip, thus readying the controllers
+ *			 for use.
+ * @mux_chip: The mux-chip to register.
+ *
+ * Do not retry registration of the same mux-chip on failure. You should
+ * instead put it away with mux_chip_free() and allocate a new one, if you
+ * for some reason would like to retry registration.
+ *
+ * Return: Zero on success or a negative errno on error.
+ */
+int mux_chip_register(struct mux_chip *mux_chip);
+
+/**
+ * mux_chip_unregister() - Take the mux-chip off-line.
+ * @mux_chip: The mux-chip to unregister.
+ *
+ * mux_chip_unregister() reverses the effects of mux_chip_register().
+ * But not completely, you should not try to call mux_chip_register()
+ * on a mux-chip that has been registered before.
+ */
+void mux_chip_unregister(struct mux_chip *mux_chip);
+
+/**
+ * mux_chip_free() - Free the mux-chip for good.
+ * @mux_chip: The mux-chip to free.
+ *
+ * mux_chip_free() reverses the effects of mux_chip_alloc().
+ */
+void mux_chip_free(struct mux_chip *mux_chip);
+
+/**
+ * mux_control_select() - Select the given multiplexer state.
+ * @mux: The mux-control to request a change of state from.
+ * @state: The new requested state.
+ *
+ * Make sure to call mux_control_deselect() when the operation is complete and
+ * the mux-control is free for others to use, but do not call
+ * mux_control_deselect() if mux_control_select() fails.
+ *
+ * Return: 0 if the requested state was already active, or 1 it the
+ * mux-control state was changed to the requested state. Or a negavive
+ * errno on error.
+ *
+ * Note that the difference in return value of zero or one is of
+ * questionable value; especially if the mux-control has several independent
+ * consumers, which is something the consumers should perhaps not be making
+ * assumptions about.
+ */
+int mux_control_select(struct mux_control *mux, int state);
+
+/**
+ * mux_control_deselect() - Deselect the previously selected multiplexer state.
+ * @mux: The mux-control to deselect.
+ *
+ * Return: 0 on success and a negative errno on error. An error can only
+ * occur if the mux has an idle state. Note that even if an error occurs, the
+ * mux-control is unlocked for others to access.
+ */
+int mux_control_deselect(struct mux_control *mux);
+
+/**
+ * mux_control_get_index() - Get the index of the given mux controller
+ * @mux: The mux-control to the the index for.
+ *
+ * Return: The index of the mux controller within the mux chip the mux
+ * controller is a part of.
+ */
+static inline unsigned int mux_control_get_index(struct mux_control *mux)
+{
+	return mux - mux->chip->mux;
+}
+
+/**
+ * mux_control_get() - Get the mux-control for a device.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *mux_control_get(struct device *dev, const char *mux_name);
+
+/**
+ * mux_control_put() - Put away the mux-control for good.
+ * @mux: The mux-control to put away.
+ *
+ * mux_control_put() reverses the effects of mux_control_get().
+ */
+void mux_control_put(struct mux_control *mux);
+
+/**
+ * devm_mux_control_get() - Get the mux-control for a device, with resource
+ *			    management.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *devm_mux_control_get(struct device *dev,
+					 const char *mux_name);
+
+/**
+ * devm_mux_control_put() - Resource-managed version mux_control_put().
+ * @dev: The device that originally got the mux-control.
+ * @mux: The mux-control to put away.
+ *
+ * Note that you do not normally need to call this function.
+ */
+void devm_mux_control_put(struct device *dev, struct mux_control *mux);
+
+#endif /* _LINUX_MUX_H */
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 3/9] iio: inkern: api for manipulating ext_info of iio channels
  2016-11-30  8:16 ` Peter Rosin
@ 2016-11-30  8:16   ` Peter Rosin
  -1 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:16 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc

Extend the inkern api with functions for reading and writing ext_info
of iio channels.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/iio/inkern.c         | 60 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/iio/consumer.h | 37 +++++++++++++++++++++++++++
 2 files changed, 97 insertions(+)

diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index b0f4630a163f..4848b8129e6c 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -863,3 +863,63 @@ int iio_write_channel_raw(struct iio_channel *chan, int val)
 	return ret;
 }
 EXPORT_SYMBOL_GPL(iio_write_channel_raw);
+
+unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan)
+{
+	const struct iio_chan_spec_ext_info *ext_info;
+	unsigned int i = 0;
+
+	if (!chan->channel->ext_info)
+		return i;
+
+	for (ext_info = chan->channel->ext_info; ext_info->name; ext_info++)
+		++i;
+
+	return i;
+}
+EXPORT_SYMBOL_GPL(iio_get_channel_ext_info_count);
+
+static const struct iio_chan_spec_ext_info *iio_lookup_ext_info(
+						const struct iio_channel *chan,
+						const char *attr)
+{
+	const struct iio_chan_spec_ext_info *ext_info;
+
+	if (!chan->channel->ext_info)
+		return NULL;
+
+	for (ext_info = chan->channel->ext_info; ext_info->name; ++ext_info) {
+		if (!strcmp(attr, ext_info->name))
+			return ext_info;
+	}
+
+	return NULL;
+}
+
+ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
+				  const char *attr, char *buf)
+{
+	const struct iio_chan_spec_ext_info *ext_info;
+
+	ext_info = iio_lookup_ext_info(chan, attr);
+	if (!ext_info)
+		return -EINVAL;
+
+	return ext_info->read(chan->indio_dev, ext_info->private,
+			      chan->channel, buf);
+}
+EXPORT_SYMBOL_GPL(iio_read_channel_ext_info);
+
+ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
+				   const char *buf, size_t len)
+{
+	const struct iio_chan_spec_ext_info *ext_info;
+
+	ext_info = iio_lookup_ext_info(chan, attr);
+	if (!ext_info)
+		return -EINVAL;
+
+	return ext_info->write(chan->indio_dev, ext_info->private,
+			       chan->channel, buf, len);
+}
+EXPORT_SYMBOL_GPL(iio_write_channel_ext_info);
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index 47eeec3218b5..5e347a9805fd 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -312,4 +312,41 @@ int iio_read_channel_scale(struct iio_channel *chan, int *val,
 int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
 	int *processed, unsigned int scale);
 
+/**
+ * iio_get_channel_ext_info_count() - get number of ext_info attributes
+ *				      connected to the channel.
+ * @chan:		The channel being queried
+ *
+ * Returns the number of ext_info attributes
+ */
+unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan);
+
+/**
+ * iio_read_channel_ext_info() - read ext_info attribute from a given channel
+ * @chan:		The channel being queried.
+ * @attr:		The ext_info attribute to read.
+ * @buf:		Where to store the attribute value. Assumed to hold
+ *			at least PAGE_SIZE bytes.
+ *
+ * Returns the number of bytes written to buf (perhaps w/o zero termination;
+ * it need not even be a string), or an error code.
+ */
+ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
+				  const char *attr, char *buf);
+
+/**
+ * iio_write_channel_ext_info() - write ext_info attribute from a given channel
+ * @chan:		The channel being queried.
+ * @attr:		The ext_info attribute to read.
+ * @buf:		The new attribute value. Strings needs to be zero-
+ *			terminated, but the terminator should not be included
+ *			in the below len.
+ * @len:		The size of the new attribute value.
+ *
+ * Returns the number of accepted bytes, which should be the same as len.
+ * An error code can also be returned.
+ */
+ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
+				   const char *buf, size_t len);
+
 #endif
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 3/9] iio: inkern: api for manipulating ext_info of iio channels
@ 2016-11-30  8:16   ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:16 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc

Extend the inkern api with functions for reading and writing ext_info
of iio channels.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/iio/inkern.c         | 60 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/iio/consumer.h | 37 +++++++++++++++++++++++++++
 2 files changed, 97 insertions(+)

diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index b0f4630a163f..4848b8129e6c 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -863,3 +863,63 @@ int iio_write_channel_raw(struct iio_channel *chan, int val)
 	return ret;
 }
 EXPORT_SYMBOL_GPL(iio_write_channel_raw);
+
+unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan)
+{
+	const struct iio_chan_spec_ext_info *ext_info;
+	unsigned int i = 0;
+
+	if (!chan->channel->ext_info)
+		return i;
+
+	for (ext_info = chan->channel->ext_info; ext_info->name; ext_info++)
+		++i;
+
+	return i;
+}
+EXPORT_SYMBOL_GPL(iio_get_channel_ext_info_count);
+
+static const struct iio_chan_spec_ext_info *iio_lookup_ext_info(
+						const struct iio_channel *chan,
+						const char *attr)
+{
+	const struct iio_chan_spec_ext_info *ext_info;
+
+	if (!chan->channel->ext_info)
+		return NULL;
+
+	for (ext_info = chan->channel->ext_info; ext_info->name; ++ext_info) {
+		if (!strcmp(attr, ext_info->name))
+			return ext_info;
+	}
+
+	return NULL;
+}
+
+ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
+				  const char *attr, char *buf)
+{
+	const struct iio_chan_spec_ext_info *ext_info;
+
+	ext_info = iio_lookup_ext_info(chan, attr);
+	if (!ext_info)
+		return -EINVAL;
+
+	return ext_info->read(chan->indio_dev, ext_info->private,
+			      chan->channel, buf);
+}
+EXPORT_SYMBOL_GPL(iio_read_channel_ext_info);
+
+ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
+				   const char *buf, size_t len)
+{
+	const struct iio_chan_spec_ext_info *ext_info;
+
+	ext_info = iio_lookup_ext_info(chan, attr);
+	if (!ext_info)
+		return -EINVAL;
+
+	return ext_info->write(chan->indio_dev, ext_info->private,
+			       chan->channel, buf, len);
+}
+EXPORT_SYMBOL_GPL(iio_write_channel_ext_info);
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index 47eeec3218b5..5e347a9805fd 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -312,4 +312,41 @@ int iio_read_channel_scale(struct iio_channel *chan, int *val,
 int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
 	int *processed, unsigned int scale);
 
+/**
+ * iio_get_channel_ext_info_count() - get number of ext_info attributes
+ *				      connected to the channel.
+ * @chan:		The channel being queried
+ *
+ * Returns the number of ext_info attributes
+ */
+unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan);
+
+/**
+ * iio_read_channel_ext_info() - read ext_info attribute from a given channel
+ * @chan:		The channel being queried.
+ * @attr:		The ext_info attribute to read.
+ * @buf:		Where to store the attribute value. Assumed to hold
+ *			at least PAGE_SIZE bytes.
+ *
+ * Returns the number of bytes written to buf (perhaps w/o zero termination;
+ * it need not even be a string), or an error code.
+ */
+ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
+				  const char *attr, char *buf);
+
+/**
+ * iio_write_channel_ext_info() - write ext_info attribute from a given channel
+ * @chan:		The channel being queried.
+ * @attr:		The ext_info attribute to read.
+ * @buf:		The new attribute value. Strings needs to be zero-
+ *			terminated, but the terminator should not be included
+ *			in the below len.
+ * @len:		The size of the new attribute value.
+ *
+ * Returns the number of accepted bytes, which should be the same as len.
+ * An error code can also be returned.
+ */
+ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
+				   const char *buf, size_t len);
+
 #endif
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 4/9] dt-bindings: iio: iio-mux: document iio-mux bindings
  2016-11-30  8:16 ` Peter Rosin
@ 2016-11-30  8:16   ` Peter Rosin
  -1 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:16 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../bindings/iio/multiplexer/iio-mux.txt           | 40 ++++++++++++++++++++++
 MAINTAINERS                                        |  6 ++++
 2 files changed, 46 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt

diff --git a/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
new file mode 100644
index 000000000000..8080cf790d82
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
@@ -0,0 +1,40 @@
+IIO multiplexer bindings
+
+If a multiplexer is used to select which hardware signal is fed to
+e.g. an ADC channel, these bindings describe that situation.
+
+Required properties:
+- compatible : "iio-mux"
+- io-channels : Channel node of the parent channel that has multiplexed
+		input.
+- io-channel-names : Should be "parent".
+- #address-cells = <1>;
+- #size-cells = <0>;
+- mux-controls : Mux controller node to use for operating the mux
+- channels : List of strings, labeling the mux controller states.
+
+The multiplexer state as described in ../misc/mux-controller.txt
+
+For each non-empty string in the channels property, an iio channel will
+be created. The number of this iio channel is the same as the index into
+the list of strings in the channels property, and also matches the mux
+controller state.
+
+Example:
+	mux: mux-controller {
+		compatible = "mux-gpio";
+		#mux-control-cells = <0>;
+
+		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
+			    <&pioA 1 GPIO_ACTIVE_HIGH>;
+	};
+
+	adc-mux {
+		compatible = "iio-mux";
+		io-channels = <&adc 0>;
+		io-channel-names = "parent";
+
+		mux-controls = <&mux>;
+
+		channels = "sync", "in", system-regulator";
+	};
diff --git a/MAINTAINERS b/MAINTAINERS
index dc7498682752..77045ae15865 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6234,6 +6234,12 @@ F:	Documentation/ABI/testing/sysfs-bus-iio-adc-envelope-detector
 F:	Documentation/devicetree/bindings/iio/adc/envelope-detector.txt
 F:	drivers/iio/adc/envelope-detector.c
 
+IIO MULTIPLEXER
+M:	Peter Rosin <peda@axentia.se>
+L:	linux-iio@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
+
 IIO SUBSYSTEM AND DRIVERS
 M:	Jonathan Cameron <jic23@kernel.org>
 R:	Hartmut Knaack <knaack.h@gmx.de>
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 4/9] dt-bindings: iio: iio-mux: document iio-mux bindings
@ 2016-11-30  8:16   ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:16 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../bindings/iio/multiplexer/iio-mux.txt           | 40 ++++++++++++++++++++++
 MAINTAINERS                                        |  6 ++++
 2 files changed, 46 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt

diff --git a/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
new file mode 100644
index 000000000000..8080cf790d82
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
@@ -0,0 +1,40 @@
+IIO multiplexer bindings
+
+If a multiplexer is used to select which hardware signal is fed to
+e.g. an ADC channel, these bindings describe that situation.
+
+Required properties:
+- compatible : "iio-mux"
+- io-channels : Channel node of the parent channel that has multiplexed
+		input.
+- io-channel-names : Should be "parent".
+- #address-cells = <1>;
+- #size-cells = <0>;
+- mux-controls : Mux controller node to use for operating the mux
+- channels : List of strings, labeling the mux controller states.
+
+The multiplexer state as described in ../misc/mux-controller.txt
+
+For each non-empty string in the channels property, an iio channel will
+be created. The number of this iio channel is the same as the index into
+the list of strings in the channels property, and also matches the mux
+controller state.
+
+Example:
+	mux: mux-controller {
+		compatible = "mux-gpio";
+		#mux-control-cells = <0>;
+
+		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
+			    <&pioA 1 GPIO_ACTIVE_HIGH>;
+	};
+
+	adc-mux {
+		compatible = "iio-mux";
+		io-channels = <&adc 0>;
+		io-channel-names = "parent";
+
+		mux-controls = <&mux>;
+
+		channels = "sync", "in", system-regulator";
+	};
diff --git a/MAINTAINERS b/MAINTAINERS
index dc7498682752..77045ae15865 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6234,6 +6234,12 @@ F:	Documentation/ABI/testing/sysfs-bus-iio-adc-envelope-detector
 F:	Documentation/devicetree/bindings/iio/adc/envelope-detector.txt
 F:	drivers/iio/adc/envelope-detector.c
 
+IIO MULTIPLEXER
+M:	Peter Rosin <peda@axentia.se>
+L:	linux-iio@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
+
 IIO SUBSYSTEM AND DRIVERS
 M:	Jonathan Cameron <jic23@kernel.org>
 R:	Hartmut Knaack <knaack.h@gmx.de>
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 5/9] iio: multiplexer: new iio category and iio-mux driver
  2016-11-30  8:16 ` Peter Rosin
@ 2016-11-30  8:16   ` Peter Rosin
  -1 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:16 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc

When a multiplexer changes how an iio device behaves (for example
by feeding different signals to an ADC), this driver can be used
to create one virtual iio channel for each multiplexer state.

Depends on the generic multiplexer subsystem.

Cache any ext_info values from the parent iio channel, creating a private
copy of the ext_info attributes for each multiplexer state/channel.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 MAINTAINERS                       |   1 +
 drivers/iio/Kconfig               |   1 +
 drivers/iio/Makefile              |   1 +
 drivers/iio/multiplexer/Kconfig   |  18 ++
 drivers/iio/multiplexer/Makefile  |   6 +
 drivers/iio/multiplexer/iio-mux.c | 456 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 483 insertions(+)
 create mode 100644 drivers/iio/multiplexer/Kconfig
 create mode 100644 drivers/iio/multiplexer/Makefile
 create mode 100644 drivers/iio/multiplexer/iio-mux.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 77045ae15865..16490fbd1721 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6239,6 +6239,7 @@ M:	Peter Rosin <peda@axentia.se>
 L:	linux-iio@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
+F:	drivers/iio/multiplexer/iio-mux.c
 
 IIO SUBSYSTEM AND DRIVERS
 M:	Jonathan Cameron <jic23@kernel.org>
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index a918270d6f54..b3c8c6ef0dff 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -83,6 +83,7 @@ source "drivers/iio/humidity/Kconfig"
 source "drivers/iio/imu/Kconfig"
 source "drivers/iio/light/Kconfig"
 source "drivers/iio/magnetometer/Kconfig"
+source "drivers/iio/multiplexer/Kconfig"
 source "drivers/iio/orientation/Kconfig"
 if IIO_TRIGGER
    source "drivers/iio/trigger/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 33fa4026f92c..93c769cd99bf 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -28,6 +28,7 @@ obj-y += humidity/
 obj-y += imu/
 obj-y += light/
 obj-y += magnetometer/
+obj-y += multiplexer/
 obj-y += orientation/
 obj-y += potentiometer/
 obj-y += potentiostat/
diff --git a/drivers/iio/multiplexer/Kconfig b/drivers/iio/multiplexer/Kconfig
new file mode 100644
index 000000000000..70a044510686
--- /dev/null
+++ b/drivers/iio/multiplexer/Kconfig
@@ -0,0 +1,18 @@
+#
+# Multiplexer drivers
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Multiplexers"
+
+config IIO_MUX
+	tristate "IIO multiplexer driver"
+	select MULTIPLEXER
+	depends on OF
+	help
+	  Say yes here to build support for the IIO multiplexer.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iio-mux.
+
+endmenu
diff --git a/drivers/iio/multiplexer/Makefile b/drivers/iio/multiplexer/Makefile
new file mode 100644
index 000000000000..68be3c4abd07
--- /dev/null
+++ b/drivers/iio/multiplexer/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for industrial I/O multiplexer drivers
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_IIO_MUX) += iio-mux.o
diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c
new file mode 100644
index 000000000000..92dfee2dfed1
--- /dev/null
+++ b/drivers/iio/multiplexer/iio-mux.c
@@ -0,0 +1,456 @@
+/*
+ * IIO multiplexer driver
+ *
+ * Copyright (C) 2016 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/iio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/mux.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+struct mux_ext_info_cache {
+	char *data;
+	size_t size;
+};
+
+struct mux_child {
+	struct mux_ext_info_cache *ext_info_cache;
+};
+
+struct mux {
+	int cached_state;
+	struct mux_control *control;
+	struct iio_channel *parent;
+	struct iio_dev *indio_dev;
+	struct iio_chan_spec *chan;
+	struct iio_chan_spec_ext_info *ext_info;
+	struct mux_child *child;
+};
+
+static int iio_mux_select(struct mux *mux, int idx)
+{
+	struct mux_child *child = &mux->child[idx];
+	struct iio_chan_spec const *chan = &mux->chan[idx];
+	int ret;
+	int i;
+
+	ret = mux_control_select(mux->control, chan->channel);
+	if (ret < 0) {
+		mux->cached_state = -1;
+		return ret;
+	}
+
+	if (mux->cached_state == chan->channel)
+		return 0;
+
+	if (chan->ext_info) {
+		for (i = 0; chan->ext_info[i].name; ++i) {
+			const char *attr = chan->ext_info[i].name;
+			struct mux_ext_info_cache *cache;
+
+			cache = &child->ext_info_cache[i];
+
+			if (cache->size < 0)
+				continue;
+
+			ret = iio_write_channel_ext_info(mux->parent, attr,
+							 cache->data,
+							 cache->size);
+
+			if (ret < 0) {
+				mux_control_deselect(mux->control);
+				mux->cached_state = -1;
+				return ret;
+			}
+		}
+	}
+	mux->cached_state = chan->channel;
+
+	return 0;
+}
+
+static void iio_mux_deselect(struct mux *mux)
+{
+	mux_control_deselect(mux->control);
+}
+
+static int mux_read_raw(struct iio_dev *indio_dev,
+			struct iio_chan_spec const *chan,
+			int *val, int *val2, long mask)
+{
+	struct mux *mux = iio_priv(indio_dev);
+	int idx = chan - mux->chan;
+	int ret;
+
+	ret = iio_mux_select(mux, idx);
+	if (ret < 0)
+		return ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = iio_read_channel_raw(mux->parent, val);
+		break;
+
+	case IIO_CHAN_INFO_SCALE:
+		ret = iio_read_channel_scale(mux->parent, val, val2);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	iio_mux_deselect(mux);
+
+	return ret;
+}
+
+static int mux_read_avail(struct iio_dev *indio_dev,
+			  struct iio_chan_spec const *chan,
+			  const int **vals, int *type, int *length,
+			  long mask)
+{
+	struct mux *mux = iio_priv(indio_dev);
+	int idx = chan - mux->chan;
+	int ret;
+
+	ret = iio_mux_select(mux, idx);
+	if (ret < 0)
+		return ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		*type = IIO_VAL_INT;
+		ret = iio_read_avail_channel_raw(mux->parent, vals, length);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	iio_mux_deselect(mux);
+
+	return ret;
+}
+
+static int mux_write_raw(struct iio_dev *indio_dev,
+			 struct iio_chan_spec const *chan,
+			 int val, int val2, long mask)
+{
+	struct mux *mux = iio_priv(indio_dev);
+	int idx = chan - mux->chan;
+	int ret;
+
+	ret = iio_mux_select(mux, idx);
+	if (ret < 0)
+		return ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = iio_write_channel_raw(mux->parent, val);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	iio_mux_deselect(mux);
+
+	return ret;
+}
+
+static const struct iio_info mux_info = {
+	.read_raw = mux_read_raw,
+	.read_avail = mux_read_avail,
+	.write_raw = mux_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static ssize_t mux_read_ext_info(struct iio_dev *indio_dev, uintptr_t private,
+				 struct iio_chan_spec const *chan, char *buf)
+{
+	struct mux *mux = iio_priv(indio_dev);
+	int idx = chan - mux->chan;
+	ssize_t ret;
+
+	ret = iio_mux_select(mux, idx);
+	if (ret < 0)
+		return ret;
+
+	ret = iio_read_channel_ext_info(mux->parent,
+					mux->ext_info[private].name,
+					buf);
+
+	iio_mux_deselect(mux);
+
+	return ret;
+}
+
+static ssize_t mux_write_ext_info(struct iio_dev *indio_dev, uintptr_t private,
+				  struct iio_chan_spec const *chan,
+				  const char *buf, size_t len)
+{
+	struct device *dev = indio_dev->dev.parent;
+	struct mux *mux = iio_priv(indio_dev);
+	int idx = chan - mux->chan;
+	char *new;
+	ssize_t ret;
+
+	ret = iio_mux_select(mux, idx);
+	if (ret < 0)
+		return ret;
+
+	new = devm_kmemdup(dev, buf, len + 1, GFP_KERNEL);
+	if (!new) {
+		iio_mux_deselect(mux);
+		return -ENOMEM;
+	}
+
+	new[len] = 0;
+
+	ret = iio_write_channel_ext_info(mux->parent,
+					 mux->ext_info[private].name,
+					 buf, len);
+	if (ret < 0) {
+		iio_mux_deselect(mux);
+		devm_kfree(dev, new);
+		return ret;
+	}
+
+	devm_kfree(dev, mux->child[idx].ext_info_cache[private].data);
+	mux->child[idx].ext_info_cache[private].data = new;
+	mux->child[idx].ext_info_cache[private].size = len;
+
+	iio_mux_deselect(mux);
+
+	return ret;
+}
+
+static int mux_configure_channel(struct device *dev, struct mux *mux,
+				 u32 state, const char *label, int idx)
+{
+	struct mux_child *child = &mux->child[idx];
+	struct iio_chan_spec *chan = &mux->chan[idx];
+	struct iio_chan_spec const *pchan = mux->parent->channel;
+	char *page = NULL;
+	int num_ext_info;
+	int i;
+	int ret;
+
+	chan->indexed = 1;
+	chan->output = pchan->output;
+	chan->datasheet_name = label;
+	chan->ext_info = mux->ext_info;
+
+	ret = iio_get_channel_type(mux->parent, &chan->type);
+	if (ret < 0) {
+		dev_err(dev, "failed to get parent channel type\n");
+		return ret;
+	}
+
+	if (iio_channel_has_info(pchan, IIO_CHAN_INFO_RAW))
+		chan->info_mask_separate |= BIT(IIO_CHAN_INFO_RAW);
+	if (iio_channel_has_info(pchan, IIO_CHAN_INFO_SCALE))
+		chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE);
+
+	if (iio_channel_has_available(pchan, IIO_CHAN_INFO_RAW))
+		chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_RAW);
+
+	if (state >= mux->control->states) {
+		dev_err(dev, "too many channels\n");
+		return -EINVAL;
+	}
+
+	chan->channel = state;
+
+	num_ext_info = iio_get_channel_ext_info_count(mux->parent);
+	if (num_ext_info) {
+		page = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL);
+		if (!page)
+			return -ENOMEM;
+	}
+	child->ext_info_cache = devm_kzalloc(dev,
+					     sizeof(*child->ext_info_cache) *
+					     num_ext_info, GFP_KERNEL);
+	for (i = 0; i < num_ext_info; ++i) {
+		child->ext_info_cache[i].size = -1;
+
+		if (!pchan->ext_info[i].write)
+			continue;
+		if (!pchan->ext_info[i].read)
+			continue;
+
+		ret = iio_read_channel_ext_info(mux->parent,
+						mux->ext_info[i].name,
+						page);
+		if (ret < 0) {
+			dev_err(dev, "failed to get ext_info '%s'\n",
+				pchan->ext_info[i].name);
+			return ret;
+		}
+		if (ret >= PAGE_SIZE) {
+			dev_err(dev, "too large ext_info '%s'\n",
+				pchan->ext_info[i].name);
+			return -EINVAL;
+		}
+
+		child->ext_info_cache[i].data = devm_kmemdup(dev, page, ret + 1,
+							     GFP_KERNEL);
+		child->ext_info_cache[i].data[ret] = 0;
+		child->ext_info_cache[i].size = ret;
+	}
+
+	if (page)
+		devm_kfree(dev, page);
+
+	return 0;
+}
+
+/*
+ * Same as of_property_for_each_string(), but also keeps track of the
+ * index of each string.
+ */
+#define of_property_for_each_string_index(np, propname, prop, s, i)	\
+	for (prop = of_find_property(np, propname, NULL),		\
+	     s = of_prop_next_string(prop, NULL),			\
+	     i = 0;							\
+	     s;								\
+	     s = of_prop_next_string(prop, s),				\
+	     i++)
+
+static int mux_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = pdev->dev.of_node;
+	struct iio_dev *indio_dev;
+	struct iio_channel *parent;
+	struct mux *mux;
+	struct property *prop;
+	const char *label;
+	u32 state;
+	int sizeof_ext_info;
+	int children;
+	int sizeof_priv;
+	int i;
+	int ret;
+
+	if (!np)
+		return -ENODEV;
+
+	parent = devm_iio_channel_get(dev, "parent");
+	if (IS_ERR(parent)) {
+		if (PTR_ERR(parent) != -EPROBE_DEFER)
+			dev_err(dev, "failed to get parent channel\n");
+		return PTR_ERR(parent);
+	}
+
+	sizeof_ext_info = iio_get_channel_ext_info_count(parent);
+	if (sizeof_ext_info) {
+		sizeof_ext_info += 1; /* one extra entry for the sentinel */
+		sizeof_ext_info *= sizeof(*mux->ext_info);
+	}
+
+	children = 0;
+	of_property_for_each_string(np, "channels", prop, label) {
+		if (*label)
+			children++;
+	}
+	if (children <= 0) {
+		dev_err(dev, "not even a single child\n");
+		return -EINVAL;
+	}
+
+	sizeof_priv = sizeof(*mux);
+	sizeof_priv += sizeof(*mux->child) * children;
+	sizeof_priv += sizeof(*mux->chan) * children;
+	sizeof_priv += sizeof_ext_info;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof_priv);
+	if (!indio_dev)
+		return -ENOMEM;
+
+	mux = iio_priv(indio_dev);
+	mux->child = (struct mux_child *)(mux + 1);
+	mux->chan = (struct iio_chan_spec *)(mux->child + children);
+
+	platform_set_drvdata(pdev, indio_dev);
+
+	mux->parent = parent;
+	mux->cached_state = -1;
+
+	indio_dev->name = dev_name(dev);
+	indio_dev->dev.parent = dev;
+	indio_dev->info = &mux_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = mux->chan;
+	indio_dev->num_channels = children;
+	if (sizeof_ext_info) {
+		mux->ext_info = devm_kmemdup(dev,
+					     parent->channel->ext_info,
+					     sizeof_ext_info, GFP_KERNEL);
+		if (!mux->ext_info)
+			return -ENOMEM;
+
+		for (i = 0; mux->ext_info[i].name; ++i) {
+			if (parent->channel->ext_info[i].read)
+				mux->ext_info[i].read = mux_read_ext_info;
+			if (parent->channel->ext_info[i].write)
+				mux->ext_info[i].write = mux_write_ext_info;
+			mux->ext_info[i].private = i;
+		}
+	}
+
+	mux->control = devm_mux_control_get(dev, NULL);
+	if (IS_ERR(mux->control)) {
+		if (PTR_ERR(mux->control) != -EPROBE_DEFER)
+			dev_err(dev, "failed to get control-mux\n");
+		return PTR_ERR(mux->control);
+	}
+
+	i = 0;
+	of_property_for_each_string_index(np, "channels", prop, label, state) {
+		if (!*label)
+			continue;
+
+		ret = mux_configure_channel(dev, mux, state, label, i++);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = devm_iio_device_register(dev, indio_dev);
+	if (ret) {
+		dev_err(dev, "failed to register iio device\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id mux_match[] = {
+	{ .compatible = "iio-mux" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mux_match);
+
+static struct platform_driver mux_driver = {
+	.probe = mux_probe,
+	.driver = {
+		.name = "iio-mux",
+		.of_match_table = mux_match,
+	},
+};
+module_platform_driver(mux_driver);
+
+MODULE_DESCRIPTION("IIO multiplexer driver");
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
+MODULE_LICENSE("GPL v2");
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 5/9] iio: multiplexer: new iio category and iio-mux driver
@ 2016-11-30  8:16   ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:16 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc

When a multiplexer changes how an iio device behaves (for example
by feeding different signals to an ADC), this driver can be used
to create one virtual iio channel for each multiplexer state.

Depends on the generic multiplexer subsystem.

Cache any ext_info values from the parent iio channel, creating a private
copy of the ext_info attributes for each multiplexer state/channel.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 MAINTAINERS                       |   1 +
 drivers/iio/Kconfig               |   1 +
 drivers/iio/Makefile              |   1 +
 drivers/iio/multiplexer/Kconfig   |  18 ++
 drivers/iio/multiplexer/Makefile  |   6 +
 drivers/iio/multiplexer/iio-mux.c | 456 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 483 insertions(+)
 create mode 100644 drivers/iio/multiplexer/Kconfig
 create mode 100644 drivers/iio/multiplexer/Makefile
 create mode 100644 drivers/iio/multiplexer/iio-mux.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 77045ae15865..16490fbd1721 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6239,6 +6239,7 @@ M:	Peter Rosin <peda@axentia.se>
 L:	linux-iio@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
+F:	drivers/iio/multiplexer/iio-mux.c
 
 IIO SUBSYSTEM AND DRIVERS
 M:	Jonathan Cameron <jic23@kernel.org>
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index a918270d6f54..b3c8c6ef0dff 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -83,6 +83,7 @@ source "drivers/iio/humidity/Kconfig"
 source "drivers/iio/imu/Kconfig"
 source "drivers/iio/light/Kconfig"
 source "drivers/iio/magnetometer/Kconfig"
+source "drivers/iio/multiplexer/Kconfig"
 source "drivers/iio/orientation/Kconfig"
 if IIO_TRIGGER
    source "drivers/iio/trigger/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 33fa4026f92c..93c769cd99bf 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -28,6 +28,7 @@ obj-y += humidity/
 obj-y += imu/
 obj-y += light/
 obj-y += magnetometer/
+obj-y += multiplexer/
 obj-y += orientation/
 obj-y += potentiometer/
 obj-y += potentiostat/
diff --git a/drivers/iio/multiplexer/Kconfig b/drivers/iio/multiplexer/Kconfig
new file mode 100644
index 000000000000..70a044510686
--- /dev/null
+++ b/drivers/iio/multiplexer/Kconfig
@@ -0,0 +1,18 @@
+#
+# Multiplexer drivers
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Multiplexers"
+
+config IIO_MUX
+	tristate "IIO multiplexer driver"
+	select MULTIPLEXER
+	depends on OF
+	help
+	  Say yes here to build support for the IIO multiplexer.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iio-mux.
+
+endmenu
diff --git a/drivers/iio/multiplexer/Makefile b/drivers/iio/multiplexer/Makefile
new file mode 100644
index 000000000000..68be3c4abd07
--- /dev/null
+++ b/drivers/iio/multiplexer/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for industrial I/O multiplexer drivers
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_IIO_MUX) += iio-mux.o
diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c
new file mode 100644
index 000000000000..92dfee2dfed1
--- /dev/null
+++ b/drivers/iio/multiplexer/iio-mux.c
@@ -0,0 +1,456 @@
+/*
+ * IIO multiplexer driver
+ *
+ * Copyright (C) 2016 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/iio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/mux.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+struct mux_ext_info_cache {
+	char *data;
+	size_t size;
+};
+
+struct mux_child {
+	struct mux_ext_info_cache *ext_info_cache;
+};
+
+struct mux {
+	int cached_state;
+	struct mux_control *control;
+	struct iio_channel *parent;
+	struct iio_dev *indio_dev;
+	struct iio_chan_spec *chan;
+	struct iio_chan_spec_ext_info *ext_info;
+	struct mux_child *child;
+};
+
+static int iio_mux_select(struct mux *mux, int idx)
+{
+	struct mux_child *child = &mux->child[idx];
+	struct iio_chan_spec const *chan = &mux->chan[idx];
+	int ret;
+	int i;
+
+	ret = mux_control_select(mux->control, chan->channel);
+	if (ret < 0) {
+		mux->cached_state = -1;
+		return ret;
+	}
+
+	if (mux->cached_state == chan->channel)
+		return 0;
+
+	if (chan->ext_info) {
+		for (i = 0; chan->ext_info[i].name; ++i) {
+			const char *attr = chan->ext_info[i].name;
+			struct mux_ext_info_cache *cache;
+
+			cache = &child->ext_info_cache[i];
+
+			if (cache->size < 0)
+				continue;
+
+			ret = iio_write_channel_ext_info(mux->parent, attr,
+							 cache->data,
+							 cache->size);
+
+			if (ret < 0) {
+				mux_control_deselect(mux->control);
+				mux->cached_state = -1;
+				return ret;
+			}
+		}
+	}
+	mux->cached_state = chan->channel;
+
+	return 0;
+}
+
+static void iio_mux_deselect(struct mux *mux)
+{
+	mux_control_deselect(mux->control);
+}
+
+static int mux_read_raw(struct iio_dev *indio_dev,
+			struct iio_chan_spec const *chan,
+			int *val, int *val2, long mask)
+{
+	struct mux *mux = iio_priv(indio_dev);
+	int idx = chan - mux->chan;
+	int ret;
+
+	ret = iio_mux_select(mux, idx);
+	if (ret < 0)
+		return ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = iio_read_channel_raw(mux->parent, val);
+		break;
+
+	case IIO_CHAN_INFO_SCALE:
+		ret = iio_read_channel_scale(mux->parent, val, val2);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	iio_mux_deselect(mux);
+
+	return ret;
+}
+
+static int mux_read_avail(struct iio_dev *indio_dev,
+			  struct iio_chan_spec const *chan,
+			  const int **vals, int *type, int *length,
+			  long mask)
+{
+	struct mux *mux = iio_priv(indio_dev);
+	int idx = chan - mux->chan;
+	int ret;
+
+	ret = iio_mux_select(mux, idx);
+	if (ret < 0)
+		return ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		*type = IIO_VAL_INT;
+		ret = iio_read_avail_channel_raw(mux->parent, vals, length);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	iio_mux_deselect(mux);
+
+	return ret;
+}
+
+static int mux_write_raw(struct iio_dev *indio_dev,
+			 struct iio_chan_spec const *chan,
+			 int val, int val2, long mask)
+{
+	struct mux *mux = iio_priv(indio_dev);
+	int idx = chan - mux->chan;
+	int ret;
+
+	ret = iio_mux_select(mux, idx);
+	if (ret < 0)
+		return ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = iio_write_channel_raw(mux->parent, val);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	iio_mux_deselect(mux);
+
+	return ret;
+}
+
+static const struct iio_info mux_info = {
+	.read_raw = mux_read_raw,
+	.read_avail = mux_read_avail,
+	.write_raw = mux_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static ssize_t mux_read_ext_info(struct iio_dev *indio_dev, uintptr_t private,
+				 struct iio_chan_spec const *chan, char *buf)
+{
+	struct mux *mux = iio_priv(indio_dev);
+	int idx = chan - mux->chan;
+	ssize_t ret;
+
+	ret = iio_mux_select(mux, idx);
+	if (ret < 0)
+		return ret;
+
+	ret = iio_read_channel_ext_info(mux->parent,
+					mux->ext_info[private].name,
+					buf);
+
+	iio_mux_deselect(mux);
+
+	return ret;
+}
+
+static ssize_t mux_write_ext_info(struct iio_dev *indio_dev, uintptr_t private,
+				  struct iio_chan_spec const *chan,
+				  const char *buf, size_t len)
+{
+	struct device *dev = indio_dev->dev.parent;
+	struct mux *mux = iio_priv(indio_dev);
+	int idx = chan - mux->chan;
+	char *new;
+	ssize_t ret;
+
+	ret = iio_mux_select(mux, idx);
+	if (ret < 0)
+		return ret;
+
+	new = devm_kmemdup(dev, buf, len + 1, GFP_KERNEL);
+	if (!new) {
+		iio_mux_deselect(mux);
+		return -ENOMEM;
+	}
+
+	new[len] = 0;
+
+	ret = iio_write_channel_ext_info(mux->parent,
+					 mux->ext_info[private].name,
+					 buf, len);
+	if (ret < 0) {
+		iio_mux_deselect(mux);
+		devm_kfree(dev, new);
+		return ret;
+	}
+
+	devm_kfree(dev, mux->child[idx].ext_info_cache[private].data);
+	mux->child[idx].ext_info_cache[private].data = new;
+	mux->child[idx].ext_info_cache[private].size = len;
+
+	iio_mux_deselect(mux);
+
+	return ret;
+}
+
+static int mux_configure_channel(struct device *dev, struct mux *mux,
+				 u32 state, const char *label, int idx)
+{
+	struct mux_child *child = &mux->child[idx];
+	struct iio_chan_spec *chan = &mux->chan[idx];
+	struct iio_chan_spec const *pchan = mux->parent->channel;
+	char *page = NULL;
+	int num_ext_info;
+	int i;
+	int ret;
+
+	chan->indexed = 1;
+	chan->output = pchan->output;
+	chan->datasheet_name = label;
+	chan->ext_info = mux->ext_info;
+
+	ret = iio_get_channel_type(mux->parent, &chan->type);
+	if (ret < 0) {
+		dev_err(dev, "failed to get parent channel type\n");
+		return ret;
+	}
+
+	if (iio_channel_has_info(pchan, IIO_CHAN_INFO_RAW))
+		chan->info_mask_separate |= BIT(IIO_CHAN_INFO_RAW);
+	if (iio_channel_has_info(pchan, IIO_CHAN_INFO_SCALE))
+		chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE);
+
+	if (iio_channel_has_available(pchan, IIO_CHAN_INFO_RAW))
+		chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_RAW);
+
+	if (state >= mux->control->states) {
+		dev_err(dev, "too many channels\n");
+		return -EINVAL;
+	}
+
+	chan->channel = state;
+
+	num_ext_info = iio_get_channel_ext_info_count(mux->parent);
+	if (num_ext_info) {
+		page = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL);
+		if (!page)
+			return -ENOMEM;
+	}
+	child->ext_info_cache = devm_kzalloc(dev,
+					     sizeof(*child->ext_info_cache) *
+					     num_ext_info, GFP_KERNEL);
+	for (i = 0; i < num_ext_info; ++i) {
+		child->ext_info_cache[i].size = -1;
+
+		if (!pchan->ext_info[i].write)
+			continue;
+		if (!pchan->ext_info[i].read)
+			continue;
+
+		ret = iio_read_channel_ext_info(mux->parent,
+						mux->ext_info[i].name,
+						page);
+		if (ret < 0) {
+			dev_err(dev, "failed to get ext_info '%s'\n",
+				pchan->ext_info[i].name);
+			return ret;
+		}
+		if (ret >= PAGE_SIZE) {
+			dev_err(dev, "too large ext_info '%s'\n",
+				pchan->ext_info[i].name);
+			return -EINVAL;
+		}
+
+		child->ext_info_cache[i].data = devm_kmemdup(dev, page, ret + 1,
+							     GFP_KERNEL);
+		child->ext_info_cache[i].data[ret] = 0;
+		child->ext_info_cache[i].size = ret;
+	}
+
+	if (page)
+		devm_kfree(dev, page);
+
+	return 0;
+}
+
+/*
+ * Same as of_property_for_each_string(), but also keeps track of the
+ * index of each string.
+ */
+#define of_property_for_each_string_index(np, propname, prop, s, i)	\
+	for (prop = of_find_property(np, propname, NULL),		\
+	     s = of_prop_next_string(prop, NULL),			\
+	     i = 0;							\
+	     s;								\
+	     s = of_prop_next_string(prop, s),				\
+	     i++)
+
+static int mux_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = pdev->dev.of_node;
+	struct iio_dev *indio_dev;
+	struct iio_channel *parent;
+	struct mux *mux;
+	struct property *prop;
+	const char *label;
+	u32 state;
+	int sizeof_ext_info;
+	int children;
+	int sizeof_priv;
+	int i;
+	int ret;
+
+	if (!np)
+		return -ENODEV;
+
+	parent = devm_iio_channel_get(dev, "parent");
+	if (IS_ERR(parent)) {
+		if (PTR_ERR(parent) != -EPROBE_DEFER)
+			dev_err(dev, "failed to get parent channel\n");
+		return PTR_ERR(parent);
+	}
+
+	sizeof_ext_info = iio_get_channel_ext_info_count(parent);
+	if (sizeof_ext_info) {
+		sizeof_ext_info += 1; /* one extra entry for the sentinel */
+		sizeof_ext_info *= sizeof(*mux->ext_info);
+	}
+
+	children = 0;
+	of_property_for_each_string(np, "channels", prop, label) {
+		if (*label)
+			children++;
+	}
+	if (children <= 0) {
+		dev_err(dev, "not even a single child\n");
+		return -EINVAL;
+	}
+
+	sizeof_priv = sizeof(*mux);
+	sizeof_priv += sizeof(*mux->child) * children;
+	sizeof_priv += sizeof(*mux->chan) * children;
+	sizeof_priv += sizeof_ext_info;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof_priv);
+	if (!indio_dev)
+		return -ENOMEM;
+
+	mux = iio_priv(indio_dev);
+	mux->child = (struct mux_child *)(mux + 1);
+	mux->chan = (struct iio_chan_spec *)(mux->child + children);
+
+	platform_set_drvdata(pdev, indio_dev);
+
+	mux->parent = parent;
+	mux->cached_state = -1;
+
+	indio_dev->name = dev_name(dev);
+	indio_dev->dev.parent = dev;
+	indio_dev->info = &mux_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = mux->chan;
+	indio_dev->num_channels = children;
+	if (sizeof_ext_info) {
+		mux->ext_info = devm_kmemdup(dev,
+					     parent->channel->ext_info,
+					     sizeof_ext_info, GFP_KERNEL);
+		if (!mux->ext_info)
+			return -ENOMEM;
+
+		for (i = 0; mux->ext_info[i].name; ++i) {
+			if (parent->channel->ext_info[i].read)
+				mux->ext_info[i].read = mux_read_ext_info;
+			if (parent->channel->ext_info[i].write)
+				mux->ext_info[i].write = mux_write_ext_info;
+			mux->ext_info[i].private = i;
+		}
+	}
+
+	mux->control = devm_mux_control_get(dev, NULL);
+	if (IS_ERR(mux->control)) {
+		if (PTR_ERR(mux->control) != -EPROBE_DEFER)
+			dev_err(dev, "failed to get control-mux\n");
+		return PTR_ERR(mux->control);
+	}
+
+	i = 0;
+	of_property_for_each_string_index(np, "channels", prop, label, state) {
+		if (!*label)
+			continue;
+
+		ret = mux_configure_channel(dev, mux, state, label, i++);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = devm_iio_device_register(dev, indio_dev);
+	if (ret) {
+		dev_err(dev, "failed to register iio device\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id mux_match[] = {
+	{ .compatible = "iio-mux" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mux_match);
+
+static struct platform_driver mux_driver = {
+	.probe = mux_probe,
+	.driver = {
+		.name = "iio-mux",
+		.of_match_table = mux_match,
+	},
+};
+module_platform_driver(mux_driver);
+
+MODULE_DESCRIPTION("IIO multiplexer driver");
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
+MODULE_LICENSE("GPL v2");
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 6/9] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
  2016-11-30  8:16 ` Peter Rosin
@ 2016-11-30  8:17   ` Peter Rosin
  -1 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../devicetree/bindings/i2c/i2c-mux-simple.txt     | 81 ++++++++++++++++++++++
 1 file changed, 81 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-simple.txt

diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-simple.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-simple.txt
new file mode 100644
index 000000000000..d32ebc9c5639
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-mux-simple.txt
@@ -0,0 +1,81 @@
+Simple I2C Bus Mux
+
+This binding describes an I2C bus multiplexer that uses a mux controller
+from the mux subsystem to route the I2C signals.
+
+                                  .-----.  .-----.
+                                  | dev |  | dev |
+    .------------.                '-----'  '-----'
+    | SoC        |                   |        |
+    |            |          .--------+--------'
+    |   .------. |  .------+    child bus A, on MUX value set to 0
+    |   | I2C  |-|--| Mux  |
+    |   '------' |  '--+---+    child bus B, on MUX value set to 1
+    |   .------. |     |    '----------+--------+--------.
+    |   | MUX- | |     |               |        |        |
+    |   | Ctrl |-|-----+            .-----.  .-----.  .-----.
+    |   '------' |                  | dev |  | dev |  | dev |
+    '------------'                  '-----'  '-----'  '-----'
+
+Required properties:
+- compatible: i2c-mux-simple,mux-locked or i2c-mux-simple,parent-locked
+- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
+  port is connected to.
+- mux-controls: The phandle of the mux controller to use for operating the
+  mux.
+* Standard I2C mux properties. See i2c-mux.txt in this directory.
+* I2C child bus nodes. See i2c-mux.txt in this directory. The sub-bus number
+  is also the mux-controller state described in ../misc/mux-controller.txt
+
+For each i2c child node, an I2C child bus will be created. They will
+be numbered based on their order in the device tree.
+
+Whenever an access is made to a device on a child bus, the value set
+in the relevant node's reg property will be set as the state in the
+mux controller.
+
+Example:
+	mux: mux-controller {
+		compatible = "mux-gpio";
+		#mux-control-cells = <0>;
+
+		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
+			    <&pioA 1 GPIO_ACTIVE_HIGH>;
+	};
+
+	i2c-mux {
+		compatible = "i2c-mux-simple,mux-locked";
+		i2c-parent = <&i2c1>;
+
+		mux-controls = <&mux>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c@1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ssd1307: oled@3c {
+				compatible = "solomon,ssd1307fb-i2c";
+				reg = <0x3c>;
+				pwms = <&pwm 4 3000>;
+				reset-gpios = <&gpio2 7 1>;
+				reset-active-low;
+			};
+		};
+
+		i2c@3 {
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pca9555: pca9555@20 {
+				compatible = "nxp,pca9555";
+				gpio-controller;
+				#gpio-cells = <2>;
+				reg = <0x20>;
+			};
+		};
+	};
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 6/9] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
@ 2016-11-30  8:17   ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../devicetree/bindings/i2c/i2c-mux-simple.txt     | 81 ++++++++++++++++++++++
 1 file changed, 81 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-simple.txt

diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-simple.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-simple.txt
new file mode 100644
index 000000000000..d32ebc9c5639
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-mux-simple.txt
@@ -0,0 +1,81 @@
+Simple I2C Bus Mux
+
+This binding describes an I2C bus multiplexer that uses a mux controller
+from the mux subsystem to route the I2C signals.
+
+                                  .-----.  .-----.
+                                  | dev |  | dev |
+    .------------.                '-----'  '-----'
+    | SoC        |                   |        |
+    |            |          .--------+--------'
+    |   .------. |  .------+    child bus A, on MUX value set to 0
+    |   | I2C  |-|--| Mux  |
+    |   '------' |  '--+---+    child bus B, on MUX value set to 1
+    |   .------. |     |    '----------+--------+--------.
+    |   | MUX- | |     |               |        |        |
+    |   | Ctrl |-|-----+            .-----.  .-----.  .-----.
+    |   '------' |                  | dev |  | dev |  | dev |
+    '------------'                  '-----'  '-----'  '-----'
+
+Required properties:
+- compatible: i2c-mux-simple,mux-locked or i2c-mux-simple,parent-locked
+- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
+  port is connected to.
+- mux-controls: The phandle of the mux controller to use for operating the
+  mux.
+* Standard I2C mux properties. See i2c-mux.txt in this directory.
+* I2C child bus nodes. See i2c-mux.txt in this directory. The sub-bus number
+  is also the mux-controller state described in ../misc/mux-controller.txt
+
+For each i2c child node, an I2C child bus will be created. They will
+be numbered based on their order in the device tree.
+
+Whenever an access is made to a device on a child bus, the value set
+in the relevant node's reg property will be set as the state in the
+mux controller.
+
+Example:
+	mux: mux-controller {
+		compatible = "mux-gpio";
+		#mux-control-cells = <0>;
+
+		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
+			    <&pioA 1 GPIO_ACTIVE_HIGH>;
+	};
+
+	i2c-mux {
+		compatible = "i2c-mux-simple,mux-locked";
+		i2c-parent = <&i2c1>;
+
+		mux-controls = <&mux>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		i2c@1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ssd1307: oled@3c {
+				compatible = "solomon,ssd1307fb-i2c";
+				reg = <0x3c>;
+				pwms = <&pwm 4 3000>;
+				reset-gpios = <&gpio2 7 1>;
+				reset-active-low;
+			};
+		};
+
+		i2c@3 {
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pca9555: pca9555@20 {
+				compatible = "nxp,pca9555";
+				gpio-controller;
+				#gpio-cells = <2>;
+				reg = <0x20>;
+			};
+		};
+	};
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 7/9] i2c: i2c-mux-simple: new driver
@ 2016-11-30  8:17   ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc

This is a generic simple i2c mux that uses the generic multiplexer
subsystem to do the muxing.

The user can select if the mux is to be mux-locked and parent-locked
as described in Documentation/i2c/i2c-topology.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/i2c/muxes/Kconfig          |  13 +++
 drivers/i2c/muxes/Makefile         |   1 +
 drivers/i2c/muxes/i2c-mux-simple.c | 179 +++++++++++++++++++++++++++++++++++++
 3 files changed, 193 insertions(+)
 create mode 100644 drivers/i2c/muxes/i2c-mux-simple.c

diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
index 10b3d17ae3ea..565921e09a96 100644
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -73,6 +73,19 @@ config I2C_MUX_REG
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-mux-reg.
 
+config I2C_MUX_SIMPLE
+	tristate "Simple I2C multiplexer"
+	select MULTIPLEXER
+	depends on OF
+	help
+	  If you say yes to this option, support will be included for a
+	  simple generic I2C multiplexer. This driver provides access to
+	  I2C busses connected through a MUX, which is controlled
+	  by a generic MUX controller.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-mux-simple.
+
 config I2C_DEMUX_PINCTRL
 	tristate "pinctrl-based I2C demultiplexer"
 	depends on PINCTRL && OF
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
index 9948fa45037f..6821d95c92a3 100644
--- a/drivers/i2c/muxes/Makefile
+++ b/drivers/i2c/muxes/Makefile
@@ -11,5 +11,6 @@ obj-$(CONFIG_I2C_MUX_PCA9541)	+= i2c-mux-pca9541.o
 obj-$(CONFIG_I2C_MUX_PCA954x)	+= i2c-mux-pca954x.o
 obj-$(CONFIG_I2C_MUX_PINCTRL)	+= i2c-mux-pinctrl.o
 obj-$(CONFIG_I2C_MUX_REG)	+= i2c-mux-reg.o
+obj-$(CONFIG_I2C_MUX_SIMPLE)	+= i2c-mux-simple.o
 
 ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/muxes/i2c-mux-simple.c b/drivers/i2c/muxes/i2c-mux-simple.c
new file mode 100644
index 000000000000..4a03493e1ad7
--- /dev/null
+++ b/drivers/i2c/muxes/i2c-mux-simple.c
@@ -0,0 +1,179 @@
+/*
+ * Generic simple I2C multiplexer
+ *
+ * Copyright (C) 2016 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+#include <linux/module.h>
+#include <linux/mux.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+struct mux {
+	struct mux_control *control;
+
+	bool do_not_deselect;
+};
+
+static int i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
+{
+	struct mux *mux = i2c_mux_priv(muxc);
+	int ret;
+
+	ret = mux_control_select(mux->control, chan);
+	mux->do_not_deselect = ret < 0;
+
+	return ret;
+}
+
+static int i2c_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
+{
+	struct mux *mux = i2c_mux_priv(muxc);
+
+	if (mux->do_not_deselect)
+		return 0;
+
+	return mux_control_deselect(mux->control);
+}
+
+static struct i2c_adapter *mux_parent_adapter(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct device_node *parent_np;
+	struct i2c_adapter *parent;
+
+	parent_np = of_parse_phandle(np, "i2c-parent", 0);
+	if (!parent_np) {
+		dev_err(dev, "Cannot parse i2c-parent\n");
+		return ERR_PTR(-ENODEV);
+	}
+	parent = of_find_i2c_adapter_by_node(parent_np);
+	of_node_put(parent_np);
+	if (!parent)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	return parent;
+}
+
+static const struct of_device_id i2c_mux_of_match[] = {
+	{ .compatible = "i2c-mux-simple,parent-locked",
+	  .data = (void *)0, },
+	{ .compatible = "i2c-mux-simple,mux-locked",
+	  .data = (void *)1, },
+	{},
+};
+MODULE_DEVICE_TABLE(of, i2c_mux_of_match);
+
+static int i2c_mux_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *child;
+	const struct of_device_id *match;
+	struct i2c_mux_core *muxc;
+	struct mux *mux;
+	struct i2c_adapter *parent;
+	int children;
+	int ret;
+
+	if (!np)
+		return -ENODEV;
+
+	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return -ENOMEM;
+
+	mux->control = devm_mux_control_get(dev, NULL);
+	if (IS_ERR(mux->control)) {
+		if (PTR_ERR(mux->control) != -EPROBE_DEFER)
+			dev_err(dev, "failed to get control-mux\n");
+		return PTR_ERR(mux->control);
+	}
+
+	parent = mux_parent_adapter(dev);
+	if (IS_ERR(parent)) {
+		if (PTR_ERR(parent) != -EPROBE_DEFER)
+			dev_err(dev, "failed to get i2c-parent adapter\n");
+		return PTR_ERR(parent);
+	}
+
+	children = of_get_child_count(np);
+
+	muxc = i2c_mux_alloc(parent, dev, children, 0, 0,
+			     i2c_mux_select, i2c_mux_deselect);
+	if (!muxc) {
+		ret = -ENOMEM;
+		goto err_parent;
+	}
+	muxc->priv = mux;
+
+	platform_set_drvdata(pdev, muxc);
+
+	match = of_match_device(of_match_ptr(i2c_mux_of_match), dev);
+	if (match)
+		muxc->mux_locked = !!of_device_get_match_data(dev);
+
+	for_each_child_of_node(np, child) {
+		u32 chan;
+
+		ret = of_property_read_u32(child, "reg", &chan);
+		if (ret < 0) {
+			dev_err(dev, "no reg property for node '%s'\n",
+				child->name);
+			goto err_children;
+		}
+
+		if (chan >= mux->control->states) {
+			dev_err(dev, "invalid reg %u\n", chan);
+			ret = -EINVAL;
+			goto err_children;
+		}
+
+		ret = i2c_mux_add_adapter(muxc, 0, chan, 0);
+		if (ret)
+			goto err_children;
+	}
+
+	dev_info(dev, "%d-port mux on %s adapter\n", children, parent->name);
+
+	return 0;
+
+err_children:
+	i2c_mux_del_adapters(muxc);
+err_parent:
+	i2c_put_adapter(parent);
+
+	return ret;
+}
+
+static int i2c_mux_remove(struct platform_device *pdev)
+{
+	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
+
+	i2c_mux_del_adapters(muxc);
+	i2c_put_adapter(muxc->parent);
+
+	return 0;
+}
+
+static struct platform_driver i2c_mux_driver = {
+	.probe	= i2c_mux_probe,
+	.remove	= i2c_mux_remove,
+	.driver	= {
+		.name	= "i2c-mux-simple",
+		.of_match_table = i2c_mux_of_match,
+	},
+};
+module_platform_driver(i2c_mux_driver);
+
+MODULE_DESCRIPTION("Simple I2C multiplexer driver");
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
+MODULE_LICENSE("GPL v2");
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 7/9] i2c: i2c-mux-simple: new driver
@ 2016-11-30  8:17   ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:17 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

This is a generic simple i2c mux that uses the generic multiplexer
subsystem to do the muxing.

The user can select if the mux is to be mux-locked and parent-locked
as described in Documentation/i2c/i2c-topology.

Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
---
 drivers/i2c/muxes/Kconfig          |  13 +++
 drivers/i2c/muxes/Makefile         |   1 +
 drivers/i2c/muxes/i2c-mux-simple.c | 179 +++++++++++++++++++++++++++++++++++++
 3 files changed, 193 insertions(+)
 create mode 100644 drivers/i2c/muxes/i2c-mux-simple.c

diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
index 10b3d17ae3ea..565921e09a96 100644
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -73,6 +73,19 @@ config I2C_MUX_REG
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-mux-reg.
 
+config I2C_MUX_SIMPLE
+	tristate "Simple I2C multiplexer"
+	select MULTIPLEXER
+	depends on OF
+	help
+	  If you say yes to this option, support will be included for a
+	  simple generic I2C multiplexer. This driver provides access to
+	  I2C busses connected through a MUX, which is controlled
+	  by a generic MUX controller.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-mux-simple.
+
 config I2C_DEMUX_PINCTRL
 	tristate "pinctrl-based I2C demultiplexer"
 	depends on PINCTRL && OF
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
index 9948fa45037f..6821d95c92a3 100644
--- a/drivers/i2c/muxes/Makefile
+++ b/drivers/i2c/muxes/Makefile
@@ -11,5 +11,6 @@ obj-$(CONFIG_I2C_MUX_PCA9541)	+= i2c-mux-pca9541.o
 obj-$(CONFIG_I2C_MUX_PCA954x)	+= i2c-mux-pca954x.o
 obj-$(CONFIG_I2C_MUX_PINCTRL)	+= i2c-mux-pinctrl.o
 obj-$(CONFIG_I2C_MUX_REG)	+= i2c-mux-reg.o
+obj-$(CONFIG_I2C_MUX_SIMPLE)	+= i2c-mux-simple.o
 
 ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/muxes/i2c-mux-simple.c b/drivers/i2c/muxes/i2c-mux-simple.c
new file mode 100644
index 000000000000..4a03493e1ad7
--- /dev/null
+++ b/drivers/i2c/muxes/i2c-mux-simple.c
@@ -0,0 +1,179 @@
+/*
+ * Generic simple I2C multiplexer
+ *
+ * Copyright (C) 2016 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+#include <linux/module.h>
+#include <linux/mux.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+struct mux {
+	struct mux_control *control;
+
+	bool do_not_deselect;
+};
+
+static int i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
+{
+	struct mux *mux = i2c_mux_priv(muxc);
+	int ret;
+
+	ret = mux_control_select(mux->control, chan);
+	mux->do_not_deselect = ret < 0;
+
+	return ret;
+}
+
+static int i2c_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
+{
+	struct mux *mux = i2c_mux_priv(muxc);
+
+	if (mux->do_not_deselect)
+		return 0;
+
+	return mux_control_deselect(mux->control);
+}
+
+static struct i2c_adapter *mux_parent_adapter(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct device_node *parent_np;
+	struct i2c_adapter *parent;
+
+	parent_np = of_parse_phandle(np, "i2c-parent", 0);
+	if (!parent_np) {
+		dev_err(dev, "Cannot parse i2c-parent\n");
+		return ERR_PTR(-ENODEV);
+	}
+	parent = of_find_i2c_adapter_by_node(parent_np);
+	of_node_put(parent_np);
+	if (!parent)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	return parent;
+}
+
+static const struct of_device_id i2c_mux_of_match[] = {
+	{ .compatible = "i2c-mux-simple,parent-locked",
+	  .data = (void *)0, },
+	{ .compatible = "i2c-mux-simple,mux-locked",
+	  .data = (void *)1, },
+	{},
+};
+MODULE_DEVICE_TABLE(of, i2c_mux_of_match);
+
+static int i2c_mux_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *child;
+	const struct of_device_id *match;
+	struct i2c_mux_core *muxc;
+	struct mux *mux;
+	struct i2c_adapter *parent;
+	int children;
+	int ret;
+
+	if (!np)
+		return -ENODEV;
+
+	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return -ENOMEM;
+
+	mux->control = devm_mux_control_get(dev, NULL);
+	if (IS_ERR(mux->control)) {
+		if (PTR_ERR(mux->control) != -EPROBE_DEFER)
+			dev_err(dev, "failed to get control-mux\n");
+		return PTR_ERR(mux->control);
+	}
+
+	parent = mux_parent_adapter(dev);
+	if (IS_ERR(parent)) {
+		if (PTR_ERR(parent) != -EPROBE_DEFER)
+			dev_err(dev, "failed to get i2c-parent adapter\n");
+		return PTR_ERR(parent);
+	}
+
+	children = of_get_child_count(np);
+
+	muxc = i2c_mux_alloc(parent, dev, children, 0, 0,
+			     i2c_mux_select, i2c_mux_deselect);
+	if (!muxc) {
+		ret = -ENOMEM;
+		goto err_parent;
+	}
+	muxc->priv = mux;
+
+	platform_set_drvdata(pdev, muxc);
+
+	match = of_match_device(of_match_ptr(i2c_mux_of_match), dev);
+	if (match)
+		muxc->mux_locked = !!of_device_get_match_data(dev);
+
+	for_each_child_of_node(np, child) {
+		u32 chan;
+
+		ret = of_property_read_u32(child, "reg", &chan);
+		if (ret < 0) {
+			dev_err(dev, "no reg property for node '%s'\n",
+				child->name);
+			goto err_children;
+		}
+
+		if (chan >= mux->control->states) {
+			dev_err(dev, "invalid reg %u\n", chan);
+			ret = -EINVAL;
+			goto err_children;
+		}
+
+		ret = i2c_mux_add_adapter(muxc, 0, chan, 0);
+		if (ret)
+			goto err_children;
+	}
+
+	dev_info(dev, "%d-port mux on %s adapter\n", children, parent->name);
+
+	return 0;
+
+err_children:
+	i2c_mux_del_adapters(muxc);
+err_parent:
+	i2c_put_adapter(parent);
+
+	return ret;
+}
+
+static int i2c_mux_remove(struct platform_device *pdev)
+{
+	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
+
+	i2c_mux_del_adapters(muxc);
+	i2c_put_adapter(muxc->parent);
+
+	return 0;
+}
+
+static struct platform_driver i2c_mux_driver = {
+	.probe	= i2c_mux_probe,
+	.remove	= i2c_mux_remove,
+	.driver	= {
+		.name	= "i2c-mux-simple",
+		.of_match_table = i2c_mux_of_match,
+	},
+};
+module_platform_driver(i2c_mux_driver);
+
+MODULE_DESCRIPTION("Simple I2C multiplexer driver");
+MODULE_AUTHOR("Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>");
+MODULE_LICENSE("GPL v2");
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 8/9] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
@ 2016-11-30  8:17   ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc

Analog Devices ADG792A/G is a triple 4:1 mux.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../devicetree/bindings/misc/mux-adg792a.txt       | 64 ++++++++++++++++++++++
 1 file changed, 64 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/misc/mux-adg792a.txt

diff --git a/Documentation/devicetree/bindings/misc/mux-adg792a.txt b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
new file mode 100644
index 000000000000..4677f9ab1c55
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
@@ -0,0 +1,64 @@
+Bindings for Analog Devices ADG792A/G Triple 4:1 Multiplexers
+
+Required properties:
+- compatible : "adi,adg792a" or "adi,adg792g"
+- #mux-control-cells : <0> if parallel, or <1> if not.
+* Standard mux-controller bindings as decribed in mux-controller.txt
+
+Optional properties:
+- adi,parallel : if present, the three muxes are bound together with a single
+  mux controller, controlling all three muxes in parallel.
+- adi,idle-state : if present, array of states the three mux controllers will
+  have when idle (or, if parallel, a single idle-state).
+
+Mux controller states 0 through 3 correspond to signals A through D in the
+datasheet. Mux controller states 4 and 5 are only available as possible idle
+states. State 4 represents that nothing is connected, and state 5 represents
+that the mux controller keeps the mux in its previously selected state during
+the idle period. State 5 is the default idle state.
+
+Example:
+
+	/* three independent mux controllers (of which one is used) */
+	&i2c0 {
+		mux: adg792a@50 {
+			compatible = "adi,adg792a";
+			reg = <0x50>;
+			#mux-control-cells = <1>;
+		};
+	};
+
+	adc-mux {
+		compatible = "iio-mux";
+		io-channels = <&adc 0>;
+		io-channel-names = "parent";
+
+		mux-controls = <&mux 1>;
+
+		channels = "sync-1", "", "out";
+	};
+
+
+	/*
+	 * Three parallel muxes with one mux controller, useful e.g. if
+	 * the adc is differential, thus needing two signals to be muxed
+	 * simultaneously for correct operation.
+	 */
+	&i2c0 {
+		pmux: adg792a@50 {
+			compatible = "adi,adg792a";
+			reg = <0x50>;
+			#mux-control-cells = <0>;
+			adi,parallel;
+		};
+	};
+
+	diff-adc-mux {
+		compatible = "iio-mux";
+		io-channels = <&adc 0>;
+		io-channel-names = "parent";
+
+		mux-controls = <&pmux>;
+
+		channels = "sync-1", "", "out";
+	};
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 8/9] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
@ 2016-11-30  8:17   ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:17 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

Analog Devices ADG792A/G is a triple 4:1 mux.

Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
---
 .../devicetree/bindings/misc/mux-adg792a.txt       | 64 ++++++++++++++++++++++
 1 file changed, 64 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/misc/mux-adg792a.txt

diff --git a/Documentation/devicetree/bindings/misc/mux-adg792a.txt b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
new file mode 100644
index 000000000000..4677f9ab1c55
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
@@ -0,0 +1,64 @@
+Bindings for Analog Devices ADG792A/G Triple 4:1 Multiplexers
+
+Required properties:
+- compatible : "adi,adg792a" or "adi,adg792g"
+- #mux-control-cells : <0> if parallel, or <1> if not.
+* Standard mux-controller bindings as decribed in mux-controller.txt
+
+Optional properties:
+- adi,parallel : if present, the three muxes are bound together with a single
+  mux controller, controlling all three muxes in parallel.
+- adi,idle-state : if present, array of states the three mux controllers will
+  have when idle (or, if parallel, a single idle-state).
+
+Mux controller states 0 through 3 correspond to signals A through D in the
+datasheet. Mux controller states 4 and 5 are only available as possible idle
+states. State 4 represents that nothing is connected, and state 5 represents
+that the mux controller keeps the mux in its previously selected state during
+the idle period. State 5 is the default idle state.
+
+Example:
+
+	/* three independent mux controllers (of which one is used) */
+	&i2c0 {
+		mux: adg792a@50 {
+			compatible = "adi,adg792a";
+			reg = <0x50>;
+			#mux-control-cells = <1>;
+		};
+	};
+
+	adc-mux {
+		compatible = "iio-mux";
+		io-channels = <&adc 0>;
+		io-channel-names = "parent";
+
+		mux-controls = <&mux 1>;
+
+		channels = "sync-1", "", "out";
+	};
+
+
+	/*
+	 * Three parallel muxes with one mux controller, useful e.g. if
+	 * the adc is differential, thus needing two signals to be muxed
+	 * simultaneously for correct operation.
+	 */
+	&i2c0 {
+		pmux: adg792a@50 {
+			compatible = "adi,adg792a";
+			reg = <0x50>;
+			#mux-control-cells = <0>;
+			adi,parallel;
+		};
+	};
+
+	diff-adc-mux {
+		compatible = "iio-mux";
+		io-channels = <&adc 0>;
+		io-channel-names = "parent";
+
+		mux-controls = <&pmux>;
+
+		channels = "sync-1", "", "out";
+	};
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 9/9] misc: mux-adg792a: add mux controller driver for ADG792A/G
@ 2016-11-30  8:17   ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio, linux-doc

Analog Devices ADG792A/G is a triple 4:1 mux.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/misc/Kconfig       |  12 ++++
 drivers/misc/Makefile      |   1 +
 drivers/misc/mux-adg792a.c | 154 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 167 insertions(+)
 create mode 100644 drivers/misc/mux-adg792a.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 2ce675e410c5..45567a444bbf 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -780,6 +780,18 @@ menuconfig MULTIPLEXER
 
 if MULTIPLEXER
 
+config MUX_ADG792A
+	tristate "Analog Devices ADG792A/ADG792G Multiplexers"
+	depends on I2C
+	help
+	  ADG792A and ADG792G Wide Bandwidth Triple 4:1 Multiplexers
+
+	  The driver supports both operating the three multiplexers in
+	  parellel and operating them independently.
+
+	  To compile the driver as a module, choose M here: the module will
+	  be called mux-adg792a.
+
 config MUX_GPIO
 	tristate "GPIO-controlled Multiplexer"
 	depends on OF && GPIOLIB
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 0befa2bba762..10ab8d34c9e5 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
 obj-$(CONFIG_CXL_BASE)		+= cxl/
 obj-$(CONFIG_PANEL)             += panel.o
 obj-$(CONFIG_MULTIPLEXER)      	+= mux-core.o
+obj-$(CONFIG_MUX_ADG792A)	+= mux-adg792a.o
 obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
 
 lkdtm-$(CONFIG_LKDTM)		+= lkdtm_core.o
diff --git a/drivers/misc/mux-adg792a.c b/drivers/misc/mux-adg792a.c
new file mode 100644
index 000000000000..7d309a78af65
--- /dev/null
+++ b/drivers/misc/mux-adg792a.c
@@ -0,0 +1,154 @@
+/*
+ * Multiplexer driver for Analog Devices ADG792A/G Triple 4:1 mux
+ *
+ * Copyright (C) 2016 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mux.h>
+
+#define ADG792A_LDSW		BIT(0)
+#define ADG792A_RESET		BIT(1)
+#define ADG792A_DISABLE(mux)	(0x50 | (mux))
+#define ADG792A_DISABLE_ALL	(0x5f)
+#define ADG792A_MUX(mux, state)	(0xc0 | (((mux) + 1) << 2) | (state))
+#define ADG792A_MUX_ALL(state)	(0xc0 | (state))
+
+#define ADG792A_DISABLE_STATE	(4)
+#define ADG792A_KEEP_STATE	(5)
+
+static int adg792a_set(struct mux_control *mux, int state)
+{
+	struct i2c_client *i2c = to_i2c_client(mux->chip->dev.parent);
+	u8 cmd;
+
+	if (mux->chip->controllers == 1) {
+		/* parallel mux controller operation */
+		if (state == ADG792A_DISABLE_STATE)
+			cmd = ADG792A_DISABLE_ALL;
+		else
+			cmd = ADG792A_MUX_ALL(state);
+	} else {
+		unsigned int controller = mux_control_get_index(mux);
+
+		if (state == ADG792A_DISABLE_STATE)
+			cmd = ADG792A_DISABLE(controller);
+		else
+			cmd = ADG792A_MUX(controller, state);
+	}
+
+	return i2c_smbus_write_byte_data(i2c, cmd, ADG792A_LDSW);
+}
+
+static const struct mux_control_ops adg792a_ops = {
+	.set = adg792a_set,
+};
+
+static int adg792a_probe(struct i2c_client *i2c,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &i2c->dev;
+	struct mux_chip *mux_chip;
+	bool parallel;
+	int ret;
+	int i;
+
+	parallel = of_property_read_bool(i2c->dev.of_node, "adi,parallel");
+
+	mux_chip = mux_chip_alloc(dev, parallel ? 1 : 3, 0);
+	if (!mux_chip)
+		return -ENOMEM;
+
+	mux_chip->ops = &adg792a_ops;
+	dev_set_drvdata(dev, mux_chip);
+
+	ret = i2c_smbus_write_byte_data(i2c, ADG792A_DISABLE_ALL,
+					ADG792A_RESET | ADG792A_LDSW);
+	if (ret < 0)
+		goto free_mux_chip;
+
+	for (i = 0; i < mux_chip->controllers; ++i) {
+		struct mux_control *mux = &mux_chip->mux[i];
+		u32 idle_state;
+
+		mux->states = 4;
+
+		ret = of_property_read_u32_index(i2c->dev.of_node,
+						 "adi,idle-state", i,
+						 &idle_state);
+		if (ret >= 0) {
+			if (idle_state > ADG792A_KEEP_STATE) {
+				dev_err(dev, "invalid idle-state %u\n",
+					idle_state);
+				ret = -EINVAL;
+				goto free_mux_chip;
+			}
+			if (idle_state != ADG792A_KEEP_STATE)
+				mux->idle_state = idle_state;
+		}
+	}
+
+	ret = mux_chip_register(mux_chip);
+	if (ret < 0) {
+		dev_err(dev, "failed to register mux-chip\n");
+		goto free_mux_chip;
+	}
+
+	if (parallel)
+		dev_info(dev, "1 triple 4-way mux-controller registered\n");
+	else
+		dev_info(dev, "3 4-way mux-controllers registered\n");
+
+	return 0;
+
+free_mux_chip:
+	mux_chip_free(mux_chip);
+	return ret;
+}
+
+static int adg792a_remove(struct i2c_client *i2c)
+{
+	struct mux_chip *mux_chip = dev_get_drvdata(&i2c->dev);
+
+	mux_chip_unregister(mux_chip);
+	mux_chip_free(mux_chip);
+
+	return 0;
+}
+
+static const struct i2c_device_id adg792a_id[] = {
+	{ .name = "adg792a", },
+	{ .name = "adg792g", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adg792a_id);
+
+static const struct of_device_id adg792a_of_match[] = {
+	{ .compatible = "adi,adg792a", },
+	{ .compatible = "adi,adg792g", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adg792a_of_match);
+
+static struct i2c_driver adg792a_driver = {
+	.driver		= {
+		.name		= "adg792a",
+		.of_match_table = of_match_ptr(adg792a_of_match),
+	},
+	.probe		= adg792a_probe,
+	.remove		= adg792a_remove,
+	.id_table	= adg792a_id,
+};
+module_i2c_driver(adg792a_driver);
+
+MODULE_DESCRIPTION("Analog Devices ADG792A/G Triple 4:1 mux driver");
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se");
+MODULE_LICENSE("GPL v2");
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v6 9/9] misc: mux-adg792a: add mux controller driver for ADG792A/G
@ 2016-11-30  8:17   ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:17 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Peter Rosin, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

Analog Devices ADG792A/G is a triple 4:1 mux.

Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
---
 drivers/misc/Kconfig       |  12 ++++
 drivers/misc/Makefile      |   1 +
 drivers/misc/mux-adg792a.c | 154 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 167 insertions(+)
 create mode 100644 drivers/misc/mux-adg792a.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 2ce675e410c5..45567a444bbf 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -780,6 +780,18 @@ menuconfig MULTIPLEXER
 
 if MULTIPLEXER
 
+config MUX_ADG792A
+	tristate "Analog Devices ADG792A/ADG792G Multiplexers"
+	depends on I2C
+	help
+	  ADG792A and ADG792G Wide Bandwidth Triple 4:1 Multiplexers
+
+	  The driver supports both operating the three multiplexers in
+	  parellel and operating them independently.
+
+	  To compile the driver as a module, choose M here: the module will
+	  be called mux-adg792a.
+
 config MUX_GPIO
 	tristate "GPIO-controlled Multiplexer"
 	depends on OF && GPIOLIB
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 0befa2bba762..10ab8d34c9e5 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
 obj-$(CONFIG_CXL_BASE)		+= cxl/
 obj-$(CONFIG_PANEL)             += panel.o
 obj-$(CONFIG_MULTIPLEXER)      	+= mux-core.o
+obj-$(CONFIG_MUX_ADG792A)	+= mux-adg792a.o
 obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
 
 lkdtm-$(CONFIG_LKDTM)		+= lkdtm_core.o
diff --git a/drivers/misc/mux-adg792a.c b/drivers/misc/mux-adg792a.c
new file mode 100644
index 000000000000..7d309a78af65
--- /dev/null
+++ b/drivers/misc/mux-adg792a.c
@@ -0,0 +1,154 @@
+/*
+ * Multiplexer driver for Analog Devices ADG792A/G Triple 4:1 mux
+ *
+ * Copyright (C) 2016 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mux.h>
+
+#define ADG792A_LDSW		BIT(0)
+#define ADG792A_RESET		BIT(1)
+#define ADG792A_DISABLE(mux)	(0x50 | (mux))
+#define ADG792A_DISABLE_ALL	(0x5f)
+#define ADG792A_MUX(mux, state)	(0xc0 | (((mux) + 1) << 2) | (state))
+#define ADG792A_MUX_ALL(state)	(0xc0 | (state))
+
+#define ADG792A_DISABLE_STATE	(4)
+#define ADG792A_KEEP_STATE	(5)
+
+static int adg792a_set(struct mux_control *mux, int state)
+{
+	struct i2c_client *i2c = to_i2c_client(mux->chip->dev.parent);
+	u8 cmd;
+
+	if (mux->chip->controllers == 1) {
+		/* parallel mux controller operation */
+		if (state == ADG792A_DISABLE_STATE)
+			cmd = ADG792A_DISABLE_ALL;
+		else
+			cmd = ADG792A_MUX_ALL(state);
+	} else {
+		unsigned int controller = mux_control_get_index(mux);
+
+		if (state == ADG792A_DISABLE_STATE)
+			cmd = ADG792A_DISABLE(controller);
+		else
+			cmd = ADG792A_MUX(controller, state);
+	}
+
+	return i2c_smbus_write_byte_data(i2c, cmd, ADG792A_LDSW);
+}
+
+static const struct mux_control_ops adg792a_ops = {
+	.set = adg792a_set,
+};
+
+static int adg792a_probe(struct i2c_client *i2c,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &i2c->dev;
+	struct mux_chip *mux_chip;
+	bool parallel;
+	int ret;
+	int i;
+
+	parallel = of_property_read_bool(i2c->dev.of_node, "adi,parallel");
+
+	mux_chip = mux_chip_alloc(dev, parallel ? 1 : 3, 0);
+	if (!mux_chip)
+		return -ENOMEM;
+
+	mux_chip->ops = &adg792a_ops;
+	dev_set_drvdata(dev, mux_chip);
+
+	ret = i2c_smbus_write_byte_data(i2c, ADG792A_DISABLE_ALL,
+					ADG792A_RESET | ADG792A_LDSW);
+	if (ret < 0)
+		goto free_mux_chip;
+
+	for (i = 0; i < mux_chip->controllers; ++i) {
+		struct mux_control *mux = &mux_chip->mux[i];
+		u32 idle_state;
+
+		mux->states = 4;
+
+		ret = of_property_read_u32_index(i2c->dev.of_node,
+						 "adi,idle-state", i,
+						 &idle_state);
+		if (ret >= 0) {
+			if (idle_state > ADG792A_KEEP_STATE) {
+				dev_err(dev, "invalid idle-state %u\n",
+					idle_state);
+				ret = -EINVAL;
+				goto free_mux_chip;
+			}
+			if (idle_state != ADG792A_KEEP_STATE)
+				mux->idle_state = idle_state;
+		}
+	}
+
+	ret = mux_chip_register(mux_chip);
+	if (ret < 0) {
+		dev_err(dev, "failed to register mux-chip\n");
+		goto free_mux_chip;
+	}
+
+	if (parallel)
+		dev_info(dev, "1 triple 4-way mux-controller registered\n");
+	else
+		dev_info(dev, "3 4-way mux-controllers registered\n");
+
+	return 0;
+
+free_mux_chip:
+	mux_chip_free(mux_chip);
+	return ret;
+}
+
+static int adg792a_remove(struct i2c_client *i2c)
+{
+	struct mux_chip *mux_chip = dev_get_drvdata(&i2c->dev);
+
+	mux_chip_unregister(mux_chip);
+	mux_chip_free(mux_chip);
+
+	return 0;
+}
+
+static const struct i2c_device_id adg792a_id[] = {
+	{ .name = "adg792a", },
+	{ .name = "adg792g", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adg792a_id);
+
+static const struct of_device_id adg792a_of_match[] = {
+	{ .compatible = "adi,adg792a", },
+	{ .compatible = "adi,adg792g", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adg792a_of_match);
+
+static struct i2c_driver adg792a_driver = {
+	.driver		= {
+		.name		= "adg792a",
+		.of_match_table = of_match_ptr(adg792a_of_match),
+	},
+	.probe		= adg792a_probe,
+	.remove		= adg792a_remove,
+	.id_table	= adg792a_id,
+};
+module_i2c_driver(adg792a_driver);
+
+MODULE_DESCRIPTION("Analog Devices ADG792A/G Triple 4:1 mux driver");
+MODULE_AUTHOR("Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org");
+MODULE_LICENSE("GPL v2");
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 4/9] dt-bindings: iio: iio-mux: document iio-mux bindings
  2016-11-30  8:16   ` Peter Rosin
@ 2016-11-30  8:52     ` Peter Rosin
  -1 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Jonathan Corbet, Arnd Bergmann, Greg Kroah-Hartman, linux-i2c,
	devicetree, linux-iio, linux-doc

Hi,

v6 was apparently rushed a little bit too much, but I really wanted to
supersede the stupidity I found elsewhere in v5. Perhaps I shouldn't
have bolted on the changes for the iio-mux bindings, but so I did...

On 2016-11-30 09:16, Peter Rosin wrote:
> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>  .../bindings/iio/multiplexer/iio-mux.txt           | 40 ++++++++++++++++++++++
>  MAINTAINERS                                        |  6 ++++
>  2 files changed, 46 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
> 
> diff --git a/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
> new file mode 100644
> index 000000000000..8080cf790d82
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
> @@ -0,0 +1,40 @@
> +IIO multiplexer bindings
> +
> +If a multiplexer is used to select which hardware signal is fed to
> +e.g. an ADC channel, these bindings describe that situation.
> +
> +Required properties:
> +- compatible : "iio-mux"
> +- io-channels : Channel node of the parent channel that has multiplexed
> +		input.
> +- io-channel-names : Should be "parent".
> +- #address-cells = <1>;
> +- #size-cells = <0>;
> +- mux-controls : Mux controller node to use for operating the mux
> +- channels : List of strings, labeling the mux controller states.
> +
> +The multiplexer state as described in ../misc/mux-controller.txt

Delete the above non-sentence, but reintroduce the gist of it...

> +For each non-empty string in the channels property, an iio channel will
> +be created. The number of this iio channel is the same as the index into
> +the list of strings in the channels property, and also matches the mux
> +controller state.

...at the end of the above sentence instead.

I'm holding off v7 pending more important changes.

Cheers,
Peter

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 4/9] dt-bindings: iio: iio-mux: document iio-mux bindings
@ 2016-11-30  8:52     ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Jonathan Corbet, Arnd Bergmann, Greg Kroah-Hartman, linux-i2c,
	devicetree, linux-iio, linux-doc

Hi,

v6 was apparently rushed a little bit too much, but I really wanted to
supersede the stupidity I found elsewhere in v5. Perhaps I shouldn't
have bolted on the changes for the iio-mux bindings, but so I did...

On 2016-11-30 09:16, Peter Rosin wrote:
> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>  .../bindings/iio/multiplexer/iio-mux.txt           | 40 ++++++++++++++++++++++
>  MAINTAINERS                                        |  6 ++++
>  2 files changed, 46 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
> 
> diff --git a/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
> new file mode 100644
> index 000000000000..8080cf790d82
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
> @@ -0,0 +1,40 @@
> +IIO multiplexer bindings
> +
> +If a multiplexer is used to select which hardware signal is fed to
> +e.g. an ADC channel, these bindings describe that situation.
> +
> +Required properties:
> +- compatible : "iio-mux"
> +- io-channels : Channel node of the parent channel that has multiplexed
> +		input.
> +- io-channel-names : Should be "parent".
> +- #address-cells = <1>;
> +- #size-cells = <0>;
> +- mux-controls : Mux controller node to use for operating the mux
> +- channels : List of strings, labeling the mux controller states.
> +
> +The multiplexer state as described in ../misc/mux-controller.txt

Delete the above non-sentence, but reintroduce the gist of it...

> +For each non-empty string in the channels property, an iio channel will
> +be created. The number of this iio channel is the same as the index into
> +the list of strings in the channels property, and also matches the mux
> +controller state.

...at the end of the above sentence instead.

I'm holding off v7 pending more important changes.

Cheers,
Peter

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 4/9] dt-bindings: iio: iio-mux: document iio-mux bindings
  2016-11-30  8:52     ` Peter Rosin
@ 2016-11-30  8:57       ` Peter Rosin
  -1 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:57 UTC (permalink / raw)
  To: linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Jonathan Corbet, Arnd Bergmann, Greg Kroah-Hartman, linux-i2c,
	devicetree, linux-iio, linux-doc

On 2016-11-30 09:52, Peter Rosin wrote:
> I'm holding off v7 pending more important changes.

Err, crap. That was ambiguous. I do not know of any important
changes to make, but please review so that important changes
can be discovered!

Cheers,
Peter

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 4/9] dt-bindings: iio: iio-mux: document iio-mux bindings
@ 2016-11-30  8:57       ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-11-30  8:57 UTC (permalink / raw)
  To: linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Jonathan Corbet, Arnd Bergmann, Greg Kroah-Hartman, linux-i2c,
	devicetree, linux-iio, linux-doc

On 2016-11-30 09:52, Peter Rosin wrote:
> I'm holding off v7 pending more important changes.

Err, crap. That was ambiguous. I do not know of any important
changes to make, but please review so that important changes
can be discovered!

Cheers,
Peter

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 4/9] dt-bindings: iio: iio-mux: document iio-mux bindings
  2016-11-30  8:16   ` Peter Rosin
  (?)
  (?)
@ 2016-12-05 23:26   ` Rob Herring
  2016-12-06  9:18       ` Peter Rosin
  -1 siblings, 1 reply; 58+ messages in thread
From: Rob Herring @ 2016-12-05 23:26 UTC (permalink / raw)
  To: Peter Rosin
  Cc: linux-kernel, Wolfram Sang, Mark Rutland, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Jonathan Corbet, Arnd Bergmann, Greg Kroah-Hartman, linux-i2c,
	devicetree, linux-iio, linux-doc

On Wed, Nov 30, 2016 at 09:16:58AM +0100, Peter Rosin wrote:
> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>  .../bindings/iio/multiplexer/iio-mux.txt           | 40 ++++++++++++++++++++++
>  MAINTAINERS                                        |  6 ++++
>  2 files changed, 46 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt

I'm still not convinced about this binding, but don't really have more 
comments ATM. Sending 6 versions in 2 weeks or so doesn't really help 
either.

> diff --git a/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
> new file mode 100644
> index 000000000000..8080cf790d82
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
> @@ -0,0 +1,40 @@
> +IIO multiplexer bindings
> +
> +If a multiplexer is used to select which hardware signal is fed to
> +e.g. an ADC channel, these bindings describe that situation.
> +
> +Required properties:
> +- compatible : "iio-mux"

This is a Linuxism. perhaps "adc-mux".

> +- io-channels : Channel node of the parent channel that has multiplexed
> +		input.
> +- io-channel-names : Should be "parent".
> +- #address-cells = <1>;
> +- #size-cells = <0>;
> +- mux-controls : Mux controller node to use for operating the mux
> +- channels : List of strings, labeling the mux controller states.
> +
> +The multiplexer state as described in ../misc/mux-controller.txt
> +
> +For each non-empty string in the channels property, an iio channel will
> +be created. The number of this iio channel is the same as the index into
> +the list of strings in the channels property, and also matches the mux
> +controller state.
> +
> +Example:
> +	mux: mux-controller {
> +		compatible = "mux-gpio";
> +		#mux-control-cells = <0>;
> +
> +		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
> +			    <&pioA 1 GPIO_ACTIVE_HIGH>;
> +	};
> +
> +	adc-mux {
> +		compatible = "iio-mux";
> +		io-channels = <&adc 0>;
> +		io-channel-names = "parent";
> +
> +		mux-controls = <&mux>;
> +
> +		channels = "sync", "in", system-regulator";
> +	};

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 4/9] dt-bindings: iio: iio-mux: document iio-mux bindings
  2016-12-05 23:26   ` Rob Herring
@ 2016-12-06  9:18       ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-12-06  9:18 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-kernel, Wolfram Sang, Mark Rutland, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Jonathan Corbet, Arnd Bergmann, Greg Kroah-Hartman, linux-i2c,
	devicetree, linux-iio, linux-doc

On 2016-12-06 00:26, Rob Herring wrote:
> On Wed, Nov 30, 2016 at 09:16:58AM +0100, Peter Rosin wrote:
>> Signed-off-by: Peter Rosin <peda@axentia.se>
>> ---
>>  .../bindings/iio/multiplexer/iio-mux.txt           | 40 ++++++++++++++++++++++
>>  MAINTAINERS                                        |  6 ++++
>>  2 files changed, 46 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
> 
> I'm still not convinced about this binding, but don't really have more 
> comments ATM. Sending 6 versions in 2 weeks or so doesn't really help 
> either.

Sorry about the noise, I'll try to be more careful going forward. On
the flip side, I haven't touched the code since v6.

I don't see how bindings that are as flexible as the current (and
original) phandle link between the mux consumer and the mux controller
would look, and at the same time be simpler to understand. You need
to be able to refer to a mux controller from several mux consumers, and
you need to support several mux controllers in one node (the ADG792A
case). And, AFAICT, the complex case wasn't really the problem, it was
that it is overly complex to describe the simple case of one mux
consumer and one mux controller. But in your comment for v2 [1] you
said that I was working around limitations with shared GPIO pins. But
solving that in the GPIO subsystem would not solve all that the
phandle approach is solving, since you would not have support for
ADG792A (or other non-GPIO controlled muxes). So, I think listing
the gpio pins inside the mux consumer node is a non-starter, the mux
controller has to live in its own node with its own compatible.

Would you be happier if I managed to marry the phandle approach with
the option of having the mux controller as a child node of the mux
consumer for the simple case?

I added an example at the end of this message (the same as the first
example in v4 [2], at least in principle) for easy comparison between
the phandle and the controller-in-child-node approaches. I can't say
that I personally find the difference all that significant, and do not
think it is worth it. As I see it, the "simple option" would just muddy
the waters...

[1] http://marc.info/?l=linux-kernel&m=147948334204795&w=2
[2] http://marc.info/?l=linux-kernel&m=148001364904240&w=2

>> diff --git a/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>> new file mode 100644
>> index 000000000000..8080cf790d82
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>> @@ -0,0 +1,40 @@
>> +IIO multiplexer bindings
>> +
>> +If a multiplexer is used to select which hardware signal is fed to
>> +e.g. an ADC channel, these bindings describe that situation.
>> +
>> +Required properties:
>> +- compatible : "iio-mux"
> 
> This is a Linuxism. perhaps "adc-mux".

No, that's not general enough, it could just as well be used to mux a
temperature sensor. Or whatever. Hmmm, given that "iio-mux" is bad, perhaps
"io-channel-mux" is better? That matches the io-channels property used to
refer to the parent channel.

>> +- io-channels : Channel node of the parent channel that has multiplexed
>> +		input.
>> +- io-channel-names : Should be "parent".
>> +- #address-cells = <1>;
>> +- #size-cells = <0>;
>> +- mux-controls : Mux controller node to use for operating the mux
>> +- channels : List of strings, labeling the mux controller states.
>> +
>> +The multiplexer state as described in ../misc/mux-controller.txt
>> +
>> +For each non-empty string in the channels property, an iio channel will
>> +be created. The number of this iio channel is the same as the index into
>> +the list of strings in the channels property, and also matches the mux
>> +controller state.
>> +
>> +Example:
>> +	mux: mux-controller {
>> +		compatible = "mux-gpio";
>> +		#mux-control-cells = <0>;
>> +
>> +		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
>> +			    <&pioA 1 GPIO_ACTIVE_HIGH>;
>> +	};
>> +
>> +	adc-mux {
>> +		compatible = "iio-mux";
>> +		io-channels = <&adc 0>;
>> +		io-channel-names = "parent";
>> +
>> +		mux-controls = <&mux>;
>> +
>> +		channels = "sync", "in", system-regulator";
>> +	};

Describing the same as above, but with the mux controller as a child
node.

	adc-mux {
		compatible = "iio-mux";
		io-channels = <&adc 0>;
		io-channel-names = "parent";

		channels = "sync", "in", system-regulator";

		mux-controller {
			compatible = "mux-gpio";

			mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
				    <&pioA 1 GPIO_ACTIVE_HIGH>;
		};
	};

Cheers,
Peter

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 4/9] dt-bindings: iio: iio-mux: document iio-mux bindings
@ 2016-12-06  9:18       ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-12-06  9:18 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, Wolfram Sang, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

On 2016-12-06 00:26, Rob Herring wrote:
> On Wed, Nov 30, 2016 at 09:16:58AM +0100, Peter Rosin wrote:
>> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>> ---
>>  .../bindings/iio/multiplexer/iio-mux.txt           | 40 ++++++++++++++++++++++
>>  MAINTAINERS                                        |  6 ++++
>>  2 files changed, 46 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
> 
> I'm still not convinced about this binding, but don't really have more 
> comments ATM. Sending 6 versions in 2 weeks or so doesn't really help 
> either.

Sorry about the noise, I'll try to be more careful going forward. On
the flip side, I haven't touched the code since v6.

I don't see how bindings that are as flexible as the current (and
original) phandle link between the mux consumer and the mux controller
would look, and at the same time be simpler to understand. You need
to be able to refer to a mux controller from several mux consumers, and
you need to support several mux controllers in one node (the ADG792A
case). And, AFAICT, the complex case wasn't really the problem, it was
that it is overly complex to describe the simple case of one mux
consumer and one mux controller. But in your comment for v2 [1] you
said that I was working around limitations with shared GPIO pins. But
solving that in the GPIO subsystem would not solve all that the
phandle approach is solving, since you would not have support for
ADG792A (or other non-GPIO controlled muxes). So, I think listing
the gpio pins inside the mux consumer node is a non-starter, the mux
controller has to live in its own node with its own compatible.

Would you be happier if I managed to marry the phandle approach with
the option of having the mux controller as a child node of the mux
consumer for the simple case?

I added an example at the end of this message (the same as the first
example in v4 [2], at least in principle) for easy comparison between
the phandle and the controller-in-child-node approaches. I can't say
that I personally find the difference all that significant, and do not
think it is worth it. As I see it, the "simple option" would just muddy
the waters...

[1] http://marc.info/?l=linux-kernel&m=147948334204795&w=2
[2] http://marc.info/?l=linux-kernel&m=148001364904240&w=2

>> diff --git a/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>> new file mode 100644
>> index 000000000000..8080cf790d82
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>> @@ -0,0 +1,40 @@
>> +IIO multiplexer bindings
>> +
>> +If a multiplexer is used to select which hardware signal is fed to
>> +e.g. an ADC channel, these bindings describe that situation.
>> +
>> +Required properties:
>> +- compatible : "iio-mux"
> 
> This is a Linuxism. perhaps "adc-mux".

No, that's not general enough, it could just as well be used to mux a
temperature sensor. Or whatever. Hmmm, given that "iio-mux" is bad, perhaps
"io-channel-mux" is better? That matches the io-channels property used to
refer to the parent channel.

>> +- io-channels : Channel node of the parent channel that has multiplexed
>> +		input.
>> +- io-channel-names : Should be "parent".
>> +- #address-cells = <1>;
>> +- #size-cells = <0>;
>> +- mux-controls : Mux controller node to use for operating the mux
>> +- channels : List of strings, labeling the mux controller states.
>> +
>> +The multiplexer state as described in ../misc/mux-controller.txt
>> +
>> +For each non-empty string in the channels property, an iio channel will
>> +be created. The number of this iio channel is the same as the index into
>> +the list of strings in the channels property, and also matches the mux
>> +controller state.
>> +
>> +Example:
>> +	mux: mux-controller {
>> +		compatible = "mux-gpio";
>> +		#mux-control-cells = <0>;
>> +
>> +		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
>> +			    <&pioA 1 GPIO_ACTIVE_HIGH>;
>> +	};
>> +
>> +	adc-mux {
>> +		compatible = "iio-mux";
>> +		io-channels = <&adc 0>;
>> +		io-channel-names = "parent";
>> +
>> +		mux-controls = <&mux>;
>> +
>> +		channels = "sync", "in", system-regulator";
>> +	};

Describing the same as above, but with the mux controller as a child
node.

	adc-mux {
		compatible = "iio-mux";
		io-channels = <&adc 0>;
		io-channel-names = "parent";

		channels = "sync", "in", system-regulator";

		mux-controller {
			compatible = "mux-gpio";

			mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
				    <&pioA 1 GPIO_ACTIVE_HIGH>;
		};
	};

Cheers,
Peter

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 4/9] dt-bindings: iio: iio-mux: document iio-mux bindings
@ 2016-12-10 18:21         ` Jonathan Cameron
  0 siblings, 0 replies; 58+ messages in thread
From: Jonathan Cameron @ 2016-12-10 18:21 UTC (permalink / raw)
  To: Peter Rosin, Rob Herring
  Cc: linux-kernel, Wolfram Sang, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 06/12/16 09:18, Peter Rosin wrote:
> On 2016-12-06 00:26, Rob Herring wrote:
>> On Wed, Nov 30, 2016 at 09:16:58AM +0100, Peter Rosin wrote:
>>> Signed-off-by: Peter Rosin <peda@axentia.se>
>>> ---
>>>  .../bindings/iio/multiplexer/iio-mux.txt           | 40 ++++++++++++++++++++++
>>>  MAINTAINERS                                        |  6 ++++
>>>  2 files changed, 46 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>
>> I'm still not convinced about this binding, but don't really have more 
>> comments ATM. Sending 6 versions in 2 weeks or so doesn't really help 
>> either.
> 
> Sorry about the noise, I'll try to be more careful going forward. On
> the flip side, I haven't touched the code since v6.
> 
> I don't see how bindings that are as flexible as the current (and
> original) phandle link between the mux consumer and the mux controller
> would look, and at the same time be simpler to understand. You need
> to be able to refer to a mux controller from several mux consumers, and
> you need to support several mux controllers in one node (the ADG792A
> case). And, AFAICT, the complex case wasn't really the problem, it was
> that it is overly complex to describe the simple case of one mux
> consumer and one mux controller. But in your comment for v2 [1] you
> said that I was working around limitations with shared GPIO pins. But
> solving that in the GPIO subsystem would not solve all that the
> phandle approach is solving, since you would not have support for
> ADG792A (or other non-GPIO controlled muxes). So, I think listing
> the gpio pins inside the mux consumer node is a non-starter, the mux
> controller has to live in its own node with its own compatible.
> 
> Would you be happier if I managed to marry the phandle approach with
> the option of having the mux controller as a child node of the mux
> consumer for the simple case?
> 
> I added an example at the end of this message (the same as the first
> example in v4 [2], at least in principle) for easy comparison between
> the phandle and the controller-in-child-node approaches. I can't say
> that I personally find the difference all that significant, and do not
> think it is worth it. As I see it, the "simple option" would just muddy
> the waters...
> 
> [1] http://marc.info/?l=linux-kernel&m=147948334204795&w=2
> [2] http://marc.info/?l=linux-kernel&m=148001364904240&w=2
> 
>>> diff --git a/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>> new file mode 100644
>>> index 000000000000..8080cf790d82
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>> @@ -0,0 +1,40 @@
>>> +IIO multiplexer bindings
>>> +
>>> +If a multiplexer is used to select which hardware signal is fed to
>>> +e.g. an ADC channel, these bindings describe that situation.
>>> +
>>> +Required properties:
>>> +- compatible : "iio-mux"
>>
>> This is a Linuxism. perhaps "adc-mux".
> 
> No, that's not general enough, it could just as well be used to mux a
> temperature sensor. Or whatever. Hmmm, given that "iio-mux" is bad, perhaps
> "io-channel-mux" is better? That matches the io-channels property used to
> refer to the parent channel.
analog-mux maybe? Makes more sense out of context (though with io-channels defined on
the next line you have plenty of context here ;)
> 
>>> +- io-channels : Channel node of the parent channel that has multiplexed
>>> +		input.
>>> +- io-channel-names : Should be "parent".
>>> +- #address-cells = <1>;
>>> +- #size-cells = <0>;
>>> +- mux-controls : Mux controller node to use for operating the mux
>>> +- channels : List of strings, labeling the mux controller states.
>>> +
>>> +The multiplexer state as described in ../misc/mux-controller.txt
>>> +
>>> +For each non-empty string in the channels property, an iio channel will
>>> +be created. The number of this iio channel is the same as the index into
>>> +the list of strings in the channels property, and also matches the mux
>>> +controller state.
>>> +
>>> +Example:
>>> +	mux: mux-controller {
>>> +		compatible = "mux-gpio";
>>> +		#mux-control-cells = <0>;
>>> +
>>> +		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
>>> +			    <&pioA 1 GPIO_ACTIVE_HIGH>;
>>> +	};
>>> +
>>> +	adc-mux {
>>> +		compatible = "iio-mux";
>>> +		io-channels = <&adc 0>;
>>> +		io-channel-names = "parent";
>>> +
>>> +		mux-controls = <&mux>;
>>> +
>>> +		channels = "sync", "in", system-regulator";
>>> +	};
> 
> Describing the same as above, but with the mux controller as a child
> node.
> 
> 	adc-mux {
> 		compatible = "iio-mux";
> 		io-channels = <&adc 0>;
> 		io-channel-names = "parent";
> 
> 		channels = "sync", "in", system-regulator";
> 
> 		mux-controller {
> 			compatible = "mux-gpio";
> 
> 			mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
> 				    <&pioA 1 GPIO_ACTIVE_HIGH>;
> 		};
> 	};
> 
> Cheers,
> Peter
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 4/9] dt-bindings: iio: iio-mux: document iio-mux bindings
@ 2016-12-10 18:21         ` Jonathan Cameron
  0 siblings, 0 replies; 58+ messages in thread
From: Jonathan Cameron @ 2016-12-10 18:21 UTC (permalink / raw)
  To: Peter Rosin, Rob Herring
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, Wolfram Sang, Mark Rutland,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Jonathan Corbet, Arnd Bergmann, Greg Kroah-Hartman,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

On 06/12/16 09:18, Peter Rosin wrote:
> On 2016-12-06 00:26, Rob Herring wrote:
>> On Wed, Nov 30, 2016 at 09:16:58AM +0100, Peter Rosin wrote:
>>> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>>> ---
>>>  .../bindings/iio/multiplexer/iio-mux.txt           | 40 ++++++++++++++++++++++
>>>  MAINTAINERS                                        |  6 ++++
>>>  2 files changed, 46 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>
>> I'm still not convinced about this binding, but don't really have more 
>> comments ATM. Sending 6 versions in 2 weeks or so doesn't really help 
>> either.
> 
> Sorry about the noise, I'll try to be more careful going forward. On
> the flip side, I haven't touched the code since v6.
> 
> I don't see how bindings that are as flexible as the current (and
> original) phandle link between the mux consumer and the mux controller
> would look, and at the same time be simpler to understand. You need
> to be able to refer to a mux controller from several mux consumers, and
> you need to support several mux controllers in one node (the ADG792A
> case). And, AFAICT, the complex case wasn't really the problem, it was
> that it is overly complex to describe the simple case of one mux
> consumer and one mux controller. But in your comment for v2 [1] you
> said that I was working around limitations with shared GPIO pins. But
> solving that in the GPIO subsystem would not solve all that the
> phandle approach is solving, since you would not have support for
> ADG792A (or other non-GPIO controlled muxes). So, I think listing
> the gpio pins inside the mux consumer node is a non-starter, the mux
> controller has to live in its own node with its own compatible.
> 
> Would you be happier if I managed to marry the phandle approach with
> the option of having the mux controller as a child node of the mux
> consumer for the simple case?
> 
> I added an example at the end of this message (the same as the first
> example in v4 [2], at least in principle) for easy comparison between
> the phandle and the controller-in-child-node approaches. I can't say
> that I personally find the difference all that significant, and do not
> think it is worth it. As I see it, the "simple option" would just muddy
> the waters...
> 
> [1] http://marc.info/?l=linux-kernel&m=147948334204795&w=2
> [2] http://marc.info/?l=linux-kernel&m=148001364904240&w=2
> 
>>> diff --git a/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>> new file mode 100644
>>> index 000000000000..8080cf790d82
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>> @@ -0,0 +1,40 @@
>>> +IIO multiplexer bindings
>>> +
>>> +If a multiplexer is used to select which hardware signal is fed to
>>> +e.g. an ADC channel, these bindings describe that situation.
>>> +
>>> +Required properties:
>>> +- compatible : "iio-mux"
>>
>> This is a Linuxism. perhaps "adc-mux".
> 
> No, that's not general enough, it could just as well be used to mux a
> temperature sensor. Or whatever. Hmmm, given that "iio-mux" is bad, perhaps
> "io-channel-mux" is better? That matches the io-channels property used to
> refer to the parent channel.
analog-mux maybe? Makes more sense out of context (though with io-channels defined on
the next line you have plenty of context here ;)
> 
>>> +- io-channels : Channel node of the parent channel that has multiplexed
>>> +		input.
>>> +- io-channel-names : Should be "parent".
>>> +- #address-cells = <1>;
>>> +- #size-cells = <0>;
>>> +- mux-controls : Mux controller node to use for operating the mux
>>> +- channels : List of strings, labeling the mux controller states.
>>> +
>>> +The multiplexer state as described in ../misc/mux-controller.txt
>>> +
>>> +For each non-empty string in the channels property, an iio channel will
>>> +be created. The number of this iio channel is the same as the index into
>>> +the list of strings in the channels property, and also matches the mux
>>> +controller state.
>>> +
>>> +Example:
>>> +	mux: mux-controller {
>>> +		compatible = "mux-gpio";
>>> +		#mux-control-cells = <0>;
>>> +
>>> +		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
>>> +			    <&pioA 1 GPIO_ACTIVE_HIGH>;
>>> +	};
>>> +
>>> +	adc-mux {
>>> +		compatible = "iio-mux";
>>> +		io-channels = <&adc 0>;
>>> +		io-channel-names = "parent";
>>> +
>>> +		mux-controls = <&mux>;
>>> +
>>> +		channels = "sync", "in", system-regulator";
>>> +	};
> 
> Describing the same as above, but with the mux controller as a child
> node.
> 
> 	adc-mux {
> 		compatible = "iio-mux";
> 		io-channels = <&adc 0>;
> 		io-channel-names = "parent";
> 
> 		channels = "sync", "in", system-regulator";
> 
> 		mux-controller {
> 			compatible = "mux-gpio";
> 
> 			mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
> 				    <&pioA 1 GPIO_ACTIVE_HIGH>;
> 		};
> 	};
> 
> Cheers,
> Peter
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 4/9] dt-bindings: iio: iio-mux: document iio-mux bindings
@ 2016-12-12 12:18           ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-12-12 12:18 UTC (permalink / raw)
  To: Jonathan Cameron, Rob Herring
  Cc: linux-kernel, Wolfram Sang, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 2016-12-10 19:21, Jonathan Cameron wrote:
> On 06/12/16 09:18, Peter Rosin wrote:
>> On 2016-12-06 00:26, Rob Herring wrote:
>>> On Wed, Nov 30, 2016 at 09:16:58AM +0100, Peter Rosin wrote:
>>>> Signed-off-by: Peter Rosin <peda@axentia.se>
>>>> ---
>>>>  .../bindings/iio/multiplexer/iio-mux.txt           | 40 ++++++++++++++++++++++
>>>>  MAINTAINERS                                        |  6 ++++
>>>>  2 files changed, 46 insertions(+)
>>>>  create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>>
>>> I'm still not convinced about this binding, but don't really have more 
>>> comments ATM. Sending 6 versions in 2 weeks or so doesn't really help 
>>> either.
>>
>> Sorry about the noise, I'll try to be more careful going forward. On
>> the flip side, I haven't touched the code since v6.
>>
>> I don't see how bindings that are as flexible as the current (and
>> original) phandle link between the mux consumer and the mux controller
>> would look, and at the same time be simpler to understand. You need
>> to be able to refer to a mux controller from several mux consumers, and
>> you need to support several mux controllers in one node (the ADG792A
>> case). And, AFAICT, the complex case wasn't really the problem, it was
>> that it is overly complex to describe the simple case of one mux
>> consumer and one mux controller. But in your comment for v2 [1] you
>> said that I was working around limitations with shared GPIO pins. But
>> solving that in the GPIO subsystem would not solve all that the
>> phandle approach is solving, since you would not have support for
>> ADG792A (or other non-GPIO controlled muxes). So, I think listing
>> the gpio pins inside the mux consumer node is a non-starter, the mux
>> controller has to live in its own node with its own compatible.
>>
>> Would you be happier if I managed to marry the phandle approach with
>> the option of having the mux controller as a child node of the mux
>> consumer for the simple case?
>>
>> I added an example at the end of this message (the same as the first
>> example in v4 [2], at least in principle) for easy comparison between
>> the phandle and the controller-in-child-node approaches. I can't say
>> that I personally find the difference all that significant, and do not
>> think it is worth it. As I see it, the "simple option" would just muddy
>> the waters...
>>
>> [1] http://marc.info/?l=linux-kernel&m=147948334204795&w=2
>> [2] http://marc.info/?l=linux-kernel&m=148001364904240&w=2
>>
>>>> diff --git a/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>>> new file mode 100644
>>>> index 000000000000..8080cf790d82
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>>> @@ -0,0 +1,40 @@
>>>> +IIO multiplexer bindings
>>>> +
>>>> +If a multiplexer is used to select which hardware signal is fed to
>>>> +e.g. an ADC channel, these bindings describe that situation.
>>>> +
>>>> +Required properties:
>>>> +- compatible : "iio-mux"
>>>
>>> This is a Linuxism. perhaps "adc-mux".
>>
>> No, that's not general enough, it could just as well be used to mux a
>> temperature sensor. Or whatever. Hmmm, given that "iio-mux" is bad, perhaps
>> "io-channel-mux" is better? That matches the io-channels property used to
>> refer to the parent channel.
> analog-mux maybe? Makes more sense out of context (though with io-channels defined on
> the next line you have plenty of context here ;)

Not that I care all that much about the name, but that doesn't really
fit if you take e.g. an IIO_INDEX channel. That sounds entirely non-analog
to me, but what do I know? Maybe that example doesn't make sense for some
reason, but I can't help but think that there will be some non-analog
channel in the future, if there isn't one already.

So, my preference is io-channel-mux, as that matches the previous dt
naming for what is muxed. But that's just my opinion, if I'm told that
it should be something else, then that's ok.

I'm more worried about other aspects, such as how to get reviewers and who
is going to take the core mux patches and what tree they are going to be
merged into etc. That is, if this series is going anywhere at all or if
someone is going to put up a road-block for some reason...

Cheers,
peda

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 4/9] dt-bindings: iio: iio-mux: document iio-mux bindings
@ 2016-12-12 12:18           ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2016-12-12 12:18 UTC (permalink / raw)
  To: Jonathan Cameron, Rob Herring
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, Wolfram Sang, Mark Rutland,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Jonathan Corbet, Arnd Bergmann, Greg Kroah-Hartman,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

On 2016-12-10 19:21, Jonathan Cameron wrote:
> On 06/12/16 09:18, Peter Rosin wrote:
>> On 2016-12-06 00:26, Rob Herring wrote:
>>> On Wed, Nov 30, 2016 at 09:16:58AM +0100, Peter Rosin wrote:
>>>> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>>>> ---
>>>>  .../bindings/iio/multiplexer/iio-mux.txt           | 40 ++++++++++++++++++++++
>>>>  MAINTAINERS                                        |  6 ++++
>>>>  2 files changed, 46 insertions(+)
>>>>  create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>>
>>> I'm still not convinced about this binding, but don't really have more 
>>> comments ATM. Sending 6 versions in 2 weeks or so doesn't really help 
>>> either.
>>
>> Sorry about the noise, I'll try to be more careful going forward. On
>> the flip side, I haven't touched the code since v6.
>>
>> I don't see how bindings that are as flexible as the current (and
>> original) phandle link between the mux consumer and the mux controller
>> would look, and at the same time be simpler to understand. You need
>> to be able to refer to a mux controller from several mux consumers, and
>> you need to support several mux controllers in one node (the ADG792A
>> case). And, AFAICT, the complex case wasn't really the problem, it was
>> that it is overly complex to describe the simple case of one mux
>> consumer and one mux controller. But in your comment for v2 [1] you
>> said that I was working around limitations with shared GPIO pins. But
>> solving that in the GPIO subsystem would not solve all that the
>> phandle approach is solving, since you would not have support for
>> ADG792A (or other non-GPIO controlled muxes). So, I think listing
>> the gpio pins inside the mux consumer node is a non-starter, the mux
>> controller has to live in its own node with its own compatible.
>>
>> Would you be happier if I managed to marry the phandle approach with
>> the option of having the mux controller as a child node of the mux
>> consumer for the simple case?
>>
>> I added an example at the end of this message (the same as the first
>> example in v4 [2], at least in principle) for easy comparison between
>> the phandle and the controller-in-child-node approaches. I can't say
>> that I personally find the difference all that significant, and do not
>> think it is worth it. As I see it, the "simple option" would just muddy
>> the waters...
>>
>> [1] http://marc.info/?l=linux-kernel&m=147948334204795&w=2
>> [2] http://marc.info/?l=linux-kernel&m=148001364904240&w=2
>>
>>>> diff --git a/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>>> new file mode 100644
>>>> index 000000000000..8080cf790d82
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>>> @@ -0,0 +1,40 @@
>>>> +IIO multiplexer bindings
>>>> +
>>>> +If a multiplexer is used to select which hardware signal is fed to
>>>> +e.g. an ADC channel, these bindings describe that situation.
>>>> +
>>>> +Required properties:
>>>> +- compatible : "iio-mux"
>>>
>>> This is a Linuxism. perhaps "adc-mux".
>>
>> No, that's not general enough, it could just as well be used to mux a
>> temperature sensor. Or whatever. Hmmm, given that "iio-mux" is bad, perhaps
>> "io-channel-mux" is better? That matches the io-channels property used to
>> refer to the parent channel.
> analog-mux maybe? Makes more sense out of context (though with io-channels defined on
> the next line you have plenty of context here ;)

Not that I care all that much about the name, but that doesn't really
fit if you take e.g. an IIO_INDEX channel. That sounds entirely non-analog
to me, but what do I know? Maybe that example doesn't make sense for some
reason, but I can't help but think that there will be some non-analog
channel in the future, if there isn't one already.

So, my preference is io-channel-mux, as that matches the previous dt
naming for what is muxed. But that's just my opinion, if I'm told that
it should be something else, then that's ok.

I'm more worried about other aspects, such as how to get reviewers and who
is going to take the core mux patches and what tree they are going to be
merged into etc. That is, if this series is going anywhere at all or if
someone is going to put up a road-block for some reason...

Cheers,
peda

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 3/9] iio: inkern: api for manipulating ext_info of iio channels
@ 2016-12-31 15:51     ` Jonathan Cameron
  0 siblings, 0 replies; 58+ messages in thread
From: Jonathan Cameron @ 2016-12-31 15:51 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 30/11/16 08:16, Peter Rosin wrote:
> Extend the inkern api with functions for reading and writing ext_info
> of iio channels.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>
Acked-by: Jonathan Cameron <jic23@kernel.org>

It may make more sense to take this particular patch separately via
IIO, but as the churn on this file is fairly low I think it is probably
going to be easier to take it with the rest of the series if / when that
heads upstream.

Jonathan
> ---
>  drivers/iio/inkern.c         | 60 ++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/iio/consumer.h | 37 +++++++++++++++++++++++++++
>  2 files changed, 97 insertions(+)
> 
> diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
> index b0f4630a163f..4848b8129e6c 100644
> --- a/drivers/iio/inkern.c
> +++ b/drivers/iio/inkern.c
> @@ -863,3 +863,63 @@ int iio_write_channel_raw(struct iio_channel *chan, int val)
>  	return ret;
>  }
>  EXPORT_SYMBOL_GPL(iio_write_channel_raw);
> +
> +unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan)
> +{
> +	const struct iio_chan_spec_ext_info *ext_info;
> +	unsigned int i = 0;
> +
> +	if (!chan->channel->ext_info)
> +		return i;
> +
> +	for (ext_info = chan->channel->ext_info; ext_info->name; ext_info++)
> +		++i;
> +
> +	return i;
> +}
> +EXPORT_SYMBOL_GPL(iio_get_channel_ext_info_count);
> +
> +static const struct iio_chan_spec_ext_info *iio_lookup_ext_info(
> +						const struct iio_channel *chan,
> +						const char *attr)
> +{
> +	const struct iio_chan_spec_ext_info *ext_info;
> +
> +	if (!chan->channel->ext_info)
> +		return NULL;
> +
> +	for (ext_info = chan->channel->ext_info; ext_info->name; ++ext_info) {
> +		if (!strcmp(attr, ext_info->name))
> +			return ext_info;
> +	}
> +
> +	return NULL;
> +}
> +
> +ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
> +				  const char *attr, char *buf)
> +{
> +	const struct iio_chan_spec_ext_info *ext_info;
> +
> +	ext_info = iio_lookup_ext_info(chan, attr);
> +	if (!ext_info)
> +		return -EINVAL;
> +
> +	return ext_info->read(chan->indio_dev, ext_info->private,
> +			      chan->channel, buf);
> +}
> +EXPORT_SYMBOL_GPL(iio_read_channel_ext_info);
> +
> +ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
> +				   const char *buf, size_t len)
> +{
> +	const struct iio_chan_spec_ext_info *ext_info;
> +
> +	ext_info = iio_lookup_ext_info(chan, attr);
> +	if (!ext_info)
> +		return -EINVAL;
> +
> +	return ext_info->write(chan->indio_dev, ext_info->private,
> +			       chan->channel, buf, len);
> +}
> +EXPORT_SYMBOL_GPL(iio_write_channel_ext_info);
> diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
> index 47eeec3218b5..5e347a9805fd 100644
> --- a/include/linux/iio/consumer.h
> +++ b/include/linux/iio/consumer.h
> @@ -312,4 +312,41 @@ int iio_read_channel_scale(struct iio_channel *chan, int *val,
>  int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
>  	int *processed, unsigned int scale);
>  
> +/**
> + * iio_get_channel_ext_info_count() - get number of ext_info attributes
> + *				      connected to the channel.
> + * @chan:		The channel being queried
> + *
> + * Returns the number of ext_info attributes
> + */
> +unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan);
> +
> +/**
> + * iio_read_channel_ext_info() - read ext_info attribute from a given channel
> + * @chan:		The channel being queried.
> + * @attr:		The ext_info attribute to read.
> + * @buf:		Where to store the attribute value. Assumed to hold
> + *			at least PAGE_SIZE bytes.
> + *
> + * Returns the number of bytes written to buf (perhaps w/o zero termination;
> + * it need not even be a string), or an error code.
> + */
> +ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
> +				  const char *attr, char *buf);
> +
> +/**
> + * iio_write_channel_ext_info() - write ext_info attribute from a given channel
> + * @chan:		The channel being queried.
> + * @attr:		The ext_info attribute to read.
> + * @buf:		The new attribute value. Strings needs to be zero-
> + *			terminated, but the terminator should not be included
> + *			in the below len.
> + * @len:		The size of the new attribute value.
> + *
> + * Returns the number of accepted bytes, which should be the same as len.
> + * An error code can also be returned.
> + */
> +ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
> +				   const char *buf, size_t len);
> +
>  #endif
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 3/9] iio: inkern: api for manipulating ext_info of iio channels
@ 2016-12-31 15:51     ` Jonathan Cameron
  0 siblings, 0 replies; 58+ messages in thread
From: Jonathan Cameron @ 2016-12-31 15:51 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

On 30/11/16 08:16, Peter Rosin wrote:
> Extend the inkern api with functions for reading and writing ext_info
> of iio channels.
> 
> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
Acked-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

It may make more sense to take this particular patch separately via
IIO, but as the churn on this file is fairly low I think it is probably
going to be easier to take it with the rest of the series if / when that
heads upstream.

Jonathan
> ---
>  drivers/iio/inkern.c         | 60 ++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/iio/consumer.h | 37 +++++++++++++++++++++++++++
>  2 files changed, 97 insertions(+)
> 
> diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
> index b0f4630a163f..4848b8129e6c 100644
> --- a/drivers/iio/inkern.c
> +++ b/drivers/iio/inkern.c
> @@ -863,3 +863,63 @@ int iio_write_channel_raw(struct iio_channel *chan, int val)
>  	return ret;
>  }
>  EXPORT_SYMBOL_GPL(iio_write_channel_raw);
> +
> +unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan)
> +{
> +	const struct iio_chan_spec_ext_info *ext_info;
> +	unsigned int i = 0;
> +
> +	if (!chan->channel->ext_info)
> +		return i;
> +
> +	for (ext_info = chan->channel->ext_info; ext_info->name; ext_info++)
> +		++i;
> +
> +	return i;
> +}
> +EXPORT_SYMBOL_GPL(iio_get_channel_ext_info_count);
> +
> +static const struct iio_chan_spec_ext_info *iio_lookup_ext_info(
> +						const struct iio_channel *chan,
> +						const char *attr)
> +{
> +	const struct iio_chan_spec_ext_info *ext_info;
> +
> +	if (!chan->channel->ext_info)
> +		return NULL;
> +
> +	for (ext_info = chan->channel->ext_info; ext_info->name; ++ext_info) {
> +		if (!strcmp(attr, ext_info->name))
> +			return ext_info;
> +	}
> +
> +	return NULL;
> +}
> +
> +ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
> +				  const char *attr, char *buf)
> +{
> +	const struct iio_chan_spec_ext_info *ext_info;
> +
> +	ext_info = iio_lookup_ext_info(chan, attr);
> +	if (!ext_info)
> +		return -EINVAL;
> +
> +	return ext_info->read(chan->indio_dev, ext_info->private,
> +			      chan->channel, buf);
> +}
> +EXPORT_SYMBOL_GPL(iio_read_channel_ext_info);
> +
> +ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
> +				   const char *buf, size_t len)
> +{
> +	const struct iio_chan_spec_ext_info *ext_info;
> +
> +	ext_info = iio_lookup_ext_info(chan, attr);
> +	if (!ext_info)
> +		return -EINVAL;
> +
> +	return ext_info->write(chan->indio_dev, ext_info->private,
> +			       chan->channel, buf, len);
> +}
> +EXPORT_SYMBOL_GPL(iio_write_channel_ext_info);
> diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
> index 47eeec3218b5..5e347a9805fd 100644
> --- a/include/linux/iio/consumer.h
> +++ b/include/linux/iio/consumer.h
> @@ -312,4 +312,41 @@ int iio_read_channel_scale(struct iio_channel *chan, int *val,
>  int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
>  	int *processed, unsigned int scale);
>  
> +/**
> + * iio_get_channel_ext_info_count() - get number of ext_info attributes
> + *				      connected to the channel.
> + * @chan:		The channel being queried
> + *
> + * Returns the number of ext_info attributes
> + */
> +unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan);
> +
> +/**
> + * iio_read_channel_ext_info() - read ext_info attribute from a given channel
> + * @chan:		The channel being queried.
> + * @attr:		The ext_info attribute to read.
> + * @buf:		Where to store the attribute value. Assumed to hold
> + *			at least PAGE_SIZE bytes.
> + *
> + * Returns the number of bytes written to buf (perhaps w/o zero termination;
> + * it need not even be a string), or an error code.
> + */
> +ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
> +				  const char *attr, char *buf);
> +
> +/**
> + * iio_write_channel_ext_info() - write ext_info attribute from a given channel
> + * @chan:		The channel being queried.
> + * @attr:		The ext_info attribute to read.
> + * @buf:		The new attribute value. Strings needs to be zero-
> + *			terminated, but the terminator should not be included
> + *			in the below len.
> + * @len:		The size of the new attribute value.
> + *
> + * Returns the number of accepted bytes, which should be the same as len.
> + * An error code can also be returned.
> + */
> +ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
> +				   const char *buf, size_t len);
> +
>  #endif
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 4/9] dt-bindings: iio: iio-mux: document iio-mux bindings
  2016-12-12 12:18           ` Peter Rosin
  (?)
@ 2016-12-31 16:01           ` Jonathan Cameron
  -1 siblings, 0 replies; 58+ messages in thread
From: Jonathan Cameron @ 2016-12-31 16:01 UTC (permalink / raw)
  To: Peter Rosin, Rob Herring
  Cc: linux-kernel, Wolfram Sang, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 12/12/16 12:18, Peter Rosin wrote:
> On 2016-12-10 19:21, Jonathan Cameron wrote:
>> On 06/12/16 09:18, Peter Rosin wrote:
>>> On 2016-12-06 00:26, Rob Herring wrote:
>>>> On Wed, Nov 30, 2016 at 09:16:58AM +0100, Peter Rosin wrote:
>>>>> Signed-off-by: Peter Rosin <peda@axentia.se>
>>>>> ---
>>>>>  .../bindings/iio/multiplexer/iio-mux.txt           | 40 ++++++++++++++++++++++
>>>>>  MAINTAINERS                                        |  6 ++++
>>>>>  2 files changed, 46 insertions(+)
>>>>>  create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>>>
>>>> I'm still not convinced about this binding, but don't really have more 
>>>> comments ATM. Sending 6 versions in 2 weeks or so doesn't really help 
>>>> either.
>>>
>>> Sorry about the noise, I'll try to be more careful going forward. On
>>> the flip side, I haven't touched the code since v6.
>>>
>>> I don't see how bindings that are as flexible as the current (and
>>> original) phandle link between the mux consumer and the mux controller
>>> would look, and at the same time be simpler to understand. You need
>>> to be able to refer to a mux controller from several mux consumers, and
>>> you need to support several mux controllers in one node (the ADG792A
>>> case). And, AFAICT, the complex case wasn't really the problem, it was
>>> that it is overly complex to describe the simple case of one mux
>>> consumer and one mux controller. But in your comment for v2 [1] you
>>> said that I was working around limitations with shared GPIO pins. But
>>> solving that in the GPIO subsystem would not solve all that the
>>> phandle approach is solving, since you would not have support for
>>> ADG792A (or other non-GPIO controlled muxes). So, I think listing
>>> the gpio pins inside the mux consumer node is a non-starter, the mux
>>> controller has to live in its own node with its own compatible.
>>>
>>> Would you be happier if I managed to marry the phandle approach with
>>> the option of having the mux controller as a child node of the mux
>>> consumer for the simple case?
>>>
>>> I added an example at the end of this message (the same as the first
>>> example in v4 [2], at least in principle) for easy comparison between
>>> the phandle and the controller-in-child-node approaches. I can't say
>>> that I personally find the difference all that significant, and do not
>>> think it is worth it. As I see it, the "simple option" would just muddy
>>> the waters...
>>>
>>> [1] http://marc.info/?l=linux-kernel&m=147948334204795&w=2
>>> [2] http://marc.info/?l=linux-kernel&m=148001364904240&w=2
>>>
>>>>> diff --git a/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>>>> new file mode 100644
>>>>> index 000000000000..8080cf790d82
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>>>> @@ -0,0 +1,40 @@
>>>>> +IIO multiplexer bindings
>>>>> +
>>>>> +If a multiplexer is used to select which hardware signal is fed to
>>>>> +e.g. an ADC channel, these bindings describe that situation.
>>>>> +
>>>>> +Required properties:
>>>>> +- compatible : "iio-mux"
>>>>
>>>> This is a Linuxism. perhaps "adc-mux".
>>>
>>> No, that's not general enough, it could just as well be used to mux a
>>> temperature sensor. Or whatever. Hmmm, given that "iio-mux" is bad, perhaps
>>> "io-channel-mux" is better? That matches the io-channels property used to
>>> refer to the parent channel.
>> analog-mux maybe? Makes more sense out of context (though with io-channels defined on
>> the next line you have plenty of context here ;)
> 
> Not that I care all that much about the name, but that doesn't really
> fit if you take e.g. an IIO_INDEX channel. That sounds entirely non-analog
> to me, but what do I know? Maybe that example doesn't make sense for some
> reason, but I can't help but think that there will be some non-analog
> channel in the future, if there isn't one already.
> 
> So, my preference is io-channel-mux, as that matches the previous dt
> naming for what is muxed. But that's just my opinion, if I'm told that
> it should be something else, then that's ok.
io-channel-mux works fine for me. It's some sort of input / output channel
and we are muxing it ;)
> 
> I'm more worried about other aspects, such as how to get reviewers and who
> is going to take the core mux patches and what tree they are going to be
> merged into etc. That is, if this series is going anywhere at all or if
> someone is going to put up a road-block for some reason...
Whilst it is meeting some resistance, I'm not seeing any absolute blockers
(people tend to be rather explicit about that).  The binding is still causing
the most friction I think and it may be that it just needs some more time for
Rob to mull it over. It's a fiddly thing to describe, so was never going
to drop straight in!

The core mux patches probably need to go one of a few possible routes.

1. Directly as a pull to linus with a good collection of Acks.
2. Via Greg KH perhaps as generic driver infrastructure, or Andrew Morton
as being in the category no one else will take.
3. Via either me or Wolfram (as a separate immutable branch) on the basis it's
core stuff but the users currently are IIO and I2C.

In any case, this needs at the very least Acks from Rob, Wolfram and myself.
Others would be most welcome, Arnd and/or Greg might be persuaded to take
a look for example...

Happy New Year,

Jonathan
> 
> Cheers,
> peda
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 1/9] dt-bindings: document devicetree bindings for mux-controllers and mux-gpio
  2016-11-30  8:16   ` Peter Rosin
  (?)
@ 2016-12-31 16:10   ` Jonathan Cameron
  -1 siblings, 0 replies; 58+ messages in thread
From: Jonathan Cameron @ 2016-12-31 16:10 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 30/11/16 08:16, Peter Rosin wrote:
> Signed-off-by: Peter Rosin <peda@axentia.se>
Bindings are still a bit of a black art to me ;)

Other than the naming of the iio-mux as discussed in the other patch
I'm happy with this. It feels like it has struck the right balance
between flexibility and complexity.  Which probably means we'll
have an application it doesn't stretch to before the day is out...

Acked-by: Jonathan Cameron <jic23@kernel.org>
> ---
>  .../devicetree/bindings/misc/mux-controller.txt    | 127 +++++++++++++++++++++
>  .../devicetree/bindings/misc/mux-gpio.txt          |  68 +++++++++++
>  MAINTAINERS                                        |   5 +
>  3 files changed, 200 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/misc/mux-controller.txt
>  create mode 100644 Documentation/devicetree/bindings/misc/mux-gpio.txt
> 
> diff --git a/Documentation/devicetree/bindings/misc/mux-controller.txt b/Documentation/devicetree/bindings/misc/mux-controller.txt
> new file mode 100644
> index 000000000000..19c36b73173e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/misc/mux-controller.txt
> @@ -0,0 +1,127 @@
> +Common multiplexer controller bindings
> +======================================
> +
> +A multiplexer (or mux) controller will have one, or several, consumer devices
> +that uses the mux controller. Thus, a mux controller can possibly control
> +several parallel multiplexers, presumably there will be at least one
> +multiplexer needed by each consumer..
> +
> +A mux controller provides a number of states to its consumers, and the state
> +space is a simple zero-based enumeration. I.e. 0-1 for a 2-way multiplexer,
> +0-7 for an 8-way multiplexer, etc.
> +
> +
> +Consumers
> +---------
> +
> +Mux controller consumers should specify a list of mux controllers that they
> +want to use with a property containing a 'mux-ctrl-list':
> +
> +	mux-ctrl-list ::= <single-mux-ctrl> [mux-ctrl-list]
> +	single-mux-ctrl ::= <mux-ctrl-phandle> [mux-ctrl-specifier]
> +	mux-ctrl-phandle : phandle to mux controller node
> +	mux-ctrl-specifier : array of #mux-control-cells specifying the
> +			     given mux controller (controller specific)
> +
> +Mux controller properties should be named "mux-controls". The exact meaning of
> +each mux controller property must be documented in the device tree binding for
> +each consumer. An optional property "mux-control-names" may contain a list of
> +strings to label each of the mux controllers listed in the "mux-controls"
> +property.
> +
> +Drivers for devices that use more than a single mux controller can use the
> +"mux-control-names" property to map the name of the mux controller requested by
> +the mux_control_get() call to an index into the list given by the
> +"mux-controls" property.
> +
> +mux-ctrl-specifier typically encodes the chip-relative mux controller number.
> +If the mux controller chip only provides a single mux controller, the
> +mux-ctrl-specifier can typically be left out.
> +
> +Example:
> +
> +	/* One consumer of a 2-way mux controller (one GPIO-line) */
> +	mux: mux-controller {
> +		compatible = "mux-gpio";
> +		#mux-control-cells = <0>;
> +
> +		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>;
> +	};
> +
> +	adc-mux {
> +		compatible = "iio-mux";
> +		io-channels = <&adc 0>;
> +		io-channel-names = "parent";
> +		mux-controls = <&mux>;
> +		mux-control-names = "adc";
> +
> +		channels = "sync", "in";
> +	};
> +
> +Note that in the example above, specifying the "mux-control-names" is redundant
> +because there is only one mux controller in the list.
> +
> +	/*
> +	 * Two consumers (one for an ADC line and one for an i2c bus) of
> +	 * parallel 4-way multiplexers controlled by the same two GPIO-lines.
> +	 */
> +	mux: mux-controller {
> +		compatible = "mux-gpio";
> +		#mux-control-cells = <0>;
> +
> +		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
> +			    <&pioA 1 GPIO_ACTIVE_HIGH>;
> +	};
> +
> +	adc-mux {
> +		compatible = "iio-mux";
> +		io-channels = <&adc 0>;
> +		io-channel-names = "parent";
> +		mux-controls = <&mux>;
> +
> +		channels = "sync-1", "in", "out", "sync-2";
> +	};
> +
> +	i2c-mux {
> +		compatible = "i2c-mux-simple,mux-locked";
> +		i2c-parent = <&i2c1>;
> +		mux-controls = <&mux>;
> +
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		i2c@0 {
> +			reg = <0>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			ssd1307: oled@3c {
> +				/* ... */
> +			};
> +		};
> +
> +		i2c@3 {
> +			reg = <3>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			pca9555: pca9555@20 {
> +				/* ... */
> +			};
> +		};
> +	};
> +
> +
> +Mux controller nodes
> +--------------------
> +
> +Mux controller nodes must specify the number of cells used for the
> +specifier using the '#mux-control-cells' property.
> +
> +An example mux controller might look like this:
> +
> +	mux: adg792a@50 {
> +		compatible = "adi,adg792a";
> +		reg = <0x50>;
> +		#mux-control-cells = <1>;
> +	};
> diff --git a/Documentation/devicetree/bindings/misc/mux-gpio.txt b/Documentation/devicetree/bindings/misc/mux-gpio.txt
> new file mode 100644
> index 000000000000..2ff814f082c8
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/misc/mux-gpio.txt
> @@ -0,0 +1,68 @@
> +GPIO-based multiplexer controller bindings
> +
> +Define what GPIO pins are used to control a multiplexer. Or several
> +multiplexers, if the same pins control more than one multiplexer.
> +
> +Required properties:
> +- compatible : "mux-gpio"
> +- mux-gpios : list of gpios used to control the multiplexer, least
> +	      significant bit first.
> +- #mux-control-cells : <0>
> +* Standard mux-controller bindings as decribed in mux-controller.txt
> +
> +Optional properties:
> +- idle-state : if present, the state the mux will have when idle.
> +
> +The multiplexer state is defined as the number represented by the
> +multiplexer GPIO pins, where the first pin is the least significant
> +bit. An active pin is a binary 1, an inactive pin is a binary 0.
> +
> +Example:
> +
> +	mux: mux-controller {
> +		compatible = "mux-gpio";
> +		#mux-control-cells = <0>;
> +
> +		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
> +			    <&pioA 1 GPIO_ACTIVE_HIGH>;
> +	};
> +
> +	adc-mux {
> +		compatible = "iio-mux";
> +		io-channels = <&adc 0>;
> +		io-channel-names = "parent";
> +
> +		mux-controls = <&mux>;
> +
> +		channels = "sync-1", "in", "out", "sync-2";
> +	};
> +
> +	i2c-mux {
> +		compatible = "i2c-mux-simple,mux-locked";
> +		i2c-parent = <&i2c1>;
> +
> +		mux-controls = <&mux>;
> +
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		i2c@0 {
> +			reg = <0>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			ssd1307: oled@3c {
> +				/* ... */
> +			};
> +		};
> +
> +		i2c@3 {
> +			reg = <3>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			pca9555: pca9555@20 {
> +				/* ... */
> +			};
> +		};
> +	};
> diff --git a/MAINTAINERS b/MAINTAINERS
> index d8eb3843dbd4..3d4d0efc2b64 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -8403,6 +8403,11 @@ S:	Orphan
>  F:	drivers/mmc/host/mmc_spi.c
>  F:	include/linux/spi/mmc_spi.h
>  
> +MULTIPLEXER SUBSYSTEM
> +M:	Peter Rosin <peda@axentia.se>
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/misc/mux-*
> +
>  MULTISOUND SOUND DRIVER
>  M:	Andrew Veliath <andrewtv@usa.net>
>  S:	Maintained
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 2/9] misc: minimal mux subsystem and gpio-based mux controller
  2016-11-30  8:16   ` Peter Rosin
  (?)
@ 2016-12-31 16:19   ` Jonathan Cameron
  2017-01-02  9:14     ` Peter Rosin
  -1 siblings, 1 reply; 58+ messages in thread
From: Jonathan Cameron @ 2016-12-31 16:19 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 30/11/16 08:16, Peter Rosin wrote:
> Add a new minimalistic subsystem that handles multiplexer controllers.
> When multiplexers are used in various places in the kernel, and the
> same multiplexer controller can be used for several independent things,
> there should be one place to implement support for said multiplexer
> controller.
> 
> A single multiplexer controller can also be used to control several
> parallel multiplexers, that are in turn used by different subsystems
> in the kernel, leading to a need to coordinate multiplexer accesses.
> The multiplexer subsystem handles this coordination.
> 
> This new mux controller subsystem initially comes with a single backend
> driver that controls gpio based multiplexers. Even though not needed by
> this initial driver, the mux controller subsystem is prepared to handle
> chips with multiple (independent) mux controllers.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>
Few trivial bits inline + question of whether misc is the right location..
It's small, but not totally trivial as subsystems go, so perhaps it needs it's
own directory.
> ---
>  Documentation/driver-model/devres.txt |   6 +-
>  MAINTAINERS                           |   2 +
>  drivers/misc/Kconfig                  |  30 ++++
>  drivers/misc/Makefile                 |   2 +
>  drivers/misc/mux-core.c               | 311 ++++++++++++++++++++++++++++++++++
>  drivers/misc/mux-gpio.c               | 138 +++++++++++++++
>  include/linux/mux.h                   | 197 +++++++++++++++++++++
>  7 files changed, 685 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/misc/mux-core.c
>  create mode 100644 drivers/misc/mux-gpio.c
>  create mode 100644 include/linux/mux.h
> 
> diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
> index ca9d1eb46bc0..d64ede85b61b 100644
> --- a/Documentation/driver-model/devres.txt
> +++ b/Documentation/driver-model/devres.txt
> @@ -330,7 +330,11 @@ MEM
>    devm_kzalloc()
>  
>  MFD
> - devm_mfd_add_devices()
Technically should be in a separate cleanup patch...
> +  devm_mfd_add_devices()
> +
> +MUX
> +  devm_mux_control_get()
> +  devm_mux_control_put()
>  
>  PER-CPU MEM
>    devm_alloc_percpu()
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3d4d0efc2b64..dc7498682752 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -8407,6 +8407,8 @@ MULTIPLEXER SUBSYSTEM
>  M:	Peter Rosin <peda@axentia.se>
>  S:	Maintained
>  F:	Documentation/devicetree/bindings/misc/mux-*
> +F:	include/linux/mux.h
> +F:	drivers/misc/mux-*
>  
>  MULTISOUND SOUND DRIVER
>  M:	Andrew Veliath <andrewtv@usa.net>
> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index 64971baf11fa..2ce675e410c5 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -766,6 +766,36 @@ config PANEL_BOOT_MESSAGE
>  	  An empty message will only clear the display at driver init time. Any other
>  	  printf()-formatted message is valid with newline and escape codes.
>  
> +menuconfig MULTIPLEXER
> +	bool "Multiplexer subsystem"
> +	help
> +	  Multiplexer controller subsystem. Multiplexers are used in a
> +	  variety of settings, and this subsystem abstracts their use
> +	  so that the rest of the kernel sees a common interface. When
> +	  multiple parallel multiplexers are controlled by one single
> +	  multiplexer controller, this subsystem also coordinates the
> +	  multiplexer accesses.
> +
> +	  If unsure, say no.
> +
Fun question of the day. Is misc the place to put this or should it
have it's own directory. I'd go for own directory...

On the plus side, whilst it's in misc you get to pester Greg and Arnd
for review.
> +if MULTIPLEXER
> +
> +config MUX_GPIO
> +	tristate "GPIO-controlled Multiplexer"
> +	depends on OF && GPIOLIB
> +	help
> +	  GPIO-controlled Multiplexer controller.
> +
> +	  The driver builds a single multiplexer controller using a number
> +	  of gpio pins. For N pins, there will be 2^N possible multiplexer
> +	  states. The GPIO pins can be connected (by the hardware) to several
> +	  multiplexers, which in that case will be operated in parallel.
> +
> +	  To compile this driver as a module, choose M here: the module will
> +	  be called mux-gpio.
> +
> +endif
> +
>  source "drivers/misc/c2port/Kconfig"
>  source "drivers/misc/eeprom/Kconfig"
>  source "drivers/misc/cb710/Kconfig"
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index 31983366090a..0befa2bba762 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -53,6 +53,8 @@ obj-$(CONFIG_ECHO)		+= echo/
>  obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
>  obj-$(CONFIG_CXL_BASE)		+= cxl/
>  obj-$(CONFIG_PANEL)             += panel.o
> +obj-$(CONFIG_MULTIPLEXER)      	+= mux-core.o
> +obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
>  
>  lkdtm-$(CONFIG_LKDTM)		+= lkdtm_core.o
>  lkdtm-$(CONFIG_LKDTM)		+= lkdtm_bugs.o
> diff --git a/drivers/misc/mux-core.c b/drivers/misc/mux-core.c
> new file mode 100644
> index 000000000000..cccaa7261a6e
> --- /dev/null
> +++ b/drivers/misc/mux-core.c
> @@ -0,0 +1,311 @@
> +/*
> + * Multiplexer subsystem
> + *
> + * Copyright (C) 2016 Axentia Technologies AB
> + *
> + * Author: Peter Rosin <peda@axentia.se>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#define pr_fmt(fmt) "mux-core: " fmt
> +
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/idr.h>
> +#include <linux/module.h>
> +#include <linux/mux.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/slab.h>
> +
> +static struct class mux_class = {
> +	.name = "mux",
> +	.owner = THIS_MODULE,
> +};
> +
> +static int __init mux_init(void)
> +{
> +	return class_register(&mux_class);
> +}
> +
> +static DEFINE_IDA(mux_ida);
> +
> +static void mux_chip_release(struct device *dev)
> +{
> +	struct mux_chip *mux_chip = to_mux_chip(dev);
> +
> +	ida_simple_remove(&mux_ida, mux_chip->id);
> +	kfree(mux_chip);
> +}
> +
> +static struct device_type mux_type = {
> +	.name = "mux-chip",
> +	.release = mux_chip_release,
> +};
> +
> +struct mux_chip *mux_chip_alloc(struct device *dev,
> +				unsigned int controllers, size_t sizeof_priv)
> +{
> +	struct mux_chip *mux_chip;
> +	int i;
> +
> +	if (!dev || !controllers)
> +		return NULL;
> +
> +	mux_chip = kzalloc(sizeof(*mux_chip) +
> +			   controllers * sizeof(*mux_chip->mux) +
> +			   sizeof_priv, GFP_KERNEL);
> +	if (!mux_chip)
> +		return NULL;
> +
> +	mux_chip->mux = (struct mux_control *)(mux_chip + 1);
> +	mux_chip->dev.class = &mux_class;
> +	mux_chip->dev.type = &mux_type;
> +	mux_chip->dev.parent = dev;
> +	mux_chip->dev.of_node = dev->of_node;
> +	dev_set_drvdata(&mux_chip->dev, mux_chip);
> +
> +	mux_chip->id = ida_simple_get(&mux_ida, 0, 0, GFP_KERNEL);
> +	if (mux_chip->id < 0) {
> +		pr_err("muxchipX failed to get a device id\n");
> +		kfree(mux_chip);
> +		return NULL;
> +	}
> +	dev_set_name(&mux_chip->dev, "muxchip%d", mux_chip->id);
> +
> +	mux_chip->controllers = controllers;
> +	for (i = 0; i < controllers; ++i) {
> +		struct mux_control *mux = &mux_chip->mux[i];
> +
> +		mux->chip = mux_chip;
> +		init_rwsem(&mux->lock);
> +		mux->cached_state = -1;
> +		mux->idle_state = -1;
> +	}
> +
> +	device_initialize(&mux_chip->dev);
> +
> +	return mux_chip;
> +}
> +EXPORT_SYMBOL_GPL(mux_chip_alloc);
> +
> +static int mux_control_set(struct mux_control *mux, int state)
> +{
> +	int ret = mux->chip->ops->set(mux, state);
> +
> +	mux->cached_state = ret < 0 ? -1 : state;
> +
> +	return ret;
> +}
> +
> +int mux_chip_register(struct mux_chip *mux_chip)
> +{
> +	int i;
> +	int ret;
> +
> +	for (i = 0; i < mux_chip->controllers; ++i) {
> +		struct mux_control *mux = &mux_chip->mux[i];
> +
> +		if (mux->idle_state == mux->cached_state)
> +			continue;
> +
> +		ret = mux_control_set(mux, mux->idle_state);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return device_add(&mux_chip->dev);
> +}
> +EXPORT_SYMBOL_GPL(mux_chip_register);
> +
> +void mux_chip_unregister(struct mux_chip *mux_chip)
> +{
> +	device_del(&mux_chip->dev);
> +}
> +EXPORT_SYMBOL_GPL(mux_chip_unregister);
> +
> +void mux_chip_free(struct mux_chip *mux_chip)
> +{
> +	if (!mux_chip)
> +		return;
I'd drop a blank line in here. Slightly nicer to read.
> +	put_device(&mux_chip->dev);
> +}
> +EXPORT_SYMBOL_GPL(mux_chip_free);
> +
> +int mux_control_select(struct mux_control *mux, int state)
> +{
> +	int ret;
> +
> +	if (down_read_trylock(&mux->lock)) {
> +		if (mux->cached_state == state)
> +			return 0;
> +
> +		/* Sigh, the mux needs updating... */
> +		up_read(&mux->lock);
> +	}
> +
> +	/* ...or it's just contended. */
> +	down_write(&mux->lock);
> +
> +	if (mux->cached_state == state) {
> +		/*
> +		 * Hmmm, someone else changed the mux to my liking.
> +		 * That makes me wonder how long I waited for nothing?
> +		 */
> +		downgrade_write(&mux->lock);
> +		return 0;
> +	}
> +
> +	ret = mux_control_set(mux, state);
> +	if (ret < 0) {
> +		if (mux->idle_state != -1)
> +			mux_control_set(mux, mux->idle_state);
> +
> +		up_write(&mux->lock);
> +		return ret;
> +	}
> +
> +	downgrade_write(&mux->lock);
> +
> +	return 1;
> +}
> +EXPORT_SYMBOL_GPL(mux_control_select);
> +
> +int mux_control_deselect(struct mux_control *mux)
> +{
> +	int ret = 0;
> +
> +	if (mux->idle_state != -1 && mux->cached_state != mux->idle_state)
> +		ret = mux_control_set(mux, mux->idle_state);
> +
> +	up_read(&mux->lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(mux_control_deselect);
> +
> +static int of_dev_node_match(struct device *dev, const void *data)
> +{
> +	return dev->of_node == data;
> +}
> +
> +static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
> +{
> +	struct device *dev;
> +
> +	dev = class_find_device(&mux_class, NULL, np, of_dev_node_match);
> +
> +	return dev ? to_mux_chip(dev) : NULL;
> +}
> +
> +struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
> +{
> +	struct device_node *np = dev->of_node;
> +	struct of_phandle_args args;
> +	struct mux_chip *mux_chip;
> +	unsigned int controller;
> +	int index = 0;
> +	int ret;
> +
> +	if (mux_name) {
> +		index = of_property_match_string(np, "mux-control-names",
> +						 mux_name);
> +		if (index < 0)
> +			return ERR_PTR(index);
> +	}
> +
> +	ret = of_parse_phandle_with_args(np,
> +					 "mux-controls", "#mux-control-cells",
> +					 index, &args);
> +	if (ret) {
> +		dev_err(dev, "%s: failed to get mux-control %s(%i)\n",
> +			np->full_name, mux_name ?: "", index);
> +		return ERR_PTR(ret);
> +	}
> +
> +	mux_chip = of_find_mux_chip_by_node(args.np);
> +	of_node_put(args.np);
> +	if (!mux_chip)
> +		return ERR_PTR(-EPROBE_DEFER);
> +
> +	if (args.args_count > 1 ||
> +	    (!args.args_count && (mux_chip->controllers > 1))) {
> +		dev_err(dev, "%s: wrong #mux-control-cells for %s\n",
> +			np->full_name, args.np->full_name);
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	controller = 0;
> +	if (args.args_count)
> +		controller = args.args[0];
> +
> +	if (controller >= mux_chip->controllers)
> +		return ERR_PTR(-EINVAL);
> +
> +	get_device(&mux_chip->dev);
> +	return &mux_chip->mux[controller];
> +}
> +EXPORT_SYMBOL_GPL(mux_control_get);
> +
> +void mux_control_put(struct mux_control *mux)
> +{
> +	put_device(&mux->chip->dev);
> +}
> +EXPORT_SYMBOL_GPL(mux_control_put);
> +
> +static void devm_mux_control_release(struct device *dev, void *res)
> +{
> +	struct mux_control *mux = *(struct mux_control **)res;
> +
> +	mux_control_put(mux);
> +}
> +
> +struct mux_control *devm_mux_control_get(struct device *dev,
> +					 const char *mux_name)
> +{
> +	struct mux_control **ptr, *mux;
> +
> +	ptr = devres_alloc(devm_mux_control_release, sizeof(*ptr), GFP_KERNEL);
> +	if (!ptr)
> +		return ERR_PTR(-ENOMEM);
> +
> +	mux = mux_control_get(dev, mux_name);
> +	if (IS_ERR(mux)) {
> +		devres_free(ptr);
> +		return mux;
> +	}
> +
> +	*ptr = mux;
> +	devres_add(dev, ptr);
> +
> +	return mux;
> +}
> +EXPORT_SYMBOL_GPL(devm_mux_control_get);
> +
> +static int devm_mux_control_match(struct device *dev, void *res, void *data)
> +{
> +	struct mux_control **r = res;
> +
> +	if (!r || !*r) {
> +		WARN_ON(!r || !*r);
> +		return 0;
> +	}
> +
> +	return *r == data;
> +}
> +
> +void devm_mux_control_put(struct device *dev, struct mux_control *mux)
> +{
> +	WARN_ON(devres_release(dev, devm_mux_control_release,
> +			       devm_mux_control_match, mux));
> +}
> +EXPORT_SYMBOL_GPL(devm_mux_control_put);
> +
> +subsys_initcall(mux_init);
> +
> +MODULE_DESCRIPTION("Multiplexer subsystem");
> +MODULE_AUTHOR("Peter Rosin <peda@axentia.se");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/misc/mux-gpio.c b/drivers/misc/mux-gpio.c
> new file mode 100644
> index 000000000000..a107a9b96854
> --- /dev/null
> +++ b/drivers/misc/mux-gpio.c
> @@ -0,0 +1,138 @@
> +/*
> + * GPIO-controlled multiplexer driver
> + *
> + * Copyright (C) 2016 Axentia Technologies AB
> + *
> + * Author: Peter Rosin <peda@axentia.se>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/mux.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +
> +struct mux_gpio {
> +	struct gpio_descs *gpios;
> +	int *val;
> +};
> +
> +static int mux_gpio_set(struct mux_control *mux, int state)
> +{
> +	struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip);
> +	int i;
> +
> +	for (i = 0; i < mux_gpio->gpios->ndescs; i++)
> +		mux_gpio->val[i] = (state >> i) & 1;
> +
> +	gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs,
> +				       mux_gpio->gpios->desc,
> +				       mux_gpio->val);
> +
> +	return 0;
> +}
> +
> +static const struct mux_control_ops mux_gpio_ops = {
> +	.set = mux_gpio_set,
> +};
> +
> +static const struct of_device_id mux_gpio_dt_ids[] = {
> +	{ .compatible = "mux-gpio", },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, mux_gpio_dt_ids);
> +
> +static int mux_gpio_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = pdev->dev.of_node;
> +	struct mux_chip *mux_chip;
> +	struct mux_gpio *mux_gpio;
> +	int pins;
> +	u32 idle_state;
> +	int ret;
> +
> +	if (!np)
> +		return -ENODEV;
> +
> +	pins = gpiod_count(dev, "mux");
> +	if (pins < 0)
> +		return pins;
> +
> +	mux_chip = mux_chip_alloc(dev, 1, sizeof(*mux_gpio) +
> +				  pins * sizeof(*mux_gpio->val));
> +	if (!mux_chip)
> +		return -ENOMEM;
Rather feels like mux_chip_alloc is a good candidate for a managed
allocator. Might be worth doing the register as well then the remove
below would go away.  I guess perhaps not that worthwhile as not many
mux types are likely to ever exist...
> +
> +	mux_gpio = mux_chip_priv(mux_chip);
> +	mux_gpio->val = (int *)(mux_gpio + 1);
> +	mux_chip->ops = &mux_gpio_ops;
> +
> +	platform_set_drvdata(pdev, mux_chip);
> +
> +	mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW);
> +	if (IS_ERR(mux_gpio->gpios)) {
> +		ret = PTR_ERR(mux_gpio->gpios);
> +		if (ret != -EPROBE_DEFER)
> +			dev_err(dev, "failed to get gpios\n");
> +		goto free_mux_chip;
> +	}
> +	WARN_ON(pins != mux_gpio->gpios->ndescs);
> +	mux_chip->mux->states = 1 << pins;
> +
> +	ret = of_property_read_u32(np, "idle-state", &idle_state);
> +	if (ret >= 0) {
> +		if (idle_state >= mux_chip->mux->states) {
> +			dev_err(dev, "invalid idle-state %u\n", idle_state);
> +			ret = -EINVAL;
> +			goto free_mux_chip;
> +		}
> +
> +		mux_chip->mux->idle_state = idle_state;
> +	}
> +
> +	ret = mux_chip_register(mux_chip);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to register mux-chip\n");
> +		goto free_mux_chip;
> +	}
> +
> +	dev_info(dev, "%u-way mux-controller registered\n",
> +		 mux_chip->mux->states);
> +
> +	return 0;
> +
> +free_mux_chip:
> +	mux_chip_free(mux_chip);
> +	return ret;
> +}
> +
> +static int mux_gpio_remove(struct platform_device *pdev)
> +{
> +	struct mux_chip *mux_chip = platform_get_drvdata(pdev);
> +
> +	mux_chip_unregister(mux_chip);
> +	mux_chip_free(mux_chip);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver mux_gpio_driver = {
> +	.driver = {
> +		.name = "mux-gpio",
> +		.of_match_table	= of_match_ptr(mux_gpio_dt_ids),
> +	},
> +	.probe = mux_gpio_probe,
> +	.remove = mux_gpio_remove,
> +};
> +module_platform_driver(mux_gpio_driver);
> +
> +MODULE_DESCRIPTION("GPIO-controlled multiplexer driver");
> +MODULE_AUTHOR("Peter Rosin <peda@axentia.se");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/mux.h b/include/linux/mux.h
> new file mode 100644
> index 000000000000..88d607b7fde7
> --- /dev/null
> +++ b/include/linux/mux.h
> @@ -0,0 +1,197 @@
> +/*
> + * mux.h - definitions for the multiplexer interface
> + *
> + * Copyright (C) 2016 Axentia Technologies AB
> + *
> + * Author: Peter Rosin <peda@axentia.se>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef _LINUX_MUX_H
> +#define _LINUX_MUX_H
> +
> +#include <linux/device.h>
> +#include <linux/rwsem.h>
> +
> +struct mux_chip;
> +struct mux_control;
> +struct platform_device;
> +
> +struct mux_control_ops {
> +	int (*set)(struct mux_control *mux, int state);
> +};
> +
> +/**
> + * struct mux_control - Represents a mux controller.
> + * @lock:		Protects the mux controller state.
> + * @chip:		The mux chip that is handling this mux controller.
> + * @states:		The number of mux controller states.
> + * @cached_state:	The current mux controller state, or -1 if none.
> + * @idle_state:		The mux controller state to use when inactive, or -1
> + *			for none.
> + */
> +struct mux_control {
> +	struct rw_semaphore lock; /* protects the state of the mux */
> +
> +	struct mux_chip *chip;
> +
> +	unsigned int states;
> +	int cached_state;
> +	int idle_state;
> +};
> +
> +/**
> + * struct mux_chip -	Represents a chip holding mux controllers.
> + * @controllers:	Number of mux controllers handled by the chip.
> + * @mux:		Array of mux controllers that is handled.
> + * @dev:		Device structure.
> + * @id:			Used to identify the device internally.
> + * @ops:		Mux controller operations.
> + */
> +struct mux_chip {
> +	unsigned int controllers;
> +	struct mux_control *mux;
> +	struct device dev;
> +	int id;
> +
> +	const struct mux_control_ops *ops;
> +};
> +
> +#define to_mux_chip(x) container_of((x), struct mux_chip, dev)
> +
> +/**
> + * mux_chip_priv() - Get the extra memory reserved by mux_chip_alloc().
> + * @mux_chip: The mux-chip to get the private memory from.
> + *
> + * Return: Pointer to the private memory reserved by the allocator.
> + */
> +static inline void *mux_chip_priv(struct mux_chip *mux_chip)
> +{
> +	return &mux_chip->mux[mux_chip->controllers];
> +}
> +
> +/**
> + * mux_chip_alloc() - Allocate a mux-chip.
> + * @dev: The parent device implementing the mux interface.
> + * @controllers: The number of mux controllers to allocate for this chip.
> + * @sizeof_priv: Size of extra memory area for private use by the caller.
> + *
> + * Return: A pointer to the new mux-chip, NULL on failure.
> + */
> +struct mux_chip *mux_chip_alloc(struct device *dev,
> +				unsigned int controllers, size_t sizeof_priv);
> +
> +/**
> + * mux_chip_register() - Register a mux-chip, thus readying the controllers
> + *			 for use.
> + * @mux_chip: The mux-chip to register.
> + *
> + * Do not retry registration of the same mux-chip on failure. You should
> + * instead put it away with mux_chip_free() and allocate a new one, if you
> + * for some reason would like to retry registration.
> + *
> + * Return: Zero on success or a negative errno on error.
> + */
> +int mux_chip_register(struct mux_chip *mux_chip);
> +
> +/**
> + * mux_chip_unregister() - Take the mux-chip off-line.
> + * @mux_chip: The mux-chip to unregister.
> + *
> + * mux_chip_unregister() reverses the effects of mux_chip_register().
> + * But not completely, you should not try to call mux_chip_register()
> + * on a mux-chip that has been registered before.
> + */
> +void mux_chip_unregister(struct mux_chip *mux_chip);
> +
> +/**
> + * mux_chip_free() - Free the mux-chip for good.
> + * @mux_chip: The mux-chip to free.
> + *
> + * mux_chip_free() reverses the effects of mux_chip_alloc().
> + */
> +void mux_chip_free(struct mux_chip *mux_chip);
> +
> +/**
> + * mux_control_select() - Select the given multiplexer state.
> + * @mux: The mux-control to request a change of state from.
> + * @state: The new requested state.
> + *
> + * Make sure to call mux_control_deselect() when the operation is complete and
> + * the mux-control is free for others to use, but do not call
> + * mux_control_deselect() if mux_control_select() fails.
> + *
> + * Return: 0 if the requested state was already active, or 1 it the
> + * mux-control state was changed to the requested state. Or a negavive
> + * errno on error.
> + *
> + * Note that the difference in return value of zero or one is of
> + * questionable value; especially if the mux-control has several independent
> + * consumers, which is something the consumers should perhaps not be making
> + * assumptions about.
> + */
> +int mux_control_select(struct mux_control *mux, int state);
> +
> +/**
> + * mux_control_deselect() - Deselect the previously selected multiplexer state.
> + * @mux: The mux-control to deselect.
> + *
> + * Return: 0 on success and a negative errno on error. An error can only
> + * occur if the mux has an idle state. Note that even if an error occurs, the
> + * mux-control is unlocked for others to access.
> + */
> +int mux_control_deselect(struct mux_control *mux);
> +
> +/**
> + * mux_control_get_index() - Get the index of the given mux controller
> + * @mux: The mux-control to the the index for.
> + *
> + * Return: The index of the mux controller within the mux chip the mux
> + * controller is a part of.
> + */
> +static inline unsigned int mux_control_get_index(struct mux_control *mux)
> +{
> +	return mux - mux->chip->mux;
> +}
> +
> +/**
> + * mux_control_get() - Get the mux-control for a device.
> + * @dev: The device that needs a mux-control.
> + * @mux_name: The name identifying the mux-control.
> + *
> + * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
> + */
> +struct mux_control *mux_control_get(struct device *dev, const char *mux_name);
> +
> +/**
> + * mux_control_put() - Put away the mux-control for good.
> + * @mux: The mux-control to put away.
> + *
> + * mux_control_put() reverses the effects of mux_control_get().
> + */
> +void mux_control_put(struct mux_control *mux);
> +
> +/**
> + * devm_mux_control_get() - Get the mux-control for a device, with resource
> + *			    management.
> + * @dev: The device that needs a mux-control.
> + * @mux_name: The name identifying the mux-control.
> + *
> + * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
> + */
> +struct mux_control *devm_mux_control_get(struct device *dev,
> +					 const char *mux_name);
> +
> +/**
> + * devm_mux_control_put() - Resource-managed version mux_control_put().
> + * @dev: The device that originally got the mux-control.
> + * @mux: The mux-control to put away.
> + *
> + * Note that you do not normally need to call this function.
> + */
> +void devm_mux_control_put(struct device *dev, struct mux_control *mux);
> +
> +#endif /* _LINUX_MUX_H */
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 5/9] iio: multiplexer: new iio category and iio-mux driver
  2016-11-30  8:16   ` Peter Rosin
  (?)
@ 2016-12-31 16:21   ` Jonathan Cameron
  -1 siblings, 0 replies; 58+ messages in thread
From: Jonathan Cameron @ 2016-12-31 16:21 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 30/11/16 08:16, Peter Rosin wrote:
> When a multiplexer changes how an iio device behaves (for example
> by feeding different signals to an ADC), this driver can be used
> to create one virtual iio channel for each multiplexer state.
> 
> Depends on the generic multiplexer subsystem.
> 
> Cache any ext_info values from the parent iio channel, creating a private
> copy of the ext_info attributes for each multiplexer state/channel.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>
Other than binding naming, I'm happy with this - so pending that changing...

Reviewed-by: Jonathan Cameron <jic23@kernel.org>

If it makes sense I can obviously take this via IIO once the core is in
place.

Jonathan
> ---
>  MAINTAINERS                       |   1 +
>  drivers/iio/Kconfig               |   1 +
>  drivers/iio/Makefile              |   1 +
>  drivers/iio/multiplexer/Kconfig   |  18 ++
>  drivers/iio/multiplexer/Makefile  |   6 +
>  drivers/iio/multiplexer/iio-mux.c | 456 ++++++++++++++++++++++++++++++++++++++
>  6 files changed, 483 insertions(+)
>  create mode 100644 drivers/iio/multiplexer/Kconfig
>  create mode 100644 drivers/iio/multiplexer/Makefile
>  create mode 100644 drivers/iio/multiplexer/iio-mux.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 77045ae15865..16490fbd1721 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6239,6 +6239,7 @@ M:	Peter Rosin <peda@axentia.se>
>  L:	linux-iio@vger.kernel.org
>  S:	Maintained
>  F:	Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
> +F:	drivers/iio/multiplexer/iio-mux.c
>  
>  IIO SUBSYSTEM AND DRIVERS
>  M:	Jonathan Cameron <jic23@kernel.org>
> diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
> index a918270d6f54..b3c8c6ef0dff 100644
> --- a/drivers/iio/Kconfig
> +++ b/drivers/iio/Kconfig
> @@ -83,6 +83,7 @@ source "drivers/iio/humidity/Kconfig"
>  source "drivers/iio/imu/Kconfig"
>  source "drivers/iio/light/Kconfig"
>  source "drivers/iio/magnetometer/Kconfig"
> +source "drivers/iio/multiplexer/Kconfig"
>  source "drivers/iio/orientation/Kconfig"
>  if IIO_TRIGGER
>     source "drivers/iio/trigger/Kconfig"
> diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
> index 33fa4026f92c..93c769cd99bf 100644
> --- a/drivers/iio/Makefile
> +++ b/drivers/iio/Makefile
> @@ -28,6 +28,7 @@ obj-y += humidity/
>  obj-y += imu/
>  obj-y += light/
>  obj-y += magnetometer/
> +obj-y += multiplexer/
>  obj-y += orientation/
>  obj-y += potentiometer/
>  obj-y += potentiostat/
> diff --git a/drivers/iio/multiplexer/Kconfig b/drivers/iio/multiplexer/Kconfig
> new file mode 100644
> index 000000000000..70a044510686
> --- /dev/null
> +++ b/drivers/iio/multiplexer/Kconfig
> @@ -0,0 +1,18 @@
> +#
> +# Multiplexer drivers
> +#
> +# When adding new entries keep the list in alphabetical order
> +
> +menu "Multiplexers"
> +
> +config IIO_MUX
> +	tristate "IIO multiplexer driver"
> +	select MULTIPLEXER
> +	depends on OF
> +	help
> +	  Say yes here to build support for the IIO multiplexer.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called iio-mux.
> +
> +endmenu
> diff --git a/drivers/iio/multiplexer/Makefile b/drivers/iio/multiplexer/Makefile
> new file mode 100644
> index 000000000000..68be3c4abd07
> --- /dev/null
> +++ b/drivers/iio/multiplexer/Makefile
> @@ -0,0 +1,6 @@
> +#
> +# Makefile for industrial I/O multiplexer drivers
> +#
> +
> +# When adding new entries keep the list in alphabetical order
> +obj-$(CONFIG_IIO_MUX) += iio-mux.o
> diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c
> new file mode 100644
> index 000000000000..92dfee2dfed1
> --- /dev/null
> +++ b/drivers/iio/multiplexer/iio-mux.c
> @@ -0,0 +1,456 @@
> +/*
> + * IIO multiplexer driver
> + *
> + * Copyright (C) 2016 Axentia Technologies AB
> + *
> + * Author: Peter Rosin <peda@axentia.se>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/iio/consumer.h>
> +#include <linux/iio/iio.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/mux.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +
> +struct mux_ext_info_cache {
> +	char *data;
> +	size_t size;
> +};
> +
> +struct mux_child {
> +	struct mux_ext_info_cache *ext_info_cache;
> +};
> +
> +struct mux {
> +	int cached_state;
> +	struct mux_control *control;
> +	struct iio_channel *parent;
> +	struct iio_dev *indio_dev;
> +	struct iio_chan_spec *chan;
> +	struct iio_chan_spec_ext_info *ext_info;
> +	struct mux_child *child;
> +};
> +
> +static int iio_mux_select(struct mux *mux, int idx)
> +{
> +	struct mux_child *child = &mux->child[idx];
> +	struct iio_chan_spec const *chan = &mux->chan[idx];
> +	int ret;
> +	int i;
> +
> +	ret = mux_control_select(mux->control, chan->channel);
> +	if (ret < 0) {
> +		mux->cached_state = -1;
> +		return ret;
> +	}
> +
> +	if (mux->cached_state == chan->channel)
> +		return 0;
> +
> +	if (chan->ext_info) {
> +		for (i = 0; chan->ext_info[i].name; ++i) {
> +			const char *attr = chan->ext_info[i].name;
> +			struct mux_ext_info_cache *cache;
> +
> +			cache = &child->ext_info_cache[i];
> +
> +			if (cache->size < 0)
> +				continue;
> +
> +			ret = iio_write_channel_ext_info(mux->parent, attr,
> +							 cache->data,
> +							 cache->size);
> +
> +			if (ret < 0) {
> +				mux_control_deselect(mux->control);
> +				mux->cached_state = -1;
> +				return ret;
> +			}
> +		}
> +	}
> +	mux->cached_state = chan->channel;
> +
> +	return 0;
> +}
> +
> +static void iio_mux_deselect(struct mux *mux)
> +{
> +	mux_control_deselect(mux->control);
> +}
> +
> +static int mux_read_raw(struct iio_dev *indio_dev,
> +			struct iio_chan_spec const *chan,
> +			int *val, int *val2, long mask)
> +{
> +	struct mux *mux = iio_priv(indio_dev);
> +	int idx = chan - mux->chan;
> +	int ret;
> +
> +	ret = iio_mux_select(mux, idx);
> +	if (ret < 0)
> +		return ret;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		ret = iio_read_channel_raw(mux->parent, val);
> +		break;
> +
> +	case IIO_CHAN_INFO_SCALE:
> +		ret = iio_read_channel_scale(mux->parent, val, val2);
> +		break;
> +
> +	default:
> +		ret = -EINVAL;
> +	}
> +
> +	iio_mux_deselect(mux);
> +
> +	return ret;
> +}
> +
> +static int mux_read_avail(struct iio_dev *indio_dev,
> +			  struct iio_chan_spec const *chan,
> +			  const int **vals, int *type, int *length,
> +			  long mask)
> +{
> +	struct mux *mux = iio_priv(indio_dev);
> +	int idx = chan - mux->chan;
> +	int ret;
> +
> +	ret = iio_mux_select(mux, idx);
> +	if (ret < 0)
> +		return ret;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		*type = IIO_VAL_INT;
> +		ret = iio_read_avail_channel_raw(mux->parent, vals, length);
> +		break;
> +
> +	default:
> +		ret = -EINVAL;
> +	}
> +
> +	iio_mux_deselect(mux);
> +
> +	return ret;
> +}
> +
> +static int mux_write_raw(struct iio_dev *indio_dev,
> +			 struct iio_chan_spec const *chan,
> +			 int val, int val2, long mask)
> +{
> +	struct mux *mux = iio_priv(indio_dev);
> +	int idx = chan - mux->chan;
> +	int ret;
> +
> +	ret = iio_mux_select(mux, idx);
> +	if (ret < 0)
> +		return ret;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		ret = iio_write_channel_raw(mux->parent, val);
> +		break;
> +
> +	default:
> +		ret = -EINVAL;
> +	}
> +
> +	iio_mux_deselect(mux);
> +
> +	return ret;
> +}
> +
> +static const struct iio_info mux_info = {
> +	.read_raw = mux_read_raw,
> +	.read_avail = mux_read_avail,
> +	.write_raw = mux_write_raw,
> +	.driver_module = THIS_MODULE,
> +};
> +
> +static ssize_t mux_read_ext_info(struct iio_dev *indio_dev, uintptr_t private,
> +				 struct iio_chan_spec const *chan, char *buf)
> +{
> +	struct mux *mux = iio_priv(indio_dev);
> +	int idx = chan - mux->chan;
> +	ssize_t ret;
> +
> +	ret = iio_mux_select(mux, idx);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = iio_read_channel_ext_info(mux->parent,
> +					mux->ext_info[private].name,
> +					buf);
> +
> +	iio_mux_deselect(mux);
> +
> +	return ret;
> +}
> +
> +static ssize_t mux_write_ext_info(struct iio_dev *indio_dev, uintptr_t private,
> +				  struct iio_chan_spec const *chan,
> +				  const char *buf, size_t len)
> +{
> +	struct device *dev = indio_dev->dev.parent;
> +	struct mux *mux = iio_priv(indio_dev);
> +	int idx = chan - mux->chan;
> +	char *new;
> +	ssize_t ret;
> +
> +	ret = iio_mux_select(mux, idx);
> +	if (ret < 0)
> +		return ret;
> +
> +	new = devm_kmemdup(dev, buf, len + 1, GFP_KERNEL);
> +	if (!new) {
> +		iio_mux_deselect(mux);
> +		return -ENOMEM;
> +	}
> +
> +	new[len] = 0;
> +
> +	ret = iio_write_channel_ext_info(mux->parent,
> +					 mux->ext_info[private].name,
> +					 buf, len);
> +	if (ret < 0) {
> +		iio_mux_deselect(mux);
> +		devm_kfree(dev, new);
> +		return ret;
> +	}
> +
> +	devm_kfree(dev, mux->child[idx].ext_info_cache[private].data);
> +	mux->child[idx].ext_info_cache[private].data = new;
> +	mux->child[idx].ext_info_cache[private].size = len;
> +
> +	iio_mux_deselect(mux);
> +
> +	return ret;
> +}
> +
> +static int mux_configure_channel(struct device *dev, struct mux *mux,
> +				 u32 state, const char *label, int idx)
> +{
> +	struct mux_child *child = &mux->child[idx];
> +	struct iio_chan_spec *chan = &mux->chan[idx];
> +	struct iio_chan_spec const *pchan = mux->parent->channel;
> +	char *page = NULL;
> +	int num_ext_info;
> +	int i;
> +	int ret;
> +
> +	chan->indexed = 1;
> +	chan->output = pchan->output;
> +	chan->datasheet_name = label;
> +	chan->ext_info = mux->ext_info;
> +
> +	ret = iio_get_channel_type(mux->parent, &chan->type);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to get parent channel type\n");
> +		return ret;
> +	}
> +
> +	if (iio_channel_has_info(pchan, IIO_CHAN_INFO_RAW))
> +		chan->info_mask_separate |= BIT(IIO_CHAN_INFO_RAW);
> +	if (iio_channel_has_info(pchan, IIO_CHAN_INFO_SCALE))
> +		chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE);
> +
> +	if (iio_channel_has_available(pchan, IIO_CHAN_INFO_RAW))
> +		chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_RAW);
> +
> +	if (state >= mux->control->states) {
> +		dev_err(dev, "too many channels\n");
> +		return -EINVAL;
> +	}
> +
> +	chan->channel = state;
> +
> +	num_ext_info = iio_get_channel_ext_info_count(mux->parent);
> +	if (num_ext_info) {
> +		page = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL);
> +		if (!page)
> +			return -ENOMEM;
> +	}
> +	child->ext_info_cache = devm_kzalloc(dev,
> +					     sizeof(*child->ext_info_cache) *
> +					     num_ext_info, GFP_KERNEL);
> +	for (i = 0; i < num_ext_info; ++i) {
> +		child->ext_info_cache[i].size = -1;
> +
> +		if (!pchan->ext_info[i].write)
> +			continue;
> +		if (!pchan->ext_info[i].read)
> +			continue;
> +
> +		ret = iio_read_channel_ext_info(mux->parent,
> +						mux->ext_info[i].name,
> +						page);
> +		if (ret < 0) {
> +			dev_err(dev, "failed to get ext_info '%s'\n",
> +				pchan->ext_info[i].name);
> +			return ret;
> +		}
> +		if (ret >= PAGE_SIZE) {
> +			dev_err(dev, "too large ext_info '%s'\n",
> +				pchan->ext_info[i].name);
> +			return -EINVAL;
> +		}
> +
> +		child->ext_info_cache[i].data = devm_kmemdup(dev, page, ret + 1,
> +							     GFP_KERNEL);
> +		child->ext_info_cache[i].data[ret] = 0;
> +		child->ext_info_cache[i].size = ret;
> +	}
> +
> +	if (page)
> +		devm_kfree(dev, page);
> +
> +	return 0;
> +}
> +
> +/*
> + * Same as of_property_for_each_string(), but also keeps track of the
> + * index of each string.
> + */
> +#define of_property_for_each_string_index(np, propname, prop, s, i)	\
> +	for (prop = of_find_property(np, propname, NULL),		\
> +	     s = of_prop_next_string(prop, NULL),			\
> +	     i = 0;							\
> +	     s;								\
> +	     s = of_prop_next_string(prop, s),				\
> +	     i++)
> +
> +static int mux_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = pdev->dev.of_node;
> +	struct iio_dev *indio_dev;
> +	struct iio_channel *parent;
> +	struct mux *mux;
> +	struct property *prop;
> +	const char *label;
> +	u32 state;
> +	int sizeof_ext_info;
> +	int children;
> +	int sizeof_priv;
> +	int i;
> +	int ret;
> +
> +	if (!np)
> +		return -ENODEV;
> +
> +	parent = devm_iio_channel_get(dev, "parent");
> +	if (IS_ERR(parent)) {
> +		if (PTR_ERR(parent) != -EPROBE_DEFER)
> +			dev_err(dev, "failed to get parent channel\n");
> +		return PTR_ERR(parent);
> +	}
> +
> +	sizeof_ext_info = iio_get_channel_ext_info_count(parent);
> +	if (sizeof_ext_info) {
> +		sizeof_ext_info += 1; /* one extra entry for the sentinel */
> +		sizeof_ext_info *= sizeof(*mux->ext_info);
> +	}
> +
> +	children = 0;
> +	of_property_for_each_string(np, "channels", prop, label) {
> +		if (*label)
> +			children++;
> +	}
> +	if (children <= 0) {
> +		dev_err(dev, "not even a single child\n");
> +		return -EINVAL;
> +	}
> +
> +	sizeof_priv = sizeof(*mux);
> +	sizeof_priv += sizeof(*mux->child) * children;
> +	sizeof_priv += sizeof(*mux->chan) * children;
> +	sizeof_priv += sizeof_ext_info;
> +
> +	indio_dev = devm_iio_device_alloc(dev, sizeof_priv);
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	mux = iio_priv(indio_dev);
> +	mux->child = (struct mux_child *)(mux + 1);
> +	mux->chan = (struct iio_chan_spec *)(mux->child + children);
> +
> +	platform_set_drvdata(pdev, indio_dev);
> +
> +	mux->parent = parent;
> +	mux->cached_state = -1;
> +
> +	indio_dev->name = dev_name(dev);
> +	indio_dev->dev.parent = dev;
> +	indio_dev->info = &mux_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = mux->chan;
> +	indio_dev->num_channels = children;
> +	if (sizeof_ext_info) {
> +		mux->ext_info = devm_kmemdup(dev,
> +					     parent->channel->ext_info,
> +					     sizeof_ext_info, GFP_KERNEL);
> +		if (!mux->ext_info)
> +			return -ENOMEM;
> +
> +		for (i = 0; mux->ext_info[i].name; ++i) {
> +			if (parent->channel->ext_info[i].read)
> +				mux->ext_info[i].read = mux_read_ext_info;
> +			if (parent->channel->ext_info[i].write)
> +				mux->ext_info[i].write = mux_write_ext_info;
> +			mux->ext_info[i].private = i;
> +		}
> +	}
> +
> +	mux->control = devm_mux_control_get(dev, NULL);
> +	if (IS_ERR(mux->control)) {
> +		if (PTR_ERR(mux->control) != -EPROBE_DEFER)
> +			dev_err(dev, "failed to get control-mux\n");
> +		return PTR_ERR(mux->control);
> +	}
> +
> +	i = 0;
> +	of_property_for_each_string_index(np, "channels", prop, label, state) {
> +		if (!*label)
> +			continue;
> +
> +		ret = mux_configure_channel(dev, mux, state, label, i++);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	ret = devm_iio_device_register(dev, indio_dev);
> +	if (ret) {
> +		dev_err(dev, "failed to register iio device\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mux_match[] = {
> +	{ .compatible = "iio-mux" },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, mux_match);
> +
> +static struct platform_driver mux_driver = {
> +	.probe = mux_probe,
> +	.driver = {
> +		.name = "iio-mux",
> +		.of_match_table = mux_match,
> +	},
> +};
> +module_platform_driver(mux_driver);
> +
> +MODULE_DESCRIPTION("IIO multiplexer driver");
> +MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
> +MODULE_LICENSE("GPL v2");
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 7/9] i2c: i2c-mux-simple: new driver
@ 2017-01-01 10:31     ` Jonathan Cameron
  0 siblings, 0 replies; 58+ messages in thread
From: Jonathan Cameron @ 2017-01-01 10:31 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 30/11/16 08:17, Peter Rosin wrote:
> This is a generic simple i2c mux that uses the generic multiplexer
> subsystem to do the muxing.
> 
> The user can select if the mux is to be mux-locked and parent-locked
> as described in Documentation/i2c/i2c-topology.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>
Looks good to me though as I haven't really commented on it I'll give
an Ack rather than a reviewed by.

Acked-by: Jonathan Cameron <jic23@kernel.org>
> ---
>  drivers/i2c/muxes/Kconfig          |  13 +++
>  drivers/i2c/muxes/Makefile         |   1 +
>  drivers/i2c/muxes/i2c-mux-simple.c | 179 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 193 insertions(+)
>  create mode 100644 drivers/i2c/muxes/i2c-mux-simple.c
> 
> diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
> index 10b3d17ae3ea..565921e09a96 100644
> --- a/drivers/i2c/muxes/Kconfig
> +++ b/drivers/i2c/muxes/Kconfig
> @@ -73,6 +73,19 @@ config I2C_MUX_REG
>  	  This driver can also be built as a module.  If so, the module
>  	  will be called i2c-mux-reg.
>  
> +config I2C_MUX_SIMPLE
> +	tristate "Simple I2C multiplexer"
> +	select MULTIPLEXER
> +	depends on OF
> +	help
> +	  If you say yes to this option, support will be included for a
> +	  simple generic I2C multiplexer. This driver provides access to
> +	  I2C busses connected through a MUX, which is controlled
> +	  by a generic MUX controller.
> +
> +	  This driver can also be built as a module.  If so, the module
> +	  will be called i2c-mux-simple.
> +
>  config I2C_DEMUX_PINCTRL
>  	tristate "pinctrl-based I2C demultiplexer"
>  	depends on PINCTRL && OF
> diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
> index 9948fa45037f..6821d95c92a3 100644
> --- a/drivers/i2c/muxes/Makefile
> +++ b/drivers/i2c/muxes/Makefile
> @@ -11,5 +11,6 @@ obj-$(CONFIG_I2C_MUX_PCA9541)	+= i2c-mux-pca9541.o
>  obj-$(CONFIG_I2C_MUX_PCA954x)	+= i2c-mux-pca954x.o
>  obj-$(CONFIG_I2C_MUX_PINCTRL)	+= i2c-mux-pinctrl.o
>  obj-$(CONFIG_I2C_MUX_REG)	+= i2c-mux-reg.o
> +obj-$(CONFIG_I2C_MUX_SIMPLE)	+= i2c-mux-simple.o
>  
>  ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
> diff --git a/drivers/i2c/muxes/i2c-mux-simple.c b/drivers/i2c/muxes/i2c-mux-simple.c
> new file mode 100644
> index 000000000000..4a03493e1ad7
> --- /dev/null
> +++ b/drivers/i2c/muxes/i2c-mux-simple.c
> @@ -0,0 +1,179 @@
> +/*
> + * Generic simple I2C multiplexer
> + *
> + * Copyright (C) 2016 Axentia Technologies AB
> + *
> + * Author: Peter Rosin <peda@axentia.se>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/i2c-mux.h>
> +#include <linux/module.h>
> +#include <linux/mux.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +
> +struct mux {
> +	struct mux_control *control;
> +
> +	bool do_not_deselect;
> +};
> +
> +static int i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
> +{
> +	struct mux *mux = i2c_mux_priv(muxc);
> +	int ret;
> +
> +	ret = mux_control_select(mux->control, chan);
> +	mux->do_not_deselect = ret < 0;
> +
> +	return ret;
> +}
> +
> +static int i2c_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
> +{
> +	struct mux *mux = i2c_mux_priv(muxc);
> +
> +	if (mux->do_not_deselect)
> +		return 0;
> +
> +	return mux_control_deselect(mux->control);
> +}
> +
> +static struct i2c_adapter *mux_parent_adapter(struct device *dev)
> +{
> +	struct device_node *np = dev->of_node;
> +	struct device_node *parent_np;
> +	struct i2c_adapter *parent;
> +
> +	parent_np = of_parse_phandle(np, "i2c-parent", 0);
> +	if (!parent_np) {
> +		dev_err(dev, "Cannot parse i2c-parent\n");
> +		return ERR_PTR(-ENODEV);
> +	}
> +	parent = of_find_i2c_adapter_by_node(parent_np);
> +	of_node_put(parent_np);
> +	if (!parent)
> +		return ERR_PTR(-EPROBE_DEFER);
> +
> +	return parent;
> +}
> +
> +static const struct of_device_id i2c_mux_of_match[] = {
> +	{ .compatible = "i2c-mux-simple,parent-locked",
> +	  .data = (void *)0, },
> +	{ .compatible = "i2c-mux-simple,mux-locked",
> +	  .data = (void *)1, },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, i2c_mux_of_match);
> +
> +static int i2c_mux_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	struct device_node *child;
> +	const struct of_device_id *match;
> +	struct i2c_mux_core *muxc;
> +	struct mux *mux;
> +	struct i2c_adapter *parent;
> +	int children;
> +	int ret;
> +
> +	if (!np)
> +		return -ENODEV;
> +
> +	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
> +	if (!mux)
> +		return -ENOMEM;
> +
> +	mux->control = devm_mux_control_get(dev, NULL);
> +	if (IS_ERR(mux->control)) {
> +		if (PTR_ERR(mux->control) != -EPROBE_DEFER)
> +			dev_err(dev, "failed to get control-mux\n");
> +		return PTR_ERR(mux->control);
> +	}
> +
> +	parent = mux_parent_adapter(dev);
> +	if (IS_ERR(parent)) {
> +		if (PTR_ERR(parent) != -EPROBE_DEFER)
> +			dev_err(dev, "failed to get i2c-parent adapter\n");
> +		return PTR_ERR(parent);
> +	}
> +
> +	children = of_get_child_count(np);
> +
> +	muxc = i2c_mux_alloc(parent, dev, children, 0, 0,
> +			     i2c_mux_select, i2c_mux_deselect);
> +	if (!muxc) {
> +		ret = -ENOMEM;
> +		goto err_parent;
> +	}
> +	muxc->priv = mux;
> +
> +	platform_set_drvdata(pdev, muxc);
> +
> +	match = of_match_device(of_match_ptr(i2c_mux_of_match), dev);
> +	if (match)
> +		muxc->mux_locked = !!of_device_get_match_data(dev);
> +
> +	for_each_child_of_node(np, child) {
> +		u32 chan;
> +
> +		ret = of_property_read_u32(child, "reg", &chan);
> +		if (ret < 0) {
> +			dev_err(dev, "no reg property for node '%s'\n",
> +				child->name);
> +			goto err_children;
> +		}
> +
> +		if (chan >= mux->control->states) {
> +			dev_err(dev, "invalid reg %u\n", chan);
> +			ret = -EINVAL;
> +			goto err_children;
> +		}
> +
> +		ret = i2c_mux_add_adapter(muxc, 0, chan, 0);
> +		if (ret)
> +			goto err_children;
> +	}
> +
> +	dev_info(dev, "%d-port mux on %s adapter\n", children, parent->name);
> +
> +	return 0;
> +
> +err_children:
> +	i2c_mux_del_adapters(muxc);
> +err_parent:
> +	i2c_put_adapter(parent);
> +
> +	return ret;
> +}
> +
> +static int i2c_mux_remove(struct platform_device *pdev)
> +{
> +	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
> +
> +	i2c_mux_del_adapters(muxc);
> +	i2c_put_adapter(muxc->parent);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver i2c_mux_driver = {
> +	.probe	= i2c_mux_probe,
> +	.remove	= i2c_mux_remove,
> +	.driver	= {
> +		.name	= "i2c-mux-simple",
> +		.of_match_table = i2c_mux_of_match,
> +	},
> +};
> +module_platform_driver(i2c_mux_driver);
> +
> +MODULE_DESCRIPTION("Simple I2C multiplexer driver");
> +MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
> +MODULE_LICENSE("GPL v2");
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 7/9] i2c: i2c-mux-simple: new driver
@ 2017-01-01 10:31     ` Jonathan Cameron
  0 siblings, 0 replies; 58+ messages in thread
From: Jonathan Cameron @ 2017-01-01 10:31 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

On 30/11/16 08:17, Peter Rosin wrote:
> This is a generic simple i2c mux that uses the generic multiplexer
> subsystem to do the muxing.
> 
> The user can select if the mux is to be mux-locked and parent-locked
> as described in Documentation/i2c/i2c-topology.
> 
> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
Looks good to me though as I haven't really commented on it I'll give
an Ack rather than a reviewed by.

Acked-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> ---
>  drivers/i2c/muxes/Kconfig          |  13 +++
>  drivers/i2c/muxes/Makefile         |   1 +
>  drivers/i2c/muxes/i2c-mux-simple.c | 179 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 193 insertions(+)
>  create mode 100644 drivers/i2c/muxes/i2c-mux-simple.c
> 
> diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
> index 10b3d17ae3ea..565921e09a96 100644
> --- a/drivers/i2c/muxes/Kconfig
> +++ b/drivers/i2c/muxes/Kconfig
> @@ -73,6 +73,19 @@ config I2C_MUX_REG
>  	  This driver can also be built as a module.  If so, the module
>  	  will be called i2c-mux-reg.
>  
> +config I2C_MUX_SIMPLE
> +	tristate "Simple I2C multiplexer"
> +	select MULTIPLEXER
> +	depends on OF
> +	help
> +	  If you say yes to this option, support will be included for a
> +	  simple generic I2C multiplexer. This driver provides access to
> +	  I2C busses connected through a MUX, which is controlled
> +	  by a generic MUX controller.
> +
> +	  This driver can also be built as a module.  If so, the module
> +	  will be called i2c-mux-simple.
> +
>  config I2C_DEMUX_PINCTRL
>  	tristate "pinctrl-based I2C demultiplexer"
>  	depends on PINCTRL && OF
> diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
> index 9948fa45037f..6821d95c92a3 100644
> --- a/drivers/i2c/muxes/Makefile
> +++ b/drivers/i2c/muxes/Makefile
> @@ -11,5 +11,6 @@ obj-$(CONFIG_I2C_MUX_PCA9541)	+= i2c-mux-pca9541.o
>  obj-$(CONFIG_I2C_MUX_PCA954x)	+= i2c-mux-pca954x.o
>  obj-$(CONFIG_I2C_MUX_PINCTRL)	+= i2c-mux-pinctrl.o
>  obj-$(CONFIG_I2C_MUX_REG)	+= i2c-mux-reg.o
> +obj-$(CONFIG_I2C_MUX_SIMPLE)	+= i2c-mux-simple.o
>  
>  ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
> diff --git a/drivers/i2c/muxes/i2c-mux-simple.c b/drivers/i2c/muxes/i2c-mux-simple.c
> new file mode 100644
> index 000000000000..4a03493e1ad7
> --- /dev/null
> +++ b/drivers/i2c/muxes/i2c-mux-simple.c
> @@ -0,0 +1,179 @@
> +/*
> + * Generic simple I2C multiplexer
> + *
> + * Copyright (C) 2016 Axentia Technologies AB
> + *
> + * Author: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/i2c-mux.h>
> +#include <linux/module.h>
> +#include <linux/mux.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +
> +struct mux {
> +	struct mux_control *control;
> +
> +	bool do_not_deselect;
> +};
> +
> +static int i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
> +{
> +	struct mux *mux = i2c_mux_priv(muxc);
> +	int ret;
> +
> +	ret = mux_control_select(mux->control, chan);
> +	mux->do_not_deselect = ret < 0;
> +
> +	return ret;
> +}
> +
> +static int i2c_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
> +{
> +	struct mux *mux = i2c_mux_priv(muxc);
> +
> +	if (mux->do_not_deselect)
> +		return 0;
> +
> +	return mux_control_deselect(mux->control);
> +}
> +
> +static struct i2c_adapter *mux_parent_adapter(struct device *dev)
> +{
> +	struct device_node *np = dev->of_node;
> +	struct device_node *parent_np;
> +	struct i2c_adapter *parent;
> +
> +	parent_np = of_parse_phandle(np, "i2c-parent", 0);
> +	if (!parent_np) {
> +		dev_err(dev, "Cannot parse i2c-parent\n");
> +		return ERR_PTR(-ENODEV);
> +	}
> +	parent = of_find_i2c_adapter_by_node(parent_np);
> +	of_node_put(parent_np);
> +	if (!parent)
> +		return ERR_PTR(-EPROBE_DEFER);
> +
> +	return parent;
> +}
> +
> +static const struct of_device_id i2c_mux_of_match[] = {
> +	{ .compatible = "i2c-mux-simple,parent-locked",
> +	  .data = (void *)0, },
> +	{ .compatible = "i2c-mux-simple,mux-locked",
> +	  .data = (void *)1, },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, i2c_mux_of_match);
> +
> +static int i2c_mux_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	struct device_node *child;
> +	const struct of_device_id *match;
> +	struct i2c_mux_core *muxc;
> +	struct mux *mux;
> +	struct i2c_adapter *parent;
> +	int children;
> +	int ret;
> +
> +	if (!np)
> +		return -ENODEV;
> +
> +	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
> +	if (!mux)
> +		return -ENOMEM;
> +
> +	mux->control = devm_mux_control_get(dev, NULL);
> +	if (IS_ERR(mux->control)) {
> +		if (PTR_ERR(mux->control) != -EPROBE_DEFER)
> +			dev_err(dev, "failed to get control-mux\n");
> +		return PTR_ERR(mux->control);
> +	}
> +
> +	parent = mux_parent_adapter(dev);
> +	if (IS_ERR(parent)) {
> +		if (PTR_ERR(parent) != -EPROBE_DEFER)
> +			dev_err(dev, "failed to get i2c-parent adapter\n");
> +		return PTR_ERR(parent);
> +	}
> +
> +	children = of_get_child_count(np);
> +
> +	muxc = i2c_mux_alloc(parent, dev, children, 0, 0,
> +			     i2c_mux_select, i2c_mux_deselect);
> +	if (!muxc) {
> +		ret = -ENOMEM;
> +		goto err_parent;
> +	}
> +	muxc->priv = mux;
> +
> +	platform_set_drvdata(pdev, muxc);
> +
> +	match = of_match_device(of_match_ptr(i2c_mux_of_match), dev);
> +	if (match)
> +		muxc->mux_locked = !!of_device_get_match_data(dev);
> +
> +	for_each_child_of_node(np, child) {
> +		u32 chan;
> +
> +		ret = of_property_read_u32(child, "reg", &chan);
> +		if (ret < 0) {
> +			dev_err(dev, "no reg property for node '%s'\n",
> +				child->name);
> +			goto err_children;
> +		}
> +
> +		if (chan >= mux->control->states) {
> +			dev_err(dev, "invalid reg %u\n", chan);
> +			ret = -EINVAL;
> +			goto err_children;
> +		}
> +
> +		ret = i2c_mux_add_adapter(muxc, 0, chan, 0);
> +		if (ret)
> +			goto err_children;
> +	}
> +
> +	dev_info(dev, "%d-port mux on %s adapter\n", children, parent->name);
> +
> +	return 0;
> +
> +err_children:
> +	i2c_mux_del_adapters(muxc);
> +err_parent:
> +	i2c_put_adapter(parent);
> +
> +	return ret;
> +}
> +
> +static int i2c_mux_remove(struct platform_device *pdev)
> +{
> +	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
> +
> +	i2c_mux_del_adapters(muxc);
> +	i2c_put_adapter(muxc->parent);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver i2c_mux_driver = {
> +	.probe	= i2c_mux_probe,
> +	.remove	= i2c_mux_remove,
> +	.driver	= {
> +		.name	= "i2c-mux-simple",
> +		.of_match_table = i2c_mux_of_match,
> +	},
> +};
> +module_platform_driver(i2c_mux_driver);
> +
> +MODULE_DESCRIPTION("Simple I2C multiplexer driver");
> +MODULE_AUTHOR("Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>");
> +MODULE_LICENSE("GPL v2");
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 8/9] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
  2016-11-30  8:17   ` Peter Rosin
  (?)
@ 2017-01-01 11:00   ` Jonathan Cameron
  2017-01-02 16:01     ` Peter Rosin
  -1 siblings, 1 reply; 58+ messages in thread
From: Jonathan Cameron @ 2017-01-01 11:00 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 30/11/16 08:17, Peter Rosin wrote:
> Analog Devices ADG792A/G is a triple 4:1 mux.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>
Few comments inline.  Worth adding anything about the gpio (output pins) to
the binding at this stage as well?  Would certainly be nice to support
them.

Jonathan
> ---
>  .../devicetree/bindings/misc/mux-adg792a.txt       | 64 ++++++++++++++++++++++
>  1 file changed, 64 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/misc/mux-adg792a.txt
> 
> diff --git a/Documentation/devicetree/bindings/misc/mux-adg792a.txt b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
> new file mode 100644
> index 000000000000..4677f9ab1c55
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
> @@ -0,0 +1,64 @@
> +Bindings for Analog Devices ADG792A/G Triple 4:1 Multiplexers
> +
> +Required properties:
> +- compatible : "adi,adg792a" or "adi,adg792g"
> +- #mux-control-cells : <0> if parallel, or <1> if not.
> +* Standard mux-controller bindings as decribed in mux-controller.txt
> +
> +Optional properties:
> +- adi,parallel : if present, the three muxes are bound together with a single
> +  mux controller, controlling all three muxes in parallel.
> +- adi,idle-state : if present, array of states the three mux controllers will
> +  have when idle (or, if parallel, a single idle-state).
Hmm. These are actually a policy decision.  As only one policy will make
sense for a given set of hardware probably fine to have it in here I guess.
Might be worth adding a note to say this though.
> +
> +Mux controller states 0 through 3 correspond to signals A through D in the
> +datasheet. Mux controller states 4 and 5 are only available as possible idle
> +states. State 4 represents that nothing is connected, and state 5 represents
> +that the mux controller keeps the mux in its previously selected state during
> +the idle period. State 5 is the default idle state.
I'm never a great fan of magic numbers.  Can we represent this more cleanly by
breaking it into multiple properties?
Optional:
adi,idle-switch-to-channel : switch to this channel when idle.
adi,idle-high-impedance : <boolean> the nothing connected state?

If neither present leaves it in previous state?
> +
> +Example:
> +
> +	/* three independent mux controllers (of which one is used) */
> +	&i2c0 {
> +		mux: adg792a@50 {
> +			compatible = "adi,adg792a";
> +			reg = <0x50>;
> +			#mux-control-cells = <1>;
> +		};
> +	};
> +
> +	adc-mux {
> +		compatible = "iio-mux";
> +		io-channels = <&adc 0>;
> +		io-channel-names = "parent";
> +
> +		mux-controls = <&mux 1>;
> +
> +		channels = "sync-1", "", "out";
> +	};
> +
> +
> +	/*
> +	 * Three parallel muxes with one mux controller, useful e.g. if
> +	 * the adc is differential, thus needing two signals to be muxed
> +	 * simultaneously for correct operation.
> +	 */
> +	&i2c0 {
> +		pmux: adg792a@50 {
> +			compatible = "adi,adg792a";
> +			reg = <0x50>;
> +			#mux-control-cells = <0>;
> +			adi,parallel;
> +		};
> +	};
> +
> +	diff-adc-mux {
> +		compatible = "iio-mux";
> +		io-channels = <&adc 0>;
> +		io-channel-names = "parent";
> +
> +		mux-controls = <&pmux>;
> +
> +		channels = "sync-1", "", "out";
> +	};
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 9/9] misc: mux-adg792a: add mux controller driver for ADG792A/G
  2016-11-30  8:17   ` Peter Rosin
  (?)
@ 2017-01-01 11:24   ` Jonathan Cameron
  2017-01-02 11:00     ` Peter Rosin
  -1 siblings, 1 reply; 58+ messages in thread
From: Jonathan Cameron @ 2017-01-01 11:24 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 30/11/16 08:17, Peter Rosin wrote:
> Analog Devices ADG792A/G is a triple 4:1 mux.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>
Looks pretty good. Some minor suggestions inline.

This convinced me of two things:
1. Need a separate subsystem directory for muxes - having them under misc
is going to lead to long term mess.
2. Devm alloc and registration functions will make the drivers all simpler.

Also, browsing through ADIs list of muxes and switches it's clear that
one classic case will be where an i2c octal or similar switch is used with
outputs wired together in weird combinations to act as a mux.  Going to
be 'fun' describing that.

There are also potentially cross point switches to be described ;)
(I had to look up what one of those was ;)

Crosspoints aren't implausible as front ends for ADCs as you might
want to be able rapidly sample any 2 of say 16 channels coming from
for example a max14661.  We'd have to figure out how to add buffered
capture support with sensible restrictions to the iio-mux driver
to do that - realistically I think we would just not allow buffered
capture with the mux having to switch.  Without hardware support
(i.e. an ADC with external mux control) it would be too slow.

Always good to bury some idle thoughts deep in the review of a random
driver ;) I'll never be able to remember where they were let alone
anyone else.

Jonathan

> ---
>  drivers/misc/Kconfig       |  12 ++++
>  drivers/misc/Makefile      |   1 +
>  drivers/misc/mux-adg792a.c | 154 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 167 insertions(+)
>  create mode 100644 drivers/misc/mux-adg792a.c
> 
> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index 2ce675e410c5..45567a444bbf 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -780,6 +780,18 @@ menuconfig MULTIPLEXER
>  
>  if MULTIPLEXER
>  
> +config MUX_ADG792A
> +	tristate "Analog Devices ADG792A/ADG792G Multiplexers"
> +	depends on I2C
> +	help
> +	  ADG792A and ADG792G Wide Bandwidth Triple 4:1 Multiplexers
> +
> +	  The driver supports both operating the three multiplexers in
> +	  parellel and operating them independently.
parallel
> +
> +	  To compile the driver as a module, choose M here: the module will
> +	  be called mux-adg792a.
> +
>  config MUX_GPIO
>  	tristate "GPIO-controlled Multiplexer"
>  	depends on OF && GPIOLIB
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index 0befa2bba762..10ab8d34c9e5 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -54,6 +54,7 @@ obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
>  obj-$(CONFIG_CXL_BASE)		+= cxl/
>  obj-$(CONFIG_PANEL)             += panel.o
>  obj-$(CONFIG_MULTIPLEXER)      	+= mux-core.o
> +obj-$(CONFIG_MUX_ADG792A)	+= mux-adg792a.o
>  obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
>  
>  lkdtm-$(CONFIG_LKDTM)		+= lkdtm_core.o
> diff --git a/drivers/misc/mux-adg792a.c b/drivers/misc/mux-adg792a.c
> new file mode 100644
> index 000000000000..7d309a78af65
> --- /dev/null
> +++ b/drivers/misc/mux-adg792a.c
> @@ -0,0 +1,154 @@
> +/*
> + * Multiplexer driver for Analog Devices ADG792A/G Triple 4:1 mux
> + *
> + * Copyright (C) 2016 Axentia Technologies AB
> + *
> + * Author: Peter Rosin <peda@axentia.se>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/mux.h>
> +
> +#define ADG792A_LDSW		BIT(0)
> +#define ADG792A_RESET		BIT(1)
> +#define ADG792A_DISABLE(mux)	(0x50 | (mux))
> +#define ADG792A_DISABLE_ALL	(0x5f)
> +#define ADG792A_MUX(mux, state)	(0xc0 | (((mux) + 1) << 2) | (state))
> +#define ADG792A_MUX_ALL(state)	(0xc0 | (state))
> +
> +#define ADG792A_DISABLE_STATE	(4)
> +#define ADG792A_KEEP_STATE	(5)
> +
> +static int adg792a_set(struct mux_control *mux, int state)
> +{
> +	struct i2c_client *i2c = to_i2c_client(mux->chip->dev.parent);
> +	u8 cmd;
> +
> +	if (mux->chip->controllers == 1) {
> +		/* parallel mux controller operation */
> +		if (state == ADG792A_DISABLE_STATE)
> +			cmd = ADG792A_DISABLE_ALL;
> +		else
> +			cmd = ADG792A_MUX_ALL(state);
> +	} else {
> +		unsigned int controller = mux_control_get_index(mux);
> +
> +		if (state == ADG792A_DISABLE_STATE)
> +			cmd = ADG792A_DISABLE(controller);
> +		else
> +			cmd = ADG792A_MUX(controller, state);
> +	}
> +
> +	return i2c_smbus_write_byte_data(i2c, cmd, ADG792A_LDSW);
> +}
> +
> +static const struct mux_control_ops adg792a_ops = {
> +	.set = adg792a_set,
> +};
> +
> +static int adg792a_probe(struct i2c_client *i2c,
> +			 const struct i2c_device_id *id)
> +{
> +	struct device *dev = &i2c->dev;
> +	struct mux_chip *mux_chip;
> +	bool parallel;
> +	int ret;
> +	int i;
> +
> +	parallel = of_property_read_bool(i2c->dev.of_node, "adi,parallel");
> +
> +	mux_chip = mux_chip_alloc(dev, parallel ? 1 : 3, 0);
This makes me wonder if we can have a more generic binding.
mux-poles = 3 vs mux-poles = 1?

> +	if (!mux_chip)
> +		return -ENOMEM;
> +
> +	mux_chip->ops = &adg792a_ops;
> +	dev_set_drvdata(dev, mux_chip);
> +
> +	ret = i2c_smbus_write_byte_data(i2c, ADG792A_DISABLE_ALL,
> +					ADG792A_RESET | ADG792A_LDSW);
> +	if (ret < 0)
> +		goto free_mux_chip;
> +
> +	for (i = 0; i < mux_chip->controllers; ++i) {
> +		struct mux_control *mux = &mux_chip->mux[i];
> +		u32 idle_state;
> +
> +		mux->states = 4;
> +
> +		ret = of_property_read_u32_index(i2c->dev.of_node,
> +						 "adi,idle-state", i,
> +						 &idle_state);
> +		if (ret >= 0) {
> +			if (idle_state > ADG792A_KEEP_STATE) {
> +				dev_err(dev, "invalid idle-state %u\n",
> +					idle_state);
> +				ret = -EINVAL;
> +				goto free_mux_chip;
> +			}
> +			if (idle_state != ADG792A_KEEP_STATE)
> +				mux->idle_state = idle_state;
> +		}
> +	}
> +
> +	ret = mux_chip_register(mux_chip);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to register mux-chip\n");
> +		goto free_mux_chip;
> +	}
> +
> +	if (parallel)
> +		dev_info(dev, "1 triple 4-way mux-controller registered\n");
I'd use the relay / switch standard description for this so 
'triple pole, quadruple throw mux registered'.
> +	else
> +		dev_info(dev, "3 4-way mux-controllers registered\n");
'3x single pole, quadruple throw muxes registered'.
> +
> +	return 0;
> +
> +free_mux_chip:
> +	mux_chip_free(mux_chip);
> +	return ret;
> +}
> +
> +static int adg792a_remove(struct i2c_client *i2c)
> +{
> +	struct mux_chip *mux_chip = dev_get_drvdata(&i2c->dev);
> +
Definitely looking like it's worth managed versions of mux_chip_register and
mux_chip_alloc given this is another case where they would let us get rid
of the remove function entirely.
> +	mux_chip_unregister(mux_chip);
> +	mux_chip_free(mux_chip);
> +
> +	return 0;
> +}
> +
> +static const struct i2c_device_id adg792a_id[] = {
> +	{ .name = "adg792a", },
> +	{ .name = "adg792g", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, adg792a_id);
> +
> +static const struct of_device_id adg792a_of_match[] = {
> +	{ .compatible = "adi,adg792a", },
> +	{ .compatible = "adi,adg792g", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, adg792a_of_match);
> +
> +static struct i2c_driver adg792a_driver = {
> +	.driver		= {
> +		.name		= "adg792a",
> +		.of_match_table = of_match_ptr(adg792a_of_match),
> +	},
> +	.probe		= adg792a_probe,
> +	.remove		= adg792a_remove,
> +	.id_table	= adg792a_id,
> +};
> +module_i2c_driver(adg792a_driver);
> +
> +MODULE_DESCRIPTION("Analog Devices ADG792A/G Triple 4:1 mux driver");
> +MODULE_AUTHOR("Peter Rosin <peda@axentia.se");
> +MODULE_LICENSE("GPL v2");
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 0/9] mux controller abstraction and iio/i2c muxes
@ 2017-01-01 11:28   ` Jonathan Cameron
  0 siblings, 0 replies; 58+ messages in thread
From: Jonathan Cameron @ 2017-01-01 11:28 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 30/11/16 08:16, Peter Rosin wrote:
> Hi!
Just a quick note to encourage people to take a look at this series
if they have the time (I can't talk as it took me almost exactly a
month to take a proper look).

It actually ended up a good deal simpler than I expected so I'm falling
on the side of this making sense rather than pushing all mux complexity
into a 'card driver'.  Covers a lot of cases without a proliferation of
code which is nice.

One addition that may make sense is to provide hooks to allow 'card
drivers' where they are needed. I can certainly conceive of devices
where the complexity does rise to the point where they make sense.
However, we can add them when needed.

Peter, don't give up on this set just yet!

Happy New Year,

Jonathan
> 
> v5 -> v6 changes
> - fix stupidity in mux_chip_priv, mux_gpio_remove and adg792a_remove.
> - change the devicetree bindings for the iio-mux to use a list of strings
>   (channels property) instead of a list children.
> 
> v4 -> v5 changes
> - remove support for fancier dt layouts and go back to the phandle
>   approach from v2 and before, killing the horrible non-working
>   refcounting crap from v4 and avoiding a bunch of life-time issues
>   in v3.
> - introduce the concept of a mux-chip, that can hold one or more
>   mux-controllers (inspired by the pwm subsystem).
> - add dt #mux-control-cells property needed to get to the desired
>   mux controller if a mux chip provides more than one.
> - take away the option to build the mux-core as a module.
> - if the mux controller has an idle state, make sure the mux controller
>   is set up in the idle state initially (when it should be idle).
> - do not use a variable length array on the stack in mux_gpio_set to
>   temporarily store the gpio state, preallocate space instead.
> - fix resource leak on one failure path in mux_gpio_probe.
> - driver for Analog Devices ADG792A/G, literally the first mux chip
>   I found on the Internet with an i2c interface (that was not a
>   dedicated i2c multiplexer like PCA9547) which I used to verify
>   that the abstractions in the mux core are up to the task. Untested,
>   just proof of concept that at least looks pretty and compiles...
> - various touch-ups.
> 
> v3 -> v4 changes
> - rebased onto next-20161122 (depends on recent _available iio changes).
> - added support for having the mux-controller in a child node of a
>   mux-consumer if it is a sole consumer, to hopefully even further satisfy
>   the complaint from Rob (and later Lars-Peter) about dt complexity.
> - the above came at the cost of some rather horrible refcounting code,
>   please review and suggest how it should be done...
> - changed to register a device class instead of a bus.
> - pass in the parent device into mux_control_alloc and require less
>   work from mux-control drivers.
> - changed device names from mux:control%d to mux%d
> - move kernel-doc from mux-core.c to mux.h (and add some bits).
> - give the gpio driver a chance to update all mux pins at once.
> - factor out iio ext_info lookup into new helper function. /Lars-Peter
> - use an unsigned type for the iio ext_info count. /Lars-Peter
> - unified "brag strings" in the file headers.
> 
> v2 -> v3 changes
> - have the mux-controller in the parent node of any mux-controller consumer,
>   to hopefully satisfy complaint from Rob about dt complexity.
> - improve commit message of the mux subsystem commit, making it more
>   general, as requested by Jonathan.
> - remove priv member from struct mux_control and calculate it on the
>   fly. /Jonathan
> - make the function comments in mux-core.c kernel doc. /Jonathan
> - add devm_mux_control_* to Documentation/driver.model/devres.txt. /Jonathan
> - add common dt bindings for mux-controllers, refer to them from the
>   mux-gpio bindings. /Rob
> - clarify how the gpio pins map to the mux state. /Rob
> - separate CONFIG_ variables for the mux core and the mux gpio driver.
> - improve Kconfig help texts.
> - make CONFIG_MUX_GPIO depend on CONFIG_GPIOLIB.
> - keep track of the number of mux states in the mux core.
> - since the iio channel number is used as mux state, it was possible
>   to drop the state member from the mux_child struct.
> - cleanup dt bindings for i2c-mux-simple, it had some of copy-paste
>   problems from ots origin (i2c-mux-gpio).
> - select the mux control subsystem in config for the i2c-mux-simple driver.
> - add entries to MAINTAINERS and my sign-off, I'm now satisfied and know
>   nothing in this to be ashamed of.
> 
> v1 -> v2 changes
> - fixup export of mux_control_put reported by kbuild
> - drop devicetree iio-ext-info property as noted by Lars-Peter,
>   and replace the functionality by exposing all ext_info
>   attributes of the parent channel for each of the muxed
>   channels. A cache on top of that and each muxed channel
>   gets its own view of the ext_info of the parent channel.
> - implement idle-state for muxes
> - clear out the cache on failure in order to force a mux
>   update on the following use
> - cleanup the probe of i2c-mux-simple driver
> - fix a bug in the i2c-mux-simple driver, where failure in
>   the selection of the mux caused a deadlock when the mux
>   was later unconditionally deselected.
> 
> I have a piece of hardware that is using the same 3 GPIO pins
> to control four 8-way muxes. Three of them control ADC lines
> to an ADS1015 chip with an iio driver, and the last one
> controls the SDA line of an i2c bus. We have some deployed
> code to handle this, but you do not want to see it or ever
> hear about it. I'm not sure why I even mention it. Anyway,
> the situation has nagged me to no end for quite some time.
> 
> So, after first getting more intimate with the i2c muxing code
> and later discovering the drivers/iio/inkern.c file and
> writing a couple of drivers making use of it, I came up with
> what I think is an acceptable solution; add a generic mux
> controller driver (and subsystem) that is shared between all
> instances, and combine that with an iio mux driver and a new
> generic i2c mux driver. The new i2c mux I called "simple"
> since it is only hooking the i2c muxing and the new mux
> controller (much like the alsa simple card driver does for ASoC).
> 
> One thing that I would like to do, but don't see a solution
> for, is to move the mux control code that is present in
> various drivers in drivers/i2c/muxes to this new minimalistic
> muxing subsystem, thus converting all present i2c muxes (but
> perhaps not gates and arbitrators) to be i2c-mux-simple muxes.
> 
> I'm using an rwsem to lock a mux, but that isn't really a
> perfect fit. Is there a better locking primitive that I don't
> know about that fits better? I had a mutex at one point, but
> that didn't allow any concurrent accesses at all. At least
> the rwsem allows concurrent access as long as all users
> agree on the mux state, but I suspect that the rwsem will
> degrade to the mutex situation pretty quickly if there is
> any contention.
> 
> Also, the "mux" name feels a bit ambitious, there are many muxes
> in the world, and this tiny bit of code is probably not good
> enough to be a nice fit for all...
> 
> Cheers,
> Peter
> 
> Peter Rosin (9):
>   dt-bindings: document devicetree bindings for mux-controllers and
>     mux-gpio
>   misc: minimal mux subsystem and gpio-based mux controller
>   iio: inkern: api for manipulating ext_info of iio channels
>   dt-bindings: iio: iio-mux: document iio-mux bindings
>   iio: multiplexer: new iio category and iio-mux driver
>   dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
>   i2c: i2c-mux-simple: new driver
>   dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G
>     mux
>   misc: mux-adg792a: add mux controller driver for ADG792A/G
> 
>  .../devicetree/bindings/i2c/i2c-mux-simple.txt     |  81 ++++
>  .../bindings/iio/multiplexer/iio-mux.txt           |  40 ++
>  .../devicetree/bindings/misc/mux-adg792a.txt       |  64 +++
>  .../devicetree/bindings/misc/mux-controller.txt    | 127 ++++++
>  .../devicetree/bindings/misc/mux-gpio.txt          |  68 +++
>  Documentation/driver-model/devres.txt              |   6 +-
>  MAINTAINERS                                        |  14 +
>  drivers/i2c/muxes/Kconfig                          |  13 +
>  drivers/i2c/muxes/Makefile                         |   1 +
>  drivers/i2c/muxes/i2c-mux-simple.c                 | 179 ++++++++
>  drivers/iio/Kconfig                                |   1 +
>  drivers/iio/Makefile                               |   1 +
>  drivers/iio/inkern.c                               |  60 +++
>  drivers/iio/multiplexer/Kconfig                    |  18 +
>  drivers/iio/multiplexer/Makefile                   |   6 +
>  drivers/iio/multiplexer/iio-mux.c                  | 456 +++++++++++++++++++++
>  drivers/misc/Kconfig                               |  42 ++
>  drivers/misc/Makefile                              |   3 +
>  drivers/misc/mux-adg792a.c                         | 154 +++++++
>  drivers/misc/mux-core.c                            | 311 ++++++++++++++
>  drivers/misc/mux-gpio.c                            | 138 +++++++
>  include/linux/iio/consumer.h                       |  37 ++
>  include/linux/mux.h                                | 197 +++++++++
>  23 files changed, 2016 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-simple.txt
>  create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>  create mode 100644 Documentation/devicetree/bindings/misc/mux-adg792a.txt
>  create mode 100644 Documentation/devicetree/bindings/misc/mux-controller.txt
>  create mode 100644 Documentation/devicetree/bindings/misc/mux-gpio.txt
>  create mode 100644 drivers/i2c/muxes/i2c-mux-simple.c
>  create mode 100644 drivers/iio/multiplexer/Kconfig
>  create mode 100644 drivers/iio/multiplexer/Makefile
>  create mode 100644 drivers/iio/multiplexer/iio-mux.c
>  create mode 100644 drivers/misc/mux-adg792a.c
>  create mode 100644 drivers/misc/mux-core.c
>  create mode 100644 drivers/misc/mux-gpio.c
>  create mode 100644 include/linux/mux.h
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 0/9] mux controller abstraction and iio/i2c muxes
@ 2017-01-01 11:28   ` Jonathan Cameron
  0 siblings, 0 replies; 58+ messages in thread
From: Jonathan Cameron @ 2017-01-01 11:28 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

On 30/11/16 08:16, Peter Rosin wrote:
> Hi!
Just a quick note to encourage people to take a look at this series
if they have the time (I can't talk as it took me almost exactly a
month to take a proper look).

It actually ended up a good deal simpler than I expected so I'm falling
on the side of this making sense rather than pushing all mux complexity
into a 'card driver'.  Covers a lot of cases without a proliferation of
code which is nice.

One addition that may make sense is to provide hooks to allow 'card
drivers' where they are needed. I can certainly conceive of devices
where the complexity does rise to the point where they make sense.
However, we can add them when needed.

Peter, don't give up on this set just yet!

Happy New Year,

Jonathan
> 
> v5 -> v6 changes
> - fix stupidity in mux_chip_priv, mux_gpio_remove and adg792a_remove.
> - change the devicetree bindings for the iio-mux to use a list of strings
>   (channels property) instead of a list children.
> 
> v4 -> v5 changes
> - remove support for fancier dt layouts and go back to the phandle
>   approach from v2 and before, killing the horrible non-working
>   refcounting crap from v4 and avoiding a bunch of life-time issues
>   in v3.
> - introduce the concept of a mux-chip, that can hold one or more
>   mux-controllers (inspired by the pwm subsystem).
> - add dt #mux-control-cells property needed to get to the desired
>   mux controller if a mux chip provides more than one.
> - take away the option to build the mux-core as a module.
> - if the mux controller has an idle state, make sure the mux controller
>   is set up in the idle state initially (when it should be idle).
> - do not use a variable length array on the stack in mux_gpio_set to
>   temporarily store the gpio state, preallocate space instead.
> - fix resource leak on one failure path in mux_gpio_probe.
> - driver for Analog Devices ADG792A/G, literally the first mux chip
>   I found on the Internet with an i2c interface (that was not a
>   dedicated i2c multiplexer like PCA9547) which I used to verify
>   that the abstractions in the mux core are up to the task. Untested,
>   just proof of concept that at least looks pretty and compiles...
> - various touch-ups.
> 
> v3 -> v4 changes
> - rebased onto next-20161122 (depends on recent _available iio changes).
> - added support for having the mux-controller in a child node of a
>   mux-consumer if it is a sole consumer, to hopefully even further satisfy
>   the complaint from Rob (and later Lars-Peter) about dt complexity.
> - the above came at the cost of some rather horrible refcounting code,
>   please review and suggest how it should be done...
> - changed to register a device class instead of a bus.
> - pass in the parent device into mux_control_alloc and require less
>   work from mux-control drivers.
> - changed device names from mux:control%d to mux%d
> - move kernel-doc from mux-core.c to mux.h (and add some bits).
> - give the gpio driver a chance to update all mux pins at once.
> - factor out iio ext_info lookup into new helper function. /Lars-Peter
> - use an unsigned type for the iio ext_info count. /Lars-Peter
> - unified "brag strings" in the file headers.
> 
> v2 -> v3 changes
> - have the mux-controller in the parent node of any mux-controller consumer,
>   to hopefully satisfy complaint from Rob about dt complexity.
> - improve commit message of the mux subsystem commit, making it more
>   general, as requested by Jonathan.
> - remove priv member from struct mux_control and calculate it on the
>   fly. /Jonathan
> - make the function comments in mux-core.c kernel doc. /Jonathan
> - add devm_mux_control_* to Documentation/driver.model/devres.txt. /Jonathan
> - add common dt bindings for mux-controllers, refer to them from the
>   mux-gpio bindings. /Rob
> - clarify how the gpio pins map to the mux state. /Rob
> - separate CONFIG_ variables for the mux core and the mux gpio driver.
> - improve Kconfig help texts.
> - make CONFIG_MUX_GPIO depend on CONFIG_GPIOLIB.
> - keep track of the number of mux states in the mux core.
> - since the iio channel number is used as mux state, it was possible
>   to drop the state member from the mux_child struct.
> - cleanup dt bindings for i2c-mux-simple, it had some of copy-paste
>   problems from ots origin (i2c-mux-gpio).
> - select the mux control subsystem in config for the i2c-mux-simple driver.
> - add entries to MAINTAINERS and my sign-off, I'm now satisfied and know
>   nothing in this to be ashamed of.
> 
> v1 -> v2 changes
> - fixup export of mux_control_put reported by kbuild
> - drop devicetree iio-ext-info property as noted by Lars-Peter,
>   and replace the functionality by exposing all ext_info
>   attributes of the parent channel for each of the muxed
>   channels. A cache on top of that and each muxed channel
>   gets its own view of the ext_info of the parent channel.
> - implement idle-state for muxes
> - clear out the cache on failure in order to force a mux
>   update on the following use
> - cleanup the probe of i2c-mux-simple driver
> - fix a bug in the i2c-mux-simple driver, where failure in
>   the selection of the mux caused a deadlock when the mux
>   was later unconditionally deselected.
> 
> I have a piece of hardware that is using the same 3 GPIO pins
> to control four 8-way muxes. Three of them control ADC lines
> to an ADS1015 chip with an iio driver, and the last one
> controls the SDA line of an i2c bus. We have some deployed
> code to handle this, but you do not want to see it or ever
> hear about it. I'm not sure why I even mention it. Anyway,
> the situation has nagged me to no end for quite some time.
> 
> So, after first getting more intimate with the i2c muxing code
> and later discovering the drivers/iio/inkern.c file and
> writing a couple of drivers making use of it, I came up with
> what I think is an acceptable solution; add a generic mux
> controller driver (and subsystem) that is shared between all
> instances, and combine that with an iio mux driver and a new
> generic i2c mux driver. The new i2c mux I called "simple"
> since it is only hooking the i2c muxing and the new mux
> controller (much like the alsa simple card driver does for ASoC).
> 
> One thing that I would like to do, but don't see a solution
> for, is to move the mux control code that is present in
> various drivers in drivers/i2c/muxes to this new minimalistic
> muxing subsystem, thus converting all present i2c muxes (but
> perhaps not gates and arbitrators) to be i2c-mux-simple muxes.
> 
> I'm using an rwsem to lock a mux, but that isn't really a
> perfect fit. Is there a better locking primitive that I don't
> know about that fits better? I had a mutex at one point, but
> that didn't allow any concurrent accesses at all. At least
> the rwsem allows concurrent access as long as all users
> agree on the mux state, but I suspect that the rwsem will
> degrade to the mutex situation pretty quickly if there is
> any contention.
> 
> Also, the "mux" name feels a bit ambitious, there are many muxes
> in the world, and this tiny bit of code is probably not good
> enough to be a nice fit for all...
> 
> Cheers,
> Peter
> 
> Peter Rosin (9):
>   dt-bindings: document devicetree bindings for mux-controllers and
>     mux-gpio
>   misc: minimal mux subsystem and gpio-based mux controller
>   iio: inkern: api for manipulating ext_info of iio channels
>   dt-bindings: iio: iio-mux: document iio-mux bindings
>   iio: multiplexer: new iio category and iio-mux driver
>   dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
>   i2c: i2c-mux-simple: new driver
>   dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G
>     mux
>   misc: mux-adg792a: add mux controller driver for ADG792A/G
> 
>  .../devicetree/bindings/i2c/i2c-mux-simple.txt     |  81 ++++
>  .../bindings/iio/multiplexer/iio-mux.txt           |  40 ++
>  .../devicetree/bindings/misc/mux-adg792a.txt       |  64 +++
>  .../devicetree/bindings/misc/mux-controller.txt    | 127 ++++++
>  .../devicetree/bindings/misc/mux-gpio.txt          |  68 +++
>  Documentation/driver-model/devres.txt              |   6 +-
>  MAINTAINERS                                        |  14 +
>  drivers/i2c/muxes/Kconfig                          |  13 +
>  drivers/i2c/muxes/Makefile                         |   1 +
>  drivers/i2c/muxes/i2c-mux-simple.c                 | 179 ++++++++
>  drivers/iio/Kconfig                                |   1 +
>  drivers/iio/Makefile                               |   1 +
>  drivers/iio/inkern.c                               |  60 +++
>  drivers/iio/multiplexer/Kconfig                    |  18 +
>  drivers/iio/multiplexer/Makefile                   |   6 +
>  drivers/iio/multiplexer/iio-mux.c                  | 456 +++++++++++++++++++++
>  drivers/misc/Kconfig                               |  42 ++
>  drivers/misc/Makefile                              |   3 +
>  drivers/misc/mux-adg792a.c                         | 154 +++++++
>  drivers/misc/mux-core.c                            | 311 ++++++++++++++
>  drivers/misc/mux-gpio.c                            | 138 +++++++
>  include/linux/iio/consumer.h                       |  37 ++
>  include/linux/mux.h                                | 197 +++++++++
>  23 files changed, 2016 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-simple.txt
>  create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>  create mode 100644 Documentation/devicetree/bindings/misc/mux-adg792a.txt
>  create mode 100644 Documentation/devicetree/bindings/misc/mux-controller.txt
>  create mode 100644 Documentation/devicetree/bindings/misc/mux-gpio.txt
>  create mode 100644 drivers/i2c/muxes/i2c-mux-simple.c
>  create mode 100644 drivers/iio/multiplexer/Kconfig
>  create mode 100644 drivers/iio/multiplexer/Makefile
>  create mode 100644 drivers/iio/multiplexer/iio-mux.c
>  create mode 100644 drivers/misc/mux-adg792a.c
>  create mode 100644 drivers/misc/mux-core.c
>  create mode 100644 drivers/misc/mux-gpio.c
>  create mode 100644 include/linux/mux.h
> 

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 7/9] i2c: i2c-mux-simple: new driver
  2016-11-30  8:17   ` Peter Rosin
  (?)
  (?)
@ 2017-01-01 15:38   ` Andy Shevchenko
  2017-01-02 15:30       ` Peter Rosin
  -1 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2017-01-01 15:38 UTC (permalink / raw)
  To: Peter Rosin
  Cc: linux-kernel, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio,
	Linux Documentation List

On Wed, Nov 30, 2016 at 10:17 AM, Peter Rosin <peda@axentia.se> wrote:
> This is a generic simple i2c mux that uses the generic multiplexer
> subsystem to do the muxing.

> +static const struct of_device_id i2c_mux_of_match[] = {
> +       { .compatible = "i2c-mux-simple,parent-locked",
> +         .data = (void *)0, },
> +       { .compatible = "i2c-mux-simple,mux-locked",
> +         .data = (void *)1, },
> +       {},
> +};

Perhaps

#define I2C_MUX_LOCKED_PARENT  0
#define I2C_MUX_LOCKED         1

?

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 2/9] misc: minimal mux subsystem and gpio-based mux controller
  2016-12-31 16:19   ` Jonathan Cameron
@ 2017-01-02  9:14     ` Peter Rosin
  2017-01-02  9:20         ` Jonathan Cameron
  0 siblings, 1 reply; 58+ messages in thread
From: Peter Rosin @ 2017-01-02  9:14 UTC (permalink / raw)
  To: Jonathan Cameron, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 2016-12-31 17:19, Jonathan Cameron wrote:
> On 30/11/16 08:16, Peter Rosin wrote:
>> Add a new minimalistic subsystem that handles multiplexer controllers.
>> When multiplexers are used in various places in the kernel, and the
>> same multiplexer controller can be used for several independent things,
>> there should be one place to implement support for said multiplexer
>> controller.
>>
>> A single multiplexer controller can also be used to control several
>> parallel multiplexers, that are in turn used by different subsystems
>> in the kernel, leading to a need to coordinate multiplexer accesses.
>> The multiplexer subsystem handles this coordination.
>>
>> This new mux controller subsystem initially comes with a single backend
>> driver that controls gpio based multiplexers. Even though not needed by
>> this initial driver, the mux controller subsystem is prepared to handle
>> chips with multiple (independent) mux controllers.
>>
>> Signed-off-by: Peter Rosin <peda@axentia.se>
> Few trivial bits inline + question of whether misc is the right location..
> It's small, but not totally trivial as subsystems go, so perhaps it needs it's
> own directory.

In [9/9] you come to the conclusion that muxes should have their own
directory, but do you think it should be
	drivers/mux/*
or
	drivers/misc/mux/*
?

>> ---
>>  Documentation/driver-model/devres.txt |   6 +-
>>  MAINTAINERS                           |   2 +
>>  drivers/misc/Kconfig                  |  30 ++++
>>  drivers/misc/Makefile                 |   2 +
>>  drivers/misc/mux-core.c               | 311 ++++++++++++++++++++++++++++++++++
>>  drivers/misc/mux-gpio.c               | 138 +++++++++++++++
>>  include/linux/mux.h                   | 197 +++++++++++++++++++++
>>  7 files changed, 685 insertions(+), 1 deletion(-)
>>  create mode 100644 drivers/misc/mux-core.c
>>  create mode 100644 drivers/misc/mux-gpio.c
>>  create mode 100644 include/linux/mux.h
>>
>> diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
>> index ca9d1eb46bc0..d64ede85b61b 100644
>> --- a/Documentation/driver-model/devres.txt
>> +++ b/Documentation/driver-model/devres.txt
>> @@ -330,7 +330,11 @@ MEM
>>    devm_kzalloc()
>>  
>>  MFD
>> - devm_mfd_add_devices()
> Technically should be in a separate cleanup patch...
>> +  devm_mfd_add_devices()
>> +
>> +MUX
>> +  devm_mux_control_get()
>> +  devm_mux_control_put()
>>  
>>  PER-CPU MEM
>>    devm_alloc_percpu()
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 3d4d0efc2b64..dc7498682752 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -8407,6 +8407,8 @@ MULTIPLEXER SUBSYSTEM
>>  M:	Peter Rosin <peda@axentia.se>
>>  S:	Maintained
>>  F:	Documentation/devicetree/bindings/misc/mux-*
>> +F:	include/linux/mux.h
>> +F:	drivers/misc/mux-*
>>  
>>  MULTISOUND SOUND DRIVER
>>  M:	Andrew Veliath <andrewtv@usa.net>
>> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
>> index 64971baf11fa..2ce675e410c5 100644
>> --- a/drivers/misc/Kconfig
>> +++ b/drivers/misc/Kconfig
>> @@ -766,6 +766,36 @@ config PANEL_BOOT_MESSAGE
>>  	  An empty message will only clear the display at driver init time. Any other
>>  	  printf()-formatted message is valid with newline and escape codes.
>>  
>> +menuconfig MULTIPLEXER
>> +	bool "Multiplexer subsystem"
>> +	help
>> +	  Multiplexer controller subsystem. Multiplexers are used in a
>> +	  variety of settings, and this subsystem abstracts their use
>> +	  so that the rest of the kernel sees a common interface. When
>> +	  multiple parallel multiplexers are controlled by one single
>> +	  multiplexer controller, this subsystem also coordinates the
>> +	  multiplexer accesses.
>> +
>> +	  If unsure, say no.
>> +
> Fun question of the day. Is misc the place to put this or should it
> have it's own directory. I'd go for own directory...

I thought it too small for its own dir and that it could always be
moved later. But I don't really care...

> On the plus side, whilst it's in misc you get to pester Greg and Arnd
> for review.

I know :-]

>> +if MULTIPLEXER
>> +
>> +config MUX_GPIO
>> +	tristate "GPIO-controlled Multiplexer"
>> +	depends on OF && GPIOLIB
>> +	help
>> +	  GPIO-controlled Multiplexer controller.
>> +
>> +	  The driver builds a single multiplexer controller using a number
>> +	  of gpio pins. For N pins, there will be 2^N possible multiplexer
>> +	  states. The GPIO pins can be connected (by the hardware) to several

*snip*

>> +
>> +void mux_chip_free(struct mux_chip *mux_chip)
>> +{
>> +	if (!mux_chip)
>> +		return;
> I'd drop a blank line in here. Slightly nicer to read.

Right.

>> +	put_device(&mux_chip->dev);
>> +}
>> +EXPORT_SYMBOL_GPL(mux_chip_free);

*snip*

>> +
>> +static int mux_gpio_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct device_node *np = pdev->dev.of_node;
>> +	struct mux_chip *mux_chip;
>> +	struct mux_gpio *mux_gpio;
>> +	int pins;
>> +	u32 idle_state;
>> +	int ret;
>> +
>> +	if (!np)
>> +		return -ENODEV;
>> +
>> +	pins = gpiod_count(dev, "mux");
>> +	if (pins < 0)
>> +		return pins;
>> +
>> +	mux_chip = mux_chip_alloc(dev, 1, sizeof(*mux_gpio) +
>> +				  pins * sizeof(*mux_gpio->val));
>> +	if (!mux_chip)
>> +		return -ENOMEM;
> Rather feels like mux_chip_alloc is a good candidate for a managed
> allocator. Might be worth doing the register as well then the remove
> below would go away.  I guess perhaps not that worthwhile as not many
> mux types are likely to ever exist...

To me it seemed like too much extra support code for just two drivers.
And it can always be added later if/when more mux drivers show up...

>> +
>> +	mux_gpio = mux_chip_priv(mux_chip);
>> +	mux_gpio->val = (int *)(mux_gpio + 1);

*snip*

Cheers,
peda

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 2/9] misc: minimal mux subsystem and gpio-based mux controller
@ 2017-01-02  9:20         ` Jonathan Cameron
  0 siblings, 0 replies; 58+ messages in thread
From: Jonathan Cameron @ 2017-01-02  9:20 UTC (permalink / raw)
  To: Peter Rosin, Jonathan Cameron, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc



On 2 January 2017 09:14:34 GMT+00:00, Peter Rosin <peda@axentia.se> wrote:
>On 2016-12-31 17:19, Jonathan Cameron wrote:
>> On 30/11/16 08:16, Peter Rosin wrote:
>>> Add a new minimalistic subsystem that handles multiplexer
>controllers.
>>> When multiplexers are used in various places in the kernel, and the
>>> same multiplexer controller can be used for several independent
>things,
>>> there should be one place to implement support for said multiplexer
>>> controller.
>>>
>>> A single multiplexer controller can also be used to control several
>>> parallel multiplexers, that are in turn used by different subsystems
>>> in the kernel, leading to a need to coordinate multiplexer accesses.
>>> The multiplexer subsystem handles this coordination.
>>>
>>> This new mux controller subsystem initially comes with a single
>backend
>>> driver that controls gpio based multiplexers. Even though not needed
>by
>>> this initial driver, the mux controller subsystem is prepared to
>handle
>>> chips with multiple (independent) mux controllers.
>>>
>>> Signed-off-by: Peter Rosin <peda@axentia.se>
>> Few trivial bits inline + question of whether misc is the right
>location..
>> It's small, but not totally trivial as subsystems go, so perhaps it
>needs it's
>> own directory.
>
>In [9/9] you come to the conclusion that muxes should have their own
>directory, but do you think it should be
>	drivers/mux/*
Probably this one...
>or
>	drivers/misc/mux/*
>?
>
>>> ---
>>>  Documentation/driver-model/devres.txt |   6 +-
>>>  MAINTAINERS                           |   2 +
>>>  drivers/misc/Kconfig                  |  30 ++++
>>>  drivers/misc/Makefile                 |   2 +
>>>  drivers/misc/mux-core.c               | 311
>++++++++++++++++++++++++++++++++++
>>>  drivers/misc/mux-gpio.c               | 138 +++++++++++++++
>>>  include/linux/mux.h                   | 197 +++++++++++++++++++++
>>>  7 files changed, 685 insertions(+), 1 deletion(-)
>>>  create mode 100644 drivers/misc/mux-core.c
>>>  create mode 100644 drivers/misc/mux-gpio.c
>>>  create mode 100644 include/linux/mux.h
>>>
>>> diff --git a/Documentation/driver-model/devres.txt
>b/Documentation/driver-model/devres.txt
>>> index ca9d1eb46bc0..d64ede85b61b 100644
>>> --- a/Documentation/driver-model/devres.txt
>>> +++ b/Documentation/driver-model/devres.txt
>>> @@ -330,7 +330,11 @@ MEM
>>>    devm_kzalloc()
>>>  
>>>  MFD
>>> - devm_mfd_add_devices()
>> Technically should be in a separate cleanup patch...
>>> +  devm_mfd_add_devices()
>>> +
>>> +MUX
>>> +  devm_mux_control_get()
>>> +  devm_mux_control_put()
>>>  
>>>  PER-CPU MEM
>>>    devm_alloc_percpu()
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index 3d4d0efc2b64..dc7498682752 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -8407,6 +8407,8 @@ MULTIPLEXER SUBSYSTEM
>>>  M:	Peter Rosin <peda@axentia.se>
>>>  S:	Maintained
>>>  F:	Documentation/devicetree/bindings/misc/mux-*
>>> +F:	include/linux/mux.h
>>> +F:	drivers/misc/mux-*
>>>  
>>>  MULTISOUND SOUND DRIVER
>>>  M:	Andrew Veliath <andrewtv@usa.net>
>>> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
>>> index 64971baf11fa..2ce675e410c5 100644
>>> --- a/drivers/misc/Kconfig
>>> +++ b/drivers/misc/Kconfig
>>> @@ -766,6 +766,36 @@ config PANEL_BOOT_MESSAGE
>>>  	  An empty message will only clear the display at driver init
>time. Any other
>>>  	  printf()-formatted message is valid with newline and escape
>codes.
>>>  
>>> +menuconfig MULTIPLEXER
>>> +	bool "Multiplexer subsystem"
>>> +	help
>>> +	  Multiplexer controller subsystem. Multiplexers are used in a
>>> +	  variety of settings, and this subsystem abstracts their use
>>> +	  so that the rest of the kernel sees a common interface. When
>>> +	  multiple parallel multiplexers are controlled by one single
>>> +	  multiplexer controller, this subsystem also coordinates the
>>> +	  multiplexer accesses.
>>> +
>>> +	  If unsure, say no.
>>> +
>> Fun question of the day. Is misc the place to put this or should it
>> have it's own directory. I'd go for own directory...
>
>I thought it too small for its own dir and that it could always be
>moved later. But I don't really care...
>
>> On the plus side, whilst it's in misc you get to pester Greg and Arnd
>> for review.
>
>I know :-]
>
>>> +if MULTIPLEXER
>>> +
>>> +config MUX_GPIO
>>> +	tristate "GPIO-controlled Multiplexer"
>>> +	depends on OF && GPIOLIB
>>> +	help
>>> +	  GPIO-controlled Multiplexer controller.
>>> +
>>> +	  The driver builds a single multiplexer controller using a number
>>> +	  of gpio pins. For N pins, there will be 2^N possible multiplexer
>>> +	  states. The GPIO pins can be connected (by the hardware) to
>several
>
>*snip*
>
>>> +
>>> +void mux_chip_free(struct mux_chip *mux_chip)
>>> +{
>>> +	if (!mux_chip)
>>> +		return;
>> I'd drop a blank line in here. Slightly nicer to read.
>
>Right.
>
>>> +	put_device(&mux_chip->dev);
>>> +}
>>> +EXPORT_SYMBOL_GPL(mux_chip_free);
>
>*snip*
>
>>> +
>>> +static int mux_gpio_probe(struct platform_device *pdev)
>>> +{
>>> +	struct device *dev = &pdev->dev;
>>> +	struct device_node *np = pdev->dev.of_node;
>>> +	struct mux_chip *mux_chip;
>>> +	struct mux_gpio *mux_gpio;
>>> +	int pins;
>>> +	u32 idle_state;
>>> +	int ret;
>>> +
>>> +	if (!np)
>>> +		return -ENODEV;
>>> +
>>> +	pins = gpiod_count(dev, "mux");
>>> +	if (pins < 0)
>>> +		return pins;
>>> +
>>> +	mux_chip = mux_chip_alloc(dev, 1, sizeof(*mux_gpio) +
>>> +				  pins * sizeof(*mux_gpio->val));
>>> +	if (!mux_chip)
>>> +		return -ENOMEM;
>> Rather feels like mux_chip_alloc is a good candidate for a managed
>> allocator. Might be worth doing the register as well then the remove
>> below would go away.  I guess perhaps not that worthwhile as not many
>> mux types are likely to ever exist...
>
>To me it seemed like too much extra support code for just two drivers.
>And it can always be added later if/when more mux drivers show up...
There will be others :) sure do it later.
>
>>> +
>>> +	mux_gpio = mux_chip_priv(mux_chip);
>>> +	mux_gpio->val = (int *)(mux_gpio + 1);
>
>*snip*
>
>Cheers,
>peda
>
>--
>To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 2/9] misc: minimal mux subsystem and gpio-based mux controller
@ 2017-01-02  9:20         ` Jonathan Cameron
  0 siblings, 0 replies; 58+ messages in thread
From: Jonathan Cameron @ 2017-01-02  9:20 UTC (permalink / raw)
  To: Peter Rosin, Jonathan Cameron, linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA



On 2 January 2017 09:14:34 GMT+00:00, Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org> wrote:
>On 2016-12-31 17:19, Jonathan Cameron wrote:
>> On 30/11/16 08:16, Peter Rosin wrote:
>>> Add a new minimalistic subsystem that handles multiplexer
>controllers.
>>> When multiplexers are used in various places in the kernel, and the
>>> same multiplexer controller can be used for several independent
>things,
>>> there should be one place to implement support for said multiplexer
>>> controller.
>>>
>>> A single multiplexer controller can also be used to control several
>>> parallel multiplexers, that are in turn used by different subsystems
>>> in the kernel, leading to a need to coordinate multiplexer accesses.
>>> The multiplexer subsystem handles this coordination.
>>>
>>> This new mux controller subsystem initially comes with a single
>backend
>>> driver that controls gpio based multiplexers. Even though not needed
>by
>>> this initial driver, the mux controller subsystem is prepared to
>handle
>>> chips with multiple (independent) mux controllers.
>>>
>>> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>> Few trivial bits inline + question of whether misc is the right
>location..
>> It's small, but not totally trivial as subsystems go, so perhaps it
>needs it's
>> own directory.
>
>In [9/9] you come to the conclusion that muxes should have their own
>directory, but do you think it should be
>	drivers/mux/*
Probably this one...
>or
>	drivers/misc/mux/*
>?
>
>>> ---
>>>  Documentation/driver-model/devres.txt |   6 +-
>>>  MAINTAINERS                           |   2 +
>>>  drivers/misc/Kconfig                  |  30 ++++
>>>  drivers/misc/Makefile                 |   2 +
>>>  drivers/misc/mux-core.c               | 311
>++++++++++++++++++++++++++++++++++
>>>  drivers/misc/mux-gpio.c               | 138 +++++++++++++++
>>>  include/linux/mux.h                   | 197 +++++++++++++++++++++
>>>  7 files changed, 685 insertions(+), 1 deletion(-)
>>>  create mode 100644 drivers/misc/mux-core.c
>>>  create mode 100644 drivers/misc/mux-gpio.c
>>>  create mode 100644 include/linux/mux.h
>>>
>>> diff --git a/Documentation/driver-model/devres.txt
>b/Documentation/driver-model/devres.txt
>>> index ca9d1eb46bc0..d64ede85b61b 100644
>>> --- a/Documentation/driver-model/devres.txt
>>> +++ b/Documentation/driver-model/devres.txt
>>> @@ -330,7 +330,11 @@ MEM
>>>    devm_kzalloc()
>>>  
>>>  MFD
>>> - devm_mfd_add_devices()
>> Technically should be in a separate cleanup patch...
>>> +  devm_mfd_add_devices()
>>> +
>>> +MUX
>>> +  devm_mux_control_get()
>>> +  devm_mux_control_put()
>>>  
>>>  PER-CPU MEM
>>>    devm_alloc_percpu()
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index 3d4d0efc2b64..dc7498682752 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -8407,6 +8407,8 @@ MULTIPLEXER SUBSYSTEM
>>>  M:	Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>>>  S:	Maintained
>>>  F:	Documentation/devicetree/bindings/misc/mux-*
>>> +F:	include/linux/mux.h
>>> +F:	drivers/misc/mux-*
>>>  
>>>  MULTISOUND SOUND DRIVER
>>>  M:	Andrew Veliath <andrewtv-Jdbf3xiKgS8@public.gmane.org>
>>> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
>>> index 64971baf11fa..2ce675e410c5 100644
>>> --- a/drivers/misc/Kconfig
>>> +++ b/drivers/misc/Kconfig
>>> @@ -766,6 +766,36 @@ config PANEL_BOOT_MESSAGE
>>>  	  An empty message will only clear the display at driver init
>time. Any other
>>>  	  printf()-formatted message is valid with newline and escape
>codes.
>>>  
>>> +menuconfig MULTIPLEXER
>>> +	bool "Multiplexer subsystem"
>>> +	help
>>> +	  Multiplexer controller subsystem. Multiplexers are used in a
>>> +	  variety of settings, and this subsystem abstracts their use
>>> +	  so that the rest of the kernel sees a common interface. When
>>> +	  multiple parallel multiplexers are controlled by one single
>>> +	  multiplexer controller, this subsystem also coordinates the
>>> +	  multiplexer accesses.
>>> +
>>> +	  If unsure, say no.
>>> +
>> Fun question of the day. Is misc the place to put this or should it
>> have it's own directory. I'd go for own directory...
>
>I thought it too small for its own dir and that it could always be
>moved later. But I don't really care...
>
>> On the plus side, whilst it's in misc you get to pester Greg and Arnd
>> for review.
>
>I know :-]
>
>>> +if MULTIPLEXER
>>> +
>>> +config MUX_GPIO
>>> +	tristate "GPIO-controlled Multiplexer"
>>> +	depends on OF && GPIOLIB
>>> +	help
>>> +	  GPIO-controlled Multiplexer controller.
>>> +
>>> +	  The driver builds a single multiplexer controller using a number
>>> +	  of gpio pins. For N pins, there will be 2^N possible multiplexer
>>> +	  states. The GPIO pins can be connected (by the hardware) to
>several
>
>*snip*
>
>>> +
>>> +void mux_chip_free(struct mux_chip *mux_chip)
>>> +{
>>> +	if (!mux_chip)
>>> +		return;
>> I'd drop a blank line in here. Slightly nicer to read.
>
>Right.
>
>>> +	put_device(&mux_chip->dev);
>>> +}
>>> +EXPORT_SYMBOL_GPL(mux_chip_free);
>
>*snip*
>
>>> +
>>> +static int mux_gpio_probe(struct platform_device *pdev)
>>> +{
>>> +	struct device *dev = &pdev->dev;
>>> +	struct device_node *np = pdev->dev.of_node;
>>> +	struct mux_chip *mux_chip;
>>> +	struct mux_gpio *mux_gpio;
>>> +	int pins;
>>> +	u32 idle_state;
>>> +	int ret;
>>> +
>>> +	if (!np)
>>> +		return -ENODEV;
>>> +
>>> +	pins = gpiod_count(dev, "mux");
>>> +	if (pins < 0)
>>> +		return pins;
>>> +
>>> +	mux_chip = mux_chip_alloc(dev, 1, sizeof(*mux_gpio) +
>>> +				  pins * sizeof(*mux_gpio->val));
>>> +	if (!mux_chip)
>>> +		return -ENOMEM;
>> Rather feels like mux_chip_alloc is a good candidate for a managed
>> allocator. Might be worth doing the register as well then the remove
>> below would go away.  I guess perhaps not that worthwhile as not many
>> mux types are likely to ever exist...
>
>To me it seemed like too much extra support code for just two drivers.
>And it can always be added later if/when more mux drivers show up...
There will be others :) sure do it later.
>
>>> +
>>> +	mux_gpio = mux_chip_priv(mux_chip);
>>> +	mux_gpio->val = (int *)(mux_gpio + 1);
>
>*snip*
>
>Cheers,
>peda
>
>--
>To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 2/9] misc: minimal mux subsystem and gpio-based mux controller
@ 2017-01-02  9:20         ` Jonathan Cameron
  0 siblings, 0 replies; 58+ messages in thread
From: Jonathan Cameron @ 2017-01-02  9:20 UTC (permalink / raw)
  To: Peter Rosin, Jonathan Cameron, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc



On 2 January 2017 09:14:34 GMT+00:00, Peter Rosin <peda@axentia=2Ese> wrot=
e:
>On 2016-12-31 17:19, Jonathan Cameron wrote:
>> On 30/11/16 08:16, Peter Rosin wrote:
>>> Add a new minimalistic subsystem that handles multiplexer
>controllers=2E
>>> When multiplexers are used in various places in the kernel, and the
>>> same multiplexer controller can be used for several independent
>things,
>>> there should be one place to implement support for said multiplexer
>>> controller=2E
>>>
>>> A single multiplexer controller can also be used to control several
>>> parallel multiplexers, that are in turn used by different subsystems
>>> in the kernel, leading to a need to coordinate multiplexer accesses=2E
>>> The multiplexer subsystem handles this coordination=2E
>>>
>>> This new mux controller subsystem initially comes with a single
>backend
>>> driver that controls gpio based multiplexers=2E Even though not needed
>by
>>> this initial driver, the mux controller subsystem is prepared to
>handle
>>> chips with multiple (independent) mux controllers=2E
>>>
>>> Signed-off-by: Peter Rosin <peda@axentia=2Ese>
>> Few trivial bits inline + question of whether misc is the right
>location=2E=2E
>> It's small, but not totally trivial as subsystems go, so perhaps it
>needs it's
>> own directory=2E
>
>In [9/9] you come to the conclusion that muxes should have their own
>directory, but do you think it should be
>	drivers/mux/*
Probably this one=2E=2E=2E
>or
>	drivers/misc/mux/*
>?
>
>>> ---
>>>  Documentation/driver-model/devres=2Etxt |   6 +-
>>>  MAINTAINERS                           |   2 +
>>>  drivers/misc/Kconfig                  |  30 ++++
>>>  drivers/misc/Makefile                 |   2 +
>>>  drivers/misc/mux-core=2Ec               | 311
>++++++++++++++++++++++++++++++++++
>>>  drivers/misc/mux-gpio=2Ec               | 138 +++++++++++++++
>>>  include/linux/mux=2Eh                   | 197 +++++++++++++++++++++
>>>  7 files changed, 685 insertions(+), 1 deletion(-)
>>>  create mode 100644 drivers/misc/mux-core=2Ec
>>>  create mode 100644 drivers/misc/mux-gpio=2Ec
>>>  create mode 100644 include/linux/mux=2Eh
>>>
>>> diff --git a/Documentation/driver-model/devres=2Etxt
>b/Documentation/driver-model/devres=2Etxt
>>> index ca9d1eb46bc0=2E=2Ed64ede85b61b 100644
>>> --- a/Documentation/driver-model/devres=2Etxt
>>> +++ b/Documentation/driver-model/devres=2Etxt
>>> @@ -330,7 +330,11 @@ MEM
>>>    devm_kzalloc()
>>> =20
>>>  MFD
>>> - devm_mfd_add_devices()
>> Technically should be in a separate cleanup patch=2E=2E=2E
>>> +  devm_mfd_add_devices()
>>> +
>>> +MUX
>>> +  devm_mux_control_get()
>>> +  devm_mux_control_put()
>>> =20
>>>  PER-CPU MEM
>>>    devm_alloc_percpu()
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index 3d4d0efc2b64=2E=2Edc7498682752 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -8407,6 +8407,8 @@ MULTIPLEXER SUBSYSTEM
>>>  M:	Peter Rosin <peda@axentia=2Ese>
>>>  S:	Maintained
>>>  F:	Documentation/devicetree/bindings/misc/mux-*
>>> +F:	include/linux/mux=2Eh
>>> +F:	drivers/misc/mux-*
>>> =20
>>>  MULTISOUND SOUND DRIVER
>>>  M:	Andrew Veliath <andrewtv@usa=2Enet>
>>> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
>>> index 64971baf11fa=2E=2E2ce675e410c5 100644
>>> --- a/drivers/misc/Kconfig
>>> +++ b/drivers/misc/Kconfig
>>> @@ -766,6 +766,36 @@ config PANEL_BOOT_MESSAGE
>>>  	  An empty message will only clear the display at driver init
>time=2E Any other
>>>  	  printf()-formatted message is valid with newline and escape
>codes=2E
>>> =20
>>> +menuconfig MULTIPLEXER
>>> +	bool "Multiplexer subsystem"
>>> +	help
>>> +	  Multiplexer controller subsystem=2E Multiplexers are used in a
>>> +	  variety of settings, and this subsystem abstracts their use
>>> +	  so that the rest of the kernel sees a common interface=2E When
>>> +	  multiple parallel multiplexers are controlled by one single
>>> +	  multiplexer controller, this subsystem also coordinates the
>>> +	  multiplexer accesses=2E
>>> +
>>> +	  If unsure, say no=2E
>>> +
>> Fun question of the day=2E Is misc the place to put this or should it
>> have it's own directory=2E I'd go for own directory=2E=2E=2E
>
>I thought it too small for its own dir and that it could always be
>moved later=2E But I don't really care=2E=2E=2E
>
>> On the plus side, whilst it's in misc you get to pester Greg and Arnd
>> for review=2E
>
>I know :-]
>
>>> +if MULTIPLEXER
>>> +
>>> +config MUX_GPIO
>>> +	tristate "GPIO-controlled Multiplexer"
>>> +	depends on OF && GPIOLIB
>>> +	help
>>> +	  GPIO-controlled Multiplexer controller=2E
>>> +
>>> +	  The driver builds a single multiplexer controller using a number
>>> +	  of gpio pins=2E For N pins, there will be 2^N possible multiplexer
>>> +	  states=2E The GPIO pins can be connected (by the hardware) to
>several
>
>*snip*
>
>>> +
>>> +void mux_chip_free(struct mux_chip *mux_chip)
>>> +{
>>> +	if (!mux_chip)
>>> +		return;
>> I'd drop a blank line in here=2E Slightly nicer to read=2E
>
>Right=2E
>
>>> +	put_device(&mux_chip->dev);
>>> +}
>>> +EXPORT_SYMBOL_GPL(mux_chip_free);
>
>*snip*
>
>>> +
>>> +static int mux_gpio_probe(struct platform_device *pdev)
>>> +{
>>> +	struct device *dev =3D &pdev->dev;
>>> +	struct device_node *np =3D pdev->dev=2Eof_node;
>>> +	struct mux_chip *mux_chip;
>>> +	struct mux_gpio *mux_gpio;
>>> +	int pins;
>>> +	u32 idle_state;
>>> +	int ret;
>>> +
>>> +	if (!np)
>>> +		return -ENODEV;
>>> +
>>> +	pins =3D gpiod_count(dev, "mux");
>>> +	if (pins < 0)
>>> +		return pins;
>>> +
>>> +	mux_chip =3D mux_chip_alloc(dev, 1, sizeof(*mux_gpio) +
>>> +				  pins * sizeof(*mux_gpio->val));
>>> +	if (!mux_chip)
>>> +		return -ENOMEM;
>> Rather feels like mux_chip_alloc is a good candidate for a managed
>> allocator=2E Might be worth doing the register as well then the remove
>> below would go away=2E  I guess perhaps not that worthwhile as not many
>> mux types are likely to ever exist=2E=2E=2E
>
>To me it seemed like too much extra support code for just two drivers=2E
>And it can always be added later if/when more mux drivers show up=2E=2E=
=2E
There will be others :) sure do it later=2E
>
>>> +
>>> +	mux_gpio =3D mux_chip_priv(mux_chip);
>>> +	mux_gpio->val =3D (int *)(mux_gpio + 1);
>
>*snip*
>
>Cheers,
>peda
>
>--
>To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>the body of a message to majordomo@vger=2Ekernel=2Eorg
>More majordomo info at  http://vger=2Ekernel=2Eorg/majordomo-info=2Ehtml

--=20
Sent from my Android device with K-9 Mail=2E Please excuse my brevity=2E

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 9/9] misc: mux-adg792a: add mux controller driver for ADG792A/G
  2017-01-01 11:24   ` Jonathan Cameron
@ 2017-01-02 11:00     ` Peter Rosin
  2017-01-02 18:08       ` Jonathan Cameron
  0 siblings, 1 reply; 58+ messages in thread
From: Peter Rosin @ 2017-01-02 11:00 UTC (permalink / raw)
  To: Jonathan Cameron, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 2017-01-01 12:24, Jonathan Cameron wrote:
> On 30/11/16 08:17, Peter Rosin wrote:
>> Analog Devices ADG792A/G is a triple 4:1 mux.
>>
>> Signed-off-by: Peter Rosin <peda@axentia.se>
> Looks pretty good. Some minor suggestions inline.
> 
> This convinced me of two things:
> 1. Need a separate subsystem directory for muxes - having them under misc
> is going to lead to long term mess.
> 2. Devm alloc and registration functions will make the drivers all simpler.

Ok, I'm making the move to drivers/mux/* for v7 and adding more devm_*
functions.

> Also, browsing through ADIs list of muxes and switches it's clear that
> one classic case will be where an i2c octal or similar switch is used with
> outputs wired together in weird combinations to act as a mux.  Going to
> be 'fun' describing that.
> 
> There are also potentially cross point switches to be described ;)
> (I had to look up what one of those was ;)
> 
> Crosspoints aren't implausible as front ends for ADCs as you might
> want to be able rapidly sample any 2 of say 16 channels coming from
> for example a max14661.  We'd have to figure out how to add buffered
> capture support with sensible restrictions to the iio-mux driver
> to do that - realistically I think we would just not allow buffered
> capture with the mux having to switch.  Without hardware support
> (i.e. an ADC with external mux control) it would be too slow.
> 
> Always good to bury some idle thoughts deep in the review of a random
> driver ;) I'll never be able to remember where they were let alone
> anyone else.

But that's switches, and this is muxes. Switches are way more flexible,
so it's only natural that they are on a completely different level when
it comes to trying a generic description of them... Intentionally not
going there :-)

>> ---
>>  drivers/misc/Kconfig       |  12 ++++
>>  drivers/misc/Makefile      |   1 +
>>  drivers/misc/mux-adg792a.c | 154 +++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 167 insertions(+)
>>  create mode 100644 drivers/misc/mux-adg792a.c
>>
>> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
>> index 2ce675e410c5..45567a444bbf 100644
>> --- a/drivers/misc/Kconfig
>> +++ b/drivers/misc/Kconfig
>> @@ -780,6 +780,18 @@ menuconfig MULTIPLEXER
>>  
>>  if MULTIPLEXER
>>  
>> +config MUX_ADG792A
>> +	tristate "Analog Devices ADG792A/ADG792G Multiplexers"
>> +	depends on I2C
>> +	help
>> +	  ADG792A and ADG792G Wide Bandwidth Triple 4:1 Multiplexers
>> +
>> +	  The driver supports both operating the three multiplexers in
>> +	  parellel and operating them independently.
> parallel
>> +
>> +	  To compile the driver as a module, choose M here: the module will
>> +	  be called mux-adg792a.
>> +
>>  config MUX_GPIO
>>  	tristate "GPIO-controlled Multiplexer"
>>  	depends on OF && GPIOLIB
>> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
>> index 0befa2bba762..10ab8d34c9e5 100644
>> --- a/drivers/misc/Makefile
>> +++ b/drivers/misc/Makefile
>> @@ -54,6 +54,7 @@ obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
>>  obj-$(CONFIG_CXL_BASE)		+= cxl/
>>  obj-$(CONFIG_PANEL)             += panel.o
>>  obj-$(CONFIG_MULTIPLEXER)      	+= mux-core.o
>> +obj-$(CONFIG_MUX_ADG792A)	+= mux-adg792a.o
>>  obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
>>  
>>  lkdtm-$(CONFIG_LKDTM)		+= lkdtm_core.o
>> diff --git a/drivers/misc/mux-adg792a.c b/drivers/misc/mux-adg792a.c
>> new file mode 100644
>> index 000000000000..7d309a78af65
>> --- /dev/null
>> +++ b/drivers/misc/mux-adg792a.c
>> @@ -0,0 +1,154 @@
>> +/*
>> + * Multiplexer driver for Analog Devices ADG792A/G Triple 4:1 mux
>> + *
>> + * Copyright (C) 2016 Axentia Technologies AB
>> + *
>> + * Author: Peter Rosin <peda@axentia.se>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/i2c.h>
>> +#include <linux/module.h>
>> +#include <linux/mux.h>
>> +
>> +#define ADG792A_LDSW		BIT(0)
>> +#define ADG792A_RESET		BIT(1)
>> +#define ADG792A_DISABLE(mux)	(0x50 | (mux))
>> +#define ADG792A_DISABLE_ALL	(0x5f)
>> +#define ADG792A_MUX(mux, state)	(0xc0 | (((mux) + 1) << 2) | (state))
>> +#define ADG792A_MUX_ALL(state)	(0xc0 | (state))
>> +
>> +#define ADG792A_DISABLE_STATE	(4)
>> +#define ADG792A_KEEP_STATE	(5)
>> +
>> +static int adg792a_set(struct mux_control *mux, int state)
>> +{
>> +	struct i2c_client *i2c = to_i2c_client(mux->chip->dev.parent);
>> +	u8 cmd;
>> +
>> +	if (mux->chip->controllers == 1) {
>> +		/* parallel mux controller operation */
>> +		if (state == ADG792A_DISABLE_STATE)
>> +			cmd = ADG792A_DISABLE_ALL;
>> +		else
>> +			cmd = ADG792A_MUX_ALL(state);
>> +	} else {
>> +		unsigned int controller = mux_control_get_index(mux);
>> +
>> +		if (state == ADG792A_DISABLE_STATE)
>> +			cmd = ADG792A_DISABLE(controller);
>> +		else
>> +			cmd = ADG792A_MUX(controller, state);
>> +	}
>> +
>> +	return i2c_smbus_write_byte_data(i2c, cmd, ADG792A_LDSW);
>> +}
>> +
>> +static const struct mux_control_ops adg792a_ops = {
>> +	.set = adg792a_set,
>> +};
>> +
>> +static int adg792a_probe(struct i2c_client *i2c,
>> +			 const struct i2c_device_id *id)
>> +{
>> +	struct device *dev = &i2c->dev;
>> +	struct mux_chip *mux_chip;
>> +	bool parallel;
>> +	int ret;
>> +	int i;
>> +
>> +	parallel = of_property_read_bool(i2c->dev.of_node, "adi,parallel");
>> +
>> +	mux_chip = mux_chip_alloc(dev, parallel ? 1 : 3, 0);
> This makes me wonder if we can have a more generic binding.
> mux-poles = 3 vs mux-poles = 1?

The adg729 in theory allows to create one double pole mux and one single
pole mux (three variations, depending on which mux is single pole).
However, I did not put all that much effort into this driver. It is
mainly a proof of concept, as mentioned in the cover letter, to "prove"
that the proposed mux bindings are valid and that it is right to
have separate mux nodes in devicetree. I'm not even sure it should
be going upstream as it has seen zero testing. (But hey, it builds, what
can be wrong?)

>> +	if (!mux_chip)
>> +		return -ENOMEM;
>> +
>> +	mux_chip->ops = &adg792a_ops;
>> +	dev_set_drvdata(dev, mux_chip);
>> +
>> +	ret = i2c_smbus_write_byte_data(i2c, ADG792A_DISABLE_ALL,
>> +					ADG792A_RESET | ADG792A_LDSW);
>> +	if (ret < 0)
>> +		goto free_mux_chip;
>> +
>> +	for (i = 0; i < mux_chip->controllers; ++i) {
>> +		struct mux_control *mux = &mux_chip->mux[i];
>> +		u32 idle_state;
>> +
>> +		mux->states = 4;
>> +
>> +		ret = of_property_read_u32_index(i2c->dev.of_node,
>> +						 "adi,idle-state", i,
>> +						 &idle_state);
>> +		if (ret >= 0) {
>> +			if (idle_state > ADG792A_KEEP_STATE) {
>> +				dev_err(dev, "invalid idle-state %u\n",
>> +					idle_state);
>> +				ret = -EINVAL;
>> +				goto free_mux_chip;
>> +			}
>> +			if (idle_state != ADG792A_KEEP_STATE)
>> +				mux->idle_state = idle_state;
>> +		}
>> +	}
>> +
>> +	ret = mux_chip_register(mux_chip);
>> +	if (ret < 0) {
>> +		dev_err(dev, "failed to register mux-chip\n");
>> +		goto free_mux_chip;
>> +	}
>> +
>> +	if (parallel)
>> +		dev_info(dev, "1 triple 4-way mux-controller registered\n");
> I'd use the relay / switch standard description for this so 
> 'triple pole, quadruple throw mux registered'.
>> +	else
>> +		dev_info(dev, "3 4-way mux-controllers registered\n");
> '3x single pole, quadruple throw muxes registered'.

Ok, fine by me.

>> +
>> +	return 0;
>> +
>> +free_mux_chip:
>> +	mux_chip_free(mux_chip);
>> +	return ret;
>> +}
>> +
>> +static int adg792a_remove(struct i2c_client *i2c)
>> +{
>> +	struct mux_chip *mux_chip = dev_get_drvdata(&i2c->dev);
>> +
> Definitely looking like it's worth managed versions of mux_chip_register and
> mux_chip_alloc given this is another case where they would let us get rid
> of the remove function entirely.
>> +	mux_chip_unregister(mux_chip);
>> +	mux_chip_free(mux_chip);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct i2c_device_id adg792a_id[] = {
>> +	{ .name = "adg792a", },
>> +	{ .name = "adg792g", },
>> +	{ }
>> +};
>> +MODULE_DEVICE_TABLE(i2c, adg792a_id);
>> +
>> +static const struct of_device_id adg792a_of_match[] = {
>> +	{ .compatible = "adi,adg792a", },
>> +	{ .compatible = "adi,adg792g", },
>> +	{ }
>> +};
>> +MODULE_DEVICE_TABLE(of, adg792a_of_match);
>> +
>> +static struct i2c_driver adg792a_driver = {
>> +	.driver		= {
>> +		.name		= "adg792a",
>> +		.of_match_table = of_match_ptr(adg792a_of_match),
>> +	},
>> +	.probe		= adg792a_probe,
>> +	.remove		= adg792a_remove,
>> +	.id_table	= adg792a_id,
>> +};
>> +module_i2c_driver(adg792a_driver);
>> +
>> +MODULE_DESCRIPTION("Analog Devices ADG792A/G Triple 4:1 mux driver");
>> +MODULE_AUTHOR("Peter Rosin <peda@axentia.se");
>> +MODULE_LICENSE("GPL v2");
>>
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 7/9] i2c: i2c-mux-simple: new driver
@ 2017-01-02 15:30       ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2017-01-02 15:30 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: linux-kernel, Wolfram Sang, Rob Herring, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Arnd Bergmann,
	Greg Kroah-Hartman, linux-i2c, devicetree, linux-iio,
	Linux Documentation List

On 2017-01-01 16:38, Andy Shevchenko wrote:
> On Wed, Nov 30, 2016 at 10:17 AM, Peter Rosin <peda@axentia.se> wrote:
>> This is a generic simple i2c mux that uses the generic multiplexer
>> subsystem to do the muxing.
> 
>> +static const struct of_device_id i2c_mux_of_match[] = {
>> +       { .compatible = "i2c-mux-simple,parent-locked",
>> +         .data = (void *)0, },
>> +       { .compatible = "i2c-mux-simple,mux-locked",
>> +         .data = (void *)1, },
>> +       {},
>> +};
> 
> Perhaps
> 
> #define I2C_MUX_LOCKED_PARENT  0
> #define I2C_MUX_LOCKED         1

I2C_MUX_LOCKED is already "taken" in include/linux/i2c-mux.h but I'll
use SIMPLE_PARENT_LOCKED and SIMPLE_MUX_LOCKED instead.

Cheers,
peda

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 7/9] i2c: i2c-mux-simple: new driver
@ 2017-01-02 15:30       ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2017-01-02 15:30 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, Wolfram Sang, Rob Herring,
	Mark Rutland, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, devicetree,
	linux-iio-u79uwXL29TY76Z2rM5mHXA, Linux Documentation List

On 2017-01-01 16:38, Andy Shevchenko wrote:
> On Wed, Nov 30, 2016 at 10:17 AM, Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org> wrote:
>> This is a generic simple i2c mux that uses the generic multiplexer
>> subsystem to do the muxing.
> 
>> +static const struct of_device_id i2c_mux_of_match[] = {
>> +       { .compatible = "i2c-mux-simple,parent-locked",
>> +         .data = (void *)0, },
>> +       { .compatible = "i2c-mux-simple,mux-locked",
>> +         .data = (void *)1, },
>> +       {},
>> +};
> 
> Perhaps
> 
> #define I2C_MUX_LOCKED_PARENT  0
> #define I2C_MUX_LOCKED         1

I2C_MUX_LOCKED is already "taken" in include/linux/i2c-mux.h but I'll
use SIMPLE_PARENT_LOCKED and SIMPLE_MUX_LOCKED instead.

Cheers,
peda

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 8/9] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
  2017-01-01 11:00   ` Jonathan Cameron
@ 2017-01-02 16:01     ` Peter Rosin
  2017-01-02 18:05       ` Jonathan Cameron
  0 siblings, 1 reply; 58+ messages in thread
From: Peter Rosin @ 2017-01-02 16:01 UTC (permalink / raw)
  To: Jonathan Cameron, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 2017-01-01 12:00, Jonathan Cameron wrote:
> On 30/11/16 08:17, Peter Rosin wrote:
>> Analog Devices ADG792A/G is a triple 4:1 mux.
>>
>> Signed-off-by: Peter Rosin <peda@axentia.se>
> Few comments inline.  Worth adding anything about the gpio (output pins) to
> the binding at this stage as well?  Would certainly be nice to support
> them.

I'll add optional properties "gpio-controller;" and "#gpio-cells = <2>;"
with the usual interpretation in v7 (but no implementation...) Is that
enough?

> Jonathan
>> ---
>>  .../devicetree/bindings/misc/mux-adg792a.txt       | 64 ++++++++++++++++++++++
>>  1 file changed, 64 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/misc/mux-adg792a.txt
>>
>> diff --git a/Documentation/devicetree/bindings/misc/mux-adg792a.txt b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
>> new file mode 100644
>> index 000000000000..4677f9ab1c55
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
>> @@ -0,0 +1,64 @@
>> +Bindings for Analog Devices ADG792A/G Triple 4:1 Multiplexers
>> +
>> +Required properties:
>> +- compatible : "adi,adg792a" or "adi,adg792g"
>> +- #mux-control-cells : <0> if parallel, or <1> if not.
>> +* Standard mux-controller bindings as decribed in mux-controller.txt
>> +
>> +Optional properties:
>> +- adi,parallel : if present, the three muxes are bound together with a single
>> +  mux controller, controlling all three muxes in parallel.
>> +- adi,idle-state : if present, array of states the three mux controllers will
>> +  have when idle (or, if parallel, a single idle-state).
> Hmm. These are actually a policy decision.  As only one policy will make
> sense for a given set of hardware probably fine to have it in here I guess.
> Might be worth adding a note to say this though.

I don't really know what you want me to add, do you have a suggestion for the
wording?

>> +
>> +Mux controller states 0 through 3 correspond to signals A through D in the
>> +datasheet. Mux controller states 4 and 5 are only available as possible idle
>> +states. State 4 represents that nothing is connected, and state 5 represents
>> +that the mux controller keeps the mux in its previously selected state during
>> +the idle period. State 5 is the default idle state.
> I'm never a great fan of magic numbers.  Can we represent this more cleanly by
> breaking it into multiple properties?
> Optional:
> adi,idle-switch-to-channel : switch to this channel when idle.
> adi,idle-high-impedance : <boolean> the nothing connected state?
> 
> If neither present leaves it in previous state?

It's not that easy. adi,idle-state is an array when there are three single
pole quadruple throw muxes, so there really needs to be a number for each
desired idle-behavior. Unless you have a better idea for how to describe
that?

Cheers,
peda

>> +
>> +Example:
>> +
>> +	/* three independent mux controllers (of which one is used) */
>> +	&i2c0 {
>> +		mux: adg792a@50 {
>> +			compatible = "adi,adg792a";
>> +			reg = <0x50>;
>> +			#mux-control-cells = <1>;
>> +		};
>> +	};
>> +
>> +	adc-mux {
>> +		compatible = "iio-mux";
>> +		io-channels = <&adc 0>;
>> +		io-channel-names = "parent";
>> +
>> +		mux-controls = <&mux 1>;
>> +
>> +		channels = "sync-1", "", "out";
>> +	};
>> +
>> +
>> +	/*
>> +	 * Three parallel muxes with one mux controller, useful e.g. if
>> +	 * the adc is differential, thus needing two signals to be muxed
>> +	 * simultaneously for correct operation.
>> +	 */
>> +	&i2c0 {
>> +		pmux: adg792a@50 {
>> +			compatible = "adi,adg792a";
>> +			reg = <0x50>;
>> +			#mux-control-cells = <0>;
>> +			adi,parallel;
>> +		};
>> +	};
>> +
>> +	diff-adc-mux {
>> +		compatible = "iio-mux";
>> +		io-channels = <&adc 0>;
>> +		io-channel-names = "parent";
>> +
>> +		mux-controls = <&pmux>;
>> +
>> +		channels = "sync-1", "", "out";
>> +	};
>>
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 8/9] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
  2017-01-02 16:01     ` Peter Rosin
@ 2017-01-02 18:05       ` Jonathan Cameron
  2017-01-02 20:47         ` Peter Rosin
  0 siblings, 1 reply; 58+ messages in thread
From: Jonathan Cameron @ 2017-01-02 18:05 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 02/01/17 16:01, Peter Rosin wrote:
> On 2017-01-01 12:00, Jonathan Cameron wrote:
>> On 30/11/16 08:17, Peter Rosin wrote:
>>> Analog Devices ADG792A/G is a triple 4:1 mux.
>>>
>>> Signed-off-by: Peter Rosin <peda@axentia.se>
>> Few comments inline.  Worth adding anything about the gpio (output pins) to
>> the binding at this stage as well?  Would certainly be nice to support
>> them.
> 
> I'll add optional properties "gpio-controller;" and "#gpio-cells = <2>;"
> with the usual interpretation in v7 (but no implementation...) Is that
> enough?
> 
>> Jonathan
>>> ---
>>>  .../devicetree/bindings/misc/mux-adg792a.txt       | 64 ++++++++++++++++++++++
>>>  1 file changed, 64 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/misc/mux-adg792a.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/misc/mux-adg792a.txt b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
>>> new file mode 100644
>>> index 000000000000..4677f9ab1c55
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
>>> @@ -0,0 +1,64 @@
>>> +Bindings for Analog Devices ADG792A/G Triple 4:1 Multiplexers
>>> +
>>> +Required properties:
>>> +- compatible : "adi,adg792a" or "adi,adg792g"
>>> +- #mux-control-cells : <0> if parallel, or <1> if not.
>>> +* Standard mux-controller bindings as decribed in mux-controller.txt
>>> +
>>> +Optional properties:
>>> +- adi,parallel : if present, the three muxes are bound together with a single
>>> +  mux controller, controlling all three muxes in parallel.
>>> +- adi,idle-state : if present, array of states the three mux controllers will
>>> +  have when idle (or, if parallel, a single idle-state).
>> Hmm. These are actually a policy decision.  As only one policy will make
>> sense for a given set of hardware probably fine to have it in here I guess.
>> Might be worth adding a note to say this though.
> 
> I don't really know what you want me to add, do you have a suggestion for the
> wording?
> 
>>> +
>>> +Mux controller states 0 through 3 correspond to signals A through D in the
>>> +datasheet. Mux controller states 4 and 5 are only available as possible idle
>>> +states. State 4 represents that nothing is connected, and state 5 represents
>>> +that the mux controller keeps the mux in its previously selected state during
>>> +the idle period. State 5 is the default idle state.
>> I'm never a great fan of magic numbers.  Can we represent this more cleanly by
>> breaking it into multiple properties?
>> Optional:
>> adi,idle-switch-to-channel : switch to this channel when idle.
>> adi,idle-high-impedance : <boolean> the nothing connected state?
>>
>> If neither present leaves it in previous state?
> 
> It's not that easy. adi,idle-state is an array when there are three single
> pole quadruple throw muxes, so there really needs to be a number for each
> desired idle-behavior. Unless you have a better idea for how to describe
> that?
The above with arrays for each of the two parameters?
Though then you need a priority documented - I'd say high impedance overrides
the channel selection if both are present.
> 
> Cheers,
> peda
> 
>>> +
>>> +Example:
>>> +
>>> +	/* three independent mux controllers (of which one is used) */
>>> +	&i2c0 {
>>> +		mux: adg792a@50 {
>>> +			compatible = "adi,adg792a";
>>> +			reg = <0x50>;
>>> +			#mux-control-cells = <1>;
>>> +		};
>>> +	};
>>> +
>>> +	adc-mux {
>>> +		compatible = "iio-mux";
>>> +		io-channels = <&adc 0>;
>>> +		io-channel-names = "parent";
>>> +
>>> +		mux-controls = <&mux 1>;
>>> +
>>> +		channels = "sync-1", "", "out";
>>> +	};
>>> +
>>> +
>>> +	/*
>>> +	 * Three parallel muxes with one mux controller, useful e.g. if
>>> +	 * the adc is differential, thus needing two signals to be muxed
>>> +	 * simultaneously for correct operation.
>>> +	 */
>>> +	&i2c0 {
>>> +		pmux: adg792a@50 {
>>> +			compatible = "adi,adg792a";
>>> +			reg = <0x50>;
>>> +			#mux-control-cells = <0>;
>>> +			adi,parallel;
>>> +		};
>>> +	};
>>> +
>>> +	diff-adc-mux {
>>> +		compatible = "iio-mux";
>>> +		io-channels = <&adc 0>;
>>> +		io-channel-names = "parent";
>>> +
>>> +		mux-controls = <&pmux>;
>>> +
>>> +		channels = "sync-1", "", "out";
>>> +	};
>>>
>>
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 9/9] misc: mux-adg792a: add mux controller driver for ADG792A/G
  2017-01-02 11:00     ` Peter Rosin
@ 2017-01-02 18:08       ` Jonathan Cameron
  0 siblings, 0 replies; 58+ messages in thread
From: Jonathan Cameron @ 2017-01-02 18:08 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 02/01/17 11:00, Peter Rosin wrote:
> On 2017-01-01 12:24, Jonathan Cameron wrote:
>> On 30/11/16 08:17, Peter Rosin wrote:
>>> Analog Devices ADG792A/G is a triple 4:1 mux.
>>>
>>> Signed-off-by: Peter Rosin <peda@axentia.se>
>> Looks pretty good. Some minor suggestions inline.
>>
>> This convinced me of two things:
>> 1. Need a separate subsystem directory for muxes - having them under misc
>> is going to lead to long term mess.
>> 2. Devm alloc and registration functions will make the drivers all simpler.
> 
> Ok, I'm making the move to drivers/mux/* for v7 and adding more devm_*
> functions.
> 
>> Also, browsing through ADIs list of muxes and switches it's clear that
>> one classic case will be where an i2c octal or similar switch is used with
>> outputs wired together in weird combinations to act as a mux.  Going to
>> be 'fun' describing that.
>>
>> There are also potentially cross point switches to be described ;)
>> (I had to look up what one of those was ;)
>>
>> Crosspoints aren't implausible as front ends for ADCs as you might
>> want to be able rapidly sample any 2 of say 16 channels coming from
>> for example a max14661.  We'd have to figure out how to add buffered
>> capture support with sensible restrictions to the iio-mux driver
>> to do that - realistically I think we would just not allow buffered
>> capture with the mux having to switch.  Without hardware support
>> (i.e. an ADC with external mux control) it would be too slow.
>>
>> Always good to bury some idle thoughts deep in the review of a random
>> driver ;) I'll never be able to remember where they were let alone
>> anyone else.
> 
> But that's switches, and this is muxes. Switches are way more flexible,
> so it's only natural that they are on a completely different level when
> it comes to trying a generic description of them... Intentionally not
> going there :-)
A switch is just a load of muxes (one per output) with the inputs
wired together. All a matter of definition!
> 
>>> ---
>>>  drivers/misc/Kconfig       |  12 ++++
>>>  drivers/misc/Makefile      |   1 +
>>>  drivers/misc/mux-adg792a.c | 154 +++++++++++++++++++++++++++++++++++++++++++++
>>>  3 files changed, 167 insertions(+)
>>>  create mode 100644 drivers/misc/mux-adg792a.c
>>>
>>> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
>>> index 2ce675e410c5..45567a444bbf 100644
>>> --- a/drivers/misc/Kconfig
>>> +++ b/drivers/misc/Kconfig
>>> @@ -780,6 +780,18 @@ menuconfig MULTIPLEXER
>>>  
>>>  if MULTIPLEXER
>>>  
>>> +config MUX_ADG792A
>>> +	tristate "Analog Devices ADG792A/ADG792G Multiplexers"
>>> +	depends on I2C
>>> +	help
>>> +	  ADG792A and ADG792G Wide Bandwidth Triple 4:1 Multiplexers
>>> +
>>> +	  The driver supports both operating the three multiplexers in
>>> +	  parellel and operating them independently.
>> parallel
>>> +
>>> +	  To compile the driver as a module, choose M here: the module will
>>> +	  be called mux-adg792a.
>>> +
>>>  config MUX_GPIO
>>>  	tristate "GPIO-controlled Multiplexer"
>>>  	depends on OF && GPIOLIB
>>> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
>>> index 0befa2bba762..10ab8d34c9e5 100644
>>> --- a/drivers/misc/Makefile
>>> +++ b/drivers/misc/Makefile
>>> @@ -54,6 +54,7 @@ obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
>>>  obj-$(CONFIG_CXL_BASE)		+= cxl/
>>>  obj-$(CONFIG_PANEL)             += panel.o
>>>  obj-$(CONFIG_MULTIPLEXER)      	+= mux-core.o
>>> +obj-$(CONFIG_MUX_ADG792A)	+= mux-adg792a.o
>>>  obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
>>>  
>>>  lkdtm-$(CONFIG_LKDTM)		+= lkdtm_core.o
>>> diff --git a/drivers/misc/mux-adg792a.c b/drivers/misc/mux-adg792a.c
>>> new file mode 100644
>>> index 000000000000..7d309a78af65
>>> --- /dev/null
>>> +++ b/drivers/misc/mux-adg792a.c
>>> @@ -0,0 +1,154 @@
>>> +/*
>>> + * Multiplexer driver for Analog Devices ADG792A/G Triple 4:1 mux
>>> + *
>>> + * Copyright (C) 2016 Axentia Technologies AB
>>> + *
>>> + * Author: Peter Rosin <peda@axentia.se>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + */
>>> +
>>> +#include <linux/err.h>
>>> +#include <linux/i2c.h>
>>> +#include <linux/module.h>
>>> +#include <linux/mux.h>
>>> +
>>> +#define ADG792A_LDSW		BIT(0)
>>> +#define ADG792A_RESET		BIT(1)
>>> +#define ADG792A_DISABLE(mux)	(0x50 | (mux))
>>> +#define ADG792A_DISABLE_ALL	(0x5f)
>>> +#define ADG792A_MUX(mux, state)	(0xc0 | (((mux) + 1) << 2) | (state))
>>> +#define ADG792A_MUX_ALL(state)	(0xc0 | (state))
>>> +
>>> +#define ADG792A_DISABLE_STATE	(4)
>>> +#define ADG792A_KEEP_STATE	(5)
>>> +
>>> +static int adg792a_set(struct mux_control *mux, int state)
>>> +{
>>> +	struct i2c_client *i2c = to_i2c_client(mux->chip->dev.parent);
>>> +	u8 cmd;
>>> +
>>> +	if (mux->chip->controllers == 1) {
>>> +		/* parallel mux controller operation */
>>> +		if (state == ADG792A_DISABLE_STATE)
>>> +			cmd = ADG792A_DISABLE_ALL;
>>> +		else
>>> +			cmd = ADG792A_MUX_ALL(state);
>>> +	} else {
>>> +		unsigned int controller = mux_control_get_index(mux);
>>> +
>>> +		if (state == ADG792A_DISABLE_STATE)
>>> +			cmd = ADG792A_DISABLE(controller);
>>> +		else
>>> +			cmd = ADG792A_MUX(controller, state);
>>> +	}
>>> +
>>> +	return i2c_smbus_write_byte_data(i2c, cmd, ADG792A_LDSW);
>>> +}
>>> +
>>> +static const struct mux_control_ops adg792a_ops = {
>>> +	.set = adg792a_set,
>>> +};
>>> +
>>> +static int adg792a_probe(struct i2c_client *i2c,
>>> +			 const struct i2c_device_id *id)
>>> +{
>>> +	struct device *dev = &i2c->dev;
>>> +	struct mux_chip *mux_chip;
>>> +	bool parallel;
>>> +	int ret;
>>> +	int i;
>>> +
>>> +	parallel = of_property_read_bool(i2c->dev.of_node, "adi,parallel");
>>> +
>>> +	mux_chip = mux_chip_alloc(dev, parallel ? 1 : 3, 0);
>> This makes me wonder if we can have a more generic binding.
>> mux-poles = 3 vs mux-poles = 1?
> 
> The adg729 in theory allows to create one double pole mux and one single
> pole mux (three variations, depending on which mux is single pole).
> However, I did not put all that much effort into this driver. It is
> mainly a proof of concept, as mentioned in the cover letter, to "prove"
> that the proposed mux bindings are valid and that it is right to
> have separate mux nodes in devicetree. I'm not even sure it should
> be going upstream as it has seen zero testing. (But hey, it builds, what
> can be wrong?)
> 
>>> +	if (!mux_chip)
>>> +		return -ENOMEM;
>>> +
>>> +	mux_chip->ops = &adg792a_ops;
>>> +	dev_set_drvdata(dev, mux_chip);
>>> +
>>> +	ret = i2c_smbus_write_byte_data(i2c, ADG792A_DISABLE_ALL,
>>> +					ADG792A_RESET | ADG792A_LDSW);
>>> +	if (ret < 0)
>>> +		goto free_mux_chip;
>>> +
>>> +	for (i = 0; i < mux_chip->controllers; ++i) {
>>> +		struct mux_control *mux = &mux_chip->mux[i];
>>> +		u32 idle_state;
>>> +
>>> +		mux->states = 4;
>>> +
>>> +		ret = of_property_read_u32_index(i2c->dev.of_node,
>>> +						 "adi,idle-state", i,
>>> +						 &idle_state);
>>> +		if (ret >= 0) {
>>> +			if (idle_state > ADG792A_KEEP_STATE) {
>>> +				dev_err(dev, "invalid idle-state %u\n",
>>> +					idle_state);
>>> +				ret = -EINVAL;
>>> +				goto free_mux_chip;
>>> +			}
>>> +			if (idle_state != ADG792A_KEEP_STATE)
>>> +				mux->idle_state = idle_state;
>>> +		}
>>> +	}
>>> +
>>> +	ret = mux_chip_register(mux_chip);
>>> +	if (ret < 0) {
>>> +		dev_err(dev, "failed to register mux-chip\n");
>>> +		goto free_mux_chip;
>>> +	}
>>> +
>>> +	if (parallel)
>>> +		dev_info(dev, "1 triple 4-way mux-controller registered\n");
>> I'd use the relay / switch standard description for this so 
>> 'triple pole, quadruple throw mux registered'.
>>> +	else
>>> +		dev_info(dev, "3 4-way mux-controllers registered\n");
>> '3x single pole, quadruple throw muxes registered'.
> 
> Ok, fine by me.
> 
>>> +
>>> +	return 0;
>>> +
>>> +free_mux_chip:
>>> +	mux_chip_free(mux_chip);
>>> +	return ret;
>>> +}
>>> +
>>> +static int adg792a_remove(struct i2c_client *i2c)
>>> +{
>>> +	struct mux_chip *mux_chip = dev_get_drvdata(&i2c->dev);
>>> +
>> Definitely looking like it's worth managed versions of mux_chip_register and
>> mux_chip_alloc given this is another case where they would let us get rid
>> of the remove function entirely.
>>> +	mux_chip_unregister(mux_chip);
>>> +	mux_chip_free(mux_chip);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static const struct i2c_device_id adg792a_id[] = {
>>> +	{ .name = "adg792a", },
>>> +	{ .name = "adg792g", },
>>> +	{ }
>>> +};
>>> +MODULE_DEVICE_TABLE(i2c, adg792a_id);
>>> +
>>> +static const struct of_device_id adg792a_of_match[] = {
>>> +	{ .compatible = "adi,adg792a", },
>>> +	{ .compatible = "adi,adg792g", },
>>> +	{ }
>>> +};
>>> +MODULE_DEVICE_TABLE(of, adg792a_of_match);
>>> +
>>> +static struct i2c_driver adg792a_driver = {
>>> +	.driver		= {
>>> +		.name		= "adg792a",
>>> +		.of_match_table = of_match_ptr(adg792a_of_match),
>>> +	},
>>> +	.probe		= adg792a_probe,
>>> +	.remove		= adg792a_remove,
>>> +	.id_table	= adg792a_id,
>>> +};
>>> +module_i2c_driver(adg792a_driver);
>>> +
>>> +MODULE_DESCRIPTION("Analog Devices ADG792A/G Triple 4:1 mux driver");
>>> +MODULE_AUTHOR("Peter Rosin <peda@axentia.se");
>>> +MODULE_LICENSE("GPL v2");
>>>
>>
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 8/9] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
  2017-01-02 18:05       ` Jonathan Cameron
@ 2017-01-02 20:47         ` Peter Rosin
  2017-01-02 21:13           ` Jonathan Cameron
  0 siblings, 1 reply; 58+ messages in thread
From: Peter Rosin @ 2017-01-02 20:47 UTC (permalink / raw)
  To: Jonathan Cameron, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 2017-01-02 19:05, Jonathan Cameron wrote:
> On 02/01/17 16:01, Peter Rosin wrote:
>> On 2017-01-01 12:00, Jonathan Cameron wrote:
>>> On 30/11/16 08:17, Peter Rosin wrote:
>>>> Analog Devices ADG792A/G is a triple 4:1 mux.
>>>>
>>>> Signed-off-by: Peter Rosin <peda@axentia.se>
>>> Few comments inline.  Worth adding anything about the gpio (output pins) to
>>> the binding at this stage as well?  Would certainly be nice to support
>>> them.
>>
>> I'll add optional properties "gpio-controller;" and "#gpio-cells = <2>;"
>> with the usual interpretation in v7 (but no implementation...) Is that
>> enough?
>>
>>> Jonathan
>>>> ---
>>>>  .../devicetree/bindings/misc/mux-adg792a.txt       | 64 ++++++++++++++++++++++
>>>>  1 file changed, 64 insertions(+)
>>>>  create mode 100644 Documentation/devicetree/bindings/misc/mux-adg792a.txt
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/misc/mux-adg792a.txt b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
>>>> new file mode 100644
>>>> index 000000000000..4677f9ab1c55
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
>>>> @@ -0,0 +1,64 @@
>>>> +Bindings for Analog Devices ADG792A/G Triple 4:1 Multiplexers
>>>> +
>>>> +Required properties:
>>>> +- compatible : "adi,adg792a" or "adi,adg792g"
>>>> +- #mux-control-cells : <0> if parallel, or <1> if not.
>>>> +* Standard mux-controller bindings as decribed in mux-controller.txt
>>>> +
>>>> +Optional properties:
>>>> +- adi,parallel : if present, the three muxes are bound together with a single
>>>> +  mux controller, controlling all three muxes in parallel.
>>>> +- adi,idle-state : if present, array of states the three mux controllers will
>>>> +  have when idle (or, if parallel, a single idle-state).
>>> Hmm. These are actually a policy decision.  As only one policy will make
>>> sense for a given set of hardware probably fine to have it in here I guess.
>>> Might be worth adding a note to say this though.
>>
>> I don't really know what you want me to add, do you have a suggestion for the
>> wording?
>>
>>>> +
>>>> +Mux controller states 0 through 3 correspond to signals A through D in the
>>>> +datasheet. Mux controller states 4 and 5 are only available as possible idle
>>>> +states. State 4 represents that nothing is connected, and state 5 represents
>>>> +that the mux controller keeps the mux in its previously selected state during
>>>> +the idle period. State 5 is the default idle state.
>>> I'm never a great fan of magic numbers.  Can we represent this more cleanly by
>>> breaking it into multiple properties?
>>> Optional:
>>> adi,idle-switch-to-channel : switch to this channel when idle.
>>> adi,idle-high-impedance : <boolean> the nothing connected state?
>>>
>>> If neither present leaves it in previous state?
>>
>> It's not that easy. adi,idle-state is an array when there are three single
>> pole quadruple throw muxes, so there really needs to be a number for each
>> desired idle-behavior. Unless you have a better idea for how to describe
>> that?
> The above with arrays for each of the two parameters?
> Though then you need a priority documented - I'd say high impedance overrides
> the channel selection if both are present.

How would you specify that the first mux should idle in "state 5", the second
should idle in "state 4" and the third in "state 0"? (original state numbering)

You'd still need a magic number for the default idle state (state 5) so that
you can skip entries in the arrays. Or am I missing something?

Cheers,
peda

>>
>> Cheers,
>> peda
>>
>>>> +
>>>> +Example:
>>>> +
>>>> +	/* three independent mux controllers (of which one is used) */
>>>> +	&i2c0 {
>>>> +		mux: adg792a@50 {
>>>> +			compatible = "adi,adg792a";
>>>> +			reg = <0x50>;
>>>> +			#mux-control-cells = <1>;
>>>> +		};
>>>> +	};
>>>> +
>>>> +	adc-mux {
>>>> +		compatible = "iio-mux";
>>>> +		io-channels = <&adc 0>;
>>>> +		io-channel-names = "parent";
>>>> +
>>>> +		mux-controls = <&mux 1>;
>>>> +
>>>> +		channels = "sync-1", "", "out";
>>>> +	};
>>>> +
>>>> +
>>>> +	/*
>>>> +	 * Three parallel muxes with one mux controller, useful e.g. if
>>>> +	 * the adc is differential, thus needing two signals to be muxed
>>>> +	 * simultaneously for correct operation.
>>>> +	 */
>>>> +	&i2c0 {
>>>> +		pmux: adg792a@50 {
>>>> +			compatible = "adi,adg792a";
>>>> +			reg = <0x50>;
>>>> +			#mux-control-cells = <0>;
>>>> +			adi,parallel;
>>>> +		};
>>>> +	};
>>>> +
>>>> +	diff-adc-mux {
>>>> +		compatible = "iio-mux";
>>>> +		io-channels = <&adc 0>;
>>>> +		io-channel-names = "parent";
>>>> +
>>>> +		mux-controls = <&pmux>;
>>>> +
>>>> +		channels = "sync-1", "", "out";
>>>> +	};
>>>>
>>>
>>
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 8/9] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
  2017-01-02 20:47         ` Peter Rosin
@ 2017-01-02 21:13           ` Jonathan Cameron
  2017-01-03  6:44               ` Peter Rosin
  0 siblings, 1 reply; 58+ messages in thread
From: Jonathan Cameron @ 2017-01-02 21:13 UTC (permalink / raw)
  To: Peter Rosin, Jonathan Cameron, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc



On 2 January 2017 20:47:58 GMT+00:00, Peter Rosin <peda@axentia.se> wrote:
>On 2017-01-02 19:05, Jonathan Cameron wrote:
>> On 02/01/17 16:01, Peter Rosin wrote:
>>> On 2017-01-01 12:00, Jonathan Cameron wrote:
>>>> On 30/11/16 08:17, Peter Rosin wrote:
>>>>> Analog Devices ADG792A/G is a triple 4:1 mux.
>>>>>
>>>>> Signed-off-by: Peter Rosin <peda@axentia.se>
>>>> Few comments inline.  Worth adding anything about the gpio (output
>pins) to
>>>> the binding at this stage as well?  Would certainly be nice to
>support
>>>> them.
>>>
>>> I'll add optional properties "gpio-controller;" and "#gpio-cells =
><2>;"
>>> with the usual interpretation in v7 (but no implementation...) Is
>that
>>> enough?
>>>
>>>> Jonathan
>>>>> ---
>>>>>  .../devicetree/bindings/misc/mux-adg792a.txt       | 64
>++++++++++++++++++++++
>>>>>  1 file changed, 64 insertions(+)
>>>>>  create mode 100644
>Documentation/devicetree/bindings/misc/mux-adg792a.txt
>>>>>
>>>>> diff --git
>a/Documentation/devicetree/bindings/misc/mux-adg792a.txt
>b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
>>>>> new file mode 100644
>>>>> index 000000000000..4677f9ab1c55
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
>>>>> @@ -0,0 +1,64 @@
>>>>> +Bindings for Analog Devices ADG792A/G Triple 4:1 Multiplexers
>>>>> +
>>>>> +Required properties:
>>>>> +- compatible : "adi,adg792a" or "adi,adg792g"
>>>>> +- #mux-control-cells : <0> if parallel, or <1> if not.
>>>>> +* Standard mux-controller bindings as decribed in
>mux-controller.txt
>>>>> +
>>>>> +Optional properties:
>>>>> +- adi,parallel : if present, the three muxes are bound together
>with a single
>>>>> +  mux controller, controlling all three muxes in parallel.
>>>>> +- adi,idle-state : if present, array of states the three mux
>controllers will
>>>>> +  have when idle (or, if parallel, a single idle-state).
>>>> Hmm. These are actually a policy decision.  As only one policy will
>make
>>>> sense for a given set of hardware probably fine to have it in here
>I guess.
>>>> Might be worth adding a note to say this though.
>>>
>>> I don't really know what you want me to add, do you have a
>suggestion for the
>>> wording?
>>>
>>>>> +
>>>>> +Mux controller states 0 through 3 correspond to signals A through
>D in the
>>>>> +datasheet. Mux controller states 4 and 5 are only available as
>possible idle
>>>>> +states. State 4 represents that nothing is connected, and state 5
>represents
>>>>> +that the mux controller keeps the mux in its previously selected
>state during
>>>>> +the idle period. State 5 is the default idle state.
>>>> I'm never a great fan of magic numbers.  Can we represent this more
>cleanly by
>>>> breaking it into multiple properties?
>>>> Optional:
>>>> adi,idle-switch-to-channel : switch to this channel when idle.
>>>> adi,idle-high-impedance : <boolean> the nothing connected state?
>>>>
>>>> If neither present leaves it in previous state?
>>>
>>> It's not that easy. adi,idle-state is an array when there are three
>single
>>> pole quadruple throw muxes, so there really needs to be a number for
>each
>>> desired idle-behavior. Unless you have a better idea for how to
>describe
>>> that?
>> The above with arrays for each of the two parameters?
>> Though then you need a priority documented - I'd say high impedance
>overrides
>> the channel selection if both are present.
>
>How would you specify that the first mux should idle in "state 5", the
>second
>should idle in "state 4" and the third in "state 0"? (original state
>numbering)
>
>You'd still need a magic number for the default idle state (state 5) so
>that
>you can skip entries in the arrays. Or am I missing something?
Ah I had missed state 5. Hmm would need explicit control for that as well. Not nice...

Perhaps 3 state control (magic number but with channel nums separate)

Idle-state array of <switchtostate, currentstate, highimpedance>

Idle-state array of states to switch to if so set?

Slight nicer than a mess of the two things perhaps?
>
>Cheers,
>peda
>
>>>
>>> Cheers,
>>> peda
>>>
>>>>> +
>>>>> +Example:
>>>>> +
>>>>> +	/* three independent mux controllers (of which one is used) */
>>>>> +	&i2c0 {
>>>>> +		mux: adg792a@50 {
>>>>> +			compatible = "adi,adg792a";
>>>>> +			reg = <0x50>;
>>>>> +			#mux-control-cells = <1>;
>>>>> +		};
>>>>> +	};
>>>>> +
>>>>> +	adc-mux {
>>>>> +		compatible = "iio-mux";
>>>>> +		io-channels = <&adc 0>;
>>>>> +		io-channel-names = "parent";
>>>>> +
>>>>> +		mux-controls = <&mux 1>;
>>>>> +
>>>>> +		channels = "sync-1", "", "out";
>>>>> +	};
>>>>> +
>>>>> +
>>>>> +	/*
>>>>> +	 * Three parallel muxes with one mux controller, useful e.g. if
>>>>> +	 * the adc is differential, thus needing two signals to be muxed
>>>>> +	 * simultaneously for correct operation.
>>>>> +	 */
>>>>> +	&i2c0 {
>>>>> +		pmux: adg792a@50 {
>>>>> +			compatible = "adi,adg792a";
>>>>> +			reg = <0x50>;
>>>>> +			#mux-control-cells = <0>;
>>>>> +			adi,parallel;
>>>>> +		};
>>>>> +	};
>>>>> +
>>>>> +	diff-adc-mux {
>>>>> +		compatible = "iio-mux";
>>>>> +		io-channels = <&adc 0>;
>>>>> +		io-channel-names = "parent";
>>>>> +
>>>>> +		mux-controls = <&pmux>;
>>>>> +
>>>>> +		channels = "sync-1", "", "out";
>>>>> +	};
>>>>>
>>>>
>>>
>> 
>
>--
>To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 8/9] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
@ 2017-01-03  6:44               ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2017-01-03  6:44 UTC (permalink / raw)
  To: Jonathan Cameron, Jonathan Cameron, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc

On 2017-01-02 22:13, Jonathan Cameron wrote:
> 
> 
> On 2 January 2017 20:47:58 GMT+00:00, Peter Rosin <peda@axentia.se> wrote:
>> On 2017-01-02 19:05, Jonathan Cameron wrote:
>>> On 02/01/17 16:01, Peter Rosin wrote:
>>>> On 2017-01-01 12:00, Jonathan Cameron wrote:
>>>>> On 30/11/16 08:17, Peter Rosin wrote:
>>>>>> Analog Devices ADG792A/G is a triple 4:1 mux.
>>>>>>
>>>>>> Signed-off-by: Peter Rosin <peda@axentia.se>
>>>>> Few comments inline.  Worth adding anything about the gpio (output pins) to
>>>>> the binding at this stage as well?  Would certainly be nice to support
>>>>> them.
>>>>
>>>> I'll add optional properties "gpio-controller;" and "#gpio-cells = <2>;"
>>>> with the usual interpretation in v7 (but no implementation...) Is that
>>>> enough?
>>>>
>>>>> Jonathan
>>>>>> ---
>>>>>>  .../devicetree/bindings/misc/mux-adg792a.txt       | 64 ++++++++++++++++++++++
>>>>>>  1 file changed, 64 insertions(+)
>>>>>>  create mode 100644 Documentation/devicetree/bindings/misc/mux-adg792a.txt
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/misc/mux-adg792a.txt b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
>>>>>> new file mode 100644
>>>>>> index 000000000000..4677f9ab1c55
>>>>>> --- /dev/null
>>>>>> +++ b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
>>>>>> @@ -0,0 +1,64 @@
>>>>>> +Bindings for Analog Devices ADG792A/G Triple 4:1 Multiplexers
>>>>>> +
>>>>>> +Required properties:
>>>>>> +- compatible : "adi,adg792a" or "adi,adg792g"
>>>>>> +- #mux-control-cells : <0> if parallel, or <1> if not.
>>>>>> +* Standard mux-controller bindings as decribed in mux-controller.txt
>>>>>> +
>>>>>> +Optional properties:
>>>>>> +- adi,parallel : if present, the three muxes are bound together with a single
>>>>>> +  mux controller, controlling all three muxes in parallel.
>>>>>> +- adi,idle-state : if present, array of states the three mux controllers will
>>>>>> +  have when idle (or, if parallel, a single idle-state).
>>>>> Hmm. These are actually a policy decision.  As only one policy will make
>>>>> sense for a given set of hardware probably fine to have it in here I guess.
>>>>> Might be worth adding a note to say this though.
>>>>
>>>> I don't really know what you want me to add, do you have a suggestion for the
>>>> wording?
>>>>
>>>>>> +
>>>>>> +Mux controller states 0 through 3 correspond to signals A through D in the
>>>>>> +datasheet. Mux controller states 4 and 5 are only available as possible idle
>>>>>> +states. State 4 represents that nothing is connected, and state 5 represents
>>>>>> +that the mux controller keeps the mux in its previously selected state during
>>>>>> +the idle period. State 5 is the default idle state.
>>>>> I'm never a great fan of magic numbers.  Can we represent this more cleanly by
>>>>> breaking it into multiple properties?
>>>>> Optional:
>>>>> adi,idle-switch-to-channel : switch to this channel when idle.
>>>>> adi,idle-high-impedance : <boolean> the nothing connected state?
>>>>>
>>>>> If neither present leaves it in previous state?
>>>>
>>>> It's not that easy. adi,idle-state is an array when there are three single
>>>> pole quadruple throw muxes, so there really needs to be a number for each
>>>> desired idle-behavior. Unless you have a better idea for how to describe
>>>> that?
>>> The above with arrays for each of the two parameters?
>>> Though then you need a priority documented - I'd say high impedance overrides
>>> the channel selection if both are present.
>>
>> How would you specify that the first mux should idle in "state 5", the second
>> should idle in "state 4" and the third in "state 0"? (original state numbering)
>>
>> You'd still need a magic number for the default idle state (state 5) so that
>> you can skip entries in the arrays. Or am I missing something?
> Ah I had missed state 5. Hmm would need explicit control for that as well. Not nice...
> 
> Perhaps 3 state control (magic number but with channel nums separate)
> 
> Idle-state array of <switchtostate, currentstate, highimpedance>
> 
> Idle-state array of states to switch to if so set?
> 
> Slight nicer than a mess of the two things perhaps?

Perhaps making adi,idle-state an array of tuples <mux-number state> and
add adi,idle-high-impedance as an array of mux-numbers, so that my example
above would come out as:

	adi,idle-high-impedance = <1>; /* mux 1 idles with high imp */
	adi,idle-state = <2 0>;  /* mux 2 idles in state 0 (signal A) */

mux 0 is not mentioned and idles in its previously selected state.


If you want mux 0 to idle with high impedance:

	adi,idle-high-impedance = <0 1>;
	adi,idle-state = <2 0>;

If you want mux 0 to idle with signal C:

	adi,idle-high-impedance = <1>;
	adi,idle-state = <0 3>, <2 0>;

>>>>>> +
>>>>>> +Example:
>>>>>> +
>>>>>> +	/* three independent mux controllers (of which one is used) */
>>>>>> +	&i2c0 {
>>>>>> +		mux: adg792a@50 {
>>>>>> +			compatible = "adi,adg792a";
>>>>>> +			reg = <0x50>;
>>>>>> +			#mux-control-cells = <1>;
>>>>>> +		};
>>>>>> +	};
>>>>>> +
>>>>>> +	adc-mux {
>>>>>> +		compatible = "iio-mux";
>>>>>> +		io-channels = <&adc 0>;
>>>>>> +		io-channel-names = "parent";
>>>>>> +
>>>>>> +		mux-controls = <&mux 1>;
>>>>>> +
>>>>>> +		channels = "sync-1", "", "out";
>>>>>> +	};
>>>>>> +
>>>>>> +
>>>>>> +	/*
>>>>>> +	 * Three parallel muxes with one mux controller, useful e.g. if
>>>>>> +	 * the adc is differential, thus needing two signals to be muxed
>>>>>> +	 * simultaneously for correct operation.
>>>>>> +	 */
>>>>>> +	&i2c0 {
>>>>>> +		pmux: adg792a@50 {
>>>>>> +			compatible = "adi,adg792a";
>>>>>> +			reg = <0x50>;
>>>>>> +			#mux-control-cells = <0>;
>>>>>> +			adi,parallel;
>>>>>> +		};
>>>>>> +	};
>>>>>> +
>>>>>> +	diff-adc-mux {
>>>>>> +		compatible = "iio-mux";
>>>>>> +		io-channels = <&adc 0>;
>>>>>> +		io-channel-names = "parent";
>>>>>> +
>>>>>> +		mux-controls = <&pmux>;
>>>>>> +
>>>>>> +		channels = "sync-1", "", "out";
>>>>>> +	};
>>>>>>
>>>>>
>>>>
>>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v6 8/9] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
@ 2017-01-03  6:44               ` Peter Rosin
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Rosin @ 2017-01-03  6:44 UTC (permalink / raw)
  To: Jonathan Cameron, Jonathan Cameron, linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

On 2017-01-02 22:13, Jonathan Cameron wrote:
> 
> 
> On 2 January 2017 20:47:58 GMT+00:00, Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org> wrote:
>> On 2017-01-02 19:05, Jonathan Cameron wrote:
>>> On 02/01/17 16:01, Peter Rosin wrote:
>>>> On 2017-01-01 12:00, Jonathan Cameron wrote:
>>>>> On 30/11/16 08:17, Peter Rosin wrote:
>>>>>> Analog Devices ADG792A/G is a triple 4:1 mux.
>>>>>>
>>>>>> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>>>>> Few comments inline.  Worth adding anything about the gpio (output pins) to
>>>>> the binding at this stage as well?  Would certainly be nice to support
>>>>> them.
>>>>
>>>> I'll add optional properties "gpio-controller;" and "#gpio-cells = <2>;"
>>>> with the usual interpretation in v7 (but no implementation...) Is that
>>>> enough?
>>>>
>>>>> Jonathan
>>>>>> ---
>>>>>>  .../devicetree/bindings/misc/mux-adg792a.txt       | 64 ++++++++++++++++++++++
>>>>>>  1 file changed, 64 insertions(+)
>>>>>>  create mode 100644 Documentation/devicetree/bindings/misc/mux-adg792a.txt
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/misc/mux-adg792a.txt b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
>>>>>> new file mode 100644
>>>>>> index 000000000000..4677f9ab1c55
>>>>>> --- /dev/null
>>>>>> +++ b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
>>>>>> @@ -0,0 +1,64 @@
>>>>>> +Bindings for Analog Devices ADG792A/G Triple 4:1 Multiplexers
>>>>>> +
>>>>>> +Required properties:
>>>>>> +- compatible : "adi,adg792a" or "adi,adg792g"
>>>>>> +- #mux-control-cells : <0> if parallel, or <1> if not.
>>>>>> +* Standard mux-controller bindings as decribed in mux-controller.txt
>>>>>> +
>>>>>> +Optional properties:
>>>>>> +- adi,parallel : if present, the three muxes are bound together with a single
>>>>>> +  mux controller, controlling all three muxes in parallel.
>>>>>> +- adi,idle-state : if present, array of states the three mux controllers will
>>>>>> +  have when idle (or, if parallel, a single idle-state).
>>>>> Hmm. These are actually a policy decision.  As only one policy will make
>>>>> sense for a given set of hardware probably fine to have it in here I guess.
>>>>> Might be worth adding a note to say this though.
>>>>
>>>> I don't really know what you want me to add, do you have a suggestion for the
>>>> wording?
>>>>
>>>>>> +
>>>>>> +Mux controller states 0 through 3 correspond to signals A through D in the
>>>>>> +datasheet. Mux controller states 4 and 5 are only available as possible idle
>>>>>> +states. State 4 represents that nothing is connected, and state 5 represents
>>>>>> +that the mux controller keeps the mux in its previously selected state during
>>>>>> +the idle period. State 5 is the default idle state.
>>>>> I'm never a great fan of magic numbers.  Can we represent this more cleanly by
>>>>> breaking it into multiple properties?
>>>>> Optional:
>>>>> adi,idle-switch-to-channel : switch to this channel when idle.
>>>>> adi,idle-high-impedance : <boolean> the nothing connected state?
>>>>>
>>>>> If neither present leaves it in previous state?
>>>>
>>>> It's not that easy. adi,idle-state is an array when there are three single
>>>> pole quadruple throw muxes, so there really needs to be a number for each
>>>> desired idle-behavior. Unless you have a better idea for how to describe
>>>> that?
>>> The above with arrays for each of the two parameters?
>>> Though then you need a priority documented - I'd say high impedance overrides
>>> the channel selection if both are present.
>>
>> How would you specify that the first mux should idle in "state 5", the second
>> should idle in "state 4" and the third in "state 0"? (original state numbering)
>>
>> You'd still need a magic number for the default idle state (state 5) so that
>> you can skip entries in the arrays. Or am I missing something?
> Ah I had missed state 5. Hmm would need explicit control for that as well. Not nice...
> 
> Perhaps 3 state control (magic number but with channel nums separate)
> 
> Idle-state array of <switchtostate, currentstate, highimpedance>
> 
> Idle-state array of states to switch to if so set?
> 
> Slight nicer than a mess of the two things perhaps?

Perhaps making adi,idle-state an array of tuples <mux-number state> and
add adi,idle-high-impedance as an array of mux-numbers, so that my example
above would come out as:

	adi,idle-high-impedance = <1>; /* mux 1 idles with high imp */
	adi,idle-state = <2 0>;  /* mux 2 idles in state 0 (signal A) */

mux 0 is not mentioned and idles in its previously selected state.


If you want mux 0 to idle with high impedance:

	adi,idle-high-impedance = <0 1>;
	adi,idle-state = <2 0>;

If you want mux 0 to idle with signal C:

	adi,idle-high-impedance = <1>;
	adi,idle-state = <0 3>, <2 0>;

>>>>>> +
>>>>>> +Example:
>>>>>> +
>>>>>> +	/* three independent mux controllers (of which one is used) */
>>>>>> +	&i2c0 {
>>>>>> +		mux: adg792a@50 {
>>>>>> +			compatible = "adi,adg792a";
>>>>>> +			reg = <0x50>;
>>>>>> +			#mux-control-cells = <1>;
>>>>>> +		};
>>>>>> +	};
>>>>>> +
>>>>>> +	adc-mux {
>>>>>> +		compatible = "iio-mux";
>>>>>> +		io-channels = <&adc 0>;
>>>>>> +		io-channel-names = "parent";
>>>>>> +
>>>>>> +		mux-controls = <&mux 1>;
>>>>>> +
>>>>>> +		channels = "sync-1", "", "out";
>>>>>> +	};
>>>>>> +
>>>>>> +
>>>>>> +	/*
>>>>>> +	 * Three parallel muxes with one mux controller, useful e.g. if
>>>>>> +	 * the adc is differential, thus needing two signals to be muxed
>>>>>> +	 * simultaneously for correct operation.
>>>>>> +	 */
>>>>>> +	&i2c0 {
>>>>>> +		pmux: adg792a@50 {
>>>>>> +			compatible = "adi,adg792a";
>>>>>> +			reg = <0x50>;
>>>>>> +			#mux-control-cells = <0>;
>>>>>> +			adi,parallel;
>>>>>> +		};
>>>>>> +	};
>>>>>> +
>>>>>> +	diff-adc-mux {
>>>>>> +		compatible = "iio-mux";
>>>>>> +		io-channels = <&adc 0>;
>>>>>> +		io-channel-names = "parent";
>>>>>> +
>>>>>> +		mux-controls = <&pmux>;
>>>>>> +
>>>>>> +		channels = "sync-1", "", "out";
>>>>>> +	};
>>>>>>
>>>>>
>>>>
>>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

end of thread, other threads:[~2017-01-03  6:45 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-11-30  8:16 [PATCH v6 0/9] mux controller abstraction and iio/i2c muxes Peter Rosin
2016-11-30  8:16 ` Peter Rosin
2016-11-30  8:16 ` [PATCH v6 1/9] dt-bindings: document devicetree bindings for mux-controllers and mux-gpio Peter Rosin
2016-11-30  8:16   ` Peter Rosin
2016-12-31 16:10   ` Jonathan Cameron
2016-11-30  8:16 ` [PATCH v6 2/9] misc: minimal mux subsystem and gpio-based mux controller Peter Rosin
2016-11-30  8:16   ` Peter Rosin
2016-12-31 16:19   ` Jonathan Cameron
2017-01-02  9:14     ` Peter Rosin
2017-01-02  9:20       ` Jonathan Cameron
2017-01-02  9:20         ` Jonathan Cameron
2017-01-02  9:20         ` Jonathan Cameron
2016-11-30  8:16 ` [PATCH v6 3/9] iio: inkern: api for manipulating ext_info of iio channels Peter Rosin
2016-11-30  8:16   ` Peter Rosin
2016-12-31 15:51   ` Jonathan Cameron
2016-12-31 15:51     ` Jonathan Cameron
2016-11-30  8:16 ` [PATCH v6 4/9] dt-bindings: iio: iio-mux: document iio-mux bindings Peter Rosin
2016-11-30  8:16   ` Peter Rosin
2016-11-30  8:52   ` Peter Rosin
2016-11-30  8:52     ` Peter Rosin
2016-11-30  8:57     ` Peter Rosin
2016-11-30  8:57       ` Peter Rosin
2016-12-05 23:26   ` Rob Herring
2016-12-06  9:18     ` Peter Rosin
2016-12-06  9:18       ` Peter Rosin
2016-12-10 18:21       ` Jonathan Cameron
2016-12-10 18:21         ` Jonathan Cameron
2016-12-12 12:18         ` Peter Rosin
2016-12-12 12:18           ` Peter Rosin
2016-12-31 16:01           ` Jonathan Cameron
2016-11-30  8:16 ` [PATCH v6 5/9] iio: multiplexer: new iio category and iio-mux driver Peter Rosin
2016-11-30  8:16   ` Peter Rosin
2016-12-31 16:21   ` Jonathan Cameron
2016-11-30  8:17 ` [PATCH v6 6/9] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings Peter Rosin
2016-11-30  8:17   ` Peter Rosin
2016-11-30  8:17 ` [PATCH v6 7/9] i2c: i2c-mux-simple: new driver Peter Rosin
2016-11-30  8:17   ` Peter Rosin
2017-01-01 10:31   ` Jonathan Cameron
2017-01-01 10:31     ` Jonathan Cameron
2017-01-01 15:38   ` Andy Shevchenko
2017-01-02 15:30     ` Peter Rosin
2017-01-02 15:30       ` Peter Rosin
2016-11-30  8:17 ` [PATCH v6 8/9] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux Peter Rosin
2016-11-30  8:17   ` Peter Rosin
2017-01-01 11:00   ` Jonathan Cameron
2017-01-02 16:01     ` Peter Rosin
2017-01-02 18:05       ` Jonathan Cameron
2017-01-02 20:47         ` Peter Rosin
2017-01-02 21:13           ` Jonathan Cameron
2017-01-03  6:44             ` Peter Rosin
2017-01-03  6:44               ` Peter Rosin
2016-11-30  8:17 ` [PATCH v6 9/9] misc: mux-adg792a: add mux controller driver for ADG792A/G Peter Rosin
2016-11-30  8:17   ` Peter Rosin
2017-01-01 11:24   ` Jonathan Cameron
2017-01-02 11:00     ` Peter Rosin
2017-01-02 18:08       ` Jonathan Cameron
2017-01-01 11:28 ` [PATCH v6 0/9] mux controller abstraction and iio/i2c muxes Jonathan Cameron
2017-01-01 11:28   ` Jonathan Cameron

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.