All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v8 00/12] mux controller abstraction and iio/i2c muxes
@ 2017-01-18 15:57 ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

Hi!

v7 -> v8 changes
- cleanup the implementation of the simplified gpio bindings, but still...
- ...reorder patches so that they appear last in the series (patches 11
  and 12 were patches 4 and 5 in v7) since Jonathan convinced me that
  they were perhaps not such a good idea after all. But I still wanted
  to show the last version I had and I'm still a bit undecided...
- added some words to the remaining otherwise empty commit messages
- added various acks/reviews from Jonathan and Wolfram.
- move mux last in drivers/Kconfig and drivers/Makefile
- bump copyright years
- centralize error reporting of common operatinons to the mux core
- add WARN_ON for faulty usage of mux_chip_register
- simplify code for other WARN_ON call sites

v6 -> v7 changes
- move from drivers/misc/mux-* to drivers/mux/
  [I will remove Cc:s to Arnd and Greg for v8, when/if that happens]
- add managed versions of mux_chip_alloc and mux_chip_register
- use the above in mux-gpio.c and mux-adg792a.c
- also use them to support a simplified binding of a gpio mux for the common
  case where there is a single consumer (and no specific idle requirements)
- new binding for describing idle behaviour of mux-adg792a
- add bindings for the gpo-pins on the mux-adg792g
- use device_property_read_u32 instead of of_property_read_u32 in mux-gpio.c
- rename iio mux compatible to io-channel-mux (was iio-mux)
- remove linuxism in the bindings (it was mentioning a function name)
- add missing quote in the example in the io-channel-mux binding
- factor out preparatory cleanup of devres docs to its own patch
- add blank line in mux_chip_free
- use SIMPLE_{PARENT,MUX}_LOCKED instead of magic numbers {0,1} in
  i2c-mux-simple.c
- add some acks and a reviewed-by from 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,
peda

Peter Rosin (12):
  devres: trivial whitespace fix
  dt-bindings: document devicetree bindings for mux-controllers and
    mux-gpio
  mux: minimal mux subsystem and gpio-based mux controller
  iio: inkern: api for manipulating ext_info of iio channels
  dt-bindings: iio: io-channel-mux: document io-channel-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
  mux: adg792a: add mux controller driver for ADG792A/G
  dt-bindings: simplified bindings for single-user gpio mux
  mux: support simplified bindings for single-user gpio mux

 .../devicetree/bindings/i2c/i2c-mux-simple.txt     |  81 ++++
 .../bindings/iio/multiplexer/io-channel-mux.txt    |  39 ++
 .../devicetree/bindings/mux/mux-adg792a.txt        |  79 ++++
 .../devicetree/bindings/mux/mux-controller.txt     | 153 +++++++
 Documentation/devicetree/bindings/mux/mux-gpio.txt |  68 +++
 Documentation/driver-model/devres.txt              |  10 +-
 MAINTAINERS                                        |  14 +
 drivers/Kconfig                                    |   2 +
 drivers/Makefile                                   |   1 +
 drivers/i2c/muxes/Kconfig                          |  13 +
 drivers/i2c/muxes/Makefile                         |   1 +
 drivers/i2c/muxes/i2c-mux-simple.c                 | 182 ++++++++
 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/mux/Kconfig                                |  42 ++
 drivers/mux/Makefile                               |   7 +
 drivers/mux/mux-adg792a.c                          | 167 ++++++++
 drivers/mux/mux-core.c                             | 425 +++++++++++++++++++
 drivers/mux/mux-gpio.c                             | 129 ++++++
 drivers/mux/mux-gpio.h                             |  13 +
 include/linux/iio/consumer.h                       |  37 ++
 include/linux/mux.h                                | 244 +++++++++++
 26 files changed, 2248 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-simple.txt
 create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt
 create mode 100644 Documentation/devicetree/bindings/mux/mux-adg792a.txt
 create mode 100644 Documentation/devicetree/bindings/mux/mux-controller.txt
 create mode 100644 Documentation/devicetree/bindings/mux/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/mux/Kconfig
 create mode 100644 drivers/mux/Makefile
 create mode 100644 drivers/mux/mux-adg792a.c
 create mode 100644 drivers/mux/mux-core.c
 create mode 100644 drivers/mux/mux-gpio.c
 create mode 100644 drivers/mux/mux-gpio.h
 create mode 100644 include/linux/mux.h

-- 
2.1.4

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

* [PATCH v8 00/12] mux controller abstraction and iio/i2c muxes
@ 2017-01-18 15:57 ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

Hi!

v7 -> v8 changes
- cleanup the implementation of the simplified gpio bindings, but still...
- ...reorder patches so that they appear last in the series (patches 11
  and 12 were patches 4 and 5 in v7) since Jonathan convinced me that
  they were perhaps not such a good idea after all. But I still wanted
  to show the last version I had and I'm still a bit undecided...
- added some words to the remaining otherwise empty commit messages
- added various acks/reviews from Jonathan and Wolfram.
- move mux last in drivers/Kconfig and drivers/Makefile
- bump copyright years
- centralize error reporting of common operatinons to the mux core
- add WARN_ON for faulty usage of mux_chip_register
- simplify code for other WARN_ON call sites

v6 -> v7 changes
- move from drivers/misc/mux-* to drivers/mux/
  [I will remove Cc:s to Arnd and Greg for v8, when/if that happens]
- add managed versions of mux_chip_alloc and mux_chip_register
- use the above in mux-gpio.c and mux-adg792a.c
- also use them to support a simplified binding of a gpio mux for the common
  case where there is a single consumer (and no specific idle requirements)
- new binding for describing idle behaviour of mux-adg792a
- add bindings for the gpo-pins on the mux-adg792g
- use device_property_read_u32 instead of of_property_read_u32 in mux-gpio.c
- rename iio mux compatible to io-channel-mux (was iio-mux)
- remove linuxism in the bindings (it was mentioning a function name)
- add missing quote in the example in the io-channel-mux binding
- factor out preparatory cleanup of devres docs to its own patch
- add blank line in mux_chip_free
- use SIMPLE_{PARENT,MUX}_LOCKED instead of magic numbers {0,1} in
  i2c-mux-simple.c
- add some acks and a reviewed-by from 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,
peda

Peter Rosin (12):
  devres: trivial whitespace fix
  dt-bindings: document devicetree bindings for mux-controllers and
    mux-gpio
  mux: minimal mux subsystem and gpio-based mux controller
  iio: inkern: api for manipulating ext_info of iio channels
  dt-bindings: iio: io-channel-mux: document io-channel-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
  mux: adg792a: add mux controller driver for ADG792A/G
  dt-bindings: simplified bindings for single-user gpio mux
  mux: support simplified bindings for single-user gpio mux

 .../devicetree/bindings/i2c/i2c-mux-simple.txt     |  81 ++++
 .../bindings/iio/multiplexer/io-channel-mux.txt    |  39 ++
 .../devicetree/bindings/mux/mux-adg792a.txt        |  79 ++++
 .../devicetree/bindings/mux/mux-controller.txt     | 153 +++++++
 Documentation/devicetree/bindings/mux/mux-gpio.txt |  68 +++
 Documentation/driver-model/devres.txt              |  10 +-
 MAINTAINERS                                        |  14 +
 drivers/Kconfig                                    |   2 +
 drivers/Makefile                                   |   1 +
 drivers/i2c/muxes/Kconfig                          |  13 +
 drivers/i2c/muxes/Makefile                         |   1 +
 drivers/i2c/muxes/i2c-mux-simple.c                 | 182 ++++++++
 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/mux/Kconfig                                |  42 ++
 drivers/mux/Makefile                               |   7 +
 drivers/mux/mux-adg792a.c                          | 167 ++++++++
 drivers/mux/mux-core.c                             | 425 +++++++++++++++++++
 drivers/mux/mux-gpio.c                             | 129 ++++++
 drivers/mux/mux-gpio.h                             |  13 +
 include/linux/iio/consumer.h                       |  37 ++
 include/linux/mux.h                                | 244 +++++++++++
 26 files changed, 2248 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-simple.txt
 create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt
 create mode 100644 Documentation/devicetree/bindings/mux/mux-adg792a.txt
 create mode 100644 Documentation/devicetree/bindings/mux/mux-controller.txt
 create mode 100644 Documentation/devicetree/bindings/mux/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/mux/Kconfig
 create mode 100644 drivers/mux/Makefile
 create mode 100644 drivers/mux/mux-adg792a.c
 create mode 100644 drivers/mux/mux-core.c
 create mode 100644 drivers/mux/mux-gpio.c
 create mode 100644 drivers/mux/mux-gpio.h
 create mode 100644 include/linux/mux.h

-- 
2.1.4

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

* [PATCH v8 01/12] devres: trivial whitespace fix
  2017-01-18 15:57 ` Peter Rosin
@ 2017-01-18 15:57   ` Peter Rosin
  -1 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

Everything else is indented with two spaces, so fix the odd one out.

Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Peter Rosin <peda@axentia.se>
---
 Documentation/driver-model/devres.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index ca9d1eb46bc0..dc51fb024190 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -330,7 +330,7 @@ MEM
   devm_kzalloc()
 
 MFD
- devm_mfd_add_devices()
+  devm_mfd_add_devices()
 
 PER-CPU MEM
   devm_alloc_percpu()
-- 
2.1.4

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

* [PATCH v8 01/12] devres: trivial whitespace fix
@ 2017-01-18 15:57   ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

Everything else is indented with two spaces, so fix the odd one out.

Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Peter Rosin <peda@axentia.se>
---
 Documentation/driver-model/devres.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index ca9d1eb46bc0..dc51fb024190 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -330,7 +330,7 @@ MEM
   devm_kzalloc()
 
 MFD
- devm_mfd_add_devices()
+  devm_mfd_add_devices()
 
 PER-CPU MEM
   devm_alloc_percpu()
-- 
2.1.4


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

* [PATCH v8 02/12] dt-bindings: document devicetree bindings for mux-controllers and mux-gpio
  2017-01-18 15:57 ` Peter Rosin
@ 2017-01-18 15:57   ` Peter Rosin
  -1 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

Allow specifying that a single multiplexer controller can be used to control
several parallel multiplexers, thus enabling sharing of the multiplexer
controller by different consumers.

Add a binding for a first mux controller in the form of a GPIO based mux
controlled.

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

diff --git a/Documentation/devicetree/bindings/mux/mux-controller.txt b/Documentation/devicetree/bindings/mux/mux-controller.txt
new file mode 100644
index 000000000000..42b2177e5ae1
--- /dev/null
+++ b/Documentation/devicetree/bindings/mux/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, but a single mux controller can of course
+control several multiplexers for a single 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 requested mux controller
+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 = "io-channel-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 = "io-channel-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/mux/mux-gpio.txt b/Documentation/devicetree/bindings/mux/mux-gpio.txt
new file mode 100644
index 000000000000..8f6bda6f9d78
--- /dev/null
+++ b/Documentation/devicetree/bindings/mux/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 = "io-channel-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 40de344ba0e6..be57f5b8f2c2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8469,6 +8469,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/mux/
+
 MULTISOUND SOUND DRIVER
 M:	Andrew Veliath <andrewtv@usa.net>
 S:	Maintained
-- 
2.1.4

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

* [PATCH v8 02/12] dt-bindings: document devicetree bindings for mux-controllers and mux-gpio
@ 2017-01-18 15:57   ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

Allow specifying that a single multiplexer controller can be used to control
several parallel multiplexers, thus enabling sharing of the multiplexer
controller by different consumers.

Add a binding for a first mux controller in the form of a GPIO based mux
controlled.

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

diff --git a/Documentation/devicetree/bindings/mux/mux-controller.txt b/Documentation/devicetree/bindings/mux/mux-controller.txt
new file mode 100644
index 000000000000..42b2177e5ae1
--- /dev/null
+++ b/Documentation/devicetree/bindings/mux/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, but a single mux controller can of course
+control several multiplexers for a single 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 requested mux controller
+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 = "io-channel-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 = "io-channel-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/mux/mux-gpio.txt b/Documentation/devicetree/bindings/mux/mux-gpio.txt
new file mode 100644
index 000000000000..8f6bda6f9d78
--- /dev/null
+++ b/Documentation/devicetree/bindings/mux/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 = "io-channel-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 40de344ba0e6..be57f5b8f2c2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8469,6 +8469,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/mux/
+
 MULTISOUND SOUND DRIVER
 M:	Andrew Veliath <andrewtv@usa.net>
 S:	Maintained
-- 
2.1.4


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

* [PATCH v8 03/12] mux: minimal mux subsystem and gpio-based mux controller
  2017-01-18 15:57 ` Peter Rosin
@ 2017-01-18 15:57   ` Peter Rosin
  -1 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	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.

Reviewed-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Peter Rosin <peda@axentia.se>
---
 Documentation/driver-model/devres.txt |   8 +
 MAINTAINERS                           |   2 +
 drivers/Kconfig                       |   2 +
 drivers/Makefile                      |   1 +
 drivers/mux/Kconfig                   |  33 +++
 drivers/mux/Makefile                  |   6 +
 drivers/mux/mux-core.c                | 406 ++++++++++++++++++++++++++++++++++
 drivers/mux/mux-gpio.c                | 115 ++++++++++
 include/linux/mux.h                   | 244 ++++++++++++++++++++
 9 files changed, 817 insertions(+)
 create mode 100644 drivers/mux/Kconfig
 create mode 100644 drivers/mux/Makefile
 create mode 100644 drivers/mux/mux-core.c
 create mode 100644 drivers/mux/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 dc51fb024190..1e9ae701a587 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -332,6 +332,14 @@ MEM
 MFD
   devm_mfd_add_devices()
 
+MUX
+  devm_mux_chip_alloc()
+  devm_mux_chip_free()
+  devm_mux_chip_register()
+  devm_mux_chip_unregister()
+  devm_mux_control_get()
+  devm_mux_control_put()
+
 PER-CPU MEM
   devm_alloc_percpu()
   devm_free_percpu()
diff --git a/MAINTAINERS b/MAINTAINERS
index be57f5b8f2c2..e4fac17e0fa4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8473,6 +8473,8 @@ MULTIPLEXER SUBSYSTEM
 M:	Peter Rosin <peda@axentia.se>
 S:	Maintained
 F:	Documentation/devicetree/bindings/mux/
+F:	include/linux/mux.h
+F:	drivers/mux/
 
 MULTISOUND SOUND DRIVER
 M:	Andrew Veliath <andrewtv@usa.net>
diff --git a/drivers/Kconfig b/drivers/Kconfig
index e1e2066cecdb..ea231018089e 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -202,4 +202,6 @@ source "drivers/hwtracing/intel_th/Kconfig"
 
 source "drivers/fpga/Kconfig"
 
+source "drivers/mux/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 060026a02f59..8ff0460bb2f8 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -173,3 +173,4 @@ obj-$(CONFIG_STM)		+= hwtracing/stm/
 obj-$(CONFIG_ANDROID)		+= android/
 obj-$(CONFIG_NVMEM)		+= nvmem/
 obj-$(CONFIG_FPGA)		+= fpga/
+obj-$(CONFIG_MULTIPLEXER)	+= mux/
diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
new file mode 100644
index 000000000000..57e6f4e5fda9
--- /dev/null
+++ b/drivers/mux/Kconfig
@@ -0,0 +1,33 @@
+#
+# Multiplexer devices
+#
+
+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 the driver as a module, choose M here: the module will
+	  be called mux-gpio.
+
+endif
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
new file mode 100644
index 000000000000..facc43da3648
--- /dev/null
+++ b/drivers/mux/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for multiplexer devices.
+#
+
+obj-$(CONFIG_MULTIPLEXER)      	+= mux-core.o
+obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c
new file mode 100644
index 000000000000..16a61253d164
--- /dev/null
+++ b/drivers/mux/mux-core.c
@@ -0,0 +1,406 @@
+/*
+ * Multiplexer subsystem
+ *
+ * Copyright (C) 2017 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 (WARN_ON(!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) {
+			dev_err(&mux_chip->dev, "unable to set idle state\n");
+			return ret;
+		}
+	}
+
+	ret = device_add(&mux_chip->dev);
+	if (ret < 0)
+		dev_err(&mux_chip->dev,
+			"device_add failed in mux_chip_register: %d\n", ret);
+	return ret;
+}
+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);
+
+static void devm_mux_chip_release(struct device *dev, void *res)
+{
+	struct mux_chip *mux_chip = *(struct mux_chip **)res;
+
+	mux_chip_free(mux_chip);
+}
+
+struct mux_chip *devm_mux_chip_alloc(struct device *dev,
+				     unsigned int controllers,
+				     size_t sizeof_priv)
+{
+	struct mux_chip **ptr, *mux_chip;
+
+	ptr = devres_alloc(devm_mux_chip_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	mux_chip = mux_chip_alloc(dev, controllers, sizeof_priv);
+	if (IS_ERR(mux_chip)) {
+		devres_free(ptr);
+		return mux_chip;
+	}
+
+	*ptr = mux_chip;
+	devres_add(dev, ptr);
+
+	return mux_chip;
+}
+EXPORT_SYMBOL_GPL(devm_mux_chip_alloc);
+
+static int devm_mux_chip_match(struct device *dev, void *res, void *data)
+{
+	struct mux_chip **r = res;
+
+	if (WARN_ON(!r || !*r))
+		return 0;
+
+	return *r == data;
+}
+
+void devm_mux_chip_free(struct device *dev, struct mux_chip *mux_chip)
+{
+	WARN_ON(devres_release(dev, devm_mux_chip_release,
+			       devm_mux_chip_match, mux_chip));
+}
+EXPORT_SYMBOL_GPL(devm_mux_chip_free);
+
+static void devm_mux_chip_reg_release(struct device *dev, void *res)
+{
+	struct mux_chip *mux_chip = *(struct mux_chip **)res;
+
+	mux_chip_unregister(mux_chip);
+}
+
+int devm_mux_chip_register(struct device *dev,
+			   struct mux_chip *mux_chip)
+{
+	struct mux_chip **ptr;
+	int res;
+
+	ptr = devres_alloc(devm_mux_chip_reg_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+
+	res = mux_chip_register(mux_chip);
+	if (res) {
+		devres_free(ptr);
+		return res;
+	}
+
+	*ptr = mux_chip;
+	devres_add(dev, ptr);
+
+	return res;
+}
+EXPORT_SYMBOL_GPL(devm_mux_chip_register);
+
+void devm_mux_chip_unregister(struct device *dev, struct mux_chip *mux_chip)
+{
+	WARN_ON(devres_release(dev, devm_mux_chip_reg_release,
+			       devm_mux_chip_match, mux_chip));
+}
+EXPORT_SYMBOL_GPL(devm_mux_chip_unregister);
+
+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) {
+			dev_err(dev, "mux controller '%s' not found\n",
+				mux_name);
+			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) {
+		dev_err(dev, "%s: bad mux controller %u specified in %s\n",
+			np->full_name, controller, args.np->full_name);
+		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 (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/mux/mux-gpio.c b/drivers/mux/mux-gpio.c
new file mode 100644
index 000000000000..48ca4d6b4fc7
--- /dev/null
+++ b/drivers/mux/mux-gpio.c
@@ -0,0 +1,115 @@
+/*
+ * GPIO-controlled multiplexer driver
+ *
+ * Copyright (C) 2017 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_platform.h>
+#include <linux/platform_device.h>
+#include <linux/property.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 = dev->of_node;
+	struct mux_chip *mux_chip;
+	struct mux_gpio *mux_gpio;
+	int pins;
+	u32 idle_state;
+	int ret;
+
+	pins = gpiod_count(dev, "mux");
+	if (pins < 0)
+		return pins;
+
+	mux_chip = devm_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;
+
+	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");
+		return ret;
+	}
+	WARN_ON(pins != mux_gpio->gpios->ndescs);
+	mux_chip->mux->states = 1 << pins;
+
+	ret = device_property_read_u32(dev, "idle-state", &idle_state);
+	if (ret >= 0) {
+		if (idle_state >= mux_chip->mux->states) {
+			dev_err(dev, "invalid idle-state %u\n", idle_state);
+			return -EINVAL;
+		}
+
+		mux_chip->mux->idle_state = idle_state;
+	}
+
+	ret = devm_mux_chip_register(dev, mux_chip);
+	if (ret < 0)
+		return ret;
+
+	dev_info(dev, "%u-way mux-controller registered\n",
+		 mux_chip->mux->states);
+
+	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,
+};
+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..ec9e605d8acf
--- /dev/null
+++ b/include/linux/mux.h
@@ -0,0 +1,244 @@
+/*
+ * mux.h - definitions for the multiplexer interface
+ *
+ * Copyright (C) 2017 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);
+
+/**
+ * devm_mux_chip_alloc() - Resource-managed version of mux_chip_alloc().
+ * @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.
+ *
+ * See mux_chip_alloc() for more details.
+ *
+ * Return: A pointer to the new mux-chip, NULL on failure.
+ */
+struct mux_chip *devm_mux_chip_alloc(struct device *dev,
+				     unsigned int controllers,
+				     size_t sizeof_priv);
+
+/**
+ * devm_mux_chip_register() - Resource-managed version mux_chip_register().
+ * @dev: The parent device implementing the mux interface.
+ * @mux_chip: The mux-chip to register.
+ *
+ * See mux_chip_register() for more details.
+ *
+ * Return: Zero on success or a negative errno on error.
+ */
+int devm_mux_chip_register(struct device *dev, struct mux_chip *mux_chip);
+
+/**
+ * devm_mux_chip_unregister() - Resource-managed version mux_chip_unregister().
+ * @dev: The device that originally registered the mux-chip.
+ * @mux_chip: The mux-chip to unregister.
+ *
+ * See mux_chip_unregister() for more details.
+ *
+ * Note that you do not normally need to call this function.
+ */
+void devm_mux_chip_unregister(struct device *dev, struct mux_chip *mux_chip);
+
+/**
+ * devm_mux_chip_free() - Resource-managed version mux_chip_free().
+ * @dev: The device that originally got the mux-chip.
+ * @mux_chip: The mux-chip to free.
+ *
+ * See mux_chip_free() for more details.
+ *
+ * Note that you do not normally need to call this function.
+ */
+void devm_mux_chip_free(struct device *dev, 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] 54+ messages in thread

* [PATCH v8 03/12] mux: minimal mux subsystem and gpio-based mux controller
@ 2017-01-18 15:57   ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	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.

Reviewed-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Peter Rosin <peda@axentia.se>
---
 Documentation/driver-model/devres.txt |   8 +
 MAINTAINERS                           |   2 +
 drivers/Kconfig                       |   2 +
 drivers/Makefile                      |   1 +
 drivers/mux/Kconfig                   |  33 +++
 drivers/mux/Makefile                  |   6 +
 drivers/mux/mux-core.c                | 406 ++++++++++++++++++++++++++++++++++
 drivers/mux/mux-gpio.c                | 115 ++++++++++
 include/linux/mux.h                   | 244 ++++++++++++++++++++
 9 files changed, 817 insertions(+)
 create mode 100644 drivers/mux/Kconfig
 create mode 100644 drivers/mux/Makefile
 create mode 100644 drivers/mux/mux-core.c
 create mode 100644 drivers/mux/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 dc51fb024190..1e9ae701a587 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -332,6 +332,14 @@ MEM
 MFD
   devm_mfd_add_devices()
 
+MUX
+  devm_mux_chip_alloc()
+  devm_mux_chip_free()
+  devm_mux_chip_register()
+  devm_mux_chip_unregister()
+  devm_mux_control_get()
+  devm_mux_control_put()
+
 PER-CPU MEM
   devm_alloc_percpu()
   devm_free_percpu()
diff --git a/MAINTAINERS b/MAINTAINERS
index be57f5b8f2c2..e4fac17e0fa4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8473,6 +8473,8 @@ MULTIPLEXER SUBSYSTEM
 M:	Peter Rosin <peda@axentia.se>
 S:	Maintained
 F:	Documentation/devicetree/bindings/mux/
+F:	include/linux/mux.h
+F:	drivers/mux/
 
 MULTISOUND SOUND DRIVER
 M:	Andrew Veliath <andrewtv@usa.net>
diff --git a/drivers/Kconfig b/drivers/Kconfig
index e1e2066cecdb..ea231018089e 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -202,4 +202,6 @@ source "drivers/hwtracing/intel_th/Kconfig"
 
 source "drivers/fpga/Kconfig"
 
+source "drivers/mux/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 060026a02f59..8ff0460bb2f8 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -173,3 +173,4 @@ obj-$(CONFIG_STM)		+= hwtracing/stm/
 obj-$(CONFIG_ANDROID)		+= android/
 obj-$(CONFIG_NVMEM)		+= nvmem/
 obj-$(CONFIG_FPGA)		+= fpga/
+obj-$(CONFIG_MULTIPLEXER)	+= mux/
diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
new file mode 100644
index 000000000000..57e6f4e5fda9
--- /dev/null
+++ b/drivers/mux/Kconfig
@@ -0,0 +1,33 @@
+#
+# Multiplexer devices
+#
+
+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 the driver as a module, choose M here: the module will
+	  be called mux-gpio.
+
+endif
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
new file mode 100644
index 000000000000..facc43da3648
--- /dev/null
+++ b/drivers/mux/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for multiplexer devices.
+#
+
+obj-$(CONFIG_MULTIPLEXER)      	+= mux-core.o
+obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c
new file mode 100644
index 000000000000..16a61253d164
--- /dev/null
+++ b/drivers/mux/mux-core.c
@@ -0,0 +1,406 @@
+/*
+ * Multiplexer subsystem
+ *
+ * Copyright (C) 2017 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 (WARN_ON(!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) {
+			dev_err(&mux_chip->dev, "unable to set idle state\n");
+			return ret;
+		}
+	}
+
+	ret = device_add(&mux_chip->dev);
+	if (ret < 0)
+		dev_err(&mux_chip->dev,
+			"device_add failed in mux_chip_register: %d\n", ret);
+	return ret;
+}
+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);
+
+static void devm_mux_chip_release(struct device *dev, void *res)
+{
+	struct mux_chip *mux_chip = *(struct mux_chip **)res;
+
+	mux_chip_free(mux_chip);
+}
+
+struct mux_chip *devm_mux_chip_alloc(struct device *dev,
+				     unsigned int controllers,
+				     size_t sizeof_priv)
+{
+	struct mux_chip **ptr, *mux_chip;
+
+	ptr = devres_alloc(devm_mux_chip_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	mux_chip = mux_chip_alloc(dev, controllers, sizeof_priv);
+	if (IS_ERR(mux_chip)) {
+		devres_free(ptr);
+		return mux_chip;
+	}
+
+	*ptr = mux_chip;
+	devres_add(dev, ptr);
+
+	return mux_chip;
+}
+EXPORT_SYMBOL_GPL(devm_mux_chip_alloc);
+
+static int devm_mux_chip_match(struct device *dev, void *res, void *data)
+{
+	struct mux_chip **r = res;
+
+	if (WARN_ON(!r || !*r))
+		return 0;
+
+	return *r == data;
+}
+
+void devm_mux_chip_free(struct device *dev, struct mux_chip *mux_chip)
+{
+	WARN_ON(devres_release(dev, devm_mux_chip_release,
+			       devm_mux_chip_match, mux_chip));
+}
+EXPORT_SYMBOL_GPL(devm_mux_chip_free);
+
+static void devm_mux_chip_reg_release(struct device *dev, void *res)
+{
+	struct mux_chip *mux_chip = *(struct mux_chip **)res;
+
+	mux_chip_unregister(mux_chip);
+}
+
+int devm_mux_chip_register(struct device *dev,
+			   struct mux_chip *mux_chip)
+{
+	struct mux_chip **ptr;
+	int res;
+
+	ptr = devres_alloc(devm_mux_chip_reg_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+
+	res = mux_chip_register(mux_chip);
+	if (res) {
+		devres_free(ptr);
+		return res;
+	}
+
+	*ptr = mux_chip;
+	devres_add(dev, ptr);
+
+	return res;
+}
+EXPORT_SYMBOL_GPL(devm_mux_chip_register);
+
+void devm_mux_chip_unregister(struct device *dev, struct mux_chip *mux_chip)
+{
+	WARN_ON(devres_release(dev, devm_mux_chip_reg_release,
+			       devm_mux_chip_match, mux_chip));
+}
+EXPORT_SYMBOL_GPL(devm_mux_chip_unregister);
+
+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) {
+			dev_err(dev, "mux controller '%s' not found\n",
+				mux_name);
+			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) {
+		dev_err(dev, "%s: bad mux controller %u specified in %s\n",
+			np->full_name, controller, args.np->full_name);
+		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 (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/mux/mux-gpio.c b/drivers/mux/mux-gpio.c
new file mode 100644
index 000000000000..48ca4d6b4fc7
--- /dev/null
+++ b/drivers/mux/mux-gpio.c
@@ -0,0 +1,115 @@
+/*
+ * GPIO-controlled multiplexer driver
+ *
+ * Copyright (C) 2017 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_platform.h>
+#include <linux/platform_device.h>
+#include <linux/property.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 = dev->of_node;
+	struct mux_chip *mux_chip;
+	struct mux_gpio *mux_gpio;
+	int pins;
+	u32 idle_state;
+	int ret;
+
+	pins = gpiod_count(dev, "mux");
+	if (pins < 0)
+		return pins;
+
+	mux_chip = devm_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;
+
+	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");
+		return ret;
+	}
+	WARN_ON(pins != mux_gpio->gpios->ndescs);
+	mux_chip->mux->states = 1 << pins;
+
+	ret = device_property_read_u32(dev, "idle-state", &idle_state);
+	if (ret >= 0) {
+		if (idle_state >= mux_chip->mux->states) {
+			dev_err(dev, "invalid idle-state %u\n", idle_state);
+			return -EINVAL;
+		}
+
+		mux_chip->mux->idle_state = idle_state;
+	}
+
+	ret = devm_mux_chip_register(dev, mux_chip);
+	if (ret < 0)
+		return ret;
+
+	dev_info(dev, "%u-way mux-controller registered\n",
+		 mux_chip->mux->states);
+
+	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,
+};
+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..ec9e605d8acf
--- /dev/null
+++ b/include/linux/mux.h
@@ -0,0 +1,244 @@
+/*
+ * mux.h - definitions for the multiplexer interface
+ *
+ * Copyright (C) 2017 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);
+
+/**
+ * devm_mux_chip_alloc() - Resource-managed version of mux_chip_alloc().
+ * @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.
+ *
+ * See mux_chip_alloc() for more details.
+ *
+ * Return: A pointer to the new mux-chip, NULL on failure.
+ */
+struct mux_chip *devm_mux_chip_alloc(struct device *dev,
+				     unsigned int controllers,
+				     size_t sizeof_priv);
+
+/**
+ * devm_mux_chip_register() - Resource-managed version mux_chip_register().
+ * @dev: The parent device implementing the mux interface.
+ * @mux_chip: The mux-chip to register.
+ *
+ * See mux_chip_register() for more details.
+ *
+ * Return: Zero on success or a negative errno on error.
+ */
+int devm_mux_chip_register(struct device *dev, struct mux_chip *mux_chip);
+
+/**
+ * devm_mux_chip_unregister() - Resource-managed version mux_chip_unregister().
+ * @dev: The device that originally registered the mux-chip.
+ * @mux_chip: The mux-chip to unregister.
+ *
+ * See mux_chip_unregister() for more details.
+ *
+ * Note that you do not normally need to call this function.
+ */
+void devm_mux_chip_unregister(struct device *dev, struct mux_chip *mux_chip);
+
+/**
+ * devm_mux_chip_free() - Resource-managed version mux_chip_free().
+ * @dev: The device that originally got the mux-chip.
+ * @mux_chip: The mux-chip to free.
+ *
+ * See mux_chip_free() for more details.
+ *
+ * Note that you do not normally need to call this function.
+ */
+void devm_mux_chip_free(struct device *dev, 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] 54+ messages in thread

* [PATCH v8 04/12] iio: inkern: api for manipulating ext_info of iio channels
  2017-01-18 15:57 ` Peter Rosin
@ 2017-01-18 15:57   ` Peter Rosin
  -1 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

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

Acked-by: Jonathan Cameron <jic23@kernel.org>
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] 54+ messages in thread

* [PATCH v8 04/12] iio: inkern: api for manipulating ext_info of iio channels
@ 2017-01-18 15:57   ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

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

Acked-by: Jonathan Cameron <jic23@kernel.org>
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] 54+ messages in thread

* [PATCH v8 05/12] dt-bindings: iio: io-channel-mux: document io-channel-mux bindings
  2017-01-18 15:57 ` Peter Rosin
@ 2017-01-18 15:57   ` Peter Rosin
  -1 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

Describe how a multiplexer can be used to select which signal is fed to
an io-channel.

Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../bindings/iio/multiplexer/io-channel-mux.txt    | 39 ++++++++++++++++++++++
 MAINTAINERS                                        |  6 ++++
 2 files changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt

diff --git a/Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt b/Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt
new file mode 100644
index 000000000000..c82794002595
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt
@@ -0,0 +1,39 @@
+I/O channel 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 : "io-channel-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.
+
+For each non-empty string in the channels property, an io-channel will
+be created. The number of this io-channel is the same as the index into
+the list of strings in the channels property, and also matches the mux
+controller state. The mux controller state is described in
+../mux/mux-controller.txt
+
+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 = "io-channel-mux";
+		io-channels = <&adc 0>;
+		io-channel-names = "parent";
+
+		mux-controls = <&mux>;
+
+		channels = "sync", "in", "system-regulator";
+	};
diff --git a/MAINTAINERS b/MAINTAINERS
index e4fac17e0fa4..35325a3d9ca4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6289,6 +6289,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] 54+ messages in thread

* [PATCH v8 05/12] dt-bindings: iio: io-channel-mux: document io-channel-mux bindings
@ 2017-01-18 15:57   ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

Describe how a multiplexer can be used to select which signal is fed to
an io-channel.

Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../bindings/iio/multiplexer/io-channel-mux.txt    | 39 ++++++++++++++++++++++
 MAINTAINERS                                        |  6 ++++
 2 files changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt

diff --git a/Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt b/Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt
new file mode 100644
index 000000000000..c82794002595
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt
@@ -0,0 +1,39 @@
+I/O channel 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 : "io-channel-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.
+
+For each non-empty string in the channels property, an io-channel will
+be created. The number of this io-channel is the same as the index into
+the list of strings in the channels property, and also matches the mux
+controller state. The mux controller state is described in
+../mux/mux-controller.txt
+
+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 = "io-channel-mux";
+		io-channels = <&adc 0>;
+		io-channel-names = "parent";
+
+		mux-controls = <&mux>;
+
+		channels = "sync", "in", "system-regulator";
+	};
diff --git a/MAINTAINERS b/MAINTAINERS
index e4fac17e0fa4..35325a3d9ca4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6289,6 +6289,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] 54+ messages in thread

* [PATCH v8 06/12] iio: multiplexer: new iio category and iio-mux driver
  2017-01-18 15:57 ` Peter Rosin
@ 2017-01-18 15:57   ` Peter Rosin
  -1 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	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.

Reviewed-by: Jonathan Cameron <jic23@kernel.org>
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 35325a3d9ca4..bfbc1a9dd3fe 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6294,6 +6294,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..94d40f9bef4c
--- /dev/null
+++ b/drivers/iio/multiplexer/iio-mux.c
@@ -0,0 +1,456 @@
+/*
+ * IIO multiplexer driver
+ *
+ * Copyright (C) 2017 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 = "io-channel-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] 54+ messages in thread

* [PATCH v8 06/12] iio: multiplexer: new iio category and iio-mux driver
@ 2017-01-18 15:57   ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	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.

Reviewed-by: Jonathan Cameron <jic23@kernel.org>
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 35325a3d9ca4..bfbc1a9dd3fe 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6294,6 +6294,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..94d40f9bef4c
--- /dev/null
+++ b/drivers/iio/multiplexer/iio-mux.c
@@ -0,0 +1,456 @@
+/*
+ * IIO multiplexer driver
+ *
+ * Copyright (C) 2017 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 = "io-channel-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] 54+ messages in thread

* [PATCH v8 07/12] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
  2017-01-18 15:57 ` Peter Rosin
@ 2017-01-18 15:57   ` Peter Rosin
  -1 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

Describe how a generic multiplexer controller is used to mux an i2c bus.

Acked-by: Jonathan Cameron <jic23@kernel.org>
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..253d5027843b
--- /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 ../mux/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] 54+ messages in thread

* [PATCH v8 07/12] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
@ 2017-01-18 15:57   ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

Describe how a generic multiplexer controller is used to mux an i2c bus.

Acked-by: Jonathan Cameron <jic23@kernel.org>
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..253d5027843b
--- /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 ../mux/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] 54+ messages in thread

* [PATCH v8 08/12] i2c: i2c-mux-simple: new driver
@ 2017-01-18 15:57   ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	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.

Acked-by: Jonathan Cameron <jic23@kernel.org>
Acked-by: Wolfram Sang <wsa@the-dreams.de>
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 | 182 +++++++++++++++++++++++++++++++++++++
 3 files changed, 196 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..6a7de6e91ae3
--- /dev/null
+++ b/drivers/i2c/muxes/i2c-mux-simple.c
@@ -0,0 +1,182 @@
+/*
+ * Generic simple I2C multiplexer
+ *
+ * Copyright (C) 2017 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>
+
+#define SIMPLE_PARENT_LOCKED (0)
+#define SIMPLE_MUX_LOCKED    (1)
+
+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 *)SIMPLE_PARENT_LOCKED, },
+	{ .compatible = "i2c-mux-simple,mux-locked",
+	  .data = (void *)SIMPLE_MUX_LOCKED, },
+	{},
+};
+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] 54+ messages in thread

* [PATCH v8 08/12] i2c: i2c-mux-simple: new driver
@ 2017-01-18 15:57   ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	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.

Acked-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Acked-by: Wolfram Sang <wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org>
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 | 182 +++++++++++++++++++++++++++++++++++++
 3 files changed, 196 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..6a7de6e91ae3
--- /dev/null
+++ b/drivers/i2c/muxes/i2c-mux-simple.c
@@ -0,0 +1,182 @@
+/*
+ * Generic simple I2C multiplexer
+ *
+ * Copyright (C) 2017 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>
+
+#define SIMPLE_PARENT_LOCKED (0)
+#define SIMPLE_MUX_LOCKED    (1)
+
+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 *)SIMPLE_PARENT_LOCKED, },
+	{ .compatible = "i2c-mux-simple,mux-locked",
+	  .data = (void *)SIMPLE_MUX_LOCKED, },
+	{},
+};
+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

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

* [PATCH v8 09/12] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
  2017-01-18 15:57 ` Peter Rosin
@ 2017-01-18 15:57   ` Peter Rosin
  -1 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

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

Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../devicetree/bindings/mux/mux-adg792a.txt        | 79 ++++++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mux/mux-adg792a.txt

diff --git a/Documentation/devicetree/bindings/mux/mux-adg792a.txt b/Documentation/devicetree/bindings/mux/mux-adg792a.txt
new file mode 100644
index 000000000000..0b26dd11f070
--- /dev/null
+++ b/Documentation/devicetree/bindings/mux/mux-adg792a.txt
@@ -0,0 +1,79 @@
+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 for ADG792G:
+- gpio-controller : if present, #gpio-cells below is required.
+- #gpio-cells : should be <2>
+			  - First cell is the GPO line number, i.e. 0 or 1
+			  - Second cell is used to specify active high (0)
+			    or active low (1)
+
+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 2-tuples with mux controller number
+  and state that mux controllers will have when idle. States 0 through 3
+  correspond to signals A through D in the datasheet.
+- adi,idle-high-impedance : if present, array of mux controller numbers that
+  should be in the disconnected high-impedance state when idle.
+
+Mux controller states 0 through 3 correspond to signals A through D in the
+datasheet. If a mux controller is mentioned in neither adi,idle-state nor
+adi,idle-high-impedance it is left in its previously selected state when idle.
+
+Example:
+
+	/*
+	 * Three independent mux controllers (of which one is used).
+	 * Mux 0 is disconnected when idle, mux 1 idles with signal C
+	 * and mux 2 idles with signal A.
+	 */
+	&i2c0 {
+		mux: adg792a@50 {
+			compatible = "adi,adg792a";
+			reg = <0x50>;
+			#mux-control-cells = <1>;
+
+			adi,idle-high-impedance = <0>;
+			adi,idle-state = <1 2>, <2 0>;
+		};
+	};
+
+	adc-mux {
+		compatible = "io-channel-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 = "io-channel-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] 54+ messages in thread

* [PATCH v8 09/12] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
@ 2017-01-18 15:57   ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

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

Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../devicetree/bindings/mux/mux-adg792a.txt        | 79 ++++++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mux/mux-adg792a.txt

diff --git a/Documentation/devicetree/bindings/mux/mux-adg792a.txt b/Documentation/devicetree/bindings/mux/mux-adg792a.txt
new file mode 100644
index 000000000000..0b26dd11f070
--- /dev/null
+++ b/Documentation/devicetree/bindings/mux/mux-adg792a.txt
@@ -0,0 +1,79 @@
+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 for ADG792G:
+- gpio-controller : if present, #gpio-cells below is required.
+- #gpio-cells : should be <2>
+			  - First cell is the GPO line number, i.e. 0 or 1
+			  - Second cell is used to specify active high (0)
+			    or active low (1)
+
+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 2-tuples with mux controller number
+  and state that mux controllers will have when idle. States 0 through 3
+  correspond to signals A through D in the datasheet.
+- adi,idle-high-impedance : if present, array of mux controller numbers that
+  should be in the disconnected high-impedance state when idle.
+
+Mux controller states 0 through 3 correspond to signals A through D in the
+datasheet. If a mux controller is mentioned in neither adi,idle-state nor
+adi,idle-high-impedance it is left in its previously selected state when idle.
+
+Example:
+
+	/*
+	 * Three independent mux controllers (of which one is used).
+	 * Mux 0 is disconnected when idle, mux 1 idles with signal C
+	 * and mux 2 idles with signal A.
+	 */
+	&i2c0 {
+		mux: adg792a@50 {
+			compatible = "adi,adg792a";
+			reg = <0x50>;
+			#mux-control-cells = <1>;
+
+			adi,idle-high-impedance = <0>;
+			adi,idle-state = <1 2>, <2 0>;
+		};
+	};
+
+	adc-mux {
+		compatible = "io-channel-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 = "io-channel-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] 54+ messages in thread

* [PATCH v8 10/12] mux: adg792a: add mux controller driver for ADG792A/G
  2017-01-18 15:57 ` Peter Rosin
@ 2017-01-18 15:57   ` Peter Rosin
  -1 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

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

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

diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index 57e6f4e5fda9..d13fcf98958e 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -16,6 +16,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
+	  parallel 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/mux/Makefile b/drivers/mux/Makefile
index facc43da3648..fddbb073fc77 100644
--- a/drivers/mux/Makefile
+++ b/drivers/mux/Makefile
@@ -3,4 +3,5 @@
 #
 
 obj-$(CONFIG_MULTIPLEXER)      	+= mux-core.o
+obj-$(CONFIG_MUX_ADG792A)	+= mux-adg792a.o
 obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
diff --git a/drivers/mux/mux-adg792a.c b/drivers/mux/mux-adg792a.c
new file mode 100644
index 000000000000..6a4c4c9f585b
--- /dev/null
+++ b/drivers/mux/mux-adg792a.c
@@ -0,0 +1,167 @@
+/*
+ * Multiplexer driver for Analog Devices ADG792A/G Triple 4:1 mux
+ *
+ * Copyright (C) 2017 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)
+
+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 count;
+	int ret;
+	int i;
+
+	parallel = of_property_read_bool(i2c->dev.of_node, "adi,parallel");
+
+	mux_chip = devm_mux_chip_alloc(dev, parallel ? 1 : 3, 0);
+	if (!mux_chip)
+		return -ENOMEM;
+
+	mux_chip->ops = &adg792a_ops;
+
+	ret = i2c_smbus_write_byte_data(i2c, ADG792A_DISABLE_ALL,
+					ADG792A_RESET | ADG792A_LDSW);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < mux_chip->controllers; ++i) {
+		struct mux_control *mux = &mux_chip->mux[i];
+
+		mux->states = 4;
+	}
+
+	count = of_property_count_u32_elems(dev->of_node, "adi,idle-state");
+	for (i = 0; i < count; i += 2) {
+		u32 index;
+		u32 idle_state;
+
+		ret = of_property_read_u32_index(dev->of_node,
+						 "adi,idle-state", i,
+						 &index);
+		if (ret < 0)
+			return ret;
+		if (index >= mux_chip->controllers) {
+			dev_err(dev, "invalid mux %u\n", index);
+			return -EINVAL;
+		}
+
+		ret = of_property_read_u32_index(dev->of_node,
+						 "adi,idle-state", i + 1,
+						 &idle_state);
+		if (ret < 0)
+			return ret;
+		if (idle_state >= ADG792A_DISABLE_STATE) {
+			dev_err(dev, "invalid idle-state %u for mux %u\n",
+				idle_state, index);
+			return -EINVAL;
+		}
+		mux_chip->mux[index].idle_state = idle_state;
+	}
+
+	count = of_property_count_u32_elems(dev->of_node,
+					    "adi,idle-high-impedance");
+	for (i = 0; i < count; ++i) {
+		u32 index;
+
+		ret = of_property_read_u32_index(dev->of_node,
+						 "adi,idle-high-impedance", i,
+						 &index);
+		if (ret < 0)
+			return ret;
+		if (index >= mux_chip->controllers) {
+			dev_err(dev, "invalid mux %u\n", index);
+			return -EINVAL;
+		}
+
+		mux_chip->mux[index].idle_state = ADG792A_DISABLE_STATE;
+	}
+
+	ret = devm_mux_chip_register(dev, mux_chip);
+	if (ret < 0)
+		return ret;
+
+	if (parallel)
+		dev_info(dev, "triple pole quadruple throw mux registered\n");
+	else
+		dev_info(dev, "3x single pole quadruple throw muxes registered\n");
+
+	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,
+	.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] 54+ messages in thread

* [PATCH v8 10/12] mux: adg792a: add mux controller driver for ADG792A/G
@ 2017-01-18 15:57   ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

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

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

diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index 57e6f4e5fda9..d13fcf98958e 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -16,6 +16,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
+	  parallel 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/mux/Makefile b/drivers/mux/Makefile
index facc43da3648..fddbb073fc77 100644
--- a/drivers/mux/Makefile
+++ b/drivers/mux/Makefile
@@ -3,4 +3,5 @@
 #
 
 obj-$(CONFIG_MULTIPLEXER)      	+= mux-core.o
+obj-$(CONFIG_MUX_ADG792A)	+= mux-adg792a.o
 obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
diff --git a/drivers/mux/mux-adg792a.c b/drivers/mux/mux-adg792a.c
new file mode 100644
index 000000000000..6a4c4c9f585b
--- /dev/null
+++ b/drivers/mux/mux-adg792a.c
@@ -0,0 +1,167 @@
+/*
+ * Multiplexer driver for Analog Devices ADG792A/G Triple 4:1 mux
+ *
+ * Copyright (C) 2017 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)
+
+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 count;
+	int ret;
+	int i;
+
+	parallel = of_property_read_bool(i2c->dev.of_node, "adi,parallel");
+
+	mux_chip = devm_mux_chip_alloc(dev, parallel ? 1 : 3, 0);
+	if (!mux_chip)
+		return -ENOMEM;
+
+	mux_chip->ops = &adg792a_ops;
+
+	ret = i2c_smbus_write_byte_data(i2c, ADG792A_DISABLE_ALL,
+					ADG792A_RESET | ADG792A_LDSW);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < mux_chip->controllers; ++i) {
+		struct mux_control *mux = &mux_chip->mux[i];
+
+		mux->states = 4;
+	}
+
+	count = of_property_count_u32_elems(dev->of_node, "adi,idle-state");
+	for (i = 0; i < count; i += 2) {
+		u32 index;
+		u32 idle_state;
+
+		ret = of_property_read_u32_index(dev->of_node,
+						 "adi,idle-state", i,
+						 &index);
+		if (ret < 0)
+			return ret;
+		if (index >= mux_chip->controllers) {
+			dev_err(dev, "invalid mux %u\n", index);
+			return -EINVAL;
+		}
+
+		ret = of_property_read_u32_index(dev->of_node,
+						 "adi,idle-state", i + 1,
+						 &idle_state);
+		if (ret < 0)
+			return ret;
+		if (idle_state >= ADG792A_DISABLE_STATE) {
+			dev_err(dev, "invalid idle-state %u for mux %u\n",
+				idle_state, index);
+			return -EINVAL;
+		}
+		mux_chip->mux[index].idle_state = idle_state;
+	}
+
+	count = of_property_count_u32_elems(dev->of_node,
+					    "adi,idle-high-impedance");
+	for (i = 0; i < count; ++i) {
+		u32 index;
+
+		ret = of_property_read_u32_index(dev->of_node,
+						 "adi,idle-high-impedance", i,
+						 &index);
+		if (ret < 0)
+			return ret;
+		if (index >= mux_chip->controllers) {
+			dev_err(dev, "invalid mux %u\n", index);
+			return -EINVAL;
+		}
+
+		mux_chip->mux[index].idle_state = ADG792A_DISABLE_STATE;
+	}
+
+	ret = devm_mux_chip_register(dev, mux_chip);
+	if (ret < 0)
+		return ret;
+
+	if (parallel)
+		dev_info(dev, "triple pole quadruple throw mux registered\n");
+	else
+		dev_info(dev, "3x single pole quadruple throw muxes registered\n");
+
+	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,
+	.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] 54+ messages in thread

* [PATCH v8 11/12] dt-bindings: simplified bindings for single-user gpio mux
  2017-01-18 15:57 ` Peter Rosin
@ 2017-01-18 15:57   ` Peter Rosin
  -1 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

Allow bindings for a GPIO controlled mux to be specified in the
mux consumer node.

Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../devicetree/bindings/mux/mux-controller.txt     | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/Documentation/devicetree/bindings/mux/mux-controller.txt b/Documentation/devicetree/bindings/mux/mux-controller.txt
index 42b2177e5ae1..4e89df8b2392 100644
--- a/Documentation/devicetree/bindings/mux/mux-controller.txt
+++ b/Documentation/devicetree/bindings/mux/mux-controller.txt
@@ -125,3 +125,29 @@ An example mux controller might look like this:
 		reg = <0x50>;
 		#mux-control-cells = <1>;
 	};
+
+
+Combinded controller and consumer of a GPIO mux
+-----------------------------------------------
+
+For the common case of a single consumer of a GPIO controlled mux, there is
+a simplified binding which will instantiate an implicit mux controller. Just
+specify a mux-gpios property with the same interpretation as in mux-gpio.txt.
+Note that other properties described in mux-gpio.txt are not available in
+this simplified form and that the mux controller is unnamed. If you need
+more than one mux controller, a shared mux controller or if you need a
+specific idle-state, use the more flexible binding with the mux controller
+in its own node.
+
+Example:
+
+	adc-mux {
+		compatible = "io-channel-mux";
+		io-channels = <&adc 0>;
+		io-channel-names = "parent";
+
+		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
+			    <&pioA 1 GPIO_ACTIVE_HIGH>;
+
+		channels = "sync-1", "in", "out", "sync-2";
+	};
-- 
2.1.4

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

* [PATCH v8 11/12] dt-bindings: simplified bindings for single-user gpio mux
@ 2017-01-18 15:57   ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

Allow bindings for a GPIO controlled mux to be specified in the
mux consumer node.

Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../devicetree/bindings/mux/mux-controller.txt     | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/Documentation/devicetree/bindings/mux/mux-controller.txt b/Documentation/devicetree/bindings/mux/mux-controller.txt
index 42b2177e5ae1..4e89df8b2392 100644
--- a/Documentation/devicetree/bindings/mux/mux-controller.txt
+++ b/Documentation/devicetree/bindings/mux/mux-controller.txt
@@ -125,3 +125,29 @@ An example mux controller might look like this:
 		reg = <0x50>;
 		#mux-control-cells = <1>;
 	};
+
+
+Combinded controller and consumer of a GPIO mux
+-----------------------------------------------
+
+For the common case of a single consumer of a GPIO controlled mux, there is
+a simplified binding which will instantiate an implicit mux controller. Just
+specify a mux-gpios property with the same interpretation as in mux-gpio.txt.
+Note that other properties described in mux-gpio.txt are not available in
+this simplified form and that the mux controller is unnamed. If you need
+more than one mux controller, a shared mux controller or if you need a
+specific idle-state, use the more flexible binding with the mux controller
+in its own node.
+
+Example:
+
+	adc-mux {
+		compatible = "io-channel-mux";
+		io-channels = <&adc 0>;
+		io-channel-names = "parent";
+
+		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
+			    <&pioA 1 GPIO_ACTIVE_HIGH>;
+
+		channels = "sync-1", "in", "out", "sync-2";
+	};
-- 
2.1.4

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

* [PATCH v8 12/12] mux: support simplified bindings for single-user gpio mux
  2017-01-18 15:57 ` Peter Rosin
@ 2017-01-18 15:57   ` Peter Rosin
  -1 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

Allow bindings for a GPIO controlled mux to be specified in the
mux consumer node.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/mux/Kconfig    |  5 +----
 drivers/mux/mux-core.c | 23 +++++++++++++++++++++--
 drivers/mux/mux-gpio.c | 28 +++++++++++++++++++++-------
 drivers/mux/mux-gpio.h | 13 +++++++++++++
 4 files changed, 56 insertions(+), 13 deletions(-)
 create mode 100644 drivers/mux/mux-gpio.h

diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index d13fcf98958e..cd161c228537 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -29,7 +29,7 @@ config MUX_ADG792A
 	  be called mux-adg792a.
 
 config MUX_GPIO
-	tristate "GPIO-controlled Multiplexer"
+	bool "GPIO-controlled Multiplexer"
 	depends on OF && GPIOLIB
 	help
 	  GPIO-controlled Multiplexer controller.
@@ -39,7 +39,4 @@ config MUX_GPIO
 	  states. The GPIO pins can be connected (by the hardware) to several
 	  multiplexers, which in that case will be operated in parallel.
 
-	  To compile the driver as a module, choose M here: the module will
-	  be called mux-gpio.
-
 endif
diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c
index 16a61253d164..0caafd6f5a77 100644
--- a/drivers/mux/mux-core.c
+++ b/drivers/mux/mux-core.c
@@ -21,6 +21,8 @@
 #include <linux/of_platform.h>
 #include <linux/slab.h>
 
+#include "mux-gpio.h"
+
 static struct class mux_class = {
 	.name = "mux",
 	.owner = THIS_MODULE,
@@ -314,9 +316,26 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
 	ret = of_parse_phandle_with_args(np,
 					 "mux-controls", "#mux-control-cells",
 					 index, &args);
+
+#ifdef CONFIG_MUX_GPIO
+	if (ret == -ENOENT && !mux_name) {
+		mux_chip = mux_gpio_alloc(dev);
+		if (!IS_ERR(mux_chip)) {
+			ret = devm_mux_chip_register(dev, mux_chip);
+			if (ret < 0)
+				return ERR_PTR(ret);
+			get_device(&mux_chip->dev);
+			return mux_chip->mux;
+		}
+
+		ret = PTR_ERR(mux_chip);
+	}
+#endif
+
 	if (ret) {
-		dev_err(dev, "%s: failed to get mux-control %s(%i)\n",
-			np->full_name, mux_name ?: "", index);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "%s: failed to get mux-control %s(%i)\n",
+				np->full_name, mux_name ?: "", index);
 		return ERR_PTR(ret);
 	}
 
diff --git a/drivers/mux/mux-gpio.c b/drivers/mux/mux-gpio.c
index 48ca4d6b4fc7..2ab8735e3415 100644
--- a/drivers/mux/mux-gpio.c
+++ b/drivers/mux/mux-gpio.c
@@ -18,6 +18,8 @@
 #include <linux/platform_device.h>
 #include <linux/property.h>
 
+#include "mux-gpio.h"
+
 struct mux_gpio {
 	struct gpio_descs *gpios;
 	int *val;
@@ -48,24 +50,21 @@ static const struct of_device_id mux_gpio_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, mux_gpio_dt_ids);
 
-static int mux_gpio_probe(struct platform_device *pdev)
+struct mux_chip *mux_gpio_alloc(struct device *dev)
 {
-	struct device *dev = &pdev->dev;
-	struct device_node *np = dev->of_node;
 	struct mux_chip *mux_chip;
 	struct mux_gpio *mux_gpio;
 	int pins;
-	u32 idle_state;
 	int ret;
 
 	pins = gpiod_count(dev, "mux");
 	if (pins < 0)
-		return pins;
+		return ERR_PTR(pins);
 
 	mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio) +
 				       pins * sizeof(*mux_gpio->val));
 	if (!mux_chip)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	mux_gpio = mux_chip_priv(mux_chip);
 	mux_gpio->val = (int *)(mux_gpio + 1);
@@ -76,11 +75,26 @@ static int mux_gpio_probe(struct platform_device *pdev)
 		ret = PTR_ERR(mux_gpio->gpios);
 		if (ret != -EPROBE_DEFER)
 			dev_err(dev, "failed to get gpios\n");
-		return ret;
+		return ERR_PTR(ret);
 	}
 	WARN_ON(pins != mux_gpio->gpios->ndescs);
 	mux_chip->mux->states = 1 << pins;
 
+	return mux_chip;
+}
+EXPORT_SYMBOL_GPL(mux_gpio_alloc);
+
+static int mux_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mux_chip *mux_chip;
+	u32 idle_state;
+	int ret;
+
+	mux_chip = mux_gpio_alloc(dev);
+	if (IS_ERR(mux_chip))
+		return PTR_ERR(mux_chip);
+
 	ret = device_property_read_u32(dev, "idle-state", &idle_state);
 	if (ret >= 0) {
 		if (idle_state >= mux_chip->mux->states) {
diff --git a/drivers/mux/mux-gpio.h b/drivers/mux/mux-gpio.h
new file mode 100644
index 000000000000..fe3e8d0173aa
--- /dev/null
+++ b/drivers/mux/mux-gpio.h
@@ -0,0 +1,13 @@
+/*
+ * GPIO-controlled multiplexer driver interface
+ *
+ * Copyright (C) 2017 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.
+ */
+
+struct mux_chip *mux_gpio_alloc(struct device *dev);
-- 
2.1.4

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

* [PATCH v8 12/12] mux: support simplified bindings for single-user gpio mux
@ 2017-01-18 15:57   ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-18 15:57 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, Andrew Morton,
	linux-i2c, devicetree, linux-iio, linux-doc

Allow bindings for a GPIO controlled mux to be specified in the
mux consumer node.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/mux/Kconfig    |  5 +----
 drivers/mux/mux-core.c | 23 +++++++++++++++++++++--
 drivers/mux/mux-gpio.c | 28 +++++++++++++++++++++-------
 drivers/mux/mux-gpio.h | 13 +++++++++++++
 4 files changed, 56 insertions(+), 13 deletions(-)
 create mode 100644 drivers/mux/mux-gpio.h

diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index d13fcf98958e..cd161c228537 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -29,7 +29,7 @@ config MUX_ADG792A
 	  be called mux-adg792a.
 
 config MUX_GPIO
-	tristate "GPIO-controlled Multiplexer"
+	bool "GPIO-controlled Multiplexer"
 	depends on OF && GPIOLIB
 	help
 	  GPIO-controlled Multiplexer controller.
@@ -39,7 +39,4 @@ config MUX_GPIO
 	  states. The GPIO pins can be connected (by the hardware) to several
 	  multiplexers, which in that case will be operated in parallel.
 
-	  To compile the driver as a module, choose M here: the module will
-	  be called mux-gpio.
-
 endif
diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c
index 16a61253d164..0caafd6f5a77 100644
--- a/drivers/mux/mux-core.c
+++ b/drivers/mux/mux-core.c
@@ -21,6 +21,8 @@
 #include <linux/of_platform.h>
 #include <linux/slab.h>
 
+#include "mux-gpio.h"
+
 static struct class mux_class = {
 	.name = "mux",
 	.owner = THIS_MODULE,
@@ -314,9 +316,26 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
 	ret = of_parse_phandle_with_args(np,
 					 "mux-controls", "#mux-control-cells",
 					 index, &args);
+
+#ifdef CONFIG_MUX_GPIO
+	if (ret == -ENOENT && !mux_name) {
+		mux_chip = mux_gpio_alloc(dev);
+		if (!IS_ERR(mux_chip)) {
+			ret = devm_mux_chip_register(dev, mux_chip);
+			if (ret < 0)
+				return ERR_PTR(ret);
+			get_device(&mux_chip->dev);
+			return mux_chip->mux;
+		}
+
+		ret = PTR_ERR(mux_chip);
+	}
+#endif
+
 	if (ret) {
-		dev_err(dev, "%s: failed to get mux-control %s(%i)\n",
-			np->full_name, mux_name ?: "", index);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "%s: failed to get mux-control %s(%i)\n",
+				np->full_name, mux_name ?: "", index);
 		return ERR_PTR(ret);
 	}
 
diff --git a/drivers/mux/mux-gpio.c b/drivers/mux/mux-gpio.c
index 48ca4d6b4fc7..2ab8735e3415 100644
--- a/drivers/mux/mux-gpio.c
+++ b/drivers/mux/mux-gpio.c
@@ -18,6 +18,8 @@
 #include <linux/platform_device.h>
 #include <linux/property.h>
 
+#include "mux-gpio.h"
+
 struct mux_gpio {
 	struct gpio_descs *gpios;
 	int *val;
@@ -48,24 +50,21 @@ static const struct of_device_id mux_gpio_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, mux_gpio_dt_ids);
 
-static int mux_gpio_probe(struct platform_device *pdev)
+struct mux_chip *mux_gpio_alloc(struct device *dev)
 {
-	struct device *dev = &pdev->dev;
-	struct device_node *np = dev->of_node;
 	struct mux_chip *mux_chip;
 	struct mux_gpio *mux_gpio;
 	int pins;
-	u32 idle_state;
 	int ret;
 
 	pins = gpiod_count(dev, "mux");
 	if (pins < 0)
-		return pins;
+		return ERR_PTR(pins);
 
 	mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio) +
 				       pins * sizeof(*mux_gpio->val));
 	if (!mux_chip)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	mux_gpio = mux_chip_priv(mux_chip);
 	mux_gpio->val = (int *)(mux_gpio + 1);
@@ -76,11 +75,26 @@ static int mux_gpio_probe(struct platform_device *pdev)
 		ret = PTR_ERR(mux_gpio->gpios);
 		if (ret != -EPROBE_DEFER)
 			dev_err(dev, "failed to get gpios\n");
-		return ret;
+		return ERR_PTR(ret);
 	}
 	WARN_ON(pins != mux_gpio->gpios->ndescs);
 	mux_chip->mux->states = 1 << pins;
 
+	return mux_chip;
+}
+EXPORT_SYMBOL_GPL(mux_gpio_alloc);
+
+static int mux_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mux_chip *mux_chip;
+	u32 idle_state;
+	int ret;
+
+	mux_chip = mux_gpio_alloc(dev);
+	if (IS_ERR(mux_chip))
+		return PTR_ERR(mux_chip);
+
 	ret = device_property_read_u32(dev, "idle-state", &idle_state);
 	if (ret >= 0) {
 		if (idle_state >= mux_chip->mux->states) {
diff --git a/drivers/mux/mux-gpio.h b/drivers/mux/mux-gpio.h
new file mode 100644
index 000000000000..fe3e8d0173aa
--- /dev/null
+++ b/drivers/mux/mux-gpio.h
@@ -0,0 +1,13 @@
+/*
+ * GPIO-controlled multiplexer driver interface
+ *
+ * Copyright (C) 2017 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.
+ */
+
+struct mux_chip *mux_gpio_alloc(struct device *dev);
-- 
2.1.4


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

* Re: [PATCH v8 12/12] mux: support simplified bindings for single-user gpio mux
@ 2017-01-22 13:30     ` Jonathan Cameron
  0 siblings, 0 replies; 54+ messages in thread
From: Jonathan Cameron @ 2017-01-22 13:30 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,
	Andrew Morton, linux-i2c, devicetree, linux-iio, linux-doc

On 18/01/17 15:57, Peter Rosin wrote:
> Allow bindings for a GPIO controlled mux to be specified in the
> mux consumer node.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>
Code is good as far as I am concerned. Only question is whether this
is worth the hassle given the normal bindings don't give that high
a burden in complexity!

I don't really care either way:)

> ---
>  drivers/mux/Kconfig    |  5 +----
>  drivers/mux/mux-core.c | 23 +++++++++++++++++++++--
>  drivers/mux/mux-gpio.c | 28 +++++++++++++++++++++-------
>  drivers/mux/mux-gpio.h | 13 +++++++++++++
>  4 files changed, 56 insertions(+), 13 deletions(-)
>  create mode 100644 drivers/mux/mux-gpio.h
> 
> diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
> index d13fcf98958e..cd161c228537 100644
> --- a/drivers/mux/Kconfig
> +++ b/drivers/mux/Kconfig
> @@ -29,7 +29,7 @@ config MUX_ADG792A
>  	  be called mux-adg792a.
>  
>  config MUX_GPIO
> -	tristate "GPIO-controlled Multiplexer"
> +	bool "GPIO-controlled Multiplexer"
>  	depends on OF && GPIOLIB
>  	help
>  	  GPIO-controlled Multiplexer controller.
> @@ -39,7 +39,4 @@ config MUX_GPIO
>  	  states. The GPIO pins can be connected (by the hardware) to several
>  	  multiplexers, which in that case will be operated in parallel.
>  
> -	  To compile the driver as a module, choose M here: the module will
> -	  be called mux-gpio.
> -
>  endif
> diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c
> index 16a61253d164..0caafd6f5a77 100644
> --- a/drivers/mux/mux-core.c
> +++ b/drivers/mux/mux-core.c
> @@ -21,6 +21,8 @@
>  #include <linux/of_platform.h>
>  #include <linux/slab.h>
>  
> +#include "mux-gpio.h"
> +
>  static struct class mux_class = {
>  	.name = "mux",
>  	.owner = THIS_MODULE,
> @@ -314,9 +316,26 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>  	ret = of_parse_phandle_with_args(np,
>  					 "mux-controls", "#mux-control-cells",
>  					 index, &args);
> +
> +#ifdef CONFIG_MUX_GPIO
> +	if (ret == -ENOENT && !mux_name) {
> +		mux_chip = mux_gpio_alloc(dev);
> +		if (!IS_ERR(mux_chip)) {
> +			ret = devm_mux_chip_register(dev, mux_chip);
> +			if (ret < 0)
> +				return ERR_PTR(ret);
> +			get_device(&mux_chip->dev);
> +			return mux_chip->mux;
> +		}
> +
> +		ret = PTR_ERR(mux_chip);
> +	}
> +#endif
> +
>  	if (ret) {
> -		dev_err(dev, "%s: failed to get mux-control %s(%i)\n",
> -			np->full_name, mux_name ?: "", index);
> +		if (ret != -EPROBE_DEFER)
> +			dev_err(dev, "%s: failed to get mux-control %s(%i)\n",
> +				np->full_name, mux_name ?: "", index);
>  		return ERR_PTR(ret);
>  	}
>  
> diff --git a/drivers/mux/mux-gpio.c b/drivers/mux/mux-gpio.c
> index 48ca4d6b4fc7..2ab8735e3415 100644
> --- a/drivers/mux/mux-gpio.c
> +++ b/drivers/mux/mux-gpio.c
> @@ -18,6 +18,8 @@
>  #include <linux/platform_device.h>
>  #include <linux/property.h>
>  
> +#include "mux-gpio.h"
> +
>  struct mux_gpio {
>  	struct gpio_descs *gpios;
>  	int *val;
> @@ -48,24 +50,21 @@ static const struct of_device_id mux_gpio_dt_ids[] = {
>  };
>  MODULE_DEVICE_TABLE(of, mux_gpio_dt_ids);
>  
> -static int mux_gpio_probe(struct platform_device *pdev)
> +struct mux_chip *mux_gpio_alloc(struct device *dev)
>  {
> -	struct device *dev = &pdev->dev;
> -	struct device_node *np = dev->of_node;
>  	struct mux_chip *mux_chip;
>  	struct mux_gpio *mux_gpio;
>  	int pins;
> -	u32 idle_state;
>  	int ret;
>  
>  	pins = gpiod_count(dev, "mux");
>  	if (pins < 0)
> -		return pins;
> +		return ERR_PTR(pins);
>  
>  	mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio) +
>  				       pins * sizeof(*mux_gpio->val));
>  	if (!mux_chip)
> -		return -ENOMEM;
> +		return ERR_PTR(-ENOMEM);
>  
>  	mux_gpio = mux_chip_priv(mux_chip);
>  	mux_gpio->val = (int *)(mux_gpio + 1);
> @@ -76,11 +75,26 @@ static int mux_gpio_probe(struct platform_device *pdev)
>  		ret = PTR_ERR(mux_gpio->gpios);
>  		if (ret != -EPROBE_DEFER)
>  			dev_err(dev, "failed to get gpios\n");
> -		return ret;
> +		return ERR_PTR(ret);
>  	}
>  	WARN_ON(pins != mux_gpio->gpios->ndescs);
>  	mux_chip->mux->states = 1 << pins;
>  
> +	return mux_chip;
> +}
> +EXPORT_SYMBOL_GPL(mux_gpio_alloc);
> +
> +static int mux_gpio_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct mux_chip *mux_chip;
> +	u32 idle_state;
> +	int ret;
> +
> +	mux_chip = mux_gpio_alloc(dev);
> +	if (IS_ERR(mux_chip))
> +		return PTR_ERR(mux_chip);
> +
>  	ret = device_property_read_u32(dev, "idle-state", &idle_state);
>  	if (ret >= 0) {
>  		if (idle_state >= mux_chip->mux->states) {
> diff --git a/drivers/mux/mux-gpio.h b/drivers/mux/mux-gpio.h
> new file mode 100644
> index 000000000000..fe3e8d0173aa
> --- /dev/null
> +++ b/drivers/mux/mux-gpio.h
> @@ -0,0 +1,13 @@
> +/*
> + * GPIO-controlled multiplexer driver interface
> + *
> + * Copyright (C) 2017 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.
> + */
> +
> +struct mux_chip *mux_gpio_alloc(struct device *dev);
> 

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

* Re: [PATCH v8 12/12] mux: support simplified bindings for single-user gpio mux
@ 2017-01-22 13:30     ` Jonathan Cameron
  0 siblings, 0 replies; 54+ messages in thread
From: Jonathan Cameron @ 2017-01-22 13:30 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,
	Andrew Morton, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

On 18/01/17 15:57, Peter Rosin wrote:
> Allow bindings for a GPIO controlled mux to be specified in the
> mux consumer node.
> 
> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
Code is good as far as I am concerned. Only question is whether this
is worth the hassle given the normal bindings don't give that high
a burden in complexity!

I don't really care either way:)

> ---
>  drivers/mux/Kconfig    |  5 +----
>  drivers/mux/mux-core.c | 23 +++++++++++++++++++++--
>  drivers/mux/mux-gpio.c | 28 +++++++++++++++++++++-------
>  drivers/mux/mux-gpio.h | 13 +++++++++++++
>  4 files changed, 56 insertions(+), 13 deletions(-)
>  create mode 100644 drivers/mux/mux-gpio.h
> 
> diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
> index d13fcf98958e..cd161c228537 100644
> --- a/drivers/mux/Kconfig
> +++ b/drivers/mux/Kconfig
> @@ -29,7 +29,7 @@ config MUX_ADG792A
>  	  be called mux-adg792a.
>  
>  config MUX_GPIO
> -	tristate "GPIO-controlled Multiplexer"
> +	bool "GPIO-controlled Multiplexer"
>  	depends on OF && GPIOLIB
>  	help
>  	  GPIO-controlled Multiplexer controller.
> @@ -39,7 +39,4 @@ config MUX_GPIO
>  	  states. The GPIO pins can be connected (by the hardware) to several
>  	  multiplexers, which in that case will be operated in parallel.
>  
> -	  To compile the driver as a module, choose M here: the module will
> -	  be called mux-gpio.
> -
>  endif
> diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c
> index 16a61253d164..0caafd6f5a77 100644
> --- a/drivers/mux/mux-core.c
> +++ b/drivers/mux/mux-core.c
> @@ -21,6 +21,8 @@
>  #include <linux/of_platform.h>
>  #include <linux/slab.h>
>  
> +#include "mux-gpio.h"
> +
>  static struct class mux_class = {
>  	.name = "mux",
>  	.owner = THIS_MODULE,
> @@ -314,9 +316,26 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>  	ret = of_parse_phandle_with_args(np,
>  					 "mux-controls", "#mux-control-cells",
>  					 index, &args);
> +
> +#ifdef CONFIG_MUX_GPIO
> +	if (ret == -ENOENT && !mux_name) {
> +		mux_chip = mux_gpio_alloc(dev);
> +		if (!IS_ERR(mux_chip)) {
> +			ret = devm_mux_chip_register(dev, mux_chip);
> +			if (ret < 0)
> +				return ERR_PTR(ret);
> +			get_device(&mux_chip->dev);
> +			return mux_chip->mux;
> +		}
> +
> +		ret = PTR_ERR(mux_chip);
> +	}
> +#endif
> +
>  	if (ret) {
> -		dev_err(dev, "%s: failed to get mux-control %s(%i)\n",
> -			np->full_name, mux_name ?: "", index);
> +		if (ret != -EPROBE_DEFER)
> +			dev_err(dev, "%s: failed to get mux-control %s(%i)\n",
> +				np->full_name, mux_name ?: "", index);
>  		return ERR_PTR(ret);
>  	}
>  
> diff --git a/drivers/mux/mux-gpio.c b/drivers/mux/mux-gpio.c
> index 48ca4d6b4fc7..2ab8735e3415 100644
> --- a/drivers/mux/mux-gpio.c
> +++ b/drivers/mux/mux-gpio.c
> @@ -18,6 +18,8 @@
>  #include <linux/platform_device.h>
>  #include <linux/property.h>
>  
> +#include "mux-gpio.h"
> +
>  struct mux_gpio {
>  	struct gpio_descs *gpios;
>  	int *val;
> @@ -48,24 +50,21 @@ static const struct of_device_id mux_gpio_dt_ids[] = {
>  };
>  MODULE_DEVICE_TABLE(of, mux_gpio_dt_ids);
>  
> -static int mux_gpio_probe(struct platform_device *pdev)
> +struct mux_chip *mux_gpio_alloc(struct device *dev)
>  {
> -	struct device *dev = &pdev->dev;
> -	struct device_node *np = dev->of_node;
>  	struct mux_chip *mux_chip;
>  	struct mux_gpio *mux_gpio;
>  	int pins;
> -	u32 idle_state;
>  	int ret;
>  
>  	pins = gpiod_count(dev, "mux");
>  	if (pins < 0)
> -		return pins;
> +		return ERR_PTR(pins);
>  
>  	mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio) +
>  				       pins * sizeof(*mux_gpio->val));
>  	if (!mux_chip)
> -		return -ENOMEM;
> +		return ERR_PTR(-ENOMEM);
>  
>  	mux_gpio = mux_chip_priv(mux_chip);
>  	mux_gpio->val = (int *)(mux_gpio + 1);
> @@ -76,11 +75,26 @@ static int mux_gpio_probe(struct platform_device *pdev)
>  		ret = PTR_ERR(mux_gpio->gpios);
>  		if (ret != -EPROBE_DEFER)
>  			dev_err(dev, "failed to get gpios\n");
> -		return ret;
> +		return ERR_PTR(ret);
>  	}
>  	WARN_ON(pins != mux_gpio->gpios->ndescs);
>  	mux_chip->mux->states = 1 << pins;
>  
> +	return mux_chip;
> +}
> +EXPORT_SYMBOL_GPL(mux_gpio_alloc);
> +
> +static int mux_gpio_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct mux_chip *mux_chip;
> +	u32 idle_state;
> +	int ret;
> +
> +	mux_chip = mux_gpio_alloc(dev);
> +	if (IS_ERR(mux_chip))
> +		return PTR_ERR(mux_chip);
> +
>  	ret = device_property_read_u32(dev, "idle-state", &idle_state);
>  	if (ret >= 0) {
>  		if (idle_state >= mux_chip->mux->states) {
> diff --git a/drivers/mux/mux-gpio.h b/drivers/mux/mux-gpio.h
> new file mode 100644
> index 000000000000..fe3e8d0173aa
> --- /dev/null
> +++ b/drivers/mux/mux-gpio.h
> @@ -0,0 +1,13 @@
> +/*
> + * GPIO-controlled multiplexer driver interface
> + *
> + * Copyright (C) 2017 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.
> + */
> +
> +struct mux_chip *mux_gpio_alloc(struct device *dev);
> 

--
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] 54+ messages in thread

* Re: [PATCH v8 12/12] mux: support simplified bindings for single-user gpio mux
  2017-01-22 13:30     ` Jonathan Cameron
  (?)
@ 2017-01-23 10:24     ` Peter Rosin
  2017-01-27 15:52       ` Rob Herring
  -1 siblings, 1 reply; 54+ messages in thread
From: Peter Rosin @ 2017-01-23 10:24 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,
	Andrew Morton, linux-i2c, devicetree, linux-iio, linux-doc

On 2017-01-22 14:30, Jonathan Cameron wrote:
> On 18/01/17 15:57, Peter Rosin wrote:
>> Allow bindings for a GPIO controlled mux to be specified in the
>> mux consumer node.
>>
>> Signed-off-by: Peter Rosin <peda@axentia.se>
> Code is good as far as I am concerned. Only question is whether this

Hmmm, now that I think some more about it, the code supporting the
simplified binding (patch 12/12) is a bit fishy in one respect.

A driver that calls mux_control_get and gets a mux_control that happens
to be backed by an implicit mux chip (i.e. using the simplified binding)
will not be able to reverse the resource allocation with less than a
complete destruction of itself. Now, this is likely not a problem in
most cases, but I bet it will creep up at the most inopportune time. And
your remark that I'm the one that has to maintain this makes me dislike
this concept...

I.e. mux_control_put *should* reverse mux_control_get, but this simply
does not happen for the implicit mux chips, as implicit mux chips are
not put away until the owning device is put away.

Every time I have tried to come up with a way to implement the simplified
bindings I seem to hit one of these subtleties.

> is worth the hassle given the normal bindings don't give that high
> a burden in complexity!

I am missing an ack from Rob though.

> I don't really care either way:)

But Rob seems to care, this series just has to find a way to get out of
his too-much-churn-will-look-at-it-later list. I sadly don't know how to
pull that trick...

Cheers,
peda

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

* Re: [PATCH v8 12/12] mux: support simplified bindings for single-user gpio mux
  2017-01-23 10:24     ` Peter Rosin
@ 2017-01-27 15:52       ` Rob Herring
  2017-01-30  8:02           ` Peter Rosin
  0 siblings, 1 reply; 54+ messages in thread
From: Rob Herring @ 2017-01-27 15:52 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Jonathan Cameron, linux-kernel, Wolfram Sang, Mark Rutland,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Jonathan Corbet, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

On Mon, Jan 23, 2017 at 11:24:18AM +0100, Peter Rosin wrote:
> On 2017-01-22 14:30, Jonathan Cameron wrote:
> > On 18/01/17 15:57, Peter Rosin wrote:
> >> Allow bindings for a GPIO controlled mux to be specified in the
> >> mux consumer node.
> >>
> >> Signed-off-by: Peter Rosin <peda@axentia.se>
> > Code is good as far as I am concerned. Only question is whether this
> 
> Hmmm, now that I think some more about it, the code supporting the
> simplified binding (patch 12/12) is a bit fishy in one respect.
> 
> A driver that calls mux_control_get and gets a mux_control that happens
> to be backed by an implicit mux chip (i.e. using the simplified binding)
> will not be able to reverse the resource allocation with less than a
> complete destruction of itself. Now, this is likely not a problem in
> most cases, but I bet it will creep up at the most inopportune time. And
> your remark that I'm the one that has to maintain this makes me dislike
> this concept...
> 
> I.e. mux_control_put *should* reverse mux_control_get, but this simply
> does not happen for the implicit mux chips, as implicit mux chips are
> not put away until the owning device is put away.

I think this is because you aren't creating a device in this case. Nodes 
in DT are not the only way to create devices. Drivers can create a child 
device when they find mux-gpios property.

> Every time I have tried to come up with a way to implement the simplified
> bindings I seem to hit one of these subtleties.
> 
> > is worth the hassle given the normal bindings don't give that high
> > a burden in complexity!

I was going to change my mind here, but we already have "mux-gpios" as a 
binding at least for i2c-gpio-mux. So really the question is do we want 
to support that here?

> I am missing an ack from Rob though.
> 
> > I don't really care either way:)
> 
> But Rob seems to care, this series just has to find a way to get out of
> his too-much-churn-will-look-at-it-later list. I sadly don't know how to
> pull that trick...

By complaining that I'm putting it off... :) I guess I'm okay with this 
series in general. I will reply on the specific patches today.

Rob

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

* Re: [PATCH v8 02/12] dt-bindings: document devicetree bindings for mux-controllers and mux-gpio
@ 2017-01-27 17:49     ` Rob Herring
  0 siblings, 0 replies; 54+ messages in thread
From: Rob Herring @ 2017-01-27 17:49 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, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

On Wed, Jan 18, 2017 at 04:57:05PM +0100, Peter Rosin wrote:
> Allow specifying that a single multiplexer controller can be used to control
> several parallel multiplexers, thus enabling sharing of the multiplexer
> controller by different consumers.
> 
> Add a binding for a first mux controller in the form of a GPIO based mux
> controlled.
> 
> Acked-by: Jonathan Cameron <jic23@kernel.org>
> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>  .../devicetree/bindings/mux/mux-controller.txt     | 127 +++++++++++++++++++++
>  Documentation/devicetree/bindings/mux/mux-gpio.txt |  68 +++++++++++
>  MAINTAINERS                                        |   5 +
>  3 files changed, 200 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mux/mux-controller.txt
>  create mode 100644 Documentation/devicetree/bindings/mux/mux-gpio.txt

A few nits. With those fixed:

Acked-by: Rob Herring <robh@kernel.org>

> 
> diff --git a/Documentation/devicetree/bindings/mux/mux-controller.txt b/Documentation/devicetree/bindings/mux/mux-controller.txt
> new file mode 100644
> index 000000000000..42b2177e5ae1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mux/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, but a single mux controller can of course
> +control several multiplexers for a single 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 requested mux controller
> +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 = "io-channel-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 = "io-channel-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 {

mux-controller@50

> +		compatible = "adi,adg792a";
> +		reg = <0x50>;
> +		#mux-control-cells = <1>;
> +	};
> diff --git a/Documentation/devicetree/bindings/mux/mux-gpio.txt b/Documentation/devicetree/bindings/mux/mux-gpio.txt
> new file mode 100644
> index 000000000000..8f6bda6f9d78
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mux/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"

Just to be consistent with other gpio compatibles: gpio-mux

> +- 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.

Why is this gpio specific. Can be a common controller property?

> +
> +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 = "io-channel-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 40de344ba0e6..be57f5b8f2c2 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -8469,6 +8469,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/mux/
> +
>  MULTISOUND SOUND DRIVER
>  M:	Andrew Veliath <andrewtv@usa.net>
>  S:	Maintained
> -- 
> 2.1.4
> 

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

* Re: [PATCH v8 02/12] dt-bindings: document devicetree bindings for mux-controllers and mux-gpio
@ 2017-01-27 17:49     ` Rob Herring
  0 siblings, 0 replies; 54+ messages in thread
From: Rob Herring @ 2017-01-27 17:49 UTC (permalink / raw)
  To: Peter Rosin
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, Wolfram Sang, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Andrew Morton,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

On Wed, Jan 18, 2017 at 04:57:05PM +0100, Peter Rosin wrote:
> Allow specifying that a single multiplexer controller can be used to control
> several parallel multiplexers, thus enabling sharing of the multiplexer
> controller by different consumers.
> 
> Add a binding for a first mux controller in the form of a GPIO based mux
> controlled.
> 
> Acked-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
> ---
>  .../devicetree/bindings/mux/mux-controller.txt     | 127 +++++++++++++++++++++
>  Documentation/devicetree/bindings/mux/mux-gpio.txt |  68 +++++++++++
>  MAINTAINERS                                        |   5 +
>  3 files changed, 200 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mux/mux-controller.txt
>  create mode 100644 Documentation/devicetree/bindings/mux/mux-gpio.txt

A few nits. With those fixed:

Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

> 
> diff --git a/Documentation/devicetree/bindings/mux/mux-controller.txt b/Documentation/devicetree/bindings/mux/mux-controller.txt
> new file mode 100644
> index 000000000000..42b2177e5ae1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mux/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, but a single mux controller can of course
> +control several multiplexers for a single 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 requested mux controller
> +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 = "io-channel-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 = "io-channel-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 {

mux-controller@50

> +		compatible = "adi,adg792a";
> +		reg = <0x50>;
> +		#mux-control-cells = <1>;
> +	};
> diff --git a/Documentation/devicetree/bindings/mux/mux-gpio.txt b/Documentation/devicetree/bindings/mux/mux-gpio.txt
> new file mode 100644
> index 000000000000..8f6bda6f9d78
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mux/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"

Just to be consistent with other gpio compatibles: gpio-mux

> +- 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.

Why is this gpio specific. Can be a common controller property?

> +
> +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 = "io-channel-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 40de344ba0e6..be57f5b8f2c2 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -8469,6 +8469,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/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	[flat|nested] 54+ messages in thread

* Re: [PATCH v8 02/12] dt-bindings: document devicetree bindings for mux-controllers and mux-gpio
  2017-01-27 17:49     ` Rob Herring
@ 2017-01-27 18:57       ` Peter Rosin
  -1 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-27 18:57 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, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

On 2017-01-27 18:49, Rob Herring wrote:
> On Wed, Jan 18, 2017 at 04:57:05PM +0100, Peter Rosin wrote:
>> Allow specifying that a single multiplexer controller can be used to control
>> several parallel multiplexers, thus enabling sharing of the multiplexer
>> controller by different consumers.
>>
>> Add a binding for a first mux controller in the form of a GPIO based mux
>> controlled.
>>
>> Acked-by: Jonathan Cameron <jic23@kernel.org>
>> Signed-off-by: Peter Rosin <peda@axentia.se>
>> ---
>>  .../devicetree/bindings/mux/mux-controller.txt     | 127 +++++++++++++++++++++
>>  Documentation/devicetree/bindings/mux/mux-gpio.txt |  68 +++++++++++
>>  MAINTAINERS                                        |   5 +
>>  3 files changed, 200 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mux/mux-controller.txt
>>  create mode 100644 Documentation/devicetree/bindings/mux/mux-gpio.txt
> 
> A few nits. With those fixed:
> 
> Acked-by: Rob Herring <robh@kernel.org>
> 
>>
>> diff --git a/Documentation/devicetree/bindings/mux/mux-controller.txt b/Documentation/devicetree/bindings/mux/mux-controller.txt
>> new file mode 100644
>> index 000000000000..42b2177e5ae1
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mux/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, but a single mux controller can of course
>> +control several multiplexers for a single 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 requested mux controller
>> +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 = "io-channel-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 = "io-channel-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 {
> 
> mux-controller@50

Right, adding that to my queue.

>> +		compatible = "adi,adg792a";
>> +		reg = <0x50>;
>> +		#mux-control-cells = <1>;
>> +	};
>> diff --git a/Documentation/devicetree/bindings/mux/mux-gpio.txt b/Documentation/devicetree/bindings/mux/mux-gpio.txt
>> new file mode 100644
>> index 000000000000..8f6bda6f9d78
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mux/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"
> 
> Just to be consistent with other gpio compatibles: gpio-mux

Sure, I'll also rename mux-gpio.txt to gpio-mux.txt and mux-adg792a.txt
to adi,adg792a.txt so that the file names match the compatible string.

>> +- 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.
> 
> Why is this gpio specific. Can be a common controller property?

The binding isn't appropriate for e.g. adg792a and it will not be
appropriate for any mux chip with more than one mux controller. But
sure, there could be a generic binding for all chips with a single
mux controller...

So, do you still think idle-state should be a generic binding?

Cheers,
peda

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

* Re: [PATCH v8 02/12] dt-bindings: document devicetree bindings for mux-controllers and mux-gpio
@ 2017-01-27 18:57       ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-27 18:57 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, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

On 2017-01-27 18:49, Rob Herring wrote:
> On Wed, Jan 18, 2017 at 04:57:05PM +0100, Peter Rosin wrote:
>> Allow specifying that a single multiplexer controller can be used to control
>> several parallel multiplexers, thus enabling sharing of the multiplexer
>> controller by different consumers.
>>
>> Add a binding for a first mux controller in the form of a GPIO based mux
>> controlled.
>>
>> Acked-by: Jonathan Cameron <jic23@kernel.org>
>> Signed-off-by: Peter Rosin <peda@axentia.se>
>> ---
>>  .../devicetree/bindings/mux/mux-controller.txt     | 127 +++++++++++++++++++++
>>  Documentation/devicetree/bindings/mux/mux-gpio.txt |  68 +++++++++++
>>  MAINTAINERS                                        |   5 +
>>  3 files changed, 200 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mux/mux-controller.txt
>>  create mode 100644 Documentation/devicetree/bindings/mux/mux-gpio.txt
> 
> A few nits. With those fixed:
> 
> Acked-by: Rob Herring <robh@kernel.org>
> 
>>
>> diff --git a/Documentation/devicetree/bindings/mux/mux-controller.txt b/Documentation/devicetree/bindings/mux/mux-controller.txt
>> new file mode 100644
>> index 000000000000..42b2177e5ae1
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mux/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, but a single mux controller can of course
>> +control several multiplexers for a single 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 requested mux controller
>> +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 = "io-channel-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 = "io-channel-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 {
> 
> mux-controller@50

Right, adding that to my queue.

>> +		compatible = "adi,adg792a";
>> +		reg = <0x50>;
>> +		#mux-control-cells = <1>;
>> +	};
>> diff --git a/Documentation/devicetree/bindings/mux/mux-gpio.txt b/Documentation/devicetree/bindings/mux/mux-gpio.txt
>> new file mode 100644
>> index 000000000000..8f6bda6f9d78
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mux/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"
> 
> Just to be consistent with other gpio compatibles: gpio-mux

Sure, I'll also rename mux-gpio.txt to gpio-mux.txt and mux-adg792a.txt
to adi,adg792a.txt so that the file names match the compatible string.

>> +- 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.
> 
> Why is this gpio specific. Can be a common controller property?

The binding isn't appropriate for e.g. adg792a and it will not be
appropriate for any mux chip with more than one mux controller. But
sure, there could be a generic binding for all chips with a single
mux controller...

So, do you still think idle-state should be a generic binding?

Cheers,
peda

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

* Re: [PATCH v8 05/12] dt-bindings: iio: io-channel-mux: document io-channel-mux bindings
  2017-01-18 15:57   ` Peter Rosin
  (?)
@ 2017-01-27 19:12   ` Rob Herring
  -1 siblings, 0 replies; 54+ messages in thread
From: Rob Herring @ 2017-01-27 19:12 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, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

On Wed, Jan 18, 2017 at 04:57:08PM +0100, Peter Rosin wrote:
> Describe how a multiplexer can be used to select which signal is fed to
> an io-channel.
> 
> Acked-by: Jonathan Cameron <jic23@kernel.org>
> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>  .../bindings/iio/multiplexer/io-channel-mux.txt    | 39 ++++++++++++++++++++++
>  MAINTAINERS                                        |  6 ++++
>  2 files changed, 45 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt

Acked-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH v8 07/12] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
  2017-01-18 15:57   ` Peter Rosin
  (?)
@ 2017-01-27 19:39   ` Rob Herring
  2017-01-28 22:42       ` Peter Rosin
  -1 siblings, 1 reply; 54+ messages in thread
From: Rob Herring @ 2017-01-27 19:39 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, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

On Wed, Jan 18, 2017 at 04:57:10PM +0100, Peter Rosin wrote:
> Describe how a generic multiplexer controller is used to mux an i2c bus.
> 
> Acked-by: Jonathan Cameron <jic23@kernel.org>
> 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..253d5027843b
> --- /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

Not a fan of using "simple" nor the ','. Perhaps lock type should be 
separate property.

I'm not sure I get the mux vs. parent locked fully. How do I determine 
what type I have? We already have bindings for several types of i2c 
muxes. How does the locking annotation fit into those?

Rob

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

* Re: [PATCH v8 09/12] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
  2017-01-18 15:57   ` Peter Rosin
  (?)
@ 2017-01-27 19:50   ` Rob Herring
  2017-01-27 22:09       ` Peter Rosin
  -1 siblings, 1 reply; 54+ messages in thread
From: Rob Herring @ 2017-01-27 19:50 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, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

On Wed, Jan 18, 2017 at 04:57:12PM +0100, Peter Rosin wrote:
> Analog Devices ADG792A/G is a triple 4:1 mux.
> 
> Acked-by: Jonathan Cameron <jic23@kernel.org>
> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>  .../devicetree/bindings/mux/mux-adg792a.txt        | 79 ++++++++++++++++++++++
>  1 file changed, 79 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mux/mux-adg792a.txt
> 
> diff --git a/Documentation/devicetree/bindings/mux/mux-adg792a.txt b/Documentation/devicetree/bindings/mux/mux-adg792a.txt
> new file mode 100644
> index 000000000000..0b26dd11f070
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mux/mux-adg792a.txt
> @@ -0,0 +1,79 @@
> +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 for ADG792G:
> +- gpio-controller : if present, #gpio-cells below is required.
> +- #gpio-cells : should be <2>
> +			  - First cell is the GPO line number, i.e. 0 or 1
> +			  - Second cell is used to specify active high (0)
> +			    or active low (1)
> +
> +Optional properties:
> +- adi,parallel : if present, the three muxes are bound together with a single
> +  mux controller, controlling all three muxes in parallel.

Can't this be implied by #mux-control-cells == 0?

> +- adi,idle-state : if present, array of 2-tuples with mux controller number
> +  and state that mux controllers will have when idle. States 0 through 3
> +  correspond to signals A through D in the datasheet.
> +- adi,idle-high-impedance : if present, array of mux controller numbers that
> +  should be in the disconnected high-impedance state when idle.

Perhaps combine these 2 to a common idle-state with the index being the 
mux controller number and a value of -1 (or 4) being hi-Z.

> +
> +Mux controller states 0 through 3 correspond to signals A through D in the
> +datasheet. If a mux controller is mentioned in neither adi,idle-state nor
> +adi,idle-high-impedance it is left in its previously selected state when idle.
> +
> +Example:
> +
> +	/*
> +	 * Three independent mux controllers (of which one is used).
> +	 * Mux 0 is disconnected when idle, mux 1 idles with signal C
> +	 * and mux 2 idles with signal A.
> +	 */
> +	&i2c0 {
> +		mux: adg792a@50 {

mux-controller@50

> +			compatible = "adi,adg792a";
> +			reg = <0x50>;
> +			#mux-control-cells = <1>;
> +
> +			adi,idle-high-impedance = <0>;
> +			adi,idle-state = <1 2>, <2 0>;
> +		};
> +	};
> +
> +	adc-mux {
> +		compatible = "io-channel-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 = "io-channel-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@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v8 09/12] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
  2017-01-27 19:50   ` Rob Herring
@ 2017-01-27 22:09       ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-27 22:09 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, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

On 2017-01-27 20:50, Rob Herring wrote:
> On Wed, Jan 18, 2017 at 04:57:12PM +0100, Peter Rosin wrote:
>> Analog Devices ADG792A/G is a triple 4:1 mux.
>>
>> Acked-by: Jonathan Cameron <jic23@kernel.org>
>> Signed-off-by: Peter Rosin <peda@axentia.se>
>> ---
>>  .../devicetree/bindings/mux/mux-adg792a.txt        | 79 ++++++++++++++++++++++
>>  1 file changed, 79 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mux/mux-adg792a.txt
>>
>> diff --git a/Documentation/devicetree/bindings/mux/mux-adg792a.txt b/Documentation/devicetree/bindings/mux/mux-adg792a.txt
>> new file mode 100644
>> index 000000000000..0b26dd11f070
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mux/mux-adg792a.txt
>> @@ -0,0 +1,79 @@
>> +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 for ADG792G:
>> +- gpio-controller : if present, #gpio-cells below is required.
>> +- #gpio-cells : should be <2>
>> +			  - First cell is the GPO line number, i.e. 0 or 1
>> +			  - Second cell is used to specify active high (0)
>> +			    or active low (1)
>> +
>> +Optional properties:
>> +- adi,parallel : if present, the three muxes are bound together with a single
>> +  mux controller, controlling all three muxes in parallel.
> 
> Can't this be implied by #mux-control-cells == 0?

Right, good point! I'll drop adi,parallel.

>> +- adi,idle-state : if present, array of 2-tuples with mux controller number
>> +  and state that mux controllers will have when idle. States 0 through 3
>> +  correspond to signals A through D in the datasheet.
>> +- adi,idle-high-impedance : if present, array of mux controller numbers that
>> +  should be in the disconnected high-impedance state when idle.
> 
> Perhaps combine these 2 to a common idle-state with the index being the 
> mux controller number and a value of -1 (or 4) being hi-Z.

At one point [1] I had a straight array for the mux controllers with state 4
being hi-Z and state 5 being the default "leave mux as-is on release", but
Jonathan didn't like magic numbers. Can you please read the follow-ups to the
referenced mail for some background, and then pick out the most suitable color
for me to paint with? :-)

[1] https://lkml.org/lkml/2016/11/30/110

>> +
>> +Mux controller states 0 through 3 correspond to signals A through D in the
>> +datasheet. If a mux controller is mentioned in neither adi,idle-state nor
>> +adi,idle-high-impedance it is left in its previously selected state when idle.
>> +
>> +Example:
>> +
>> +	/*
>> +	 * Three independent mux controllers (of which one is used).
>> +	 * Mux 0 is disconnected when idle, mux 1 idles with signal C
>> +	 * and mux 2 idles with signal A.
>> +	 */
>> +	&i2c0 {
>> +		mux: adg792a@50 {
> 
> mux-controller@50

Yep. Hmm, where have I seen that before? :-)

Cheers,
peda

>> +			compatible = "adi,adg792a";
>> +			reg = <0x50>;
>> +			#mux-control-cells = <1>;
>> +
>> +			adi,idle-high-impedance = <0>;
>> +			adi,idle-state = <1 2>, <2 0>;
>> +		};
>> +	};
>> +
>> +	adc-mux {
>> +		compatible = "io-channel-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 = "io-channel-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@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v8 09/12] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
@ 2017-01-27 22:09       ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-27 22:09 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, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

On 2017-01-27 20:50, Rob Herring wrote:
> On Wed, Jan 18, 2017 at 04:57:12PM +0100, Peter Rosin wrote:
>> Analog Devices ADG792A/G is a triple 4:1 mux.
>>
>> Acked-by: Jonathan Cameron <jic23@kernel.org>
>> Signed-off-by: Peter Rosin <peda@axentia.se>
>> ---
>>  .../devicetree/bindings/mux/mux-adg792a.txt        | 79 ++++++++++++++++++++++
>>  1 file changed, 79 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mux/mux-adg792a.txt
>>
>> diff --git a/Documentation/devicetree/bindings/mux/mux-adg792a.txt b/Documentation/devicetree/bindings/mux/mux-adg792a.txt
>> new file mode 100644
>> index 000000000000..0b26dd11f070
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mux/mux-adg792a.txt
>> @@ -0,0 +1,79 @@
>> +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 for ADG792G:
>> +- gpio-controller : if present, #gpio-cells below is required.
>> +- #gpio-cells : should be <2>
>> +			  - First cell is the GPO line number, i.e. 0 or 1
>> +			  - Second cell is used to specify active high (0)
>> +			    or active low (1)
>> +
>> +Optional properties:
>> +- adi,parallel : if present, the three muxes are bound together with a single
>> +  mux controller, controlling all three muxes in parallel.
> 
> Can't this be implied by #mux-control-cells == 0?

Right, good point! I'll drop adi,parallel.

>> +- adi,idle-state : if present, array of 2-tuples with mux controller number
>> +  and state that mux controllers will have when idle. States 0 through 3
>> +  correspond to signals A through D in the datasheet.
>> +- adi,idle-high-impedance : if present, array of mux controller numbers that
>> +  should be in the disconnected high-impedance state when idle.
> 
> Perhaps combine these 2 to a common idle-state with the index being the 
> mux controller number and a value of -1 (or 4) being hi-Z.

At one point [1] I had a straight array for the mux controllers with state 4
being hi-Z and state 5 being the default "leave mux as-is on release", but
Jonathan didn't like magic numbers. Can you please read the follow-ups to the
referenced mail for some background, and then pick out the most suitable color
for me to paint with? :-)

[1] https://lkml.org/lkml/2016/11/30/110

>> +
>> +Mux controller states 0 through 3 correspond to signals A through D in the
>> +datasheet. If a mux controller is mentioned in neither adi,idle-state nor
>> +adi,idle-high-impedance it is left in its previously selected state when idle.
>> +
>> +Example:
>> +
>> +	/*
>> +	 * Three independent mux controllers (of which one is used).
>> +	 * Mux 0 is disconnected when idle, mux 1 idles with signal C
>> +	 * and mux 2 idles with signal A.
>> +	 */
>> +	&i2c0 {
>> +		mux: adg792a@50 {
> 
> mux-controller@50

Yep. Hmm, where have I seen that before? :-)

Cheers,
peda

>> +			compatible = "adi,adg792a";
>> +			reg = <0x50>;
>> +			#mux-control-cells = <1>;
>> +
>> +			adi,idle-high-impedance = <0>;
>> +			adi,idle-state = <1 2>, <2 0>;
>> +		};
>> +	};
>> +
>> +	adc-mux {
>> +		compatible = "io-channel-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 = "io-channel-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@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v8 09/12] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
@ 2017-01-28 10:34         ` Peter Meerwald-Stadler
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Meerwald-Stadler @ 2017-01-28 10:34 UTC (permalink / raw)
  To: Peter Rosin
  Cc: linux-kernel, Jonathan Cameron, devicetree, linux-doc, linux-iio

On Fri, 27 Jan 2017, Peter Rosin wrote:

comments below, picking on typos

> On 2017-01-27 20:50, Rob Herring wrote:
> > On Wed, Jan 18, 2017 at 04:57:12PM +0100, Peter Rosin wrote:
> >> Analog Devices ADG792A/G is a triple 4:1 mux.
> >>
> >> Acked-by: Jonathan Cameron <jic23@kernel.org>
> >> Signed-off-by: Peter Rosin <peda@axentia.se>
> >> ---
> >>  .../devicetree/bindings/mux/mux-adg792a.txt        | 79 ++++++++++++++++++++++
> >>  1 file changed, 79 insertions(+)
> >>  create mode 100644 Documentation/devicetree/bindings/mux/mux-adg792a.txt
> >>
> >> diff --git a/Documentation/devicetree/bindings/mux/mux-adg792a.txt b/Documentation/devicetree/bindings/mux/mux-adg792a.txt
> >> new file mode 100644
> >> index 000000000000..0b26dd11f070
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/mux/mux-adg792a.txt
> >> @@ -0,0 +1,79 @@
> >> +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

described

> >> +
> >> +Optional properties for ADG792G:
> >> +- gpio-controller : if present, #gpio-cells below is required.
> >> +- #gpio-cells : should be <2>
> >> +			  - First cell is the GPO line number, i.e. 0 or 1
> >> +			  - Second cell is used to specify active high (0)
> >> +			    or active low (1)
> >> +
> >> +Optional properties:
> >> +- adi,parallel : if present, the three muxes are bound together with a single
> >> +  mux controller, controlling all three muxes in parallel.
> > 
> > Can't this be implied by #mux-control-cells == 0?
> 
> Right, good point! I'll drop adi,parallel.
> 
> >> +- adi,idle-state : if present, array of 2-tuples with mux controller number
> >> +  and state that mux controllers will have when idle. States 0 through 3
> >> +  correspond to signals A through D in the datasheet.
> >> +- adi,idle-high-impedance : if present, array of mux controller numbers that
> >> +  should be in the disconnected high-impedance state when idle.
> > 
> > Perhaps combine these 2 to a common idle-state with the index being the 
> > mux controller number and a value of -1 (or 4) being hi-Z.
> 
> At one point [1] I had a straight array for the mux controllers with state 4
> being hi-Z and state 5 being the default "leave mux as-is on release", but
> Jonathan didn't like magic numbers. Can you please read the follow-ups to the
> referenced mail for some background, and then pick out the most suitable color
> for me to paint with? :-)
> 
> [1] https://lkml.org/lkml/2016/11/30/110
> 
> >> +
> >> +Mux controller states 0 through 3 correspond to signals A through D in the
> >> +datasheet. If a mux controller is mentioned in neither adi,idle-state nor

that is already being said under 'adi,idle-state'

> >> +adi,idle-high-impedance it is left in its previously selected state when idle.
> >> +
> >> +Example:
> >> +
> >> +	/*
> >> +	 * Three independent mux controllers (of which one is used).
> >> +	 * Mux 0 is disconnected when idle, mux 1 idles with signal C
> >> +	 * and mux 2 idles with signal A.
> >> +	 */
> >> +	&i2c0 {
> >> +		mux: adg792a@50 {
> > 
> > mux-controller@50
> 
> Yep. Hmm, where have I seen that before? :-)
> 
> Cheers,
> peda
> 
> >> +			compatible = "adi,adg792a";
> >> +			reg = <0x50>;
> >> +			#mux-control-cells = <1>;
> >> +
> >> +			adi,idle-high-impedance = <0>;
> >> +			adi,idle-state = <1 2>, <2 0>;
> >> +		};
> >> +	};
> >> +
> >> +	adc-mux {
> >> +		compatible = "io-channel-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 = "io-channel-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@vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

-- 

Peter Meerwald-Stadler
+43-664-2444418 (mobile)

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

* Re: [PATCH v8 09/12] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
@ 2017-01-28 10:34         ` Peter Meerwald-Stadler
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Meerwald-Stadler @ 2017-01-28 10:34 UTC (permalink / raw)
  To: Peter Rosin
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, Jonathan Cameron,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA

On Fri, 27 Jan 2017, Peter Rosin wrote:

comments below, picking on typos

> On 2017-01-27 20:50, Rob Herring wrote:
> > On Wed, Jan 18, 2017 at 04:57:12PM +0100, Peter Rosin wrote:
> >> Analog Devices ADG792A/G is a triple 4:1 mux.
> >>
> >> Acked-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> >> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
> >> ---
> >>  .../devicetree/bindings/mux/mux-adg792a.txt        | 79 ++++++++++++++++++++++
> >>  1 file changed, 79 insertions(+)
> >>  create mode 100644 Documentation/devicetree/bindings/mux/mux-adg792a.txt
> >>
> >> diff --git a/Documentation/devicetree/bindings/mux/mux-adg792a.txt b/Documentation/devicetree/bindings/mux/mux-adg792a.txt
> >> new file mode 100644
> >> index 000000000000..0b26dd11f070
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/mux/mux-adg792a.txt
> >> @@ -0,0 +1,79 @@
> >> +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

described

> >> +
> >> +Optional properties for ADG792G:
> >> +- gpio-controller : if present, #gpio-cells below is required.
> >> +- #gpio-cells : should be <2>
> >> +			  - First cell is the GPO line number, i.e. 0 or 1
> >> +			  - Second cell is used to specify active high (0)
> >> +			    or active low (1)
> >> +
> >> +Optional properties:
> >> +- adi,parallel : if present, the three muxes are bound together with a single
> >> +  mux controller, controlling all three muxes in parallel.
> > 
> > Can't this be implied by #mux-control-cells == 0?
> 
> Right, good point! I'll drop adi,parallel.
> 
> >> +- adi,idle-state : if present, array of 2-tuples with mux controller number
> >> +  and state that mux controllers will have when idle. States 0 through 3
> >> +  correspond to signals A through D in the datasheet.
> >> +- adi,idle-high-impedance : if present, array of mux controller numbers that
> >> +  should be in the disconnected high-impedance state when idle.
> > 
> > Perhaps combine these 2 to a common idle-state with the index being the 
> > mux controller number and a value of -1 (or 4) being hi-Z.
> 
> At one point [1] I had a straight array for the mux controllers with state 4
> being hi-Z and state 5 being the default "leave mux as-is on release", but
> Jonathan didn't like magic numbers. Can you please read the follow-ups to the
> referenced mail for some background, and then pick out the most suitable color
> for me to paint with? :-)
> 
> [1] https://lkml.org/lkml/2016/11/30/110
> 
> >> +
> >> +Mux controller states 0 through 3 correspond to signals A through D in the
> >> +datasheet. If a mux controller is mentioned in neither adi,idle-state nor

that is already being said under 'adi,idle-state'

> >> +adi,idle-high-impedance it is left in its previously selected state when idle.
> >> +
> >> +Example:
> >> +
> >> +	/*
> >> +	 * Three independent mux controllers (of which one is used).
> >> +	 * Mux 0 is disconnected when idle, mux 1 idles with signal C
> >> +	 * and mux 2 idles with signal A.
> >> +	 */
> >> +	&i2c0 {
> >> +		mux: adg792a@50 {
> > 
> > mux-controller@50
> 
> Yep. Hmm, where have I seen that before? :-)
> 
> Cheers,
> peda
> 
> >> +			compatible = "adi,adg792a";
> >> +			reg = <0x50>;
> >> +			#mux-control-cells = <1>;
> >> +
> >> +			adi,idle-high-impedance = <0>;
> >> +			adi,idle-state = <1 2>, <2 0>;
> >> +		};
> >> +	};
> >> +
> >> +	adc-mux {
> >> +		compatible = "io-channel-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 = "io-channel-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
> 

-- 

Peter Meerwald-Stadler
+43-664-2444418 (mobile)

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

* Re: [PATCH v8 09/12] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
  2017-01-27 22:09       ` Peter Rosin
  (?)
  (?)
@ 2017-01-28 11:40       ` Jonathan Cameron
  -1 siblings, 0 replies; 54+ messages in thread
From: Jonathan Cameron @ 2017-01-28 11:40 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,
	Andrew Morton, linux-i2c, devicetree, linux-iio, linux-doc

On 27/01/17 22:09, Peter Rosin wrote:
> On 2017-01-27 20:50, Rob Herring wrote:
>> On Wed, Jan 18, 2017 at 04:57:12PM +0100, Peter Rosin wrote:
>>> Analog Devices ADG792A/G is a triple 4:1 mux.
>>>
>>> Acked-by: Jonathan Cameron <jic23@kernel.org>
>>> Signed-off-by: Peter Rosin <peda@axentia.se>
>>> ---
>>>  .../devicetree/bindings/mux/mux-adg792a.txt        | 79 ++++++++++++++++++++++
>>>  1 file changed, 79 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/mux/mux-adg792a.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/mux/mux-adg792a.txt b/Documentation/devicetree/bindings/mux/mux-adg792a.txt
>>> new file mode 100644
>>> index 000000000000..0b26dd11f070
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/mux/mux-adg792a.txt
>>> @@ -0,0 +1,79 @@
>>> +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 for ADG792G:
>>> +- gpio-controller : if present, #gpio-cells below is required.
>>> +- #gpio-cells : should be <2>
>>> +			  - First cell is the GPO line number, i.e. 0 or 1
>>> +			  - Second cell is used to specify active high (0)
>>> +			    or active low (1)
>>> +
>>> +Optional properties:
>>> +- adi,parallel : if present, the three muxes are bound together with a single
>>> +  mux controller, controlling all three muxes in parallel.
>>
>> Can't this be implied by #mux-control-cells == 0?
> 
> Right, good point! I'll drop adi,parallel.
> 
>>> +- adi,idle-state : if present, array of 2-tuples with mux controller number
>>> +  and state that mux controllers will have when idle. States 0 through 3
>>> +  correspond to signals A through D in the datasheet.
>>> +- adi,idle-high-impedance : if present, array of mux controller numbers that
>>> +  should be in the disconnected high-impedance state when idle.
>>
>> Perhaps combine these 2 to a common idle-state with the index being the 
>> mux controller number and a value of -1 (or 4) being hi-Z.
> 
> At one point [1] I had a straight array for the mux controllers with state 4
> being hi-Z and state 5 being the default "leave mux as-is on release", but
> Jonathan didn't like magic numbers. Can you please read the follow-ups to the
> referenced mail for some background, and then pick out the most suitable color
> for me to paint with? :-)
Hohum.  Given it can be cleanly represented as two properties rather than a single
property with a single magic value alongside the obvious ones I asked Peter
to split it.

Not all that fussed though as I don't have to maintain this ;)
*ducks*

Jonathan
> 
> [1] https://lkml.org/lkml/2016/11/30/110
> 
>>> +
>>> +Mux controller states 0 through 3 correspond to signals A through D in the
>>> +datasheet. If a mux controller is mentioned in neither adi,idle-state nor
>>> +adi,idle-high-impedance it is left in its previously selected state when idle.
>>> +
>>> +Example:
>>> +
>>> +	/*
>>> +	 * Three independent mux controllers (of which one is used).
>>> +	 * Mux 0 is disconnected when idle, mux 1 idles with signal C
>>> +	 * and mux 2 idles with signal A.
>>> +	 */
>>> +	&i2c0 {
>>> +		mux: adg792a@50 {
>>
>> mux-controller@50
> 
> Yep. Hmm, where have I seen that before? :-)
> 
> Cheers,
> peda
> 
>>> +			compatible = "adi,adg792a";
>>> +			reg = <0x50>;
>>> +			#mux-control-cells = <1>;
>>> +
>>> +			adi,idle-high-impedance = <0>;
>>> +			adi,idle-state = <1 2>, <2 0>;
>>> +		};
>>> +	};
>>> +
>>> +	adc-mux {
>>> +		compatible = "io-channel-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 = "io-channel-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@vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

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

* Re: [PATCH v8 07/12] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
  2017-01-27 19:39   ` Rob Herring
@ 2017-01-28 22:42       ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-28 22:42 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, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

On 2017-01-27 20:39, Rob Herring wrote:
> On Wed, Jan 18, 2017 at 04:57:10PM +0100, Peter Rosin wrote:
>> Describe how a generic multiplexer controller is used to mux an i2c bus.
>>
>> Acked-by: Jonathan Cameron <jic23@kernel.org>
>> 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..253d5027843b
>> --- /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
> 
> Not a fan of using "simple" nor the ','. Perhaps lock type should be 
> separate property.

How about just i2c-mux for the compatible? Because i2c-mux-mux (which
follows the naming of previous i2c muxes) looks really stupid. Or
perhaps i2c-mux-generic?

I'm also happy to have the lock type as a separate property. One lock
type, e.g. parent-locked, could be the default and adding a 'mux-locked'
property could change that. Would that be ok?

Or should it be a requirement that one of 'mux-locked'/'parent-locked'
is always present?

> I'm not sure I get the mux vs. parent locked fully. How do I determine 
> what type I have? We already have bindings for several types of i2c 
> muxes. How does the locking annotation fit into those?

We have briefly discussed this before [1] in the context of i2c-mux-gpio
and i2c-mux-pinctrl, when I added the mux-locked/parent-locked distinction
to the i2c-mux infrastructure (it wasn't named mux-locked/parent-locked
way back then though). There is more detail on what the difference is
between the two in Documentation/i2c/i2c-topology.

Side note regarding your remark "use an I2C controlled mux instead"; it
appears that I'm not alone [2] with this kind of requirement...

[1] https://lkml.org/lkml/2016/1/6/437
[2] http://marc.info/?t=147877959100002&r=1&w=2

But, now that I have pondered on this for a year or so, I firmly
believe it was a mistake to have the code in i2c-mux-gpio and
i2c-mux-pinctrl automatically try to deduce if the mux should be
mux-locked or parent-locked. It might be easy to make that call
in some trivial cases, but it is not difficult to dream up
scenarios where it would be extremely hard for the code to get
this decision right. It's just fragile. But now we have code in
those two muxes that has unwanted tentacles into the guts of the
gpio and pinctrl subsystems. Hopefully those unwanted tentacles
can be replaced with something based on device links? However, it
is still not hard to come up with scenarios that will require
manual intervention in order to select the right kind of i2c mux
locking. So, I fear that we have inadequate code trying to make a
decision automatically, and that we at some point down the line
will have some impossible case needing a binding that trumps the
heuristic. Why have a heuristic at all in that case? In short, it
should have been a binding from the start, methinks.

That was a long rant regarding i2c-mux-gpio and i2c-mux-pinctrl.
I obviously think it is bad to have this new i2c mux go in the
same direction as those two drivers. I.e. I think a binding that
specifies the desired locking is preferable to any attempted
heuristic.

Cheers,
peda

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

* Re: [PATCH v8 07/12] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
@ 2017-01-28 22:42       ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-28 22:42 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, Andrew Morton,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

On 2017-01-27 20:39, Rob Herring wrote:
> On Wed, Jan 18, 2017 at 04:57:10PM +0100, Peter Rosin wrote:
>> Describe how a generic multiplexer controller is used to mux an i2c bus.
>>
>> Acked-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>> ---
>>  .../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..253d5027843b
>> --- /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
> 
> Not a fan of using "simple" nor the ','. Perhaps lock type should be 
> separate property.

How about just i2c-mux for the compatible? Because i2c-mux-mux (which
follows the naming of previous i2c muxes) looks really stupid. Or
perhaps i2c-mux-generic?

I'm also happy to have the lock type as a separate property. One lock
type, e.g. parent-locked, could be the default and adding a 'mux-locked'
property could change that. Would that be ok?

Or should it be a requirement that one of 'mux-locked'/'parent-locked'
is always present?

> I'm not sure I get the mux vs. parent locked fully. How do I determine 
> what type I have? We already have bindings for several types of i2c 
> muxes. How does the locking annotation fit into those?

We have briefly discussed this before [1] in the context of i2c-mux-gpio
and i2c-mux-pinctrl, when I added the mux-locked/parent-locked distinction
to the i2c-mux infrastructure (it wasn't named mux-locked/parent-locked
way back then though). There is more detail on what the difference is
between the two in Documentation/i2c/i2c-topology.

Side note regarding your remark "use an I2C controlled mux instead"; it
appears that I'm not alone [2] with this kind of requirement...

[1] https://lkml.org/lkml/2016/1/6/437
[2] http://marc.info/?t=147877959100002&r=1&w=2

But, now that I have pondered on this for a year or so, I firmly
believe it was a mistake to have the code in i2c-mux-gpio and
i2c-mux-pinctrl automatically try to deduce if the mux should be
mux-locked or parent-locked. It might be easy to make that call
in some trivial cases, but it is not difficult to dream up
scenarios where it would be extremely hard for the code to get
this decision right. It's just fragile. But now we have code in
those two muxes that has unwanted tentacles into the guts of the
gpio and pinctrl subsystems. Hopefully those unwanted tentacles
can be replaced with something based on device links? However, it
is still not hard to come up with scenarios that will require
manual intervention in order to select the right kind of i2c mux
locking. So, I fear that we have inadequate code trying to make a
decision automatically, and that we at some point down the line
will have some impossible case needing a binding that trumps the
heuristic. Why have a heuristic at all in that case? In short, it
should have been a binding from the start, methinks.

That was a long rant regarding i2c-mux-gpio and i2c-mux-pinctrl.
I obviously think it is bad to have this new i2c mux go in the
same direction as those two drivers. I.e. I think a binding that
specifies the desired locking is preferable to any attempted
heuristic.

Cheers,
peda

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

* Re: [PATCH v8 12/12] mux: support simplified bindings for single-user gpio mux
  2017-01-27 15:52       ` Rob Herring
@ 2017-01-30  8:02           ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-30  8:02 UTC (permalink / raw)
  To: Rob Herring
  Cc: Jonathan Cameron, linux-kernel, Wolfram Sang, Mark Rutland,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Jonathan Corbet, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

[-- Attachment #1: Type: text/plain, Size: 2895 bytes --]

On 2017-01-27 16:52, Rob Herring wrote:
> On Mon, Jan 23, 2017 at 11:24:18AM +0100, Peter Rosin wrote:
>> On 2017-01-22 14:30, Jonathan Cameron wrote:
>>> On 18/01/17 15:57, Peter Rosin wrote:
>>>> Allow bindings for a GPIO controlled mux to be specified in the
>>>> mux consumer node.
>>>>
>>>> Signed-off-by: Peter Rosin <peda@axentia.se>
>>> Code is good as far as I am concerned. Only question is whether this
>>
>> Hmmm, now that I think some more about it, the code supporting the
>> simplified binding (patch 12/12) is a bit fishy in one respect.
>>
>> A driver that calls mux_control_get and gets a mux_control that happens
>> to be backed by an implicit mux chip (i.e. using the simplified binding)
>> will not be able to reverse the resource allocation with less than a
>> complete destruction of itself. Now, this is likely not a problem in
>> most cases, but I bet it will creep up at the most inopportune time. And
>> your remark that I'm the one that has to maintain this makes me dislike
>> this concept...
>>
>> I.e. mux_control_put *should* reverse mux_control_get, but this simply
>> does not happen for the implicit mux chips, as implicit mux chips are
>> not put away until the owning device is put away.
> 
> I think this is because you aren't creating a device in this case. Nodes 
> in DT are not the only way to create devices. Drivers can create a child 
> device when they find mux-gpios property.

Yes, but even with such a child device, a flag is needed somewhere that
triggers cleanup when the mux_control is put away. And then it is possible
to cleanup w/o the help of a child device. I wrote some code for this when
I realized the problem, and it looks simple enough, but I haven't tested
it yet, so who knows... It is attached (patch to be applied on top of 12/12)
if anyone cares.

>> Every time I have tried to come up with a way to implement the simplified
>> bindings I seem to hit one of these subtleties.
>>
>>> is worth the hassle given the normal bindings don't give that high
>>> a burden in complexity!
> 
> I was going to change my mind here, but we already have "mux-gpios" as a 
> binding at least for i2c-gpio-mux. So really the question is do we want 
> to support that here?

I think my preference is to drop the simplified binding, but I can also
live with it. But as there appears to be no strong feelings, let's just
drop it. It is always possible to add it later. Ok?

>> I am missing an ack from Rob though.
>>
>>> I don't really care either way:)
>>
>> But Rob seems to care, this series just has to find a way to get out of
>> his too-much-churn-will-look-at-it-later list. I sadly don't know how to
>> pull that trick...
> 
> By complaining that I'm putting it off... :) I guess I'm okay with this 
> series in general. I will reply on the specific patches today.

Great, it appears that I'm quite the magician. :-) Thanks!

Cheers,
peda


[-- Attachment #2: 0001-mux-fix-cleanup-for-simplified-bindings.patch --]
[-- Type: text/plain, Size: 2402 bytes --]

>From 5c448b8dfd831c7bc501d9543d48b2077ee1ba7b Mon Sep 17 00:00:00 2001
From: Peter Rosin <peda@axentia.se>
Date: Tue, 24 Jan 2017 16:58:58 +0100
Subject: [PATCH] mux: fix cleanup for simplified bindings

---
 drivers/mux/mux-core.c | 19 ++++++++++++++++++-
 include/linux/mux.h    |  2 ++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c
index 0caafd6f5a77..53954bd12709 100644
--- a/drivers/mux/mux-core.c
+++ b/drivers/mux/mux-core.c
@@ -321,9 +321,12 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
 	if (ret == -ENOENT && !mux_name) {
 		mux_chip = mux_gpio_alloc(dev);
 		if (!IS_ERR(mux_chip)) {
+			mux_chip->private = true;
 			ret = devm_mux_chip_register(dev, mux_chip);
-			if (ret < 0)
+			if (ret < 0) {
+				devm_mux_chip_free(dev, mux_chip);
 				return ERR_PTR(ret);
+			}
 			get_device(&mux_chip->dev);
 			return mux_chip->mux;
 		}
@@ -344,6 +347,12 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
 	if (!mux_chip)
 		return ERR_PTR(-EPROBE_DEFER);
 
+	if (mux_chip->private) {
+		dev_err(dev, "%s: private mux chip specified in %s\n",
+			np->full_name, args.np->full_name);
+		return ERR_PTR(-EBUSY);
+	}
+
 	if (args.args_count > 1 ||
 	    (!args.args_count && (mux_chip->controllers > 1))) {
 		dev_err(dev, "%s: wrong #mux-control-cells for %s\n",
@@ -368,7 +377,15 @@ EXPORT_SYMBOL_GPL(mux_control_get);
 
 void mux_control_put(struct mux_control *mux)
 {
+	bool private = mux->chip->private;
+	struct device *parent = mux->chip->dev.parent;
+
 	put_device(&mux->chip->dev);
+
+	if (private) {
+		devm_mux_chip_unregister(parent, mux->chip);
+		devm_mux_chip_free(parent, mux->chip);
+	}
 }
 EXPORT_SYMBOL_GPL(mux_control_put);
 
diff --git a/include/linux/mux.h b/include/linux/mux.h
index ec9e605d8acf..3ad2e475c9dd 100644
--- a/include/linux/mux.h
+++ b/include/linux/mux.h
@@ -49,6 +49,7 @@ struct mux_control {
  * @mux:		Array of mux controllers that is handled.
  * @dev:		Device structure.
  * @id:			Used to identify the device internally.
+ * @private:		The mux chip is implicitly allocated by a single user.
  * @ops:		Mux controller operations.
  */
 struct mux_chip {
@@ -56,6 +57,7 @@ struct mux_chip {
 	struct mux_control *mux;
 	struct device dev;
 	int id;
+	bool private;
 
 	const struct mux_control_ops *ops;
 };
-- 
2.1.4


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

* Re: [PATCH v8 12/12] mux: support simplified bindings for single-user gpio mux
@ 2017-01-30  8:02           ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-30  8:02 UTC (permalink / raw)
  To: Rob Herring
  Cc: Jonathan Cameron, linux-kernel, Wolfram Sang, Mark Rutland,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Jonathan Corbet, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

[-- Attachment #1: Type: text/plain, Size: 2895 bytes --]

On 2017-01-27 16:52, Rob Herring wrote:
> On Mon, Jan 23, 2017 at 11:24:18AM +0100, Peter Rosin wrote:
>> On 2017-01-22 14:30, Jonathan Cameron wrote:
>>> On 18/01/17 15:57, Peter Rosin wrote:
>>>> Allow bindings for a GPIO controlled mux to be specified in the
>>>> mux consumer node.
>>>>
>>>> Signed-off-by: Peter Rosin <peda@axentia.se>
>>> Code is good as far as I am concerned. Only question is whether this
>>
>> Hmmm, now that I think some more about it, the code supporting the
>> simplified binding (patch 12/12) is a bit fishy in one respect.
>>
>> A driver that calls mux_control_get and gets a mux_control that happens
>> to be backed by an implicit mux chip (i.e. using the simplified binding)
>> will not be able to reverse the resource allocation with less than a
>> complete destruction of itself. Now, this is likely not a problem in
>> most cases, but I bet it will creep up at the most inopportune time. And
>> your remark that I'm the one that has to maintain this makes me dislike
>> this concept...
>>
>> I.e. mux_control_put *should* reverse mux_control_get, but this simply
>> does not happen for the implicit mux chips, as implicit mux chips are
>> not put away until the owning device is put away.
> 
> I think this is because you aren't creating a device in this case. Nodes 
> in DT are not the only way to create devices. Drivers can create a child 
> device when they find mux-gpios property.

Yes, but even with such a child device, a flag is needed somewhere that
triggers cleanup when the mux_control is put away. And then it is possible
to cleanup w/o the help of a child device. I wrote some code for this when
I realized the problem, and it looks simple enough, but I haven't tested
it yet, so who knows... It is attached (patch to be applied on top of 12/12)
if anyone cares.

>> Every time I have tried to come up with a way to implement the simplified
>> bindings I seem to hit one of these subtleties.
>>
>>> is worth the hassle given the normal bindings don't give that high
>>> a burden in complexity!
> 
> I was going to change my mind here, but we already have "mux-gpios" as a 
> binding at least for i2c-gpio-mux. So really the question is do we want 
> to support that here?

I think my preference is to drop the simplified binding, but I can also
live with it. But as there appears to be no strong feelings, let's just
drop it. It is always possible to add it later. Ok?

>> I am missing an ack from Rob though.
>>
>>> I don't really care either way:)
>>
>> But Rob seems to care, this series just has to find a way to get out of
>> his too-much-churn-will-look-at-it-later list. I sadly don't know how to
>> pull that trick...
> 
> By complaining that I'm putting it off... :) I guess I'm okay with this 
> series in general. I will reply on the specific patches today.

Great, it appears that I'm quite the magician. :-) Thanks!

Cheers,
peda


[-- Attachment #2: 0001-mux-fix-cleanup-for-simplified-bindings.patch --]
[-- Type: text/plain, Size: 2402 bytes --]

>From 5c448b8dfd831c7bc501d9543d48b2077ee1ba7b Mon Sep 17 00:00:00 2001
From: Peter Rosin <peda@axentia.se>
Date: Tue, 24 Jan 2017 16:58:58 +0100
Subject: [PATCH] mux: fix cleanup for simplified bindings

---
 drivers/mux/mux-core.c | 19 ++++++++++++++++++-
 include/linux/mux.h    |  2 ++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c
index 0caafd6f5a77..53954bd12709 100644
--- a/drivers/mux/mux-core.c
+++ b/drivers/mux/mux-core.c
@@ -321,9 +321,12 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
 	if (ret == -ENOENT && !mux_name) {
 		mux_chip = mux_gpio_alloc(dev);
 		if (!IS_ERR(mux_chip)) {
+			mux_chip->private = true;
 			ret = devm_mux_chip_register(dev, mux_chip);
-			if (ret < 0)
+			if (ret < 0) {
+				devm_mux_chip_free(dev, mux_chip);
 				return ERR_PTR(ret);
+			}
 			get_device(&mux_chip->dev);
 			return mux_chip->mux;
 		}
@@ -344,6 +347,12 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
 	if (!mux_chip)
 		return ERR_PTR(-EPROBE_DEFER);
 
+	if (mux_chip->private) {
+		dev_err(dev, "%s: private mux chip specified in %s\n",
+			np->full_name, args.np->full_name);
+		return ERR_PTR(-EBUSY);
+	}
+
 	if (args.args_count > 1 ||
 	    (!args.args_count && (mux_chip->controllers > 1))) {
 		dev_err(dev, "%s: wrong #mux-control-cells for %s\n",
@@ -368,7 +377,15 @@ EXPORT_SYMBOL_GPL(mux_control_get);
 
 void mux_control_put(struct mux_control *mux)
 {
+	bool private = mux->chip->private;
+	struct device *parent = mux->chip->dev.parent;
+
 	put_device(&mux->chip->dev);
+
+	if (private) {
+		devm_mux_chip_unregister(parent, mux->chip);
+		devm_mux_chip_free(parent, mux->chip);
+	}
 }
 EXPORT_SYMBOL_GPL(mux_control_put);
 
diff --git a/include/linux/mux.h b/include/linux/mux.h
index ec9e605d8acf..3ad2e475c9dd 100644
--- a/include/linux/mux.h
+++ b/include/linux/mux.h
@@ -49,6 +49,7 @@ struct mux_control {
  * @mux:		Array of mux controllers that is handled.
  * @dev:		Device structure.
  * @id:			Used to identify the device internally.
+ * @private:		The mux chip is implicitly allocated by a single user.
  * @ops:		Mux controller operations.
  */
 struct mux_chip {
@@ -56,6 +57,7 @@ struct mux_chip {
 	struct mux_control *mux;
 	struct device dev;
 	int id;
+	bool private;
 
 	const struct mux_control_ops *ops;
 };
-- 
2.1.4


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

* Re: [PATCH v8 07/12] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
@ 2017-01-30 17:20         ` Rob Herring
  0 siblings, 0 replies; 54+ messages in thread
From: Rob Herring @ 2017-01-30 17:20 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, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

On Sat, Jan 28, 2017 at 4:42 PM, Peter Rosin <peda@axentia.se> wrote:
> On 2017-01-27 20:39, Rob Herring wrote:
>> On Wed, Jan 18, 2017 at 04:57:10PM +0100, Peter Rosin wrote:
>>> Describe how a generic multiplexer controller is used to mux an i2c bus.
>>>
>>> Acked-by: Jonathan Cameron <jic23@kernel.org>
>>> 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..253d5027843b
>>> --- /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
>>
>> Not a fan of using "simple" nor the ','. Perhaps lock type should be
>> separate property.
>
> How about just i2c-mux for the compatible? Because i2c-mux-mux (which
> follows the naming of previous i2c muxes) looks really stupid. Or
> perhaps i2c-mux-generic?

I like "generic" only slightly more than "simple". :)

If the mux is gpio controlled, then it should still be called
i2c-gpio-mux. Let's not invent brand new bindings when current ones
are easily extended. We already have pretty generic names here, let's
not make them more generic.

>
> I'm also happy to have the lock type as a separate property. One lock
> type, e.g. parent-locked, could be the default and adding a 'mux-locked'
> property could change that. Would that be ok?

I prefer this. Then existing bindings can use it.

> Or should it be a requirement that one of 'mux-locked'/'parent-locked'
> is always present?

I would make it boolean and make not present be the more common case.
Not present could also mean determined via other means as you have
today with existing bindings. Maybe then you need both properties.

>> I'm not sure I get the mux vs. parent locked fully. How do I determine
>> what type I have? We already have bindings for several types of i2c
>> muxes. How does the locking annotation fit into those?
>
> We have briefly discussed this before [1] in the context of i2c-mux-gpio
> and i2c-mux-pinctrl, when I added the mux-locked/parent-locked distinction
> to the i2c-mux infrastructure (it wasn't named mux-locked/parent-locked
> way back then though). There is more detail on what the difference is
> between the two in Documentation/i2c/i2c-topology.
>
> Side note regarding your remark "use an I2C controlled mux instead"; it
> appears that I'm not alone [2] with this kind of requirement...
>
> [1] https://lkml.org/lkml/2016/1/6/437
> [2] http://marc.info/?t=147877959100002&r=1&w=2
>
> But, now that I have pondered on this for a year or so, I firmly
> believe it was a mistake to have the code in i2c-mux-gpio and
> i2c-mux-pinctrl automatically try to deduce if the mux should be
> mux-locked or parent-locked. It might be easy to make that call
> in some trivial cases, but it is not difficult to dream up
> scenarios where it would be extremely hard for the code to get
> this decision right. It's just fragile. But now we have code in
> those two muxes that has unwanted tentacles into the guts of the
> gpio and pinctrl subsystems. Hopefully those unwanted tentacles
> can be replaced with something based on device links? However, it
> is still not hard to come up with scenarios that will require
> manual intervention in order to select the right kind of i2c mux
> locking. So, I fear that we have inadequate code trying to make a
> decision automatically, and that we at some point down the line
> will have some impossible case needing a binding that trumps the
> heuristic. Why have a heuristic at all in that case? In short, it
> should have been a binding from the start, methinks.
>
> That was a long rant regarding i2c-mux-gpio and i2c-mux-pinctrl.
> I obviously think it is bad to have this new i2c mux go in the
> same direction as those two drivers. I.e. I think a binding that
> specifies the desired locking is preferable to any attempted
> heuristic.

Having a separate, common property(ies) for these would solve this then.

Rob

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

* Re: [PATCH v8 07/12] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
@ 2017-01-30 17:20         ` Rob Herring
  0 siblings, 0 replies; 54+ messages in thread
From: Rob Herring @ 2017-01-30 17:20 UTC (permalink / raw)
  To: Peter Rosin
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, Wolfram Sang, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Andrew Morton,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

On Sat, Jan 28, 2017 at 4:42 PM, Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org> wrote:
> On 2017-01-27 20:39, Rob Herring wrote:
>> On Wed, Jan 18, 2017 at 04:57:10PM +0100, Peter Rosin wrote:
>>> Describe how a generic multiplexer controller is used to mux an i2c bus.
>>>
>>> Acked-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>>> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>>> ---
>>>  .../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..253d5027843b
>>> --- /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
>>
>> Not a fan of using "simple" nor the ','. Perhaps lock type should be
>> separate property.
>
> How about just i2c-mux for the compatible? Because i2c-mux-mux (which
> follows the naming of previous i2c muxes) looks really stupid. Or
> perhaps i2c-mux-generic?

I like "generic" only slightly more than "simple". :)

If the mux is gpio controlled, then it should still be called
i2c-gpio-mux. Let's not invent brand new bindings when current ones
are easily extended. We already have pretty generic names here, let's
not make them more generic.

>
> I'm also happy to have the lock type as a separate property. One lock
> type, e.g. parent-locked, could be the default and adding a 'mux-locked'
> property could change that. Would that be ok?

I prefer this. Then existing bindings can use it.

> Or should it be a requirement that one of 'mux-locked'/'parent-locked'
> is always present?

I would make it boolean and make not present be the more common case.
Not present could also mean determined via other means as you have
today with existing bindings. Maybe then you need both properties.

>> I'm not sure I get the mux vs. parent locked fully. How do I determine
>> what type I have? We already have bindings for several types of i2c
>> muxes. How does the locking annotation fit into those?
>
> We have briefly discussed this before [1] in the context of i2c-mux-gpio
> and i2c-mux-pinctrl, when I added the mux-locked/parent-locked distinction
> to the i2c-mux infrastructure (it wasn't named mux-locked/parent-locked
> way back then though). There is more detail on what the difference is
> between the two in Documentation/i2c/i2c-topology.
>
> Side note regarding your remark "use an I2C controlled mux instead"; it
> appears that I'm not alone [2] with this kind of requirement...
>
> [1] https://lkml.org/lkml/2016/1/6/437
> [2] http://marc.info/?t=147877959100002&r=1&w=2
>
> But, now that I have pondered on this for a year or so, I firmly
> believe it was a mistake to have the code in i2c-mux-gpio and
> i2c-mux-pinctrl automatically try to deduce if the mux should be
> mux-locked or parent-locked. It might be easy to make that call
> in some trivial cases, but it is not difficult to dream up
> scenarios where it would be extremely hard for the code to get
> this decision right. It's just fragile. But now we have code in
> those two muxes that has unwanted tentacles into the guts of the
> gpio and pinctrl subsystems. Hopefully those unwanted tentacles
> can be replaced with something based on device links? However, it
> is still not hard to come up with scenarios that will require
> manual intervention in order to select the right kind of i2c mux
> locking. So, I fear that we have inadequate code trying to make a
> decision automatically, and that we at some point down the line
> will have some impossible case needing a binding that trumps the
> heuristic. Why have a heuristic at all in that case? In short, it
> should have been a binding from the start, methinks.
>
> That was a long rant regarding i2c-mux-gpio and i2c-mux-pinctrl.
> I obviously think it is bad to have this new i2c mux go in the
> same direction as those two drivers. I.e. I think a binding that
> specifies the desired locking is preferable to any attempted
> heuristic.

Having a separate, common property(ies) for these would solve this then.

Rob
--
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] 54+ messages in thread

* Re: [PATCH v8 07/12] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
@ 2017-01-31  7:36           ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-31  7:36 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, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

On 2017-01-30 18:20, Rob Herring wrote:
> On Sat, Jan 28, 2017 at 4:42 PM, Peter Rosin <peda@axentia.se> wrote:
>> On 2017-01-27 20:39, Rob Herring wrote:
>>> On Wed, Jan 18, 2017 at 04:57:10PM +0100, Peter Rosin wrote:
>>>> Describe how a generic multiplexer controller is used to mux an i2c bus.
>>>>
>>>> Acked-by: Jonathan Cameron <jic23@kernel.org>
>>>> 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..253d5027843b
>>>> --- /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
>>>
>>> Not a fan of using "simple" nor the ','. Perhaps lock type should be
>>> separate property.
>>
>> How about just i2c-mux for the compatible? Because i2c-mux-mux (which
>> follows the naming of previous i2c muxes) looks really stupid. Or
>> perhaps i2c-mux-generic?
> 
> I like "generic" only slightly more than "simple". :)
> 
> If the mux is gpio controlled, then it should still be called
> i2c-gpio-mux. Let's not invent brand new bindings when current ones
> are easily extended. We already have pretty generic names here, let's
> not make them more generic.

Ahh, but the whole point of this new driver is that it does not know
if the mux is gpio controlled, if it is controlled by an adg792 chip
or whatever might appear down the line. So, I think i2c-mux-gpio (and
i2c-gpio-mux) is actively wrong.

This new driver is in fact an i2c-mux driver that (in this aspect) is more
generic than any of the existing i2c-mux drivers, hence my suggestion.

If you see this new driver as something that is superseding the existing
i2c-mux-gpio driver, I'm sad to inform you that the code is not simply
not there. i2c-mux-gpio has acpi support and users may provide platform
data from code. The existing i2c-mux-gpio driver also has the below
mentioned locking heuristic. Adding all those things to the new driver
would make it big and unwieldy and having even more unwanted tentacles
into other subsystems. And why should it be only i2c-mux-gpio that is
merged into this new i2c-mux driver? Why not implement a mux-pinctrl
driver for the new mux subsustem and then merge i2c-mux-pinctrl as well?
I say no, that way lies madness.

>>
>> I'm also happy to have the lock type as a separate property. One lock
>> type, e.g. parent-locked, could be the default and adding a 'mux-locked'
>> property could change that. Would that be ok?
> 
> I prefer this. Then existing bindings can use it.
> 
>> Or should it be a requirement that one of 'mux-locked'/'parent-locked'
>> is always present?
> 
> I would make it boolean and make not present be the more common case.
> Not present could also mean determined via other means as you have
> today with existing bindings. Maybe then you need both properties.

Ok. Lets define that every type of i2c-mux have a default locking.
If no property is found that overrides this default, a heuristic may
be applied that is only allowed to very defensively use non-default
locking (like the current heuristics in i2c-mux-gpio/i2c-mux-pinctrl
attempt to do, they only adjust the locking for impossible cases that
would invariably lead to a deadlock with the default locking). Then,
there should never exist a need to enforce the default locking with
a property.

And given that no current i2c-mux that is mux-locked by default even
have the ability to be parent-locked, there is (currently) no need
for more than a bool 'mux-locked' property.

>>> I'm not sure I get the mux vs. parent locked fully. How do I determine
>>> what type I have? We already have bindings for several types of i2c
>>> muxes. How does the locking annotation fit into those?
>>
>> We have briefly discussed this before [1] in the context of i2c-mux-gpio
>> and i2c-mux-pinctrl, when I added the mux-locked/parent-locked distinction
>> to the i2c-mux infrastructure (it wasn't named mux-locked/parent-locked
>> way back then though). There is more detail on what the difference is
>> between the two in Documentation/i2c/i2c-topology.
>>
>> Side note regarding your remark "use an I2C controlled mux instead"; it
>> appears that I'm not alone [2] with this kind of requirement...
>>
>> [1] https://lkml.org/lkml/2016/1/6/437
>> [2] http://marc.info/?t=147877959100002&r=1&w=2
>>
>> But, now that I have pondered on this for a year or so, I firmly
>> believe it was a mistake to have the code in i2c-mux-gpio and
>> i2c-mux-pinctrl automatically try to deduce if the mux should be
>> mux-locked or parent-locked. It might be easy to make that call
>> in some trivial cases, but it is not difficult to dream up
>> scenarios where it would be extremely hard for the code to get
>> this decision right. It's just fragile. But now we have code in
>> those two muxes that has unwanted tentacles into the guts of the
>> gpio and pinctrl subsystems. Hopefully those unwanted tentacles
>> can be replaced with something based on device links? However, it
>> is still not hard to come up with scenarios that will require
>> manual intervention in order to select the right kind of i2c mux
>> locking. So, I fear that we have inadequate code trying to make a
>> decision automatically, and that we at some point down the line
>> will have some impossible case needing a binding that trumps the
>> heuristic. Why have a heuristic at all in that case? In short, it
>> should have been a binding from the start, methinks.
>>
>> That was a long rant regarding i2c-mux-gpio and i2c-mux-pinctrl.
>> I obviously think it is bad to have this new i2c mux go in the
>> same direction as those two drivers. I.e. I think a binding that
>> specifies the desired locking is preferable to any attempted
>> heuristic.
> 
> Having a separate, common property(ies) for these would solve this then.

Yep, the plan is now to make this new i2c-mux parent-locked by default
and then look for an optional mux-locked property, thus eliminating the
comma and the suffix in the compatible string, leaving only whatever is
eventually picked from 'i2c-mux-simple', 'i2c-mux', 'i2c-mux-generic' and
'i2c-mux-whatever'.

Do I need to re-document the mux-locked/parent-locked difference? I.e.,
is it enough to refer to Documentation/i2c/i2c-topology, or does the
Documentation/devicetree subdir need to self-contained?

Cheers,
peda

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

* Re: [PATCH v8 07/12] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
@ 2017-01-31  7:36           ` Peter Rosin
  0 siblings, 0 replies; 54+ messages in thread
From: Peter Rosin @ 2017-01-31  7:36 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, Andrew Morton,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

On 2017-01-30 18:20, Rob Herring wrote:
> On Sat, Jan 28, 2017 at 4:42 PM, Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org> wrote:
>> On 2017-01-27 20:39, Rob Herring wrote:
>>> On Wed, Jan 18, 2017 at 04:57:10PM +0100, Peter Rosin wrote:
>>>> Describe how a generic multiplexer controller is used to mux an i2c bus.
>>>>
>>>> Acked-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>>>> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>>>> ---
>>>>  .../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..253d5027843b
>>>> --- /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
>>>
>>> Not a fan of using "simple" nor the ','. Perhaps lock type should be
>>> separate property.
>>
>> How about just i2c-mux for the compatible? Because i2c-mux-mux (which
>> follows the naming of previous i2c muxes) looks really stupid. Or
>> perhaps i2c-mux-generic?
> 
> I like "generic" only slightly more than "simple". :)
> 
> If the mux is gpio controlled, then it should still be called
> i2c-gpio-mux. Let's not invent brand new bindings when current ones
> are easily extended. We already have pretty generic names here, let's
> not make them more generic.

Ahh, but the whole point of this new driver is that it does not know
if the mux is gpio controlled, if it is controlled by an adg792 chip
or whatever might appear down the line. So, I think i2c-mux-gpio (and
i2c-gpio-mux) is actively wrong.

This new driver is in fact an i2c-mux driver that (in this aspect) is more
generic than any of the existing i2c-mux drivers, hence my suggestion.

If you see this new driver as something that is superseding the existing
i2c-mux-gpio driver, I'm sad to inform you that the code is not simply
not there. i2c-mux-gpio has acpi support and users may provide platform
data from code. The existing i2c-mux-gpio driver also has the below
mentioned locking heuristic. Adding all those things to the new driver
would make it big and unwieldy and having even more unwanted tentacles
into other subsystems. And why should it be only i2c-mux-gpio that is
merged into this new i2c-mux driver? Why not implement a mux-pinctrl
driver for the new mux subsustem and then merge i2c-mux-pinctrl as well?
I say no, that way lies madness.

>>
>> I'm also happy to have the lock type as a separate property. One lock
>> type, e.g. parent-locked, could be the default and adding a 'mux-locked'
>> property could change that. Would that be ok?
> 
> I prefer this. Then existing bindings can use it.
> 
>> Or should it be a requirement that one of 'mux-locked'/'parent-locked'
>> is always present?
> 
> I would make it boolean and make not present be the more common case.
> Not present could also mean determined via other means as you have
> today with existing bindings. Maybe then you need both properties.

Ok. Lets define that every type of i2c-mux have a default locking.
If no property is found that overrides this default, a heuristic may
be applied that is only allowed to very defensively use non-default
locking (like the current heuristics in i2c-mux-gpio/i2c-mux-pinctrl
attempt to do, they only adjust the locking for impossible cases that
would invariably lead to a deadlock with the default locking). Then,
there should never exist a need to enforce the default locking with
a property.

And given that no current i2c-mux that is mux-locked by default even
have the ability to be parent-locked, there is (currently) no need
for more than a bool 'mux-locked' property.

>>> I'm not sure I get the mux vs. parent locked fully. How do I determine
>>> what type I have? We already have bindings for several types of i2c
>>> muxes. How does the locking annotation fit into those?
>>
>> We have briefly discussed this before [1] in the context of i2c-mux-gpio
>> and i2c-mux-pinctrl, when I added the mux-locked/parent-locked distinction
>> to the i2c-mux infrastructure (it wasn't named mux-locked/parent-locked
>> way back then though). There is more detail on what the difference is
>> between the two in Documentation/i2c/i2c-topology.
>>
>> Side note regarding your remark "use an I2C controlled mux instead"; it
>> appears that I'm not alone [2] with this kind of requirement...
>>
>> [1] https://lkml.org/lkml/2016/1/6/437
>> [2] http://marc.info/?t=147877959100002&r=1&w=2
>>
>> But, now that I have pondered on this for a year or so, I firmly
>> believe it was a mistake to have the code in i2c-mux-gpio and
>> i2c-mux-pinctrl automatically try to deduce if the mux should be
>> mux-locked or parent-locked. It might be easy to make that call
>> in some trivial cases, but it is not difficult to dream up
>> scenarios where it would be extremely hard for the code to get
>> this decision right. It's just fragile. But now we have code in
>> those two muxes that has unwanted tentacles into the guts of the
>> gpio and pinctrl subsystems. Hopefully those unwanted tentacles
>> can be replaced with something based on device links? However, it
>> is still not hard to come up with scenarios that will require
>> manual intervention in order to select the right kind of i2c mux
>> locking. So, I fear that we have inadequate code trying to make a
>> decision automatically, and that we at some point down the line
>> will have some impossible case needing a binding that trumps the
>> heuristic. Why have a heuristic at all in that case? In short, it
>> should have been a binding from the start, methinks.
>>
>> That was a long rant regarding i2c-mux-gpio and i2c-mux-pinctrl.
>> I obviously think it is bad to have this new i2c mux go in the
>> same direction as those two drivers. I.e. I think a binding that
>> specifies the desired locking is preferable to any attempted
>> heuristic.
> 
> Having a separate, common property(ies) for these would solve this then.

Yep, the plan is now to make this new i2c-mux parent-locked by default
and then look for an optional mux-locked property, thus eliminating the
comma and the suffix in the compatible string, leaving only whatever is
eventually picked from 'i2c-mux-simple', 'i2c-mux', 'i2c-mux-generic' and
'i2c-mux-whatever'.

Do I need to re-document the mux-locked/parent-locked difference? I.e.,
is it enough to refer to Documentation/i2c/i2c-topology, or does the
Documentation/devicetree subdir need to self-contained?

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] 54+ messages in thread

* Re: [PATCH v8 07/12] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
  2017-01-31  7:36           ` Peter Rosin
  (?)
@ 2017-02-02 16:08           ` Rob Herring
  2017-02-03  8:25             ` Peter Rosin
  -1 siblings, 1 reply; 54+ messages in thread
From: Rob Herring @ 2017-02-02 16:08 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, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

On Tue, Jan 31, 2017 at 1:36 AM, Peter Rosin <peda@axentia.se> wrote:
> On 2017-01-30 18:20, Rob Herring wrote:
>> On Sat, Jan 28, 2017 at 4:42 PM, Peter Rosin <peda@axentia.se> wrote:
>>> On 2017-01-27 20:39, Rob Herring wrote:
>>>> On Wed, Jan 18, 2017 at 04:57:10PM +0100, Peter Rosin wrote:
>>>>> Describe how a generic multiplexer controller is used to mux an i2c bus.
>>>>>
>>>>> Acked-by: Jonathan Cameron <jic23@kernel.org>
>>>>> 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..253d5027843b
>>>>> --- /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
>>>>
>>>> Not a fan of using "simple" nor the ','. Perhaps lock type should be
>>>> separate property.
>>>
>>> How about just i2c-mux for the compatible? Because i2c-mux-mux (which
>>> follows the naming of previous i2c muxes) looks really stupid. Or
>>> perhaps i2c-mux-generic?
>>
>> I like "generic" only slightly more than "simple". :)
>>
>> If the mux is gpio controlled, then it should still be called
>> i2c-gpio-mux. Let's not invent brand new bindings when current ones
>> are easily extended. We already have pretty generic names here, let's
>> not make them more generic.
>
> Ahh, but the whole point of this new driver is that it does not know
> if the mux is gpio controlled, if it is controlled by an adg792 chip
> or whatever might appear down the line. So, I think i2c-mux-gpio (and
> i2c-gpio-mux) is actively wrong.

That's fine for the driver, but the DT bindings should reflect the
h/w. Be happy that i2c-gpio-mux is allowed. I could easily say it
needs to be actual part numbers for compatible strings.

How is it okay that we now have 2 drivers for the same thing: the
i2c-gpio-mux driver and this i2c mux-controller driver with a gpio
mux-controller driver. I'm surprised Wolfram is okay with that.

> This new driver is in fact an i2c-mux driver that (in this aspect) is more
> generic than any of the existing i2c-mux drivers, hence my suggestion.

If it is more generic, then it should be able to replace existing drivers.

> If you see this new driver as something that is superseding the existing
> i2c-mux-gpio driver, I'm sad to inform you that the code is not simply
> not there. i2c-mux-gpio has acpi support and users may provide platform
> data from code. The existing i2c-mux-gpio driver also has the below
> mentioned locking heuristic. Adding all those things to the new driver
> would make it big and unwieldy and having even more unwanted tentacles
> into other subsystems. And why should it be only i2c-mux-gpio that is
> merged into this new i2c-mux driver? Why not implement a mux-pinctrl
> driver for the new mux subsustem and then merge i2c-mux-pinctrl as well?
> I say no, that way lies madness.

Sounds like a good idea to me. I'm not saying you need to merge any of
them right now though (that's Wolfram's call).

None of this has anything to do with the binding though. Compatible
strings should be specific. That's not up for debate. Whether the
driver bound to a compatible string is common or specific to that
compatible string is completely up to the OS. That decision can change
over time, but the binding should not.

>>> I'm also happy to have the lock type as a separate property. One lock
>>> type, e.g. parent-locked, could be the default and adding a 'mux-locked'
>>> property could change that. Would that be ok?
>>
>> I prefer this. Then existing bindings can use it.
>>
>>> Or should it be a requirement that one of 'mux-locked'/'parent-locked'
>>> is always present?
>>
>> I would make it boolean and make not present be the more common case.
>> Not present could also mean determined via other means as you have
>> today with existing bindings. Maybe then you need both properties.
>
> Ok. Lets define that every type of i2c-mux have a default locking.
> If no property is found that overrides this default, a heuristic may
> be applied that is only allowed to very defensively use non-default
> locking (like the current heuristics in i2c-mux-gpio/i2c-mux-pinctrl
> attempt to do, they only adjust the locking for impossible cases that
> would invariably lead to a deadlock with the default locking). Then,
> there should never exist a need to enforce the default locking with
> a property.
>
> And given that no current i2c-mux that is mux-locked by default even
> have the ability to be parent-locked, there is (currently) no need
> for more than a bool 'mux-locked' property.

Okay, good.

>>>> I'm not sure I get the mux vs. parent locked fully. How do I determine
>>>> what type I have? We already have bindings for several types of i2c
>>>> muxes. How does the locking annotation fit into those?
>>>
>>> We have briefly discussed this before [1] in the context of i2c-mux-gpio
>>> and i2c-mux-pinctrl, when I added the mux-locked/parent-locked distinction
>>> to the i2c-mux infrastructure (it wasn't named mux-locked/parent-locked
>>> way back then though). There is more detail on what the difference is
>>> between the two in Documentation/i2c/i2c-topology.
>>>
>>> Side note regarding your remark "use an I2C controlled mux instead"; it
>>> appears that I'm not alone [2] with this kind of requirement...
>>>
>>> [1] https://lkml.org/lkml/2016/1/6/437
>>> [2] http://marc.info/?t=147877959100002&r=1&w=2
>>>
>>> But, now that I have pondered on this for a year or so, I firmly
>>> believe it was a mistake to have the code in i2c-mux-gpio and
>>> i2c-mux-pinctrl automatically try to deduce if the mux should be
>>> mux-locked or parent-locked. It might be easy to make that call
>>> in some trivial cases, but it is not difficult to dream up
>>> scenarios where it would be extremely hard for the code to get
>>> this decision right. It's just fragile. But now we have code in
>>> those two muxes that has unwanted tentacles into the guts of the
>>> gpio and pinctrl subsystems. Hopefully those unwanted tentacles
>>> can be replaced with something based on device links? However, it
>>> is still not hard to come up with scenarios that will require
>>> manual intervention in order to select the right kind of i2c mux
>>> locking. So, I fear that we have inadequate code trying to make a
>>> decision automatically, and that we at some point down the line
>>> will have some impossible case needing a binding that trumps the
>>> heuristic. Why have a heuristic at all in that case? In short, it
>>> should have been a binding from the start, methinks.
>>>
>>> That was a long rant regarding i2c-mux-gpio and i2c-mux-pinctrl.
>>> I obviously think it is bad to have this new i2c mux go in the
>>> same direction as those two drivers. I.e. I think a binding that
>>> specifies the desired locking is preferable to any attempted
>>> heuristic.
>>
>> Having a separate, common property(ies) for these would solve this then.
>
> Yep, the plan is now to make this new i2c-mux parent-locked by default
> and then look for an optional mux-locked property, thus eliminating the
> comma and the suffix in the compatible string, leaving only whatever is
> eventually picked from 'i2c-mux-simple', 'i2c-mux', 'i2c-mux-generic' and
> 'i2c-mux-whatever'.
>
> Do I need to re-document the mux-locked/parent-locked difference? I.e.,
> is it enough to refer to Documentation/i2c/i2c-topology, or does the
> Documentation/devicetree subdir need to self-contained?

We do try to keep things self contained, but I'm okay with not
duplicating everything in the binding. Just try to summarize what
mux-locked means.

Rob

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

* Re: [PATCH v8 07/12] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
  2017-02-02 16:08           ` Rob Herring
@ 2017-02-03  8:25             ` Peter Rosin
  2017-02-06 21:22                 ` Rob Herring
  0 siblings, 1 reply; 54+ messages in thread
From: Peter Rosin @ 2017-02-03  8:25 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, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

On 2017-02-02 17:08, Rob Herring wrote:
> On Tue, Jan 31, 2017 at 1:36 AM, Peter Rosin <peda@axentia.se> wrote:
>> If you see this new driver as something that is superseding the existing
>> i2c-mux-gpio driver, I'm sad to inform you that the code is not simply
>> not there. i2c-mux-gpio has acpi support and users may provide platform
>> data from code. The existing i2c-mux-gpio driver also has the below
>> mentioned locking heuristic. Adding all those things to the new driver
>> would make it big and unwieldy and having even more unwanted tentacles
>> into other subsystems. And why should it be only i2c-mux-gpio that is
>> merged into this new i2c-mux driver? Why not implement a mux-pinctrl
>> driver for the new mux subsustem and then merge i2c-mux-pinctrl as well?
>> I say no, that way lies madness.
> 
> Sounds like a good idea to me. I'm not saying you need to merge any of
> them right now though (that's Wolfram's call).

If we're pedantic I probably have some stake in it too, being the i2c-mux
maintainer and all. But, agreed, I arrived quite late to the Linux kernel
party and my opinion might perhaps not carry all that much weight...

> None of this has anything to do with the binding though. Compatible
> strings should be specific. That's not up for debate. Whether the

Ok, I'm going to focus on the compatible string for a minute and leave
the implementation details for some other discussion.

> driver bound to a compatible string is common or specific to that
> compatible string is completely up to the OS. That decision can change
> over time, but the binding should not.

So, there's the existing compatible "i2c-mux-gpio" ("i2c-gpio-mux" is
wrong) that you seem to suggest is what I should stick to. I object to
that.

As you say, the bindings and compatible strings should describe hardware,
and you also state they should be specific. I agree. But, why are you
then apparently suggesting (by implication) that for this (hypothetical)
hardware...

    .----.
    |SDA0|-----------.
    |SCL0|---------. |
    |    |         | |
    |    |      .-------.
    |    |      |adg792a|
    |    |      |       |
    |ADC0|------|D1  S1A|---- signal A
    |    |      |    S1B|---- signal B
    |    |      |    S1C|---- signal C
    |    |      |    S1D|---- signal D
    |    |      |       |
    |SDA1|---+--|D2  S2A|---- i2s segment foo A
    |SCL1|-. |  |    S2B|---- i2s segment foo B
    '----' | |  |    S2C|---- i2s segment foo C
           | |  |    S2D|---- i2s segment foo D
           | |  |       |
           | '--|D3  S3A|---- i2s segment bar A
           |    |    S3B|---- i2s segment bar B
           |    |    S3C|---- i2s segment bar C
           |    |    S3D|---- i2s segment bar D
           |    '-------'
           |                  A B C D   A B C D  (feed SCL1 to each of
           |                  | | | |   | | | |   the 8 muxed segments)
           '------------------+-+-+-+---+-+-+-'

...the devicetree should be like below?

&i2c0 {
	mux: mux-controller@50 {
		compatible = "adi,adg792a";
		reg = <0x50>;
		#mux-control-cells = <1>;
	};
};

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

	mux-controls = <&mux 0>;

	...
};

i2c-mux-foo {
	compatible = "i2c-mux-gpio";
	i2c-parent = <&i2c1>;

	mux-controls = <&mux 1>;

	...
};

i2c-mux-bar {
	compatible = "i2c-mux-gpio";
	i2c-parent = <&i2c1>;

	mux-controls = <&mux 2>;

	...
};

There must be some disconnect, because those "i2c-mux-gpio" compatible
strings are just dead wrong. There simply are no gpio pins involved at
all and that "gpio" suffix is just totally out of place.

So, since you are not happy with "i2c-mux-simple", "i2c-mux-generic" or
"i2c-mux" that I have suggested, can you please come up with something
that is good enough for the above?

Or, are you /really/ suggesting "i2c-mux-gpio"?

Cheers,
peda

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

* Re: [PATCH v8 07/12] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
@ 2017-02-06 21:22                 ` Rob Herring
  0 siblings, 0 replies; 54+ messages in thread
From: Rob Herring @ 2017-02-06 21:22 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, Andrew Morton, linux-i2c, devicetree, linux-iio,
	linux-doc

On Fri, Feb 3, 2017 at 2:25 AM, Peter Rosin <peda@axentia.se> wrote:
> On 2017-02-02 17:08, Rob Herring wrote:
>> On Tue, Jan 31, 2017 at 1:36 AM, Peter Rosin <peda@axentia.se> wrote:
>>> If you see this new driver as something that is superseding the existing
>>> i2c-mux-gpio driver, I'm sad to inform you that the code is not simply
>>> not there. i2c-mux-gpio has acpi support and users may provide platform
>>> data from code. The existing i2c-mux-gpio driver also has the below
>>> mentioned locking heuristic. Adding all those things to the new driver
>>> would make it big and unwieldy and having even more unwanted tentacles
>>> into other subsystems. And why should it be only i2c-mux-gpio that is
>>> merged into this new i2c-mux driver? Why not implement a mux-pinctrl
>>> driver for the new mux subsustem and then merge i2c-mux-pinctrl as well?
>>> I say no, that way lies madness.
>>
>> Sounds like a good idea to me. I'm not saying you need to merge any of
>> them right now though (that's Wolfram's call).
>
> If we're pedantic I probably have some stake in it too, being the i2c-mux
> maintainer and all. But, agreed, I arrived quite late to the Linux kernel
> party and my opinion might perhaps not carry all that much weight...
>
>> None of this has anything to do with the binding though. Compatible
>> strings should be specific. That's not up for debate. Whether the
>
> Ok, I'm going to focus on the compatible string for a minute and leave
> the implementation details for some other discussion.
>
>> driver bound to a compatible string is common or specific to that
>> compatible string is completely up to the OS. That decision can change
>> over time, but the binding should not.
>
> So, there's the existing compatible "i2c-mux-gpio" ("i2c-gpio-mux" is
> wrong) that you seem to suggest is what I should stick to. I object to
> that.
>
> As you say, the bindings and compatible strings should describe hardware,
> and you also state they should be specific. I agree. But, why are you
> then apparently suggesting (by implication) that for this (hypothetical)
> hardware...
>
>     .----.
>     |SDA0|-----------.
>     |SCL0|---------. |
>     |    |         | |
>     |    |      .-------.
>     |    |      |adg792a|
>     |    |      |       |
>     |ADC0|------|D1  S1A|---- signal A
>     |    |      |    S1B|---- signal B
>     |    |      |    S1C|---- signal C
>     |    |      |    S1D|---- signal D
>     |    |      |       |
>     |SDA1|---+--|D2  S2A|---- i2s segment foo A
>     |SCL1|-. |  |    S2B|---- i2s segment foo B
>     '----' | |  |    S2C|---- i2s segment foo C
>            | |  |    S2D|---- i2s segment foo D
>            | |  |       |
>            | '--|D3  S3A|---- i2s segment bar A
>            |    |    S3B|---- i2s segment bar B
>            |    |    S3C|---- i2s segment bar C
>            |    |    S3D|---- i2s segment bar D
>            |    '-------'
>            |                  A B C D   A B C D  (feed SCL1 to each of
>            |                  | | | |   | | | |   the 8 muxed segments)
>            '------------------+-+-+-+---+-+-+-'
>
> ...the devicetree should be like below?
>
> &i2c0 {
>         mux: mux-controller@50 {
>                 compatible = "adi,adg792a";
>                 reg = <0x50>;
>                 #mux-control-cells = <1>;
>         };
> };
>
> adc-mux {
>         compatible = "io-channel-mux";
>         io-channels = <&adc 0>;
>         io-channel-names = "parent";
>
>         mux-controls = <&mux 0>;
>
>         ...
> };
>
> i2c-mux-foo {
>         compatible = "i2c-mux-gpio";
>         i2c-parent = <&i2c1>;
>
>         mux-controls = <&mux 1>;
>
>         ...
> };
>
> i2c-mux-bar {
>         compatible = "i2c-mux-gpio";
>         i2c-parent = <&i2c1>;
>
>         mux-controls = <&mux 2>;
>
>         ...
> };
>
> There must be some disconnect, because those "i2c-mux-gpio" compatible
> strings are just dead wrong. There simply are no gpio pins involved at
> all and that "gpio" suffix is just totally out of place.

Indeed. In the above case, that makes no sense.

> So, since you are not happy with "i2c-mux-simple", "i2c-mux-generic" or
> "i2c-mux" that I have suggested, can you please come up with something
> that is good enough for the above?

Let's go with just "i2c-mux". I've got nothing better and simple or
generic doesn't add anything.

Rob

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

* Re: [PATCH v8 07/12] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
@ 2017-02-06 21:22                 ` Rob Herring
  0 siblings, 0 replies; 54+ messages in thread
From: Rob Herring @ 2017-02-06 21:22 UTC (permalink / raw)
  To: Peter Rosin
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, Wolfram Sang, Mark Rutland,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, Andrew Morton,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

On Fri, Feb 3, 2017 at 2:25 AM, Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org> wrote:
> On 2017-02-02 17:08, Rob Herring wrote:
>> On Tue, Jan 31, 2017 at 1:36 AM, Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org> wrote:
>>> If you see this new driver as something that is superseding the existing
>>> i2c-mux-gpio driver, I'm sad to inform you that the code is not simply
>>> not there. i2c-mux-gpio has acpi support and users may provide platform
>>> data from code. The existing i2c-mux-gpio driver also has the below
>>> mentioned locking heuristic. Adding all those things to the new driver
>>> would make it big and unwieldy and having even more unwanted tentacles
>>> into other subsystems. And why should it be only i2c-mux-gpio that is
>>> merged into this new i2c-mux driver? Why not implement a mux-pinctrl
>>> driver for the new mux subsustem and then merge i2c-mux-pinctrl as well?
>>> I say no, that way lies madness.
>>
>> Sounds like a good idea to me. I'm not saying you need to merge any of
>> them right now though (that's Wolfram's call).
>
> If we're pedantic I probably have some stake in it too, being the i2c-mux
> maintainer and all. But, agreed, I arrived quite late to the Linux kernel
> party and my opinion might perhaps not carry all that much weight...
>
>> None of this has anything to do with the binding though. Compatible
>> strings should be specific. That's not up for debate. Whether the
>
> Ok, I'm going to focus on the compatible string for a minute and leave
> the implementation details for some other discussion.
>
>> driver bound to a compatible string is common or specific to that
>> compatible string is completely up to the OS. That decision can change
>> over time, but the binding should not.
>
> So, there's the existing compatible "i2c-mux-gpio" ("i2c-gpio-mux" is
> wrong) that you seem to suggest is what I should stick to. I object to
> that.
>
> As you say, the bindings and compatible strings should describe hardware,
> and you also state they should be specific. I agree. But, why are you
> then apparently suggesting (by implication) that for this (hypothetical)
> hardware...
>
>     .----.
>     |SDA0|-----------.
>     |SCL0|---------. |
>     |    |         | |
>     |    |      .-------.
>     |    |      |adg792a|
>     |    |      |       |
>     |ADC0|------|D1  S1A|---- signal A
>     |    |      |    S1B|---- signal B
>     |    |      |    S1C|---- signal C
>     |    |      |    S1D|---- signal D
>     |    |      |       |
>     |SDA1|---+--|D2  S2A|---- i2s segment foo A
>     |SCL1|-. |  |    S2B|---- i2s segment foo B
>     '----' | |  |    S2C|---- i2s segment foo C
>            | |  |    S2D|---- i2s segment foo D
>            | |  |       |
>            | '--|D3  S3A|---- i2s segment bar A
>            |    |    S3B|---- i2s segment bar B
>            |    |    S3C|---- i2s segment bar C
>            |    |    S3D|---- i2s segment bar D
>            |    '-------'
>            |                  A B C D   A B C D  (feed SCL1 to each of
>            |                  | | | |   | | | |   the 8 muxed segments)
>            '------------------+-+-+-+---+-+-+-'
>
> ...the devicetree should be like below?
>
> &i2c0 {
>         mux: mux-controller@50 {
>                 compatible = "adi,adg792a";
>                 reg = <0x50>;
>                 #mux-control-cells = <1>;
>         };
> };
>
> adc-mux {
>         compatible = "io-channel-mux";
>         io-channels = <&adc 0>;
>         io-channel-names = "parent";
>
>         mux-controls = <&mux 0>;
>
>         ...
> };
>
> i2c-mux-foo {
>         compatible = "i2c-mux-gpio";
>         i2c-parent = <&i2c1>;
>
>         mux-controls = <&mux 1>;
>
>         ...
> };
>
> i2c-mux-bar {
>         compatible = "i2c-mux-gpio";
>         i2c-parent = <&i2c1>;
>
>         mux-controls = <&mux 2>;
>
>         ...
> };
>
> There must be some disconnect, because those "i2c-mux-gpio" compatible
> strings are just dead wrong. There simply are no gpio pins involved at
> all and that "gpio" suffix is just totally out of place.

Indeed. In the above case, that makes no sense.

> So, since you are not happy with "i2c-mux-simple", "i2c-mux-generic" or
> "i2c-mux" that I have suggested, can you please come up with something
> that is good enough for the above?

Let's go with just "i2c-mux". I've got nothing better and simple or
generic doesn't add anything.

Rob

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

end of thread, other threads:[~2017-02-06 21:22 UTC | newest]

Thread overview: 54+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-18 15:57 [PATCH v8 00/12] mux controller abstraction and iio/i2c muxes Peter Rosin
2017-01-18 15:57 ` Peter Rosin
2017-01-18 15:57 ` [PATCH v8 01/12] devres: trivial whitespace fix Peter Rosin
2017-01-18 15:57   ` Peter Rosin
2017-01-18 15:57 ` [PATCH v8 02/12] dt-bindings: document devicetree bindings for mux-controllers and mux-gpio Peter Rosin
2017-01-18 15:57   ` Peter Rosin
2017-01-27 17:49   ` Rob Herring
2017-01-27 17:49     ` Rob Herring
2017-01-27 18:57     ` Peter Rosin
2017-01-27 18:57       ` Peter Rosin
2017-01-18 15:57 ` [PATCH v8 03/12] mux: minimal mux subsystem and gpio-based mux controller Peter Rosin
2017-01-18 15:57   ` Peter Rosin
2017-01-18 15:57 ` [PATCH v8 04/12] iio: inkern: api for manipulating ext_info of iio channels Peter Rosin
2017-01-18 15:57   ` Peter Rosin
2017-01-18 15:57 ` [PATCH v8 05/12] dt-bindings: iio: io-channel-mux: document io-channel-mux bindings Peter Rosin
2017-01-18 15:57   ` Peter Rosin
2017-01-27 19:12   ` Rob Herring
2017-01-18 15:57 ` [PATCH v8 06/12] iio: multiplexer: new iio category and iio-mux driver Peter Rosin
2017-01-18 15:57   ` Peter Rosin
2017-01-18 15:57 ` [PATCH v8 07/12] dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings Peter Rosin
2017-01-18 15:57   ` Peter Rosin
2017-01-27 19:39   ` Rob Herring
2017-01-28 22:42     ` Peter Rosin
2017-01-28 22:42       ` Peter Rosin
2017-01-30 17:20       ` Rob Herring
2017-01-30 17:20         ` Rob Herring
2017-01-31  7:36         ` Peter Rosin
2017-01-31  7:36           ` Peter Rosin
2017-02-02 16:08           ` Rob Herring
2017-02-03  8:25             ` Peter Rosin
2017-02-06 21:22               ` Rob Herring
2017-02-06 21:22                 ` Rob Herring
2017-01-18 15:57 ` [PATCH v8 08/12] i2c: i2c-mux-simple: new driver Peter Rosin
2017-01-18 15:57   ` Peter Rosin
2017-01-18 15:57 ` [PATCH v8 09/12] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux Peter Rosin
2017-01-18 15:57   ` Peter Rosin
2017-01-27 19:50   ` Rob Herring
2017-01-27 22:09     ` Peter Rosin
2017-01-27 22:09       ` Peter Rosin
2017-01-28 10:34       ` Peter Meerwald-Stadler
2017-01-28 10:34         ` Peter Meerwald-Stadler
2017-01-28 11:40       ` Jonathan Cameron
2017-01-18 15:57 ` [PATCH v8 10/12] mux: adg792a: add mux controller driver for ADG792A/G Peter Rosin
2017-01-18 15:57   ` Peter Rosin
2017-01-18 15:57 ` [PATCH v8 11/12] dt-bindings: simplified bindings for single-user gpio mux Peter Rosin
2017-01-18 15:57   ` Peter Rosin
2017-01-18 15:57 ` [PATCH v8 12/12] mux: support " Peter Rosin
2017-01-18 15:57   ` Peter Rosin
2017-01-22 13:30   ` Jonathan Cameron
2017-01-22 13:30     ` Jonathan Cameron
2017-01-23 10:24     ` Peter Rosin
2017-01-27 15:52       ` Rob Herring
2017-01-30  8:02         ` Peter Rosin
2017-01-30  8:02           ` Peter Rosin

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.