Linux-Hwmon Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH v3 00/16] Add support for Kontron sl28cpld
@ 2020-04-23 17:45 Michael Walle
  2020-04-23 17:45 ` [PATCH v3 01/16] include/linux/ioport.h: add helper to define REG resource constructs Michael Walle
                   ` (15 more replies)
  0 siblings, 16 replies; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle

The Kontron sl28cpld is a board management chip providing gpio, pwm, fan
monitoring and an interrupt controller. For now this controller is used on
the Kontron SMARC-sAL28 board. But because of its flexible nature, it
might also be used on other boards in the future. The individual blocks
(like gpio, pwm, etc) are kept intentionally small. The MFD core driver
then instantiates different (or multiple of the same) blocks. It also
provides the register layout so it might be updated in the future without a
device tree change; and support other boards with a different layout or
functionalities.

See also [1] for more information.

This is my first take of a MFD driver. I don't know whether the subsystem
maintainers should only be CCed on the patches which affect the subsystem
or on all patches for this series. I've chosen the latter so you can get a
more complete picture.

[1] https://lore.kernel.org/linux-devicetree/0e3e8204ab992d75aa07fc36af7e4ab2@walle.cc/

Changes since v2:
As suggested by Guenter Roeck:
 - added sl28cpld.rst to index.rst
 - removed sl28cpld_wdt_status()
 - reverse christmas tree local variable ordering
 - assign device_property_read_bool() retval directly
 - introduce WDT_DEFAULT_TIMEOUT and use it if the hardware reports
   0 as timeout.
 - set WDOG_HW_RUNNING if applicable
 - remove platform_set_drvdata() leftover

As suggested by Bartosz Golaszewski:
 - don't export gpio_regmap_simple_xlate()
 - combine local variable declaration of the same type
 - drop the "struct gpio_regmap_addr", instead use -1 to force an address
   offset of zero
 - fix typo
 - use "struct gpio_regmap_config" pattern, keep "struct gpio_regmap"
   private. this also means we need a getter/setter for the driver_data
   element.

As suggested by Linus Walleij:
 - don't store irq_domain in gpio-regmap. drop to_irq() altogether for now.
   Instead there is now a new patch which lets us set the irqdomain of the
   gpiochip_irqchip and use its .to_irq() function. This way we don't have
   to expose the gpio_chip inside the gpio-regmap to the user.

Changes since v1:
 - use of_match_table in all drivers, needed for automatic module loading,
   when using OF_MFD_CELL()
 - add new gpio-regmap.c which adds a generic regmap gpio_chip
   implementation
 - new patch for reqmap_irq, so we can reuse its implementation
 - remove almost any code from gpio-sl28cpld.c, instead use gpio-regmap and
   regmap-irq
 - change the handling of the mfd core vs device tree nodes; add a new
   property "of_reg" to the mfd_cell struct which, when set, is matched to
   the unit-address of the device tree nodes.
 - fix sl28cpld watchdog when it is not initialized by the bootloader.
   Explicitly set the operation mode.
 - also add support for kontron,assert-wdt-timeout-pin in sl28cpld-wdt.

As suggested by Bartosz Golaszewski:
 - define registers as hex
 - make gpio enum uppercase
 - move parent regmap check before memory allocation
 - use device_property_read_bool() instead of the of_ version
 - mention the gpio flavors in the bindings documentation

As suggested by Guenter Roeck:
 - cleanup #includes and sort them
 - use devm_watchdog_register_device()
 - use watchdog_stop_on_reboot()
 - provide a Documentation/hwmon/sl28cpld.rst
 - cleaned up the weird tristate->bool and I2C=y issue. Instead mention
   that the MFD driver is bool because of the following intc patch
 - removed the SL28CPLD_IRQ typo

As suggested by Rob Herring:
 - combine all dt bindings docs into one patch
 - change the node name for all gpio flavors to "gpio"
 - removed the interrupts-extended rule
 - cleaned up the unit-address space, see above

Michael Walle (16):
  include/linux/ioport.h: add helper to define REG resource constructs
  mfd: mfd-core: Don't overwrite the dma_mask of the child device
  mfd: mfd-core: match device tree node against reg property
  dt-bindings: mfd: Add bindings for sl28cpld
  mfd: Add support for Kontron sl28cpld management controller
  irqchip: add sl28cpld interrupt controller support
  watchdog: add support for sl28cpld watchdog
  pwm: add support for sl28cpld PWM controller
  gpiolib: Introduce gpiochip_irqchip_add_domain()
  gpio: add a reusable generic gpio_chip using regmap
  gpio: add support for the sl28cpld GPIO controller
  hwmon: add support for the sl28cpld hardware monitoring controller
  arm64: dts: freescale: sl28: enable sl28cpld
  arm64: dts: freescale: sl28: map GPIOs to input events
  arm64: dts: freescale: sl28: enable LED support
  arm64: dts: freescale: sl28: enable fan support

 .../bindings/gpio/kontron,sl28cpld-gpio.yaml  |  51 +++
 .../hwmon/kontron,sl28cpld-hwmon.yaml         |  27 ++
 .../bindings/mfd/kontron,sl28cpld.yaml        | 162 ++++++++
 .../bindings/pwm/kontron,sl28cpld-pwm.yaml    |  35 ++
 .../watchdog/kontron,sl28cpld-wdt.yaml        |  35 ++
 Documentation/hwmon/index.rst                 |   1 +
 Documentation/hwmon/sl28cpld.rst              |  36 ++
 .../fsl-ls1028a-kontron-kbox-a-230-ls.dts     |  14 +
 .../fsl-ls1028a-kontron-sl28-var3-ads2.dts    |   9 +
 .../freescale/fsl-ls1028a-kontron-sl28.dts    | 124 +++++++
 drivers/gpio/Kconfig                          |  15 +
 drivers/gpio/Makefile                         |   2 +
 drivers/gpio/gpio-regmap.c                    | 348 ++++++++++++++++++
 drivers/gpio/gpio-sl28cpld.c                  | 184 +++++++++
 drivers/gpio/gpiolib.c                        |  20 +
 drivers/hwmon/Kconfig                         |  10 +
 drivers/hwmon/Makefile                        |   1 +
 drivers/hwmon/sl28cpld-hwmon.c                | 151 ++++++++
 drivers/irqchip/Kconfig                       |   3 +
 drivers/irqchip/Makefile                      |   1 +
 drivers/irqchip/irq-sl28cpld.c                |  97 +++++
 drivers/mfd/Kconfig                           |  21 ++
 drivers/mfd/Makefile                          |   2 +
 drivers/mfd/mfd-core.c                        |  31 +-
 drivers/mfd/sl28cpld.c                        | 153 ++++++++
 drivers/pwm/Kconfig                           |  10 +
 drivers/pwm/Makefile                          |   1 +
 drivers/pwm/pwm-sl28cpld.c                    | 203 ++++++++++
 drivers/watchdog/Kconfig                      |  11 +
 drivers/watchdog/Makefile                     |   1 +
 drivers/watchdog/sl28cpld_wdt.c               | 233 ++++++++++++
 include/linux/gpio-regmap.h                   |  69 ++++
 include/linux/gpio/driver.h                   |   3 +
 include/linux/ioport.h                        |   5 +
 include/linux/mfd/core.h                      |  26 +-
 35 files changed, 2079 insertions(+), 16 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/gpio/kontron,sl28cpld-gpio.yaml
 create mode 100644 Documentation/devicetree/bindings/hwmon/kontron,sl28cpld-hwmon.yaml
 create mode 100644 Documentation/devicetree/bindings/mfd/kontron,sl28cpld.yaml
 create mode 100644 Documentation/devicetree/bindings/pwm/kontron,sl28cpld-pwm.yaml
 create mode 100644 Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml
 create mode 100644 Documentation/hwmon/sl28cpld.rst
 create mode 100644 drivers/gpio/gpio-regmap.c
 create mode 100644 drivers/gpio/gpio-sl28cpld.c
 create mode 100644 drivers/hwmon/sl28cpld-hwmon.c
 create mode 100644 drivers/irqchip/irq-sl28cpld.c
 create mode 100644 drivers/mfd/sl28cpld.c
 create mode 100644 drivers/pwm/pwm-sl28cpld.c
 create mode 100644 drivers/watchdog/sl28cpld_wdt.c
 create mode 100644 include/linux/gpio-regmap.h

-- 
2.20.1


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

* [PATCH v3 01/16] include/linux/ioport.h: add helper to define REG resource constructs
  2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
@ 2020-04-23 17:45 ` Michael Walle
  2020-04-23 17:45 ` [PATCH v3 02/16] mfd: mfd-core: Don't overwrite the dma_mask of the child device Michael Walle
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle

Similar to the existing helpers, add one for IORESOURCE_REG which comes
in handy for most common resource declarations.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 include/linux/ioport.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index a9b9170b5dd2..cdcceeec0f86 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -165,6 +165,11 @@ enum {
 #define DEFINE_RES_MEM(_start, _size)					\
 	DEFINE_RES_MEM_NAMED((_start), (_size), NULL)
 
+#define DEFINE_RES_REG_NAMED(_start, _size, _name)			\
+	DEFINE_RES_NAMED((_start), (_size), (_name), IORESOURCE_REG)
+#define DEFINE_RES_REG(_start, _size)					\
+	DEFINE_RES_REG_NAMED((_start), (_size), NULL)
+
 #define DEFINE_RES_IRQ_NAMED(_irq, _name)				\
 	DEFINE_RES_NAMED((_irq), 1, (_name), IORESOURCE_IRQ)
 #define DEFINE_RES_IRQ(_irq)						\
-- 
2.20.1


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

* [PATCH v3 02/16] mfd: mfd-core: Don't overwrite the dma_mask of the child device
  2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
  2020-04-23 17:45 ` [PATCH v3 01/16] include/linux/ioport.h: add helper to define REG resource constructs Michael Walle
@ 2020-04-23 17:45 ` Michael Walle
  2020-04-28 12:45   ` Andy Shevchenko
  2020-04-23 17:45 ` [PATCH v3 03/16] mfd: mfd-core: match device tree node against reg property Michael Walle
                   ` (13 subsequent siblings)
  15 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle, Robin Murphy

Commit cdfee5623290 ("driver core: initialize a default DMA mask for
platform device") initialize the DMA of a platform device. But if the
parent doesn't have a dma_mask set, for example if it's an I2C device,
the dma_mask of the child platform device will be set to zero again.
Which leads to many "DMA mask not set" warnings, if the MFD cell has the
of_compatible property set.

[    1.877937] sl28cpld-pwm sl28cpld-pwm: DMA mask not set
[    1.883282] sl28cpld-pwm sl28cpld-pwm.0: DMA mask not set
[    1.888795] sl28cpld-gpio sl28cpld-gpio: DMA mask not set

Thus don't overwrite the dma_mask of the children. Instead set the
dma_mask of the platform device.

Signed-off-by: Michael Walle <michael@walle.cc>
Suggested-by: Robin Murphy <robin.murphy@arm.com>
---
 drivers/mfd/mfd-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index f5a73af60dd4..e735565969b3 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -138,7 +138,7 @@ static int mfd_add_device(struct device *parent, int id,
 
 	pdev->dev.parent = parent;
 	pdev->dev.type = &mfd_dev_type;
-	pdev->dev.dma_mask = parent->dma_mask;
+	pdev->platform_dma_mask = parent->dma_mask ? *parent->dma_mask : 0;
 	pdev->dev.dma_parms = parent->dma_parms;
 	pdev->dev.coherent_dma_mask = parent->coherent_dma_mask;
 
-- 
2.20.1


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

* [PATCH v3 03/16] mfd: mfd-core: match device tree node against reg property
  2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
  2020-04-23 17:45 ` [PATCH v3 01/16] include/linux/ioport.h: add helper to define REG resource constructs Michael Walle
  2020-04-23 17:45 ` [PATCH v3 02/16] mfd: mfd-core: Don't overwrite the dma_mask of the child device Michael Walle
@ 2020-04-23 17:45 ` Michael Walle
  2020-04-29 22:18   ` Michael Walle
  2020-04-23 17:45 ` [PATCH v3 04/16] dt-bindings: mfd: Add bindings for sl28cpld Michael Walle
                   ` (12 subsequent siblings)
  15 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle

There might be multiple children with the device tree compatible, for
example if a MFD has multiple instances of the same function. In this
case only the first is matched and the other children get a wrong
of_node reference.
Add a new option to match also against the unit address of the child
node. Additonally, a new helper OF_MFD_CELL_REG is added.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 drivers/mfd/mfd-core.c   | 29 ++++++++++++++++++++---------
 include/linux/mfd/core.h | 26 ++++++++++++++++++++------
 2 files changed, 40 insertions(+), 15 deletions(-)

diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index e735565969b3..4ecb376338f7 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -117,6 +117,7 @@ static int mfd_add_device(struct device *parent, int id,
 	struct device_node *np = NULL;
 	int ret = -ENOMEM;
 	int platform_id;
+	u32 of_reg;
 	int r;
 
 	if (id == PLATFORM_DEVID_AUTO)
@@ -151,16 +152,26 @@ static int mfd_add_device(struct device *parent, int id,
 
 	if (parent->of_node && cell->of_compatible) {
 		for_each_child_of_node(parent->of_node, np) {
-			if (of_device_is_compatible(np, cell->of_compatible)) {
-				if (!of_device_is_available(np)) {
-					/* Ignore disabled devices error free */
-					ret = 0;
-					goto fail_alias;
-				}
-				pdev->dev.of_node = np;
-				pdev->dev.fwnode = &np->fwnode;
-				break;
+			if (!of_device_is_compatible(np, cell->of_compatible))
+				continue;
+
+			/* also match the unit address if set */
+			if (cell->of_reg & MFD_OF_REG_VALID) {
+				if (of_property_read_u32(np, "reg", &of_reg))
+					continue;
+				if ((cell->of_reg & MFD_OF_REG_MASK) != of_reg)
+					continue;
 			}
+
+			if (!of_device_is_available(np)) {
+				/* Ignore disabled devices error free */
+				ret = 0;
+				goto fail_alias;
+			}
+
+			pdev->dev.of_node = np;
+			pdev->dev.fwnode = &np->fwnode;
+			break;
 		}
 	}
 
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
index d01d1299e49d..c2c0ad6b14f3 100644
--- a/include/linux/mfd/core.h
+++ b/include/linux/mfd/core.h
@@ -13,8 +13,11 @@
 #include <linux/platform_device.h>
 
 #define MFD_RES_SIZE(arr) (sizeof(arr) / sizeof(struct resource))
+#define MFD_OF_REG_VALID	BIT(31)
+#define MFD_OF_REG_MASK		GENMASK(30, 0)
 
-#define MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, _match)\
+#define MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat,	\
+		     _of_reg, _match)					\
 	{								\
 		.name = (_name),					\
 		.resources = (_res),					\
@@ -22,24 +25,32 @@
 		.platform_data = (_pdata),				\
 		.pdata_size = (_pdsize),				\
 		.of_compatible = (_compat),				\
+		.of_reg = (_of_reg),					\
 		.acpi_match = (_match),					\
 		.id = (_id),						\
 	}
 
+#define OF_MFD_CELL_REG(_name, _res, _pdata, _pdsize, _id, _compat,	\
+			_of_reg)					\
+	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat,	\
+		     ((_of_reg) | MFD_OF_REG_VALID), NULL)		\
+
 #define OF_MFD_CELL(_name, _res, _pdata, _pdsize,_id, _compat)		\
-	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, NULL)	\
+	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat,	\
+		     0, NULL)						\
 
 #define ACPI_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _match)	\
-	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, _match)	\
+	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, 0,	\
+		     _match)						\
 
 #define MFD_CELL_BASIC(_name, _res, _pdata, _pdsize, _id)		\
-	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, NULL)	\
+	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, 0, NULL) \
 
 #define MFD_CELL_RES(_name, _res)					\
-	MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, NULL)		\
+	MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, 0, NULL)		\
 
 #define MFD_CELL_NAME(_name)						\
-	MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, NULL)		\
+	MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, 0, NULL)		\
 
 struct irq_domain;
 struct property_entry;
@@ -78,6 +89,9 @@ struct mfd_cell {
 	 */
 	const char		*of_compatible;
 
+	/* matching the reg property if set */
+	unsigned int		of_reg;
+
 	/* Matches ACPI */
 	const struct mfd_cell_acpi_match	*acpi_match;
 
-- 
2.20.1


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

* [PATCH v3 04/16] dt-bindings: mfd: Add bindings for sl28cpld
  2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
                   ` (2 preceding siblings ...)
  2020-04-23 17:45 ` [PATCH v3 03/16] mfd: mfd-core: match device tree node against reg property Michael Walle
@ 2020-04-23 17:45 ` Michael Walle
  2020-04-28 12:48   ` Andy Shevchenko
  2020-04-23 17:45 ` [PATCH v3 05/16] mfd: Add support for Kontron sl28cpld management controller Michael Walle
                   ` (11 subsequent siblings)
  15 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle

This adds device tree bindings for the board management controller found
on the Kontron SMARC-sAL28 board.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 .../bindings/gpio/kontron,sl28cpld-gpio.yaml  |  51 ++++++
 .../hwmon/kontron,sl28cpld-hwmon.yaml         |  27 +++
 .../bindings/mfd/kontron,sl28cpld.yaml        | 162 ++++++++++++++++++
 .../bindings/pwm/kontron,sl28cpld-pwm.yaml    |  35 ++++
 .../watchdog/kontron,sl28cpld-wdt.yaml        |  35 ++++
 5 files changed, 310 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/kontron,sl28cpld-gpio.yaml
 create mode 100644 Documentation/devicetree/bindings/hwmon/kontron,sl28cpld-hwmon.yaml
 create mode 100644 Documentation/devicetree/bindings/mfd/kontron,sl28cpld.yaml
 create mode 100644 Documentation/devicetree/bindings/pwm/kontron,sl28cpld-pwm.yaml
 create mode 100644 Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml

diff --git a/Documentation/devicetree/bindings/gpio/kontron,sl28cpld-gpio.yaml b/Documentation/devicetree/bindings/gpio/kontron,sl28cpld-gpio.yaml
new file mode 100644
index 000000000000..291ca116743d
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/kontron,sl28cpld-gpio.yaml
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/kontron,sl28cpld-gpio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: GPIO driver for the sl28cpld board management controller
+
+maintainers:
+  - Michael Walle <michael@walle.cc>
+
+description: |
+  This module is part of the sl28cpld multi-function device. For more
+  details see Documentation/devicetree/bindings/mfd/kontron,sl28cpld.yaml.
+
+  There are three flavors of the GPIO controller, one full featured
+  input/output with interrupt support (kontron,sl28cpld-gpio), one
+  output-only (kontron,sl28-gpo) and one input-only (kontron,sl28-gpi).
+
+  Each controller supports 8 GPIO lines.
+
+properties:
+  compatible:
+    enum:
+      - kontron,sl28cpld-gpio
+      - kontron,sl28cpld-gpi
+      - kontron,sl28cpld-gpo
+
+  reg:
+    maxItems: 1
+
+  "#interrupt-cells":
+    const: 2
+
+  interrupt-controller: true
+
+  "#gpio-cells":
+    const: 2
+
+  gpio-controller: true
+
+  gpio-line-names:
+      minItems: 1
+      maxItems: 8
+
+required:
+  - compatible
+  - "#gpio-cells"
+  - gpio-controller
+
+additionalProperties: false
diff --git a/Documentation/devicetree/bindings/hwmon/kontron,sl28cpld-hwmon.yaml b/Documentation/devicetree/bindings/hwmon/kontron,sl28cpld-hwmon.yaml
new file mode 100644
index 000000000000..1cebd61c6c32
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/kontron,sl28cpld-hwmon.yaml
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/hwmon/kontron,sl28cpld-hwmon.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Hardware monitoring driver for the sl28cpld board management controller
+
+maintainers:
+  - Michael Walle <michael@walle.cc>
+
+description: |
+  This module is part of the sl28cpld multi-function device. For more
+  details see Documentation/devicetree/bindings/mfd/kontron,sl28cpld.yaml.
+
+properties:
+  compatible:
+    enum:
+      - kontron,sl28cpld-fan
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+
+additionalProperties: false
diff --git a/Documentation/devicetree/bindings/mfd/kontron,sl28cpld.yaml b/Documentation/devicetree/bindings/mfd/kontron,sl28cpld.yaml
new file mode 100644
index 000000000000..e155e3035513
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/kontron,sl28cpld.yaml
@@ -0,0 +1,162 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/kontron,sl28cpld.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Kontron's sl28cpld board management controller
+
+maintainers:
+  - Michael Walle <michael@walle.cc>
+
+description: |
+  The board management controller may contain different IP blocks like
+  watchdog, fan monitoring, PWM controller, interrupt controller and a
+  GPIO controller.
+
+  Currently the MFD exports the following functions at the given
+  unit-addresses.
+
+  === =========== =======================
+   ua name        compatible
+  === =========== =======================
+   0  watchdog    kontron,sl28cpld-wdt
+   1  hwmon       kontron,sl28cpld-fan
+   2  pwm         kontron,sl28cpld-pwm
+   3  pwm         kontron,sl28cpld-pwm
+   4  gpio        kontron,sl28cpld-gpio
+   5  gpio        kontron,sl28cpld-gpio
+   6  gpio        kontron,sl28cpld-gpo
+   7  gpio        kontron,sl28cpld-gpi
+  === =========== =======================
+
+  The MFD driver will match the child nodes according to the unit-address
+  (eg. the reg property) and the compatible string.
+
+properties:
+  compatible:
+    const: kontron,sl28cpld
+
+  reg:
+    description:
+      I2C device address.
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  "#interrupt-cells":
+    const: 2
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+patternProperties:
+  "^gpio(@[0-9]+)?$":
+    $ref: ../gpio/kontron,sl28cpld-gpio.yaml
+
+  "^hwmon(@[0-9]+)?$":
+    $ref: ../hwmon/kontron,sl28cpld-hwmon.yaml
+
+  "^pwm(@[0-9]+)?$":
+    $ref: ../pwm/kontron,sl28cpld-pwm.yaml
+
+  "^watchdog(@[0-9]+)?$":
+    $ref: ../watchdog/kontron,sl28cpld-wdt.yaml
+
+required:
+  - "#address-cells"
+  - "#size-cells"
+  - compatible
+  - reg
+  - interrupts
+  - "#interrupt-cells"
+  - interrupt-controller
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        sl28cpld@4a {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            compatible = "kontron,sl28cpld";
+            reg = <0x4a>;
+            interrupts-extended = <&gpio2 6 IRQ_TYPE_EDGE_FALLING>;
+
+            #interrupt-cells = <2>;
+            interrupt-controller;
+
+            watchdog@0 {
+                compatible = "kontron,sl28cpld-wdt";
+                reg = <0>;
+                kontron,assert-wdt-timeout-pin;
+            };
+
+            hwmon@1 {
+                compatible = "kontron,sl28cpld-fan";
+                reg = <1>;
+            };
+
+            pwm@2 {
+                compatible = "kontron,sl28cpld-pwm";
+                reg = <2>;
+                #pwm-cells = <2>;
+            };
+
+            pwm@3 {
+                compatible = "kontron,sl28cpld-pwm";
+                reg = <3>;
+                #pwm-cells = <2>;
+            };
+
+            gpio@4 {
+                compatible = "kontron,sl28cpld-gpio";
+                reg = <4>;
+
+                gpio-controller;
+                #gpio-cells = <2>;
+
+                interrupt-controller;
+                #interrupt-cells = <2>;
+            };
+
+            gpio@5 {
+                compatible = "kontron,sl28cpld-gpio";
+                reg = <5>;
+
+                gpio-controller;
+                #gpio-cells = <2>;
+
+                interrupt-controller;
+                #interrupt-cells = <2>;
+            };
+
+            gpio@6 {
+                compatible = "kontron,sl28cpld-gpo";
+                reg = <6>;
+
+                gpio-controller;
+                #gpio-cells = <2>;
+                gpio-line-names = "a", "b", "c";
+            };
+
+            gpio@7 {
+                compatible = "kontron,sl28cpld-gpi";
+                reg = <7>;
+
+                gpio-controller;
+                #gpio-cells = <2>;
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/pwm/kontron,sl28cpld-pwm.yaml b/Documentation/devicetree/bindings/pwm/kontron,sl28cpld-pwm.yaml
new file mode 100644
index 000000000000..02fe88c30233
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/kontron,sl28cpld-pwm.yaml
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/kontron,sl28cpld-pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: PWM driver for the sl28cpld board management controller
+
+maintainers:
+  - Michael Walle <michael@walle.cc>
+
+description: |
+  This module is part of the sl28cpld multi-function device. For more
+  details see Documentation/devicetree/bindings/mfd/kontron,sl28cpld.yaml.
+
+  The controller supports one PWM channel and supports only four distinct
+  frequencies (250Hz, 500Hz, 1kHz, 2kHz).
+
+allOf:
+  - $ref: pwm.yaml#
+
+properties:
+  compatible:
+    const: kontron,sl28cpld-pwm
+
+  reg:
+    maxItems: 1
+
+  "#pwm-cells":
+    const: 2
+
+required:
+  - compatible
+
+additionalProperties: false
diff --git a/Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml b/Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml
new file mode 100644
index 000000000000..dd6559f2973a
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/watchdog/kontron,sl28cpld-wdt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Watchdog driver for the sl28cpld board management controller
+
+maintainers:
+  - Michael Walle <michael@walle.cc>
+
+description: |
+  This module is part of the sl28cpld multi-function device. For more
+  details see Documentation/devicetree/bindings/mfd/kontron,sl28cpld.yaml.
+
+allOf:
+  - $ref: watchdog.yaml#
+
+properties:
+  compatible:
+    const: kontron,sl28cpld-wdt
+
+  reg:
+    maxItems: 1
+
+  kontron,assert-wdt-timeout-pin:
+    description: The SMARC standard defines a WDT_TIME_OUT# pin. If this
+      property is set, this output will be pulsed when the watchdog bites
+      and the system resets.
+    type: boolean
+
+required:
+  - compatible
+
+additionalProperties: false
-- 
2.20.1


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

* [PATCH v3 05/16] mfd: Add support for Kontron sl28cpld management controller
  2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
                   ` (3 preceding siblings ...)
  2020-04-23 17:45 ` [PATCH v3 04/16] dt-bindings: mfd: Add bindings for sl28cpld Michael Walle
@ 2020-04-23 17:45 ` Michael Walle
  2020-04-28 12:50   ` Andy Shevchenko
  2020-05-11 21:13   ` Rob Herring
  2020-04-23 17:45 ` [PATCH v3 06/16] irqchip: add sl28cpld interrupt controller support Michael Walle
                   ` (10 subsequent siblings)
  15 siblings, 2 replies; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle

This patch adds core support for the board management controller found
on the SMARC-sAL28 board. It consists of the following functions:
 - watchdog
 - GPIO controller
 - PWM controller
 - fan sensor
 - interrupt controller

At the moment, this controller is used on the Kontron SMARC-sAL28 board.

Please note that the MFD driver is defined as bool in the Kconfig
because the next patch will add interrupt support.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 drivers/mfd/Kconfig    |  19 +++++
 drivers/mfd/Makefile   |   2 +
 drivers/mfd/sl28cpld.c | 153 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 174 insertions(+)
 create mode 100644 drivers/mfd/sl28cpld.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 0a59249198d3..be0c8d93c526 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -2060,5 +2060,24 @@ config SGI_MFD_IOC3
 	  If you have an SGI Origin, Octane, or a PCI IOC3 card,
 	  then say Y. Otherwise say N.
 
+config MFD_SL28CPLD
+	bool "Kontron sl28 core driver"
+	depends on I2C=y
+	depends on OF
+	select REGMAP_I2C
+	select MFD_CORE
+	help
+	  This option enables support for the board management controller
+	  found on the Kontron sl28 CPLD. You have to select individual
+	  functions, such as watchdog, GPIO, etc, under the corresponding menus
+	  in order to enable them.
+
+	  Currently supported boards are:
+
+		Kontron SMARC-sAL28
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called sl28cpld.
+
 endmenu
 endif
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f935d10cbf0f..9bc38863b9c7 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -259,3 +259,5 @@ obj-$(CONFIG_MFD_ROHM_BD718XX)	+= rohm-bd718x7.o
 obj-$(CONFIG_MFD_STMFX) 	+= stmfx.o
 
 obj-$(CONFIG_SGI_MFD_IOC3)	+= ioc3.o
+
+obj-$(CONFIG_MFD_SL28CPLD)	+= sl28cpld.o
diff --git a/drivers/mfd/sl28cpld.c b/drivers/mfd/sl28cpld.c
new file mode 100644
index 000000000000..1e5860cc7ffc
--- /dev/null
+++ b/drivers/mfd/sl28cpld.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MFD core for the sl28cpld.
+ *
+ * Copyright 2019 Kontron Europe GmbH
+ */
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+
+#define SL28CPLD_VERSION	0x03
+#define SL28CPLD_WATCHDOG_BASE	0x04
+#define SL28CPLD_HWMON_FAN_BASE	0x0b
+#define SL28CPLD_PWM0_BASE	0x0c
+#define SL28CPLD_PWM1_BASE	0x0e
+#define SL28CPLD_GPIO0_BASE	0x10
+#define SL28CPLD_GPIO1_BASE	0x15
+#define SL28CPLD_GPO_BASE	0x1a
+#define SL28CPLD_GPI_BASE	0x1b
+#define SL28CPLD_INTC_BASE	0x1c
+
+/* all subdevices share the same IRQ */
+#define SL28CPLD_IRQ 0
+
+#define SL28CPLD_MIN_REQ_VERSION 14
+
+struct sl28cpld {
+	struct device *dev;
+	struct regmap *regmap;
+};
+
+static const struct regmap_config sl28cpld_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.reg_stride = 1,
+};
+
+static struct resource sl28cpld_watchdog_resources[] = {
+	DEFINE_RES_REG(SL28CPLD_WATCHDOG_BASE, 1),
+};
+
+static struct resource sl28cpld_hwmon_fan_resources[] = {
+	DEFINE_RES_REG(SL28CPLD_HWMON_FAN_BASE, 1),
+};
+
+static struct resource sl28cpld_pwm0_resources[] = {
+	DEFINE_RES_REG(SL28CPLD_PWM0_BASE, 1),
+};
+
+static struct resource sl28cpld_pwm1_resources[] = {
+	DEFINE_RES_REG(SL28CPLD_PWM1_BASE, 1),
+};
+
+static struct resource sl28cpld_gpio0_resources[] = {
+	DEFINE_RES_REG(SL28CPLD_GPIO0_BASE, 1),
+	DEFINE_RES_IRQ(SL28CPLD_IRQ),
+};
+
+static struct resource sl28cpld_gpio1_resources[] = {
+	DEFINE_RES_REG(SL28CPLD_GPIO1_BASE, 1),
+	DEFINE_RES_IRQ(SL28CPLD_IRQ),
+};
+
+static struct resource sl28cpld_gpo_resources[] = {
+	DEFINE_RES_REG(SL28CPLD_GPO_BASE, 1),
+};
+
+static struct resource sl28cpld_gpi_resources[] = {
+	DEFINE_RES_REG(SL28CPLD_GPI_BASE, 1),
+};
+
+static struct resource sl28cpld_intc_resources[] = {
+	DEFINE_RES_REG(SL28CPLD_INTC_BASE, 1),
+	DEFINE_RES_IRQ(SL28CPLD_IRQ),
+};
+
+static const struct mfd_cell sl28cpld_devs[] = {
+	OF_MFD_CELL_REG("sl28cpld-wdt", sl28cpld_watchdog_resources,
+			NULL, 0, 0, "kontron,sl28cpld-wdt", 0),
+	OF_MFD_CELL_REG("sl28cpld-fan", sl28cpld_hwmon_fan_resources,
+			NULL, 0, 0, "kontron,sl28cpld-fan", 1),
+	OF_MFD_CELL_REG("sl28cpld-pwm", sl28cpld_pwm0_resources,
+			NULL, 0, 0, "kontron,sl28cpld-pwm", 2),
+	OF_MFD_CELL_REG("sl28cpld-pwm", sl28cpld_pwm1_resources,
+			NULL, 0, 1, "kontron,sl28cpld-pwm", 3),
+	OF_MFD_CELL_REG("sl28cpld-gpio", sl28cpld_gpio0_resources,
+			NULL, 0, 0, "kontron,sl28cpld-gpio", 4),
+	OF_MFD_CELL_REG("sl28cpld-gpio", sl28cpld_gpio1_resources,
+			NULL, 0, 1, "kontron,sl28cpld-gpio", 5),
+	OF_MFD_CELL_REG("sl28cpld-gpo", sl28cpld_gpo_resources,
+			NULL, 0, 0, "kontron,sl28cpld-gpo", 6),
+	OF_MFD_CELL_REG("sl28cpld-gpi", sl28cpld_gpi_resources,
+			NULL, 0, 0, "kontron,sl28cpld-gpi", 7),
+	MFD_CELL_RES("sl28cpld-intc", sl28cpld_intc_resources),
+};
+
+static int sl28cpld_probe(struct i2c_client *i2c)
+{
+	struct sl28cpld *sl28cpld;
+	struct device *dev = &i2c->dev;
+	unsigned int cpld_version;
+	int ret;
+
+	sl28cpld = devm_kzalloc(dev, sizeof(*sl28cpld), GFP_KERNEL);
+	if (!sl28cpld)
+		return -ENOMEM;
+
+	sl28cpld->regmap = devm_regmap_init_i2c(i2c, &sl28cpld_regmap_config);
+	if (IS_ERR(sl28cpld->regmap))
+		return PTR_ERR(sl28cpld->regmap);
+
+	ret = regmap_read(sl28cpld->regmap, SL28CPLD_VERSION, &cpld_version);
+	if (ret)
+		return ret;
+
+	if (cpld_version < SL28CPLD_MIN_REQ_VERSION) {
+		dev_err(dev, "unsupported CPLD version %d\n", cpld_version);
+		return -ENODEV;
+	}
+
+	sl28cpld->dev = dev;
+	i2c_set_clientdata(i2c, sl28cpld);
+
+	dev_info(dev, "successfully probed. CPLD version %d\n", cpld_version);
+
+	return devm_mfd_add_devices(dev, -1, sl28cpld_devs,
+				    ARRAY_SIZE(sl28cpld_devs), NULL,
+				    i2c->irq, NULL);
+}
+
+static const struct of_device_id sl28cpld_of_match[] = {
+	{ .compatible = "kontron,sl28cpld", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, sl28cpld_of_match);
+
+static struct i2c_driver sl28cpld_driver = {
+	.probe_new = sl28cpld_probe,
+	.driver = {
+		.name = "sl28cpld",
+		.of_match_table = of_match_ptr(sl28cpld_of_match),
+	},
+};
+module_i2c_driver(sl28cpld_driver);
+
+MODULE_DESCRIPTION("sl28cpld MFD Core Driver");
+MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
+MODULE_LICENSE("GPL");
-- 
2.20.1


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

* [PATCH v3 06/16] irqchip: add sl28cpld interrupt controller support
  2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
                   ` (4 preceding siblings ...)
  2020-04-23 17:45 ` [PATCH v3 05/16] mfd: Add support for Kontron sl28cpld management controller Michael Walle
@ 2020-04-23 17:45 ` Michael Walle
  2020-04-27 11:40   ` Thomas Gleixner
  2020-04-23 17:45 ` [PATCH v3 07/16] watchdog: add support for sl28cpld watchdog Michael Walle
                   ` (9 subsequent siblings)
  15 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle

This patch adds support for the interrupt controller inside the sl28
CPLD management controller.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 drivers/irqchip/Kconfig        |  3 ++
 drivers/irqchip/Makefile       |  1 +
 drivers/irqchip/irq-sl28cpld.c | 97 ++++++++++++++++++++++++++++++++++
 drivers/mfd/Kconfig            |  2 +
 4 files changed, 103 insertions(+)
 create mode 100644 drivers/irqchip/irq-sl28cpld.c

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index a85aada04a64..234db932e7cf 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -246,6 +246,9 @@ config RENESAS_RZA1_IRQC
 	  Enable support for the Renesas RZ/A1 Interrupt Controller, to use up
 	  to 8 external interrupts with configurable sense select.
 
+config SL28CPLD_INTC
+	bool
+
 config ST_IRQCHIP
 	bool
 	select REGMAP
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 37bbe39bf909..e3c6b94f7b0a 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -107,3 +107,4 @@ obj-$(CONFIG_TI_SCI_INTR_IRQCHIP)	+= irq-ti-sci-intr.o
 obj-$(CONFIG_TI_SCI_INTA_IRQCHIP)	+= irq-ti-sci-inta.o
 obj-$(CONFIG_LOONGSON_LIOINTC)		+= irq-loongson-liointc.o
 obj-$(CONFIG_LOONGSON_HTPIC)		+= irq-loongson-htpic.o
+obj-$(CONFIG_SL28CPLD_INTC)		+= irq-sl28cpld.o
diff --git a/drivers/irqchip/irq-sl28cpld.c b/drivers/irqchip/irq-sl28cpld.c
new file mode 100644
index 000000000000..88de71d32b09
--- /dev/null
+++ b/drivers/irqchip/irq-sl28cpld.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * sl28cpld interrupt controller driver.
+ *
+ * Copyright 2019 Kontron Europe GmbH
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define INTC_IE 0x00
+#define INTC_IP 0x01
+
+static const struct regmap_irq sl28cpld_irqs[] = {
+	REGMAP_IRQ_REG_LINE(0, 8),
+	REGMAP_IRQ_REG_LINE(1, 8),
+	REGMAP_IRQ_REG_LINE(2, 8),
+	REGMAP_IRQ_REG_LINE(3, 8),
+	REGMAP_IRQ_REG_LINE(4, 8),
+	REGMAP_IRQ_REG_LINE(5, 8),
+	REGMAP_IRQ_REG_LINE(6, 8),
+	REGMAP_IRQ_REG_LINE(7, 8),
+};
+
+struct sl28cpld_intc {
+	struct regmap *regmap;
+	struct regmap_irq_chip chip;
+	struct regmap_irq_chip_data *irq_data;
+};
+
+static int sl28cpld_intc_probe(struct platform_device *pdev)
+{
+	struct sl28cpld_intc *irqchip;
+	struct resource *res;
+	unsigned int irq;
+	int ret;
+
+	if (!pdev->dev.parent)
+		return -ENODEV;
+
+	irqchip = devm_kzalloc(&pdev->dev, sizeof(*irqchip), GFP_KERNEL);
+	if (!irqchip)
+		return -ENOMEM;
+
+	irqchip->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!irqchip->regmap)
+		return -ENODEV;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
+	if (!res)
+		return -EINVAL;
+
+	irqchip->chip.name = "sl28cpld-intc";
+	irqchip->chip.irqs = sl28cpld_irqs;
+	irqchip->chip.num_irqs = ARRAY_SIZE(sl28cpld_irqs);
+	irqchip->chip.num_regs = 1;
+	irqchip->chip.status_base = res->start + INTC_IP;
+	irqchip->chip.mask_base = res->start + INTC_IE;
+	irqchip->chip.mask_invert = true,
+	irqchip->chip.ack_base = res->start + INTC_IP;
+
+	ret = devm_regmap_add_irq_chip(&pdev->dev, irqchip->regmap, irq,
+				       IRQF_SHARED | IRQF_ONESHOT, 0,
+				       &irqchip->chip, &irqchip->irq_data);
+	if (ret)
+		return ret;
+	dev_info(&pdev->dev, "registered IRQ %d\n", irq);
+
+	return 0;
+}
+
+static const struct platform_device_id sl28cpld_intc_id_table[] = {
+	{ "sl28cpld-intc" },
+	{}
+};
+MODULE_DEVICE_TABLE(platform, sl28cpld_intc_id_table);
+
+static struct platform_driver sl28cpld_intc_driver = {
+	.probe	= sl28cpld_intc_probe,
+	.id_table = sl28cpld_intc_id_table,
+	.driver = {
+		.name = KBUILD_MODNAME,
+	}
+};
+module_platform_driver(sl28cpld_intc_driver);
+
+MODULE_DESCRIPTION("sl28cpld Interrupt Controller Driver");
+MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index be0c8d93c526..9e848a455172 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -2065,6 +2065,8 @@ config MFD_SL28CPLD
 	depends on I2C=y
 	depends on OF
 	select REGMAP_I2C
+	select REGMAP_IRQ
+	select SL28CPLD_INTC
 	select MFD_CORE
 	help
 	  This option enables support for the board management controller
-- 
2.20.1


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

* [PATCH v3 07/16] watchdog: add support for sl28cpld watchdog
  2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
                   ` (5 preceding siblings ...)
  2020-04-23 17:45 ` [PATCH v3 06/16] irqchip: add sl28cpld interrupt controller support Michael Walle
@ 2020-04-23 17:45 ` Michael Walle
  2020-04-25 17:02   ` Guenter Roeck
  2020-04-23 17:45 ` [PATCH v3 08/16] pwm: add support for sl28cpld PWM controller Michael Walle
                   ` (8 subsequent siblings)
  15 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle

This adds support for the watchdog of the sl28cpld board management
controller. This is part of a multi-function device driver.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 drivers/watchdog/Kconfig        |  11 ++
 drivers/watchdog/Makefile       |   1 +
 drivers/watchdog/sl28cpld_wdt.c | 233 ++++++++++++++++++++++++++++++++
 3 files changed, 245 insertions(+)
 create mode 100644 drivers/watchdog/sl28cpld_wdt.c

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 0663c604bd64..6c53c1d0f348 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -340,6 +340,17 @@ config MLX_WDT
 	  To compile this driver as a module, choose M here: the
 	  module will be called mlx-wdt.
 
+config SL28CPLD_WATCHDOG
+	tristate "Kontron sl28 watchdog"
+	depends on MFD_SL28CPLD
+	select WATCHDOG_CORE
+	help
+	  Say Y here to include support for the watchdog timer
+	  on the Kontron sl28 CPLD.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sl28cpld_wdt.
+
 # ALPHA Architecture
 
 # ARM Architecture
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 6de2e4ceef19..b9ecdf2d7347 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -224,3 +224,4 @@ obj-$(CONFIG_MENF21BMC_WATCHDOG) += menf21bmc_wdt.o
 obj-$(CONFIG_MENZ069_WATCHDOG) += menz69_wdt.o
 obj-$(CONFIG_RAVE_SP_WATCHDOG) += rave-sp-wdt.o
 obj-$(CONFIG_STPMIC1_WATCHDOG) += stpmic1_wdt.o
+obj-$(CONFIG_SL28CPLD_WATCHDOG) += sl28cpld_wdt.o
diff --git a/drivers/watchdog/sl28cpld_wdt.c b/drivers/watchdog/sl28cpld_wdt.c
new file mode 100644
index 000000000000..2640084ace5c
--- /dev/null
+++ b/drivers/watchdog/sl28cpld_wdt.c
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * sl28cpld watchdog driver.
+ *
+ * Copyright 2019 Kontron Europe GmbH
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/watchdog.h>
+
+/*
+ * Watchdog timer block registers.
+ */
+#define WDT_CTRL			0x00
+#define  WDT_CTRL_EN			BIT(0)
+#define  WDT_CTRL_LOCK			BIT(2)
+#define  WDT_CTRL_ASSERT_SYS_RESET	BIT(6)
+#define  WDT_CTRL_ASSERT_WDT_TIMEOUT	BIT(7)
+#define WDT_TIMEOUT			0x01
+#define WDT_KICK			0x02
+#define  WDT_KICK_VALUE			0x6b
+#define WDT_COUNT			0x03
+
+#define WDT_DEFAULT_TIMEOUT		10
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static int timeout;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Initial watchdog timeout in seconds");
+
+struct sl28cpld_wdt {
+	struct watchdog_device wdd;
+	struct regmap *regmap;
+	u32 offset;
+	bool assert_wdt_timeout;
+};
+
+static int sl28cpld_wdt_ping(struct watchdog_device *wdd)
+{
+	struct sl28cpld_wdt *wdt = watchdog_get_drvdata(wdd);
+
+	return regmap_write(wdt->regmap, wdt->offset + WDT_KICK,
+			    WDT_KICK_VALUE);
+}
+
+static int sl28cpld_wdt_start(struct watchdog_device *wdd)
+{
+	struct sl28cpld_wdt *wdt = watchdog_get_drvdata(wdd);
+	unsigned int val;
+
+	val = WDT_CTRL_EN | WDT_CTRL_ASSERT_SYS_RESET;
+	if (wdt->assert_wdt_timeout)
+		val |= WDT_CTRL_ASSERT_WDT_TIMEOUT;
+	if (nowayout)
+		val |= WDT_CTRL_LOCK;
+
+	return regmap_update_bits(wdt->regmap, wdt->offset + WDT_CTRL,
+				  val, val);
+}
+
+static int sl28cpld_wdt_stop(struct watchdog_device *wdd)
+{
+	struct sl28cpld_wdt *wdt = watchdog_get_drvdata(wdd);
+
+	return regmap_update_bits(wdt->regmap, wdt->offset + WDT_CTRL,
+				  WDT_CTRL_EN, 0);
+}
+
+static unsigned int sl28cpld_wdt_get_timeleft(struct watchdog_device *wdd)
+{
+	struct sl28cpld_wdt *wdt = watchdog_get_drvdata(wdd);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(wdt->regmap, wdt->offset + WDT_COUNT, &val);
+
+	return (ret < 0) ? 0 : val;
+}
+
+static int sl28cpld_wdt_set_timeout(struct watchdog_device *wdd,
+				    unsigned int timeout)
+{
+	struct sl28cpld_wdt *wdt = watchdog_get_drvdata(wdd);
+	int ret;
+
+	ret = regmap_write(wdt->regmap, wdt->offset + WDT_TIMEOUT, timeout);
+	if (!ret)
+		wdd->timeout = timeout;
+
+	return ret;
+}
+
+static const struct watchdog_info sl28cpld_wdt_info = {
+	.options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+	.identity = "sl28cpld watchdog",
+};
+
+static struct watchdog_ops sl28cpld_wdt_ops = {
+	.owner = THIS_MODULE,
+	.start = sl28cpld_wdt_start,
+	.stop = sl28cpld_wdt_stop,
+	.ping = sl28cpld_wdt_ping,
+	.set_timeout = sl28cpld_wdt_set_timeout,
+	.get_timeleft = sl28cpld_wdt_get_timeleft,
+};
+
+static int sl28cpld_wdt_probe(struct platform_device *pdev)
+{
+	struct watchdog_device *wdd;
+	struct sl28cpld_wdt *wdt;
+	struct resource *res;
+	unsigned int status;
+	unsigned int val;
+	int ret;
+
+	if (!pdev->dev.parent)
+		return -ENODEV;
+
+	wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+	if (!wdt)
+		return -ENOMEM;
+
+	wdt->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!wdt->regmap)
+		return -ENODEV;
+
+	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
+	if (!res)
+		return -EINVAL;
+	wdt->offset = res->start;
+
+	wdt->assert_wdt_timeout = device_property_read_bool(&pdev->dev,
+							    "kontron,assert-wdt-timeout-pin");
+
+	/* initialize struct watchdog_device */
+	wdd = &wdt->wdd;
+	wdd->parent = &pdev->dev;
+	wdd->info = &sl28cpld_wdt_info;
+	wdd->ops = &sl28cpld_wdt_ops;
+	wdd->min_timeout = 1;
+	wdd->max_timeout = 255;
+
+	watchdog_set_drvdata(wdd, wdt);
+	watchdog_stop_on_reboot(wdd);
+
+	/*
+	 * Read the status early, in case of an error, we haven't modified the
+	 * hardware.
+	 */
+	ret = regmap_read(wdt->regmap, wdt->offset + WDT_CTRL, &status);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Initial timeout value, may be overwritten by device tree or module
+	 * parmeter in watchdog_init_timeout().
+	 *
+	 * Reading a zero here means that either the hardware has a default
+	 * value of zero (which is very unlikely and definitely a hardware
+	 * bug) or the bootloader set it to zero. In any case, we handle
+	 * this case gracefully and set out own timeout.
+	 */
+	ret = regmap_read(wdt->regmap, wdt->offset + WDT_TIMEOUT, &val);
+	if (ret < 0)
+		return ret;
+
+	if (val)
+		wdd->timeout = val;
+	else
+		wdd->timeout = WDT_DEFAULT_TIMEOUT;
+
+	watchdog_init_timeout(wdd, timeout, &pdev->dev);
+	sl28cpld_wdt_set_timeout(wdd, wdd->timeout);
+
+	/* if the watchdog is locked, we set nowayout */
+	if (status & WDT_CTRL_LOCK)
+		nowayout = true;
+	watchdog_set_nowayout(wdd, nowayout);
+
+	/*
+	 * If watchdog is already running, keep it enabled, but make
+	 * sure its mode is set correctly.
+	 */
+	if (status & WDT_CTRL_EN) {
+		sl28cpld_wdt_start(wdd);
+		set_bit(WDOG_HW_RUNNING, &wdd->status);
+	}
+
+	ret = devm_watchdog_register_device(&pdev->dev, wdd);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to register watchdog device\n");
+		return ret;
+	}
+
+	dev_info(&pdev->dev, "initial timeout %d sec%s\n",
+		 wdd->timeout, nowayout ? ", nowayout" : "");
+
+	return 0;
+}
+
+static const struct of_device_id sl28cpld_wdt_of_match[] = {
+	{ .compatible = "kontron,sl28cpld-wdt" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, sl28cpld_wdt_of_match);
+
+static const struct platform_device_id sl28cpld_wdt_id_table[] = {
+	{ "sl28cpld-wdt" },
+	{},
+};
+MODULE_DEVICE_TABLE(platform, sl28cpld_wdt_id_table);
+
+static struct platform_driver sl28cpld_wdt_driver = {
+	.probe = sl28cpld_wdt_probe,
+	.id_table = sl28cpld_wdt_id_table,
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.of_match_table = sl28cpld_wdt_of_match,
+	},
+};
+module_platform_driver(sl28cpld_wdt_driver);
+
+MODULE_DESCRIPTION("sl28cpld Watchdog Driver");
+MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
+MODULE_LICENSE("GPL");
-- 
2.20.1


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

* [PATCH v3 08/16] pwm: add support for sl28cpld PWM controller
  2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
                   ` (6 preceding siblings ...)
  2020-04-23 17:45 ` [PATCH v3 07/16] watchdog: add support for sl28cpld watchdog Michael Walle
@ 2020-04-23 17:45 ` Michael Walle
  2020-05-11 20:45   ` Rob Herring
  2020-04-23 17:45 ` [PATCH v3 09/16] gpiolib: Introduce gpiochip_irqchip_add_domain() Michael Walle
                   ` (7 subsequent siblings)
  15 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle

This adds support for the PWM controller of the sl28cpld board
management controller. This is part of a multi-function device driver.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 drivers/pwm/Kconfig        |  10 ++
 drivers/pwm/Makefile       |   1 +
 drivers/pwm/pwm-sl28cpld.c | 203 +++++++++++++++++++++++++++++++++++++
 3 files changed, 214 insertions(+)
 create mode 100644 drivers/pwm/pwm-sl28cpld.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index c13d146cdde5..45b308482f92 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -437,6 +437,16 @@ config PWM_SIFIVE
 	  To compile this driver as a module, choose M here: the module
 	  will be called pwm-sifive.
 
+config PWM_SL28CPLD
+	tristate "Kontron sl28 PWM support"
+	depends on MFD_SL28CPLD
+	help
+	  Generic PWM framework driver for board management controller
+	  found on the Kontron sl28 CPLD.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-sl28cpld.
+
 config PWM_SPEAR
 	tristate "STMicroelectronics SPEAr PWM support"
 	depends on PLAT_SPEAR || COMPILE_TEST
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index a59c710e98c7..c479623724e8 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_PWM_RENESAS_TPU)	+= pwm-renesas-tpu.o
 obj-$(CONFIG_PWM_ROCKCHIP)	+= pwm-rockchip.o
 obj-$(CONFIG_PWM_SAMSUNG)	+= pwm-samsung.o
 obj-$(CONFIG_PWM_SIFIVE)	+= pwm-sifive.o
+obj-$(CONFIG_PWM_SL28CPLD)	+= pwm-sl28cpld.o
 obj-$(CONFIG_PWM_SPEAR)		+= pwm-spear.o
 obj-$(CONFIG_PWM_SPRD)		+= pwm-sprd.o
 obj-$(CONFIG_PWM_STI)		+= pwm-sti.o
diff --git a/drivers/pwm/pwm-sl28cpld.c b/drivers/pwm/pwm-sl28cpld.c
new file mode 100644
index 000000000000..c6b372bf45fa
--- /dev/null
+++ b/drivers/pwm/pwm-sl28cpld.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * sl28cpld PWM driver.
+ *
+ * Copyright 2019 Kontron Europe GmbH
+ */
+
+#include <linux/bitfield.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+
+/*
+ * PWM timer block registers.
+ */
+#define PWM_CTRL		0x00
+#define   PWM_ENABLE		BIT(7)
+#define   PWM_MODE_250HZ	0
+#define   PWM_MODE_500HZ	1
+#define   PWM_MODE_1KHZ		2
+#define   PWM_MODE_2KHZ		3
+#define   PWM_MODE_MASK		GENMASK(1, 0)
+#define PWM_CYCLE		0x01
+#define   PWM_CYCLE_MAX		0x7f
+
+struct sl28cpld_pwm {
+	struct pwm_chip pwm_chip;
+	struct regmap *regmap;
+	u32 offset;
+};
+
+struct sl28cpld_pwm_periods {
+	u8 ctrl;
+	unsigned long duty_cycle;
+};
+
+struct sl28cpld_pwm_config {
+	unsigned long period_ns;
+	u8 max_duty_cycle;
+};
+
+static struct sl28cpld_pwm_config sl28cpld_pwm_config[] = {
+	[PWM_MODE_250HZ] = { .period_ns = 4000000, .max_duty_cycle = 0x80 },
+	[PWM_MODE_500HZ] = { .period_ns = 2000000, .max_duty_cycle = 0x40 },
+	[PWM_MODE_1KHZ] = { .period_ns = 1000000, .max_duty_cycle = 0x20 },
+	[PWM_MODE_2KHZ] = { .period_ns =  500000, .max_duty_cycle = 0x10 },
+};
+
+static inline struct sl28cpld_pwm *to_sl28cpld_pwm(struct pwm_chip *chip)
+{
+	return container_of(chip, struct sl28cpld_pwm, pwm_chip);
+}
+
+static void sl28cpld_pwm_get_state(struct pwm_chip *chip,
+				   struct pwm_device *pwm,
+				   struct pwm_state *state)
+{
+	struct sl28cpld_pwm *spc = to_sl28cpld_pwm(chip);
+	static struct sl28cpld_pwm_config *config;
+	unsigned int reg;
+	unsigned long cycle;
+	unsigned int mode;
+
+	regmap_read(spc->regmap, spc->offset + PWM_CTRL, &reg);
+
+	state->enabled = reg & PWM_ENABLE;
+
+	mode = FIELD_GET(PWM_MODE_MASK, reg);
+	config = &sl28cpld_pwm_config[mode];
+	state->period = config->period_ns;
+
+	regmap_read(spc->regmap, spc->offset + PWM_CYCLE, &reg);
+	cycle = reg * config->period_ns;
+	state->duty_cycle = DIV_ROUND_CLOSEST_ULL(cycle,
+						  config->max_duty_cycle);
+}
+
+static int sl28cpld_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+			      const struct pwm_state *state)
+{
+	struct sl28cpld_pwm *spc = to_sl28cpld_pwm(chip);
+	struct sl28cpld_pwm_config *config;
+	unsigned long long cycle;
+	int ret;
+	int mode;
+	u8 ctrl;
+
+	/* update config, first search best matching period */
+	for (mode = 0; mode < ARRAY_SIZE(sl28cpld_pwm_config); mode++) {
+		config = &sl28cpld_pwm_config[mode];
+		if (state->period == config->period_ns)
+			break;
+	}
+
+	if (mode == ARRAY_SIZE(sl28cpld_pwm_config))
+		return -EINVAL;
+
+	ctrl = FIELD_PREP(PWM_MODE_MASK, mode);
+	if (state->enabled)
+		ctrl |= PWM_ENABLE;
+
+	cycle = state->duty_cycle * config->max_duty_cycle;
+	do_div(cycle, state->period);
+
+	/*
+	 * The hardware doesn't allow to set max_duty_cycle if the
+	 * 250Hz mode is enabled. But since this is "all-high" output
+	 * just use the 500Hz mode with the duty cycle to max value.
+	 */
+	if (cycle == config->max_duty_cycle) {
+		ctrl &= ~PWM_MODE_MASK;
+		ctrl |= FIELD_PREP(PWM_MODE_MASK, PWM_MODE_500HZ);
+		cycle = PWM_CYCLE_MAX;
+	}
+
+	ret = regmap_write(spc->regmap, spc->offset + PWM_CTRL, ctrl);
+	if (ret)
+		return ret;
+
+	return regmap_write(spc->regmap, spc->offset + PWM_CYCLE, (u8)cycle);
+}
+
+static const struct pwm_ops sl28cpld_pwm_ops = {
+	.apply = sl28cpld_pwm_apply,
+	.get_state = sl28cpld_pwm_get_state,
+	.owner = THIS_MODULE,
+};
+
+static int sl28cpld_pwm_probe(struct platform_device *pdev)
+{
+	struct sl28cpld_pwm *pwm;
+	struct pwm_chip *chip;
+	struct resource *res;
+	int ret;
+
+	if (!pdev->dev.parent)
+		return -ENODEV;
+
+	pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
+	if (!pwm)
+		return -ENOMEM;
+
+	pwm->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!pwm->regmap)
+		return -ENODEV;
+
+	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
+	if (!res)
+		return -EINVAL;
+	pwm->offset = res->start;
+
+	/* initialize struct gpio_chip */
+	chip = &pwm->pwm_chip;
+	chip->dev = &pdev->dev;
+	chip->ops = &sl28cpld_pwm_ops;
+	chip->base = -1;
+	chip->npwm = 1;
+
+	ret = pwmchip_add(&pwm->pwm_chip);
+	if (ret < 0)
+		return ret;
+
+	platform_set_drvdata(pdev, pwm);
+
+	return 0;
+}
+
+static int sl28cpld_pwm_remove(struct platform_device *pdev)
+{
+	struct sl28cpld_pwm *pwm = platform_get_drvdata(pdev);
+
+	return pwmchip_remove(&pwm->pwm_chip);
+}
+
+static const struct of_device_id sl28cpld_pwm_of_match[] = {
+	{ .compatible = "kontron,sl28cpld-pwm" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, sl28cpld_pwm_of_match);
+
+static const struct platform_device_id sl28cpld_pwm_id_table[] = {
+	{"sl28cpld-gpio"},
+	{},
+};
+MODULE_DEVICE_TABLE(platform, sl28cpld_pwm_id_table);
+
+static struct platform_driver sl28cpld_pwm_driver = {
+	.probe = sl28cpld_pwm_probe,
+	.remove	= sl28cpld_pwm_remove,
+	.id_table = sl28cpld_pwm_id_table,
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.of_match_table = sl28cpld_pwm_of_match,
+	},
+};
+module_platform_driver(sl28cpld_pwm_driver);
+
+MODULE_DESCRIPTION("sl28cpld PWM Driver");
+MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
+MODULE_LICENSE("GPL");
-- 
2.20.1


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

* [PATCH v3 09/16] gpiolib: Introduce gpiochip_irqchip_add_domain()
  2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
                   ` (7 preceding siblings ...)
  2020-04-23 17:45 ` [PATCH v3 08/16] pwm: add support for sl28cpld PWM controller Michael Walle
@ 2020-04-23 17:45 ` Michael Walle
  2020-04-27 11:42   ` Thomas Gleixner
  2020-04-23 17:45 ` [PATCH v3 10/16] gpio: add a reusable generic gpio_chip using regmap Michael Walle
                   ` (6 subsequent siblings)
  15 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle

This connects an IRQ domain to a gpiochip and reuses gpiochip_to_irq().

Signed-off-by: Michael Walle <michael@walle.cc>
---
 drivers/gpio/gpiolib.c      | 20 ++++++++++++++++++++
 include/linux/gpio/driver.h |  3 +++
 2 files changed, 23 insertions(+)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 40f2d7f69be2..7b3d7f496b9a 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2722,6 +2722,26 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gc,
 }
 EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
 
+/**
+ * gpiochip_irqchip_add_key() - adds an irqdomain to a gpiochip
+ * @gc: the gpiochip to add the irqchip to
+ * @domain: the irqdomain to add to the gpiochip
+ *
+ * This function adds an IRQ domain to the gpiochip.
+ */
+int gpiochip_irqchip_add_domain(struct gpio_chip *gc,
+				struct irq_domain *domain)
+{
+	if (!domain)
+		return -EINVAL;
+
+	gc->to_irq = gpiochip_to_irq;
+	gc->irq.domain = domain;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_domain);
+
 #else /* CONFIG_GPIOLIB_IRQCHIP */
 
 static inline int gpiochip_add_irqchip(struct gpio_chip *gc,
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index b8fc92c177eb..dfb1aa0ad4dc 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -599,6 +599,9 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gc,
 bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gc,
 				unsigned int offset);
 
+int gpiochip_irqchip_add_domain(struct gpio_chip *gc,
+				struct irq_domain *domain);
+
 #ifdef CONFIG_LOCKDEP
 
 /*
-- 
2.20.1


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

* [PATCH v3 10/16] gpio: add a reusable generic gpio_chip using regmap
  2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
                   ` (8 preceding siblings ...)
  2020-04-23 17:45 ` [PATCH v3 09/16] gpiolib: Introduce gpiochip_irqchip_add_domain() Michael Walle
@ 2020-04-23 17:45 ` Michael Walle
  2020-05-12 12:48   ` Bartosz Golaszewski
  2020-04-23 17:45 ` [PATCH v3 11/16] gpio: add support for the sl28cpld GPIO controller Michael Walle
                   ` (5 subsequent siblings)
  15 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle

There are quite a lot simple GPIO controller which are using regmap to
access the hardware. This driver tries to be a base to unify existing
code into one place. This won't cover everything but it should be a good
starting point.

It does not implement its own irq_chip because there is already a
generic one for regmap based devices. Instead, the irq_chip will be
instantiated in the parent driver and its irq domain will be associate
to this driver.

For now it consists of the usual registers, like set (and an optional
clear) data register, an input register and direction registers.
Out-of-the-box, it supports consecutive register mappings and mappings
where the registers have gaps between them with a linear mapping between
GPIO offset and bit position. For weirder mappings the user can register
its own .xlate().

Signed-off-by: Michael Walle <michael@walle.cc>
---
 drivers/gpio/Kconfig        |   4 +
 drivers/gpio/Makefile       |   1 +
 drivers/gpio/gpio-regmap.c  | 343 ++++++++++++++++++++++++++++++++++++
 include/linux/gpio-regmap.h |  69 ++++++++
 4 files changed, 417 insertions(+)
 create mode 100644 drivers/gpio/gpio-regmap.c
 create mode 100644 include/linux/gpio-regmap.h

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 8ef2179fb999..ae3a49a2e970 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -73,6 +73,10 @@ config GPIO_GENERIC
 	depends on HAS_IOMEM # Only for IOMEM drivers
 	tristate
 
+config GPIO_REGMAP
+	depends on REGMAP
+	tristate
+
 # put drivers in the right section, in alphabetical order
 
 # This symbol is selected by both I2C and SPI expanders
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index b2cfc21a97f3..93e139fdfa57 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_GPIO_SYSFS)	+= gpiolib-sysfs.o
 obj-$(CONFIG_GPIO_ACPI)		+= gpiolib-acpi.o
 
 # Device drivers. Generally keep list sorted alphabetically
+obj-$(CONFIG_GPIO_REGMAP)	+= gpio-regmap.o
 obj-$(CONFIG_GPIO_GENERIC)	+= gpio-generic.o
 
 # directly supported by gpio-generic
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
new file mode 100644
index 000000000000..04939c0a22f9
--- /dev/null
+++ b/drivers/gpio/gpio-regmap.c
@@ -0,0 +1,343 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * regmap based generic GPIO driver
+ *
+ * Copyright 2019 Michael Walle <michael@walle.cc>
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/gpio-regmap.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+struct gpio_regmap {
+	struct device *parent;
+	struct regmap *regmap;
+	struct gpio_chip gpio_chip;
+
+	int reg_stride;
+	int ngpio_per_reg;
+	unsigned int reg_dat_base;
+	unsigned int reg_set_base;
+	unsigned int reg_clr_base;
+	unsigned int reg_dir_in_base;
+	unsigned int reg_dir_out_base;
+
+	int (*reg_mask_xlate)(struct gpio_regmap *gpio, unsigned int base,
+			      unsigned int offset, unsigned int *reg,
+			      unsigned int *mask);
+
+	void *driver_data;
+};
+
+static unsigned int gpio_regmap_addr(unsigned int addr)
+{
+	return (addr == GPIO_REGMAP_ADDR_ZERO) ? 0 : addr;
+}
+
+/**
+ * gpio_regmap_simple_xlate() - translate base/offset to reg/mask
+ *
+ * Use a simple linear mapping to translate the offset to the bitmask.
+ */
+static int gpio_regmap_simple_xlate(struct gpio_regmap *gpio,
+				    unsigned int base, unsigned int offset,
+				    unsigned int *reg, unsigned int *mask)
+{
+	unsigned int line = offset % gpio->ngpio_per_reg;
+	unsigned int stride = offset / gpio->ngpio_per_reg;
+
+	*reg = base + stride * gpio->reg_stride;
+	*mask = BIT(line);
+
+	return 0;
+}
+
+static int gpio_regmap_get(struct gpio_chip *chip, unsigned int offset)
+{
+	struct gpio_regmap *gpio = gpiochip_get_data(chip);
+	unsigned int base, val, reg, mask;
+	int ret;
+
+	/* we might not have an output register if we are input only */
+	if (gpio->reg_dat_base)
+		base = gpio_regmap_addr(gpio->reg_dat_base);
+	else
+		base = gpio_regmap_addr(gpio->reg_set_base);
+
+	ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
+	if (ret)
+		return ret;
+
+	ret = regmap_read(gpio->regmap, reg, &val);
+	if (ret)
+		return ret;
+
+	return (val & mask) ? 1 : 0;
+}
+
+static void gpio_regmap_set(struct gpio_chip *chip, unsigned int offset,
+			    int val)
+{
+	struct gpio_regmap *gpio = gpiochip_get_data(chip);
+	unsigned int base = gpio_regmap_addr(gpio->reg_set_base);
+	unsigned int reg, mask;
+
+	gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
+	if (val)
+		regmap_update_bits(gpio->regmap, reg, mask, mask);
+	else
+		regmap_update_bits(gpio->regmap, reg, mask, 0);
+}
+
+static void gpio_regmap_set_with_clear(struct gpio_chip *chip,
+				       unsigned int offset, int val)
+{
+	struct gpio_regmap *gpio = gpiochip_get_data(chip);
+	unsigned int base, reg, mask;
+
+	if (val)
+		base = gpio_regmap_addr(gpio->reg_set_base);
+	else
+		base = gpio_regmap_addr(gpio->reg_clr_base);
+
+	gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
+	regmap_write(gpio->regmap, reg, mask);
+}
+
+static int gpio_regmap_get_direction(struct gpio_chip *chip,
+				     unsigned int offset)
+{
+	struct gpio_regmap *gpio = gpiochip_get_data(chip);
+	unsigned int base, val, reg, mask;
+	int invert, ret;
+
+	if (gpio->reg_dir_out_base) {
+		base = gpio_regmap_addr(gpio->reg_dir_out_base);
+		invert = 0;
+	} else if (gpio->reg_dir_in_base) {
+		base = gpio_regmap_addr(gpio->reg_dir_in_base);
+		invert = 1;
+	} else {
+		return GPIO_LINE_DIRECTION_IN;
+	}
+
+	ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
+	if (ret)
+		return ret;
+
+	ret = regmap_read(gpio->regmap, reg, &val);
+	if (ret)
+		return ret;
+
+	if (!!(val & mask) ^ invert)
+		return GPIO_LINE_DIRECTION_OUT;
+	else
+		return GPIO_LINE_DIRECTION_IN;
+}
+
+static int gpio_regmap_set_direction(struct gpio_chip *chip,
+				     unsigned int offset, bool output)
+{
+	struct gpio_regmap *gpio = gpiochip_get_data(chip);
+	unsigned int base, val, reg, mask;
+	int invert, ret;
+
+	if (gpio->reg_dir_out_base) {
+		base = gpio_regmap_addr(gpio->reg_dir_out_base);
+		invert = 0;
+	} else if (gpio->reg_dir_in_base) {
+		base = gpio_regmap_addr(gpio->reg_dir_in_base);
+		invert = 1;
+	} else {
+		return 0;
+	}
+
+	ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
+	if (ret)
+		return ret;
+
+	if (!invert)
+		val = (output) ? mask : 0;
+	else
+		val = (output) ? 0 : mask;
+
+	return regmap_update_bits(gpio->regmap, reg, mask, val);
+}
+
+static int gpio_regmap_direction_input(struct gpio_chip *chip,
+				       unsigned int offset)
+{
+	return gpio_regmap_set_direction(chip, offset, false);
+}
+
+static int gpio_regmap_direction_output(struct gpio_chip *chip,
+					unsigned int offset, int value)
+{
+	gpio_regmap_set(chip, offset, value);
+
+	return gpio_regmap_set_direction(chip, offset, true);
+}
+
+void gpio_regmap_set_drvdata(struct gpio_regmap *gpio, void *data)
+{
+	gpio->driver_data = data;
+}
+EXPORT_SYMBOL_GPL(gpio_regmap_set_drvdata);
+
+void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio)
+{
+	return gpio->driver_data;
+}
+EXPORT_SYMBOL_GPL(gpio_regmap_get_drvdata);
+
+/**
+ * gpio_regmap_register() - Register a generic regmap GPIO controller
+ *
+ * @gpio: gpio_regmap device to register
+ *
+ * Returns 0 on success or an errno on failure.
+ */
+struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config)
+{
+	struct gpio_regmap *gpio;
+	struct gpio_chip *chip;
+	int ret;
+
+	if (!config->parent)
+		return ERR_PTR(-EINVAL);
+
+	if (!config->ngpio)
+		return ERR_PTR(-EINVAL);
+
+	/* we need at least one */
+	if (!config->reg_dat_base && !config->reg_set_base)
+		return ERR_PTR(-EINVAL);
+
+	/* we don't support having both registers simulaniously for now */
+	if (config->reg_dir_out_base && config->reg_dir_in_base)
+		return ERR_PTR(-EINVAL);
+
+	gpio = kzalloc(sizeof(*gpio), GFP_KERNEL);
+	if (!gpio)
+		return ERR_PTR(-ENOMEM);
+
+	gpio->parent = config->parent;
+	gpio->regmap = config->regmap;
+	gpio->ngpio_per_reg = config->ngpio_per_reg;
+	gpio->reg_stride = config->reg_stride;
+	gpio->reg_mask_xlate = config->reg_mask_xlate;
+	gpio->reg_set_base = config->reg_set_base;
+	gpio->reg_clr_base = config->reg_clr_base;
+	gpio->reg_dir_in_base = config->reg_dir_in_base;
+	gpio->reg_dir_out_base = config->reg_dir_out_base;
+
+	/* if not set, assume there is only one register */
+	if (!gpio->ngpio_per_reg)
+		gpio->ngpio_per_reg = config->ngpio;
+
+	/* if not set, assume they are consecutive */
+	if (!gpio->reg_stride)
+		gpio->reg_stride = 1;
+
+	if (!gpio->reg_mask_xlate)
+		gpio->reg_mask_xlate = gpio_regmap_simple_xlate;
+
+	chip = &gpio->gpio_chip;
+	chip->parent = config->parent;
+	chip->base = -1;
+	chip->ngpio = config->ngpio;
+	chip->can_sleep = true;
+
+	if (!chip->label)
+		chip->label = dev_name(config->parent);
+	else
+		chip->label = config->label;
+
+	chip->get = gpio_regmap_get;
+	if (gpio->reg_set_base && gpio->reg_clr_base)
+		chip->set = gpio_regmap_set_with_clear;
+	else if (gpio->reg_set_base)
+		chip->set = gpio_regmap_set;
+
+	if (gpio->reg_dir_in_base || gpio->reg_dir_out_base) {
+		chip->get_direction = gpio_regmap_get_direction;
+		chip->direction_input = gpio_regmap_direction_input;
+		chip->direction_output = gpio_regmap_direction_output;
+	}
+
+	ret = gpiochip_add_data(chip, gpio);
+	if (ret < 0) {
+		kfree(gpio);
+		return ERR_PTR(ret);
+	}
+
+	if (config->irq_domain) {
+		ret = gpiochip_irqchip_add_domain(chip, config->irq_domain);
+		if (ret < 0)
+			goto err;
+	}
+
+	return gpio;
+
+err:
+	gpiochip_remove(chip);
+	kfree(gpio);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(gpio_regmap_register);
+
+/**
+ * gpio_regmap_unregister() - Unregister a generic regmap GPIO controller
+ *
+ * @gpio: gpio_regmap device to unregister
+ */
+void gpio_regmap_unregister(struct gpio_regmap *gpio)
+{
+	gpiochip_remove(&gpio->gpio_chip);
+	kfree(gpio);
+}
+EXPORT_SYMBOL_GPL(gpio_regmap_unregister);
+
+static void devm_gpio_regmap_unregister(struct device *dev, void *res)
+{
+	gpio_regmap_unregister(*(struct gpio_regmap **)res);
+}
+
+/**
+ * devm_gpio_regmap_register() - resource managed gpio_regmap_register()
+ *
+ * @dev: device that is registering this GPIO device
+ * @gpio: gpio_regmap device to register
+ *
+ * Managed gpio_regmap_register(). For generic regmap GPIO device registered by
+ * this function, gpio_regmap_unregister() is automatically called on driver
+ * detach. See gpio_regmap_register() for more information.
+ */
+struct gpio_regmap *devm_gpio_regmap_register(struct device *dev,
+					      const struct gpio_regmap_config *config)
+{
+	struct gpio_regmap **ptr, *gpio;
+
+	ptr = devres_alloc(devm_gpio_regmap_unregister, sizeof(*ptr),
+			   GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	gpio = gpio_regmap_register(config);
+
+	if (!IS_ERR(gpio)) {
+		*ptr = gpio;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return gpio;
+}
+EXPORT_SYMBOL_GPL(devm_gpio_regmap_register);
+
+MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
+MODULE_DESCRIPTION("GPIO generic regmap driver core");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/gpio-regmap.h b/include/linux/gpio-regmap.h
new file mode 100644
index 000000000000..a868cbcde6e9
--- /dev/null
+++ b/include/linux/gpio-regmap.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _LINUX_GPIO_REGMAP_H
+#define _LINUX_GPIO_REGMAP_H
+
+struct gpio_regmap;
+
+#define GPIO_REGMAP_ADDR_ZERO ((unsigned long)(-1))
+#define GPIO_REGMAP_ADDR(addr) ((addr) ? : GPIO_REGMAP_ADDR_ZERO)
+
+/**
+ * struct gpio_regmap_config - Description of a generic regmap gpio_chip.
+ *
+ * @parent:		The parent device
+ * @regmap:		The regmap used to access the registers
+ *			given, the name of the device is used
+ * @label:		(Optional) Descriptive name for GPIO controller.
+ *			If not given, the name of the device is used.
+ * @ngpio:		Number of GPIOs
+ * @reg_dat_base:	(Optional) (in) register base address
+ * @reg_set_base:	(Optional) set register base address
+ * @reg_clr_base:	(Optional) clear register base address
+ * @reg_dir_in_base:	(Optional) out setting register base address
+ * @reg_dir_out_base:	(Optional) in setting register base address
+ * @reg_stride:		(Optional) May be set if the registers (of the
+ *			same type, dat, set, etc) are not consecutive.
+ * @ngpio_per_reg:	Number of GPIOs per register
+ * @irq_domain:		(Optional) IRQ domain if the controller is
+ *			interrupt-capable
+ * @reg_mask_xlate:     (Optional) Translates base address and GPIO
+ *			offset to a register/bitmask pair. If not
+ *			given the default gpio_regmap_simple_xlate()
+ *			is used.
+ *
+ * The reg_mask_xlate translates a given base address and GPIO offset to
+ * register and mask pair. The base address is one of the given reg_*_base.
+ *
+ * All base addresses may have the special value GPIO_REGMAP_ADDR_ZERO
+ * which forces the address to the value 0.
+ */
+struct gpio_regmap_config {
+	struct device *parent;
+	struct regmap *regmap;
+
+	const char *label;
+	int ngpio;
+
+	unsigned int reg_dat_base;
+	unsigned int reg_set_base;
+	unsigned int reg_clr_base;
+	unsigned int reg_dir_in_base;
+	unsigned int reg_dir_out_base;
+	int reg_stride;
+	int ngpio_per_reg;
+	struct irq_domain *irq_domain;
+
+	int (*reg_mask_xlate)(struct gpio_regmap *gpio, unsigned int base,
+			      unsigned int offset, unsigned int *reg,
+			      unsigned int *mask);
+};
+
+struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config);
+void gpio_regmap_unregister(struct gpio_regmap *gpio);
+struct gpio_regmap *devm_gpio_regmap_register(struct device *dev,
+					      const struct gpio_regmap_config *config);
+void gpio_regmap_set_drvdata(struct gpio_regmap *gpio, void *data);
+void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio);
+
+#endif /* _LINUX_GPIO_REGMAP_H */
-- 
2.20.1


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

* [PATCH v3 11/16] gpio: add support for the sl28cpld GPIO controller
  2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
                   ` (9 preceding siblings ...)
  2020-04-23 17:45 ` [PATCH v3 10/16] gpio: add a reusable generic gpio_chip using regmap Michael Walle
@ 2020-04-23 17:45 ` Michael Walle
  2020-04-27 11:45   ` Thomas Gleixner
  2020-04-23 17:45 ` [PATCH v3 12/16] hwmon: add support for the sl28cpld hardware monitoring controller Michael Walle
                   ` (4 subsequent siblings)
  15 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle

This adds support for the GPIO controller of the sl28 board management
controller. This driver is part of a multi-function device.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 drivers/gpio/Kconfig         |  11 +++
 drivers/gpio/Makefile        |   1 +
 drivers/gpio/gpio-sl28cpld.c | 184 +++++++++++++++++++++++++++++++++++
 3 files changed, 196 insertions(+)
 create mode 100644 drivers/gpio/gpio-sl28cpld.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index ae3a49a2e970..95e2f223b34e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1215,6 +1215,17 @@ config GPIO_RC5T583
 	  This driver provides the support for driving/reading the gpio pins
 	  of RC5T583 device through standard gpio library.
 
+config GPIO_SL28CPLD
+	tristate "Kontron sl28 GPIO"
+	depends on MFD_SL28CPLD
+	select GPIO_REGMAP
+	select GPIOLIB_IRQCHIP
+	help
+	  This enables support for the GPIOs found on the Kontron sl28 CPLD.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called gpio-sl28cpld.
+
 config GPIO_STMPE
 	bool "STMPE GPIOs"
 	depends on MFD_STMPE
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 93e139fdfa57..f50ccf13f5eb 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -129,6 +129,7 @@ obj-$(CONFIG_GPIO_SCH311X)		+= gpio-sch311x.o
 obj-$(CONFIG_GPIO_SCH)			+= gpio-sch.o
 obj-$(CONFIG_GPIO_SIFIVE)		+= gpio-sifive.o
 obj-$(CONFIG_GPIO_SIOX)			+= gpio-siox.o
+obj-$(CONFIG_GPIO_SL28CPLD)		+= gpio-sl28cpld.o
 obj-$(CONFIG_GPIO_SODAVILLE)		+= gpio-sodaville.o
 obj-$(CONFIG_GPIO_SPEAR_SPICS)		+= gpio-spear-spics.o
 obj-$(CONFIG_GPIO_SPRD)			+= gpio-sprd.o
diff --git a/drivers/gpio/gpio-sl28cpld.c b/drivers/gpio/gpio-sl28cpld.c
new file mode 100644
index 000000000000..98033d40e9d9
--- /dev/null
+++ b/drivers/gpio/gpio-sl28cpld.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * sl28cpld GPIO driver.
+ *
+ * Copyright 2019 Michael Walle <michael@walle.cc>
+ */
+
+#include <linux/device.h>
+#include <linux/gpio-regmap.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/* GPIO flavor */
+#define GPIO_REG_DIR	0x00
+#define GPIO_REG_OUT	0x01
+#define GPIO_REG_IN	0x02
+#define GPIO_REG_IE	0x03
+#define GPIO_REG_IP	0x04
+
+/* input-only flavor */
+#define GPI_REG_IN	0x00
+
+/* output-only flavor */
+#define GPO_REG_OUT	0x00
+
+enum sl28cpld_gpio_type {
+	SL28CPLD_GPIO = 1,
+	SL28CPLD_GPI,
+	SL28CPLD_GPO,
+};
+
+struct sl28cpld_gpio {
+	struct regmap_irq_chip irq_chip;
+	struct regmap_irq_chip_data *irq_data;
+};
+
+static const struct regmap_irq sl28cpld_gpio_irqs[] = {
+	REGMAP_IRQ_REG_LINE(0, 8),
+	REGMAP_IRQ_REG_LINE(1, 8),
+	REGMAP_IRQ_REG_LINE(2, 8),
+	REGMAP_IRQ_REG_LINE(3, 8),
+	REGMAP_IRQ_REG_LINE(4, 8),
+	REGMAP_IRQ_REG_LINE(5, 8),
+	REGMAP_IRQ_REG_LINE(6, 8),
+	REGMAP_IRQ_REG_LINE(7, 8),
+};
+
+static int sl28cpld_gpio_irq_init(struct device *dev,
+				  struct sl28cpld_gpio *gpio,
+				  struct regmap *regmap, unsigned int base,
+				  int irq)
+{
+	struct regmap_irq_chip *irq_chip = &gpio->irq_chip;
+
+	irq_chip->name = "sl28cpld-gpio-irq",
+	irq_chip->irqs = sl28cpld_gpio_irqs;
+	irq_chip->num_irqs = ARRAY_SIZE(sl28cpld_gpio_irqs);
+	irq_chip->num_regs = 1;
+	irq_chip->status_base = base + GPIO_REG_IP;
+	irq_chip->mask_base = base + GPIO_REG_IE;
+	irq_chip->mask_invert = true,
+	irq_chip->ack_base = base + GPIO_REG_IP;
+
+	return devm_regmap_add_irq_chip_np(dev, dev_of_node(dev), regmap,
+					   irq, IRQF_SHARED | IRQF_ONESHOT, 0,
+					   irq_chip, &gpio->irq_data);
+}
+
+static int sl28cpld_gpio_probe(struct platform_device *pdev)
+{
+	const struct platform_device_id *dev_id;
+	enum sl28cpld_gpio_type type;
+	struct sl28cpld_gpio *gpio;
+	struct gpio_regmap_config config = {0};
+	struct regmap *regmap;
+	struct resource *res;
+	bool irq_support = false;
+	unsigned int base;
+	int ret;
+	int irq;
+
+	if (!pdev->dev.parent)
+		return -ENODEV;
+
+	dev_id = platform_get_device_id(pdev);
+	if (dev_id)
+		type = dev_id->driver_data;
+	else
+		type = (uintptr_t)of_device_get_match_data(&pdev->dev);
+	if (!type)
+		return -ENODEV;
+
+	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+	if (!gpio)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
+	if (!res)
+		return -EINVAL;
+	base = res->start;
+
+	regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!regmap)
+		return -ENODEV;
+
+	config.regmap = regmap;
+	config.parent = &pdev->dev;
+	config.ngpio = 8;
+
+	switch (type) {
+	case SL28CPLD_GPIO:
+		config.reg_dat_base = base + GPIO_REG_IN;
+		config.reg_set_base = base + GPIO_REG_OUT;
+		/* reg_dir_out_base might be zero */
+		config.reg_dir_out_base = GPIO_REGMAP_ADDR(base +
+							   GPIO_REG_DIR);
+		irq_support = true;
+		break;
+	case SL28CPLD_GPO:
+		config.reg_set_base = base + GPO_REG_OUT;
+		break;
+	case SL28CPLD_GPI:
+		config.reg_dat_base = base + GPI_REG_IN;
+		break;
+	default:
+		dev_err(&pdev->dev, "unknown type %d\n", type);
+		return -ENODEV;
+	}
+
+	if (irq_support &&
+	    device_property_read_bool(&pdev->dev, "interrupt-controller")) {
+		irq = platform_get_irq(pdev, 0);
+		if (irq < 0)
+			return irq;
+
+		ret = sl28cpld_gpio_irq_init(&pdev->dev, gpio, regmap,
+					     base, irq);
+		if (ret)
+			return ret;
+
+		config.irq_domain = regmap_irq_get_domain(gpio->irq_data);
+		dev_info(&pdev->dev, "registered IRQ %d\n", irq);
+	}
+
+	return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(&pdev->dev, &config));
+}
+
+static const struct of_device_id sl28cpld_gpio_of_match[] = {
+	{ .compatible = "kontron,sl28cpld-gpio",
+	  .data = (void *)SL28CPLD_GPIO },
+	{ .compatible = "kontron,sl28cpld-gpi",
+	  .data = (void *)SL28CPLD_GPI },
+	{ .compatible = "kontron,sl28cpld-gpo",
+	  .data = (void *)SL28CPLD_GPO },
+	{},
+};
+MODULE_DEVICE_TABLE(of, sl28cpld_gpio_of_match);
+
+static const struct platform_device_id sl28cpld_gpio_id_table[] = {
+	{ "sl28cpld-gpio", SL28CPLD_GPIO },
+	{ "sl28cpld-gpi", SL28CPLD_GPI },
+	{ "sl28cpld-gpo", SL28CPLD_GPO },
+	{}
+};
+MODULE_DEVICE_TABLE(platform, sl28cpld_gpio_id_table);
+
+static struct platform_driver sl28cpld_gpio_driver = {
+	.probe = sl28cpld_gpio_probe,
+	.id_table = sl28cpld_gpio_id_table,
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.of_match_table = sl28cpld_gpio_of_match,
+	},
+};
+module_platform_driver(sl28cpld_gpio_driver);
+
+MODULE_DESCRIPTION("sl28cpld GPIO Driver");
+MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
+MODULE_LICENSE("GPL");
-- 
2.20.1


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

* [PATCH v3 12/16] hwmon: add support for the sl28cpld hardware monitoring controller
  2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
                   ` (10 preceding siblings ...)
  2020-04-23 17:45 ` [PATCH v3 11/16] gpio: add support for the sl28cpld GPIO controller Michael Walle
@ 2020-04-23 17:45 ` Michael Walle
  2020-04-23 17:45 ` [PATCH v3 13/16] arm64: dts: freescale: sl28: enable sl28cpld Michael Walle
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle

This adds support for the hardware monitoring controller of the sl28cpld
board management controller. This driver is part of a multi-function
device.

Signed-off-by: Michael Walle <michael@walle.cc>
Acked-by: Guenter Roeck <linux@roeck-us.net>
---
 Documentation/hwmon/index.rst    |   1 +
 Documentation/hwmon/sl28cpld.rst |  36 ++++++++
 drivers/hwmon/Kconfig            |  10 ++
 drivers/hwmon/Makefile           |   1 +
 drivers/hwmon/sl28cpld-hwmon.c   | 151 +++++++++++++++++++++++++++++++
 5 files changed, 199 insertions(+)
 create mode 100644 Documentation/hwmon/sl28cpld.rst
 create mode 100644 drivers/hwmon/sl28cpld-hwmon.c

diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index 1f0affb3b6e0..19ad0846736d 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -149,6 +149,7 @@ Hardware Monitoring Kernel Drivers
    sht3x
    shtc1
    sis5595
+   sl28cpld
    smm665
    smsc47b397
    smsc47m192
diff --git a/Documentation/hwmon/sl28cpld.rst b/Documentation/hwmon/sl28cpld.rst
new file mode 100644
index 000000000000..7ed65f78250c
--- /dev/null
+++ b/Documentation/hwmon/sl28cpld.rst
@@ -0,0 +1,36 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+
+Kernel driver sl28cpld
+======================
+
+Supported chips:
+
+   * Kontron sl28cpld
+
+     Prefix: 'sl28cpld'
+
+     Datasheet: not available
+
+Authors: Michael Walle <michael@walle.cc>
+
+Description
+-----------
+
+The sl28cpld is a board management controller which also exposes a hardware
+monitoring controller. At the moment this controller supports a single fan
+supervisor. In the future there might be other flavours and additional
+hardware monitoring might be supported.
+
+The fan supervisor has a 7 bit counter register and a counter period of 1
+second. If the 7 bit counter overflows, the supervisor will automatically
+switch to x8 mode to support a wider input range at the loss of
+granularity.
+
+Sysfs entries
+-------------
+
+The following attributes are supported.
+
+======================= ========================================================
+fan1_input		Fan RPM. Assuming 2 pulses per revolution.
+======================= ========================================================
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index a08765c80a49..cefa8b1e3af1 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1414,6 +1414,16 @@ config SENSORS_RASPBERRYPI_HWMON
 	  This driver can also be built as a module. If so, the module
 	  will be called raspberrypi-hwmon.
 
+config SENSORS_SL28CPLD
+	tristate "Kontron sl28cpl hardware monitoring driver"
+	depends on MFD_SL28CPLD
+	help
+	  If you say yes here you get support for the fan supervisor of the
+	  sl28cpld board management controller.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called sl28cpld-hwmon.
+
 config SENSORS_SHT15
 	tristate "Sensiron humidity and temperature sensors. SHT15 and compat."
 	depends on GPIOLIB || COMPILE_TEST
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index b0b9c8e57176..dfb0f8cda2dd 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -155,6 +155,7 @@ obj-$(CONFIG_SENSORS_S3C)	+= s3c-hwmon.o
 obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o
 obj-$(CONFIG_SENSORS_SCH5627)	+= sch5627.o
 obj-$(CONFIG_SENSORS_SCH5636)	+= sch5636.o
+obj-$(CONFIG_SENSORS_SL28CPLD)	+= sl28cpld-hwmon.o
 obj-$(CONFIG_SENSORS_SHT15)	+= sht15.o
 obj-$(CONFIG_SENSORS_SHT21)	+= sht21.o
 obj-$(CONFIG_SENSORS_SHT3x)	+= sht3x.o
diff --git a/drivers/hwmon/sl28cpld-hwmon.c b/drivers/hwmon/sl28cpld-hwmon.c
new file mode 100644
index 000000000000..c79bdfed8332
--- /dev/null
+++ b/drivers/hwmon/sl28cpld-hwmon.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * sl28cpld hardware monitoring driver.
+ *
+ * Copyright 2019 Kontron Europe GmbH
+ */
+
+#include <linux/bitfield.h>
+#include <linux/hwmon.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define FAN_INPUT		0x00
+#define   FAN_SCALE_X8		BIT(7)
+#define   FAN_VALUE_MASK	GENMASK(6, 0)
+
+struct sl28cpld_hwmon {
+	struct regmap *regmap;
+	u32 offset;
+};
+
+static umode_t sl28cpld_hwmon_is_visible(const void *data,
+					 enum hwmon_sensor_types type,
+					 u32 attr, int channel)
+{
+	return 0444;
+}
+
+static int sl28cpld_hwmon_read(struct device *dev,
+			       enum hwmon_sensor_types type, u32 attr,
+			       int channel, long *input)
+{
+	struct sl28cpld_hwmon *hwmon = dev_get_drvdata(dev);
+	unsigned int value;
+	int ret;
+
+	switch (attr) {
+	case hwmon_fan_input:
+		ret = regmap_read(hwmon->regmap, hwmon->offset + FAN_INPUT,
+				  &value);
+		if (ret)
+			return ret;
+		/*
+		 * The register has a 7 bit value and 1 bit which indicates the
+		 * scale. If the MSB is set, then the lower 7 bit has to be
+		 * multiplied by 8, to get the correct reading.
+		 */
+		if (value & FAN_SCALE_X8)
+			value = FIELD_GET(FAN_VALUE_MASK, value) << 3;
+
+		/*
+		 * The counter period is 1000ms and the sysfs specification
+		 * says we should asssume 2 pulses per revolution.
+		 */
+		value *= 60 / 2;
+
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	*input = value;
+	return 0;
+}
+
+static const u32 sl28cpld_hwmon_fan_config[] = {
+	HWMON_F_INPUT,
+	0
+};
+
+static const struct hwmon_channel_info sl28cpld_hwmon_fan = {
+	.type = hwmon_fan,
+	.config = sl28cpld_hwmon_fan_config,
+};
+
+static const struct hwmon_channel_info *sl28cpld_hwmon_info[] = {
+	&sl28cpld_hwmon_fan,
+	NULL
+};
+
+static const struct hwmon_ops sl28cpld_hwmon_ops = {
+	.is_visible = sl28cpld_hwmon_is_visible,
+	.read = sl28cpld_hwmon_read,
+};
+
+static const struct hwmon_chip_info sl28cpld_hwmon_chip_info = {
+	.ops = &sl28cpld_hwmon_ops,
+	.info = sl28cpld_hwmon_info,
+};
+
+static int sl28cpld_hwmon_probe(struct platform_device *pdev)
+{
+	struct device *hwmon_dev;
+	struct sl28cpld_hwmon *hwmon;
+	struct resource *res;
+
+	if (!pdev->dev.parent)
+		return -ENODEV;
+
+	hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
+	if (!hwmon)
+		return -ENOMEM;
+
+	hwmon->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!hwmon->regmap)
+		return -ENODEV;
+
+	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
+	if (!res)
+		return -EINVAL;
+	hwmon->offset = res->start;
+
+	hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
+				"sl28cpld_hwmon", hwmon,
+				&sl28cpld_hwmon_chip_info, NULL);
+	if (IS_ERR(hwmon_dev)) {
+		dev_err(&pdev->dev, "failed to register as hwmon device");
+		return PTR_ERR(hwmon_dev);
+	}
+
+	return 0;
+}
+
+static const struct of_device_id sl28cpld_hwmon_of_match[] = {
+	{ .compatible = "kontron,sl28cpld-fan" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, sl28cpld_hwmon_of_match);
+
+static const struct platform_device_id sl28cpld_hwmon_id_table[] = {
+	{ "sl28cpld-fan" },
+	{}
+};
+MODULE_DEVICE_TABLE(platform, sl28cpld_hwmon_id_table);
+
+static struct platform_driver sl28cpld_hwmon_driver = {
+	.probe = sl28cpld_hwmon_probe,
+	.id_table = sl28cpld_hwmon_id_table,
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.of_match_table = sl28cpld_hwmon_of_match,
+	},
+};
+module_platform_driver(sl28cpld_hwmon_driver);
+
+MODULE_DESCRIPTION("sl28cpld Hardware Monitoring Driver");
+MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
+MODULE_LICENSE("GPL");
-- 
2.20.1


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

* [PATCH v3 13/16] arm64: dts: freescale: sl28: enable sl28cpld
  2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
                   ` (11 preceding siblings ...)
  2020-04-23 17:45 ` [PATCH v3 12/16] hwmon: add support for the sl28cpld hardware monitoring controller Michael Walle
@ 2020-04-23 17:45 ` Michael Walle
  2020-04-23 17:45 ` [PATCH v3 14/16] arm64: dts: freescale: sl28: map GPIOs to input events Michael Walle
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle

Add the board management controller node.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 .../freescale/fsl-ls1028a-kontron-sl28.dts    | 92 +++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28.dts
index 41ba38adc906..b73794d57db4 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28.dts
@@ -8,6 +8,7 @@
 
 /dts-v1/;
 #include "fsl-ls1028a.dtsi"
+#include <dt-bindings/interrupt-controller/irq.h>
 
 / {
 	model = "Kontron SMARC-sAL28";
@@ -174,6 +175,97 @@
 		reg = <0x32>;
 	};
 
+	sl28cpld: sl28cpld@4a {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "kontron,sl28cpld";
+		reg = <0x4a>;
+		interrupts-extended = <&gpio2 6 IRQ_TYPE_EDGE_FALLING>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		watchdog@0 {
+			compatible = "kontron,sl28cpld-wdt";
+			reg = <0>;
+			kontron,assert-wdt-timeout-pin;
+		};
+
+		hwmon@4 {
+			compatible = "kontron,sl28cpld-fan";
+			reg = <1>;
+		};
+
+		sl28cpld_pwm0: pwm@5 {
+			#pwm-cells = <2>;
+			compatible = "kontron,sl28cpld-pwm";
+			reg = <2>;
+		};
+
+		sl28cpld_pwm1: pwm@6 {
+			#pwm-cells = <2>;
+			compatible = "kontron,sl28cpld-pwm";
+			reg = <3>;
+		};
+
+		sl28cpld_gpio0: gpio@0 {
+			compatible = "kontron,sl28cpld-gpio";
+			reg = <4>;
+
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-line-names =
+				"GPIO0_CAM0_PWR_N", "GPIO1_CAM1_PWR_N",
+				"GPIO2_CAM0_RST_N", "GPIO3_CAM1_RST_N",
+				"GPIO4_HDA_RST_N", "GPIO5_PWM_OUT",
+				"GPIO6_TACHIN", "GPIO7";
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		sl28cpld_gpio1: gpio@1 {
+			compatible = "kontron,sl28cpld-gpio";
+			reg = <5>;
+
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-line-names =
+				"GPIO8", "GPIO9", "GPIO10", "GPIO11",
+				"", "", "", "";
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		sl28cpld_gpio2: gpio@2 {
+			compatible = "kontron,sl28cpld-gpo";
+			reg = <6>;
+
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-line-names =
+				"LCD0 voltage enable",
+				"LCD0 backlight enable",
+				"eMMC reset", "LVDS bridge reset",
+				"LVDS bridge power-down",
+				"SDIO power enable",
+				"", "";
+		};
+
+		sl28cpld_gpio3: gpio@3 {
+			compatible = "kontron,sl28cpld-gpi";
+			reg = <7>;
+
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-line-names =
+				"Power button", "Force recovery", "Sleep",
+				"Battery low", "Lid state", "Charging",
+				"Charger present", "";
+		};
+	};
+
 	eeprom@50 {
 		compatible = "atmel,24c32";
 		reg = <0x50>;
-- 
2.20.1


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

* [PATCH v3 14/16] arm64: dts: freescale: sl28: map GPIOs to input events
  2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
                   ` (12 preceding siblings ...)
  2020-04-23 17:45 ` [PATCH v3 13/16] arm64: dts: freescale: sl28: enable sl28cpld Michael Walle
@ 2020-04-23 17:45 ` Michael Walle
  2020-04-23 17:45 ` [PATCH v3 15/16] arm64: dts: freescale: sl28: enable LED support Michael Walle
  2020-04-23 17:45 ` [PATCH v3 16/16] arm64: dts: freescale: sl28: enable fan support Michael Walle
  15 siblings, 0 replies; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle

Now that we have support for GPIO lines of the SMARC connector, map the
sleep, power and lid switch signals to the corresponding keys using the
gpio-keys and gpio-keys-polled drivers. The power and sleep signals have
dedicated interrupts, thus we use these ones. The lid switch is just
mapped to a GPIO input and needs polling.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 .../freescale/fsl-ls1028a-kontron-sl28.dts    | 32 +++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28.dts
index b73794d57db4..263ce50b0b79 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28.dts
@@ -9,6 +9,8 @@
 /dts-v1/;
 #include "fsl-ls1028a.dtsi"
 #include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 
 / {
 	model = "Kontron SMARC-sAL28";
@@ -23,6 +25,36 @@
 		spi1 = &dspi2;
 	};
 
+	buttons0 {
+		compatible = "gpio-keys";
+
+		power-button {
+			interrupts-extended = <&sl28cpld
+					       4 IRQ_TYPE_EDGE_BOTH>;
+			linux,code = <KEY_POWER>;
+			label = "Power";
+		};
+
+		sleep-button {
+			interrupts-extended = <&sl28cpld
+					       5 IRQ_TYPE_EDGE_BOTH>;
+			linux,code = <KEY_SLEEP>;
+			label = "Sleep";
+		};
+	};
+
+	buttons1 {
+		compatible = "gpio-keys-polled";
+		poll-interval = <200>;
+
+		lid-switch {
+			linux,input-type = <EV_SW>;
+			linux,code = <SW_LID>;
+			gpios = <&sl28cpld_gpio3 4 GPIO_ACTIVE_LOW>;
+			label = "Lid";
+		};
+	};
+
 	chosen {
 		stdout-path = "serial0:115200n8";
 	};
-- 
2.20.1


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

* [PATCH v3 15/16] arm64: dts: freescale: sl28: enable LED support
  2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
                   ` (13 preceding siblings ...)
  2020-04-23 17:45 ` [PATCH v3 14/16] arm64: dts: freescale: sl28: map GPIOs to input events Michael Walle
@ 2020-04-23 17:45 ` Michael Walle
  2020-04-23 17:45 ` [PATCH v3 16/16] arm64: dts: freescale: sl28: enable fan support Michael Walle
  15 siblings, 0 replies; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle

Now that we have support for GPIO lines of the SMARC connector, enable
LED support on the KBox A-230-LS. There are two LEDs without fixed
functions, one is yellow and one is green. Unfortunately, it is just one
multi-color LED, thus while it is possible to enable both at the same
time it is hard to tell the difference between "yellow only" and "yellow
and green".

Signed-off-by: Michael Walle <michael@walle.cc>
---
 .../fsl-ls1028a-kontron-kbox-a-230-ls.dts          | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-kbox-a-230-ls.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-kbox-a-230-ls.dts
index 4b4cc6a1573d..49cf4fe05c80 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-kbox-a-230-ls.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-kbox-a-230-ls.dts
@@ -16,6 +16,20 @@
 	model = "Kontron KBox A-230-LS";
 	compatible = "kontron,kbox-a-230-ls", "kontron,sl28-var4",
 		     "kontron,sl28", "fsl,ls1028a";
+
+	leds {
+		compatible = "gpio-leds";
+
+		user_yellow {
+			label = "s1914:yellow:user";
+			gpios = <&sl28cpld_gpio0 0 0>;
+		};
+
+		user_green {
+			label = "s1914:green:user";
+			gpios = <&sl28cpld_gpio1 3 0>;
+		};
+	};
 };
 
 &enetc_mdio_pf3 {
-- 
2.20.1


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

* [PATCH v3 16/16] arm64: dts: freescale: sl28: enable fan support
  2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
                   ` (14 preceding siblings ...)
  2020-04-23 17:45 ` [PATCH v3 15/16] arm64: dts: freescale: sl28: enable LED support Michael Walle
@ 2020-04-23 17:45 ` Michael Walle
  15 siblings, 0 replies; 60+ messages in thread
From: Michael Walle @ 2020-04-23 17:45 UTC (permalink / raw)
  To: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Michael Walle

Add a pwm-fan mapped to the PWM channel 0 which is connected to the
fan connector of the carrier.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 .../dts/freescale/fsl-ls1028a-kontron-sl28-var3-ads2.dts | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28-var3-ads2.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28-var3-ads2.dts
index 0973a6a45217..c45d7b40e374 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28-var3-ads2.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28-var3-ads2.dts
@@ -15,6 +15,15 @@
 	compatible = "kontron,sl28-var3-ads2", "kontron,sl28-var3",
 		     "kontron,sl28", "fsl,ls1028a";
 
+	pwm-fan {
+		compatible = "pwm-fan";
+		cooling-min-state = <0>;
+		cooling-max-state = <3>;
+		#cooling-cells = <2>;
+		pwms = <&sl28cpld_pwm0 0 4000000>;
+		cooling-levels = <1 128 192 255>;
+	};
+
 	sound {
 		#address-cells = <1>;
 		#size-cells = <0>;
-- 
2.20.1


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

* Re: [PATCH v3 07/16] watchdog: add support for sl28cpld watchdog
  2020-04-23 17:45 ` [PATCH v3 07/16] watchdog: add support for sl28cpld watchdog Michael Walle
@ 2020-04-25 17:02   ` Guenter Roeck
  0 siblings, 0 replies; 60+ messages in thread
From: Guenter Roeck @ 2020-04-25 17:02 UTC (permalink / raw)
  To: Michael Walle, Andy Shevchenko, linux-gpio, devicetree,
	linux-kernel, linux-hwmon, linux-pwm, linux-watchdog,
	linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman

On 4/23/20 10:45 AM, Michael Walle wrote:
> This adds support for the watchdog of the sl28cpld board management
> controller. This is part of a multi-function device driver.
> 
> Signed-off-by: Michael Walle <michael@walle.cc>

Acked-by: Guenter Roeck <linux@roeck-us.net>

> ---
>  drivers/watchdog/Kconfig        |  11 ++
>  drivers/watchdog/Makefile       |   1 +
>  drivers/watchdog/sl28cpld_wdt.c | 233 ++++++++++++++++++++++++++++++++
>  3 files changed, 245 insertions(+)
>  create mode 100644 drivers/watchdog/sl28cpld_wdt.c
> 
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index 0663c604bd64..6c53c1d0f348 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -340,6 +340,17 @@ config MLX_WDT
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called mlx-wdt.
>  
> +config SL28CPLD_WATCHDOG
> +	tristate "Kontron sl28 watchdog"
> +	depends on MFD_SL28CPLD
> +	select WATCHDOG_CORE
> +	help
> +	  Say Y here to include support for the watchdog timer
> +	  on the Kontron sl28 CPLD.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called sl28cpld_wdt.
> +
>  # ALPHA Architecture
>  
>  # ARM Architecture
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index 6de2e4ceef19..b9ecdf2d7347 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -224,3 +224,4 @@ obj-$(CONFIG_MENF21BMC_WATCHDOG) += menf21bmc_wdt.o
>  obj-$(CONFIG_MENZ069_WATCHDOG) += menz69_wdt.o
>  obj-$(CONFIG_RAVE_SP_WATCHDOG) += rave-sp-wdt.o
>  obj-$(CONFIG_STPMIC1_WATCHDOG) += stpmic1_wdt.o
> +obj-$(CONFIG_SL28CPLD_WATCHDOG) += sl28cpld_wdt.o
> diff --git a/drivers/watchdog/sl28cpld_wdt.c b/drivers/watchdog/sl28cpld_wdt.c
> new file mode 100644
> index 000000000000..2640084ace5c
> --- /dev/null
> +++ b/drivers/watchdog/sl28cpld_wdt.c
> @@ -0,0 +1,233 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * sl28cpld watchdog driver.
> + *
> + * Copyright 2019 Kontron Europe GmbH
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/watchdog.h>
> +
> +/*
> + * Watchdog timer block registers.
> + */
> +#define WDT_CTRL			0x00
> +#define  WDT_CTRL_EN			BIT(0)
> +#define  WDT_CTRL_LOCK			BIT(2)
> +#define  WDT_CTRL_ASSERT_SYS_RESET	BIT(6)
> +#define  WDT_CTRL_ASSERT_WDT_TIMEOUT	BIT(7)
> +#define WDT_TIMEOUT			0x01
> +#define WDT_KICK			0x02
> +#define  WDT_KICK_VALUE			0x6b
> +#define WDT_COUNT			0x03
> +
> +#define WDT_DEFAULT_TIMEOUT		10
> +
> +static bool nowayout = WATCHDOG_NOWAYOUT;
> +module_param(nowayout, bool, 0);
> +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
> +				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
> +
> +static int timeout;
> +module_param(timeout, int, 0);
> +MODULE_PARM_DESC(timeout, "Initial watchdog timeout in seconds");
> +
> +struct sl28cpld_wdt {
> +	struct watchdog_device wdd;
> +	struct regmap *regmap;
> +	u32 offset;
> +	bool assert_wdt_timeout;
> +};
> +
> +static int sl28cpld_wdt_ping(struct watchdog_device *wdd)
> +{
> +	struct sl28cpld_wdt *wdt = watchdog_get_drvdata(wdd);
> +
> +	return regmap_write(wdt->regmap, wdt->offset + WDT_KICK,
> +			    WDT_KICK_VALUE);
> +}
> +
> +static int sl28cpld_wdt_start(struct watchdog_device *wdd)
> +{
> +	struct sl28cpld_wdt *wdt = watchdog_get_drvdata(wdd);
> +	unsigned int val;
> +
> +	val = WDT_CTRL_EN | WDT_CTRL_ASSERT_SYS_RESET;
> +	if (wdt->assert_wdt_timeout)
> +		val |= WDT_CTRL_ASSERT_WDT_TIMEOUT;
> +	if (nowayout)
> +		val |= WDT_CTRL_LOCK;
> +
> +	return regmap_update_bits(wdt->regmap, wdt->offset + WDT_CTRL,
> +				  val, val);
> +}
> +
> +static int sl28cpld_wdt_stop(struct watchdog_device *wdd)
> +{
> +	struct sl28cpld_wdt *wdt = watchdog_get_drvdata(wdd);
> +
> +	return regmap_update_bits(wdt->regmap, wdt->offset + WDT_CTRL,
> +				  WDT_CTRL_EN, 0);
> +}
> +
> +static unsigned int sl28cpld_wdt_get_timeleft(struct watchdog_device *wdd)
> +{
> +	struct sl28cpld_wdt *wdt = watchdog_get_drvdata(wdd);
> +	unsigned int val;
> +	int ret;
> +
> +	ret = regmap_read(wdt->regmap, wdt->offset + WDT_COUNT, &val);
> +
> +	return (ret < 0) ? 0 : val;
> +}
> +
> +static int sl28cpld_wdt_set_timeout(struct watchdog_device *wdd,
> +				    unsigned int timeout)
> +{
> +	struct sl28cpld_wdt *wdt = watchdog_get_drvdata(wdd);
> +	int ret;
> +
> +	ret = regmap_write(wdt->regmap, wdt->offset + WDT_TIMEOUT, timeout);
> +	if (!ret)
> +		wdd->timeout = timeout;
> +
> +	return ret;
> +}
> +
> +static const struct watchdog_info sl28cpld_wdt_info = {
> +	.options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
> +	.identity = "sl28cpld watchdog",
> +};
> +
> +static struct watchdog_ops sl28cpld_wdt_ops = {
> +	.owner = THIS_MODULE,
> +	.start = sl28cpld_wdt_start,
> +	.stop = sl28cpld_wdt_stop,
> +	.ping = sl28cpld_wdt_ping,
> +	.set_timeout = sl28cpld_wdt_set_timeout,
> +	.get_timeleft = sl28cpld_wdt_get_timeleft,
> +};
> +
> +static int sl28cpld_wdt_probe(struct platform_device *pdev)
> +{
> +	struct watchdog_device *wdd;
> +	struct sl28cpld_wdt *wdt;
> +	struct resource *res;
> +	unsigned int status;
> +	unsigned int val;
> +	int ret;
> +
> +	if (!pdev->dev.parent)
> +		return -ENODEV;
> +
> +	wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
> +	if (!wdt)
> +		return -ENOMEM;
> +
> +	wdt->regmap = dev_get_regmap(pdev->dev.parent, NULL);
> +	if (!wdt->regmap)
> +		return -ENODEV;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
> +	if (!res)
> +		return -EINVAL;
> +	wdt->offset = res->start;
> +
> +	wdt->assert_wdt_timeout = device_property_read_bool(&pdev->dev,
> +							    "kontron,assert-wdt-timeout-pin");
> +
> +	/* initialize struct watchdog_device */
> +	wdd = &wdt->wdd;
> +	wdd->parent = &pdev->dev;
> +	wdd->info = &sl28cpld_wdt_info;
> +	wdd->ops = &sl28cpld_wdt_ops;
> +	wdd->min_timeout = 1;
> +	wdd->max_timeout = 255;
> +
> +	watchdog_set_drvdata(wdd, wdt);
> +	watchdog_stop_on_reboot(wdd);
> +
> +	/*
> +	 * Read the status early, in case of an error, we haven't modified the
> +	 * hardware.
> +	 */
> +	ret = regmap_read(wdt->regmap, wdt->offset + WDT_CTRL, &status);
> +	if (ret < 0)
> +		return ret;
> +
> +	/*
> +	 * Initial timeout value, may be overwritten by device tree or module
> +	 * parmeter in watchdog_init_timeout().
> +	 *
> +	 * Reading a zero here means that either the hardware has a default
> +	 * value of zero (which is very unlikely and definitely a hardware
> +	 * bug) or the bootloader set it to zero. In any case, we handle
> +	 * this case gracefully and set out own timeout.
> +	 */
> +	ret = regmap_read(wdt->regmap, wdt->offset + WDT_TIMEOUT, &val);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (val)
> +		wdd->timeout = val;
> +	else
> +		wdd->timeout = WDT_DEFAULT_TIMEOUT;
> +
> +	watchdog_init_timeout(wdd, timeout, &pdev->dev);
> +	sl28cpld_wdt_set_timeout(wdd, wdd->timeout);
> +
> +	/* if the watchdog is locked, we set nowayout */
> +	if (status & WDT_CTRL_LOCK)
> +		nowayout = true;
> +	watchdog_set_nowayout(wdd, nowayout);
> +
> +	/*
> +	 * If watchdog is already running, keep it enabled, but make
> +	 * sure its mode is set correctly.
> +	 */
> +	if (status & WDT_CTRL_EN) {
> +		sl28cpld_wdt_start(wdd);
> +		set_bit(WDOG_HW_RUNNING, &wdd->status);
> +	}
> +
> +	ret = devm_watchdog_register_device(&pdev->dev, wdd);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to register watchdog device\n");
> +		return ret;
> +	}
> +
> +	dev_info(&pdev->dev, "initial timeout %d sec%s\n",
> +		 wdd->timeout, nowayout ? ", nowayout" : "");
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id sl28cpld_wdt_of_match[] = {
> +	{ .compatible = "kontron,sl28cpld-wdt" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, sl28cpld_wdt_of_match);
> +
> +static const struct platform_device_id sl28cpld_wdt_id_table[] = {
> +	{ "sl28cpld-wdt" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(platform, sl28cpld_wdt_id_table);
> +
> +static struct platform_driver sl28cpld_wdt_driver = {
> +	.probe = sl28cpld_wdt_probe,
> +	.id_table = sl28cpld_wdt_id_table,
> +	.driver = {
> +		.name = KBUILD_MODNAME,
> +		.of_match_table = sl28cpld_wdt_of_match,
> +	},
> +};
> +module_platform_driver(sl28cpld_wdt_driver);
> +
> +MODULE_DESCRIPTION("sl28cpld Watchdog Driver");
> +MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
> +MODULE_LICENSE("GPL");
> 


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

* Re: [PATCH v3 06/16] irqchip: add sl28cpld interrupt controller support
  2020-04-23 17:45 ` [PATCH v3 06/16] irqchip: add sl28cpld interrupt controller support Michael Walle
@ 2020-04-27 11:40   ` Thomas Gleixner
  2020-04-27 17:40     ` Michael Walle
  0 siblings, 1 reply; 60+ messages in thread
From: Thomas Gleixner @ 2020-04-27 11:40 UTC (permalink / raw)
  To: Michael Walle, Andy Shevchenko, linux-gpio, devicetree,
	linux-kernel, linux-hwmon, linux-pwm, linux-watchdog,
	linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Jason Cooper, Marc Zyngier,
	Mark Brown, Greg Kroah-Hartman, Michael Walle

Michael Walle <michael@walle.cc> writes:

> This patch adds support for the interrupt controller inside the sl28

git grep 'This patch' Documentation/process/

> CPLD management controller.
>
> +static int sl28cpld_intc_probe(struct platform_device *pdev)
> +{
> +	struct sl28cpld_intc *irqchip;
> +	struct resource *res;
> +	unsigned int irq;
> +	int ret;
> +
> +	if (!pdev->dev.parent)
> +		return -ENODEV;
> +
> +	irqchip = devm_kzalloc(&pdev->dev, sizeof(*irqchip), GFP_KERNEL);
> +	if (!irqchip)
> +		return -ENOMEM;
> +
> +	irqchip->regmap = dev_get_regmap(pdev->dev.parent, NULL);
> +	if (!irqchip->regmap)
> +		return -ENODEV;
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0)
> +		return irq;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
> +	if (!res)
> +		return -EINVAL;
> +
> +	irqchip->chip.name = "sl28cpld-intc";
> +	irqchip->chip.irqs = sl28cpld_irqs;
> +	irqchip->chip.num_irqs = ARRAY_SIZE(sl28cpld_irqs);
> +	irqchip->chip.num_regs = 1;
> +	irqchip->chip.status_base = res->start + INTC_IP;
> +	irqchip->chip.mask_base = res->start + INTC_IE;
> +	irqchip->chip.mask_invert = true,
> +	irqchip->chip.ack_base = res->start + INTC_IP;
> +
> +	ret = devm_regmap_add_irq_chip(&pdev->dev, irqchip->regmap, irq,
> +				       IRQF_SHARED | IRQF_ONESHOT, 0,

What's the point of IRQF_SHARED | IRQF_ONESHOT here?

> +				       &irqchip->chip, &irqchip->irq_data);

Thanks,

        tglx

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

* Re: [PATCH v3 09/16] gpiolib: Introduce gpiochip_irqchip_add_domain()
  2020-04-23 17:45 ` [PATCH v3 09/16] gpiolib: Introduce gpiochip_irqchip_add_domain() Michael Walle
@ 2020-04-27 11:42   ` Thomas Gleixner
  2020-04-27 17:49     ` Michael Walle
  0 siblings, 1 reply; 60+ messages in thread
From: Thomas Gleixner @ 2020-04-27 11:42 UTC (permalink / raw)
  To: Michael Walle, Andy Shevchenko, linux-gpio, devicetree,
	linux-kernel, linux-hwmon, linux-pwm, linux-watchdog,
	linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Jason Cooper, Marc Zyngier,
	Mark Brown, Greg Kroah-Hartman, Michael Walle

Michael Walle <michael@walle.cc> writes:
> This connects an IRQ domain to a gpiochip and reuses
> gpiochip_to_irq().

A little bit more context and explanation why this function is useful
would be appreciated.

> Signed-off-by: Michael Walle <michael@walle.cc>
> ---
>  drivers/gpio/gpiolib.c      | 20 ++++++++++++++++++++
>  include/linux/gpio/driver.h |  3 +++
>  2 files changed, 23 insertions(+)
>
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index 40f2d7f69be2..7b3d7f496b9a 100644
> --- a/drivers/gpio/gpiolib.c
> +++ b/drivers/gpio/gpiolib.c
> @@ -2722,6 +2722,26 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gc,
>  }
>  EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
>  
> +/**
> + * gpiochip_irqchip_add_key() - adds an irqdomain to a gpiochip

Copy & paste is wonderful

> + * @gc: the gpiochip to add the irqchip to
> + * @domain: the irqdomain to add to the gpiochip
> + *
> + * This function adds an IRQ domain to the gpiochip.
> + */
> +int gpiochip_irqchip_add_domain(struct gpio_chip *gc,
> +				struct irq_domain *domain)
> +{
> +	if (!domain)
> +		return -EINVAL;
> +
> +	gc->to_irq = gpiochip_to_irq;
> +	gc->irq.domain = domain;
> +
> +	return 0;
> +}

Thanks,

        tglx

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

* Re: [PATCH v3 11/16] gpio: add support for the sl28cpld GPIO controller
  2020-04-23 17:45 ` [PATCH v3 11/16] gpio: add support for the sl28cpld GPIO controller Michael Walle
@ 2020-04-27 11:45   ` Thomas Gleixner
  2020-04-27 17:58     ` Michael Walle
  0 siblings, 1 reply; 60+ messages in thread
From: Thomas Gleixner @ 2020-04-27 11:45 UTC (permalink / raw)
  To: Michael Walle, Andy Shevchenko, linux-gpio, devicetree,
	linux-kernel, linux-hwmon, linux-pwm, linux-watchdog,
	linux-arm-kernel
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Jason Cooper, Marc Zyngier,
	Mark Brown, Greg Kroah-Hartman, Michael Walle

Michael Walle <michael@walle.cc> writes:
> +struct sl28cpld_gpio {
> +	struct regmap_irq_chip irq_chip;
> +	struct regmap_irq_chip_data *irq_data;
> +};
> +
> +static const struct regmap_irq sl28cpld_gpio_irqs[] = {
> +	REGMAP_IRQ_REG_LINE(0, 8),
> +	REGMAP_IRQ_REG_LINE(1, 8),
> +	REGMAP_IRQ_REG_LINE(2, 8),
> +	REGMAP_IRQ_REG_LINE(3, 8),
> +	REGMAP_IRQ_REG_LINE(4, 8),
> +	REGMAP_IRQ_REG_LINE(5, 8),
> +	REGMAP_IRQ_REG_LINE(6, 8),
> +	REGMAP_IRQ_REG_LINE(7, 8),
> +};

This is exactly the same as the one in the irq chip patch.

> +static int sl28cpld_gpio_irq_init(struct device *dev,
> +				  struct sl28cpld_gpio *gpio,
> +				  struct regmap *regmap, unsigned int base,
> +				  int irq)
> +{
> +	struct regmap_irq_chip *irq_chip = &gpio->irq_chip;
> +
> +	irq_chip->name = "sl28cpld-gpio-irq",
> +	irq_chip->irqs = sl28cpld_gpio_irqs;
> +	irq_chip->num_irqs = ARRAY_SIZE(sl28cpld_gpio_irqs);
> +	irq_chip->num_regs = 1;
> +	irq_chip->status_base = base + GPIO_REG_IP;
> +	irq_chip->mask_base = base + GPIO_REG_IE;
> +	irq_chip->mask_invert = true,
> +	irq_chip->ack_base = base + GPIO_REG_IP;
> +
> +	return devm_regmap_add_irq_chip_np(dev, dev_of_node(dev), regmap,
> +					   irq, IRQF_SHARED | IRQF_ONESHOT, 0,
> +					   irq_chip, &gpio->irq_data);
> +}

And this looks pretty familiar as well. What's the point of duplicating
that code?

Thanks,

        tglx

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

* Re: [PATCH v3 06/16] irqchip: add sl28cpld interrupt controller support
  2020-04-27 11:40   ` Thomas Gleixner
@ 2020-04-27 17:40     ` Michael Walle
  2020-04-27 17:44       ` Mark Brown
  2020-04-27 19:00       ` Thomas Gleixner
  0 siblings, 2 replies; 60+ messages in thread
From: Michael Walle @ 2020-04-27 17:40 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel,
	Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Jason Cooper, Marc Zyngier,
	Mark Brown, Greg Kroah-Hartman

Hi Thomas,

thanks for the review.

Am 2020-04-27 13:40, schrieb Thomas Gleixner:
> Michael Walle <michael@walle.cc> writes:
> 
>> This patch adds support for the interrupt controller inside the sl28
> 
> git grep 'This patch' Documentation/process/

ok.

> 
>> CPLD management controller.
>> 
>> +static int sl28cpld_intc_probe(struct platform_device *pdev)
>> +{
>> +	struct sl28cpld_intc *irqchip;
>> +	struct resource *res;
>> +	unsigned int irq;
>> +	int ret;
>> +
>> +	if (!pdev->dev.parent)
>> +		return -ENODEV;
>> +
>> +	irqchip = devm_kzalloc(&pdev->dev, sizeof(*irqchip), GFP_KERNEL);
>> +	if (!irqchip)
>> +		return -ENOMEM;
>> +
>> +	irqchip->regmap = dev_get_regmap(pdev->dev.parent, NULL);
>> +	if (!irqchip->regmap)
>> +		return -ENODEV;
>> +
>> +	irq = platform_get_irq(pdev, 0);
>> +	if (irq < 0)
>> +		return irq;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
>> +	if (!res)
>> +		return -EINVAL;
>> +
>> +	irqchip->chip.name = "sl28cpld-intc";
>> +	irqchip->chip.irqs = sl28cpld_irqs;
>> +	irqchip->chip.num_irqs = ARRAY_SIZE(sl28cpld_irqs);
>> +	irqchip->chip.num_regs = 1;
>> +	irqchip->chip.status_base = res->start + INTC_IP;
>> +	irqchip->chip.mask_base = res->start + INTC_IE;
>> +	irqchip->chip.mask_invert = true,
>> +	irqchip->chip.ack_base = res->start + INTC_IP;
>> +
>> +	ret = devm_regmap_add_irq_chip(&pdev->dev, irqchip->regmap, irq,
>> +				       IRQF_SHARED | IRQF_ONESHOT, 0,
> 
> What's the point of IRQF_SHARED | IRQF_ONESHOT here?

IRQF_SHARED because this interrupt is shared with all the blocks
which can generate interrupts, i.e. the GPIO contollers.

IRQF_ONESHOT, because its is a threaded interrupt with no primary
handler. But I just noticed, that regmap-irq will also set the
IRQF_ONESHOT. But that the commit 09cadf6e088b ("regmap-irq:
set IRQF_ONESHOT flag to ensure IRQ request") reads like it is
just there to be sure. So I don't know if it should also be set
here.

-michael

> 
>> +				       &irqchip->chip, &irqchip->irq_data);
> 
> Thanks,
> 
>         tglx

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

* Re: [PATCH v3 06/16] irqchip: add sl28cpld interrupt controller support
  2020-04-27 17:40     ` Michael Walle
@ 2020-04-27 17:44       ` Mark Brown
  2020-04-27 18:01         ` Michael Walle
  2020-04-27 19:00       ` Thomas Gleixner
  1 sibling, 1 reply; 60+ messages in thread
From: Mark Brown @ 2020-04-27 17:44 UTC (permalink / raw)
  To: Michael Walle
  Cc: Thomas Gleixner, Andy Shevchenko, linux-gpio, devicetree,
	linux-kernel, linux-hwmon, linux-pwm, linux-watchdog,
	linux-arm-kernel, Linus Walleij, Bartosz Golaszewski,
	Rob Herring, Jean Delvare, Guenter Roeck, Lee Jones,
	Thierry Reding, Uwe Kleine-König, Wim Van Sebroeck,
	Shawn Guo, Li Yang, Jason Cooper, Marc Zyngier,
	Greg Kroah-Hartman


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

On Mon, Apr 27, 2020 at 07:40:11PM +0200, Michael Walle wrote:

> IRQF_ONESHOT, because its is a threaded interrupt with no primary
> handler. But I just noticed, that regmap-irq will also set the
> IRQF_ONESHOT. But that the commit 09cadf6e088b ("regmap-irq:
> set IRQF_ONESHOT flag to ensure IRQ request") reads like it is
> just there to be sure. So I don't know if it should also be set
> here.

Looking at the changelog there the "we can't be sure" bit is that
coccinelle couldn't follow the flags through from the caller to make
sure that IRQF_ONESHOT is set so we're just oring it in unconditionally.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH v3 09/16] gpiolib: Introduce gpiochip_irqchip_add_domain()
  2020-04-27 11:42   ` Thomas Gleixner
@ 2020-04-27 17:49     ` Michael Walle
  0 siblings, 0 replies; 60+ messages in thread
From: Michael Walle @ 2020-04-27 17:49 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel,
	Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Jason Cooper, Marc Zyngier,
	Mark Brown, Greg Kroah-Hartman

Am 2020-04-27 13:42, schrieb Thomas Gleixner:
> Michael Walle <michael@walle.cc> writes:
>> This connects an IRQ domain to a gpiochip and reuses
>> gpiochip_to_irq().
> 
> A little bit more context and explanation why this function is useful
> would be appreciated.

Ok I'll try to be a bit more elaborate the in the next version, (if
this function is still there).

For now:

gpiochip_irqchip_add_domain() allows to use reqmap-irq, which exports
an irqdomain, with gpiolib while reusing gpiochip_to_irq(). Both
gpiochip_irqchip_* and regmap_irq partially provides the same
functionality. The new function will help to connect just the
minimal functionality of the gpiochip_irqchip which is needed to
work together with regmap-irq.

> 
>> Signed-off-by: Michael Walle <michael@walle.cc>
>> ---
>>  drivers/gpio/gpiolib.c      | 20 ++++++++++++++++++++
>>  include/linux/gpio/driver.h |  3 +++
>>  2 files changed, 23 insertions(+)
>> 
>> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
>> index 40f2d7f69be2..7b3d7f496b9a 100644
>> --- a/drivers/gpio/gpiolib.c
>> +++ b/drivers/gpio/gpiolib.c
>> @@ -2722,6 +2722,26 @@ int gpiochip_irqchip_add_key(struct gpio_chip 
>> *gc,
>>  }
>>  EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
>> 
>> +/**
>> + * gpiochip_irqchip_add_key() - adds an irqdomain to a gpiochip
> 
> Copy & paste is wonderful

whoops.

-michael

> 
>> + * @gc: the gpiochip to add the irqchip to
>> + * @domain: the irqdomain to add to the gpiochip
>> + *
>> + * This function adds an IRQ domain to the gpiochip.
>> + */
>> +int gpiochip_irqchip_add_domain(struct gpio_chip *gc,
>> +				struct irq_domain *domain)
>> +{
>> +	if (!domain)
>> +		return -EINVAL;
>> +
>> +	gc->to_irq = gpiochip_to_irq;
>> +	gc->irq.domain = domain;
>> +
>> +	return 0;
>> +}
> 
> Thanks,
> 
>         tglx

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

* Re: [PATCH v3 11/16] gpio: add support for the sl28cpld GPIO controller
  2020-04-27 11:45   ` Thomas Gleixner
@ 2020-04-27 17:58     ` Michael Walle
  0 siblings, 0 replies; 60+ messages in thread
From: Michael Walle @ 2020-04-27 17:58 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel,
	Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Jason Cooper, Marc Zyngier,
	Mark Brown, Greg Kroah-Hartman

Am 2020-04-27 13:45, schrieb Thomas Gleixner:
> Michael Walle <michael@walle.cc> writes:
>> +struct sl28cpld_gpio {
>> +	struct regmap_irq_chip irq_chip;
>> +	struct regmap_irq_chip_data *irq_data;
>> +};
>> +
>> +static const struct regmap_irq sl28cpld_gpio_irqs[] = {
>> +	REGMAP_IRQ_REG_LINE(0, 8),
>> +	REGMAP_IRQ_REG_LINE(1, 8),
>> +	REGMAP_IRQ_REG_LINE(2, 8),
>> +	REGMAP_IRQ_REG_LINE(3, 8),
>> +	REGMAP_IRQ_REG_LINE(4, 8),
>> +	REGMAP_IRQ_REG_LINE(5, 8),
>> +	REGMAP_IRQ_REG_LINE(6, 8),
>> +	REGMAP_IRQ_REG_LINE(7, 8),
>> +};
> 
> This is exactly the same as the one in the irq chip patch.

To my knowledge this boilerplate is just to describe this
irqchip has 8 different IRQs.

>> +static int sl28cpld_gpio_irq_init(struct device *dev,
>> +				  struct sl28cpld_gpio *gpio,
>> +				  struct regmap *regmap, unsigned int base,
>> +				  int irq)
>> +{
>> +	struct regmap_irq_chip *irq_chip = &gpio->irq_chip;
>> +
>> +	irq_chip->name = "sl28cpld-gpio-irq",
>> +	irq_chip->irqs = sl28cpld_gpio_irqs;
>> +	irq_chip->num_irqs = ARRAY_SIZE(sl28cpld_gpio_irqs);
>> +	irq_chip->num_regs = 1;
>> +	irq_chip->status_base = base + GPIO_REG_IP;
>> +	irq_chip->mask_base = base + GPIO_REG_IE;
>> +	irq_chip->mask_invert = true,
>> +	irq_chip->ack_base = base + GPIO_REG_IP;
>> +
>> +	return devm_regmap_add_irq_chip_np(dev, dev_of_node(dev), regmap,
>> +					   irq, IRQF_SHARED | IRQF_ONESHOT, 0,
>> +					   irq_chip, &gpio->irq_data);
>> +}
> 
> And this looks pretty familiar as well. What's the point of duplicating
> that code?

this is also just boilerplate to configure the irqchip. But there are 
two
distinct blocks inside the board management controller:
  - an interrupt controller (which has 8 interrupts)
  - and gpio controllers which also happen to have 8 interrupts and
    both have some shared semantics for now. But the GPIO building block
    might be extended to provide interrupt type settings, i.e. falling/
    rising/level triggered interrupts.

So yes both look similar, but they are two different blocks, they use
different registers and they might drift apart in the future.

-michael

> 
> Thanks,
> 
>         tglx

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

* Re: [PATCH v3 06/16] irqchip: add sl28cpld interrupt controller support
  2020-04-27 17:44       ` Mark Brown
@ 2020-04-27 18:01         ` Michael Walle
  2020-04-27 18:05           ` Mark Brown
  0 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-04-27 18:01 UTC (permalink / raw)
  To: Mark Brown
  Cc: Thomas Gleixner, Andy Shevchenko, linux-gpio, devicetree,
	linux-kernel, linux-hwmon, linux-pwm, linux-watchdog,
	linux-arm-kernel, Linus Walleij, Bartosz Golaszewski,
	Rob Herring, Jean Delvare, Guenter Roeck, Lee Jones,
	Thierry Reding, Uwe Kleine-König, Wim Van Sebroeck,
	Shawn Guo, Li Yang, Jason Cooper, Marc Zyngier,
	Greg Kroah-Hartman

Am 2020-04-27 19:44, schrieb Mark Brown:
> On Mon, Apr 27, 2020 at 07:40:11PM +0200, Michael Walle wrote:
> 
>> IRQF_ONESHOT, because its is a threaded interrupt with no primary
>> handler. But I just noticed, that regmap-irq will also set the
>> IRQF_ONESHOT. But that the commit 09cadf6e088b ("regmap-irq:
>> set IRQF_ONESHOT flag to ensure IRQ request") reads like it is
>> just there to be sure. So I don't know if it should also be set
>> here.
> 
> Looking at the changelog there the "we can't be sure" bit is that
> coccinelle couldn't follow the flags through from the caller to make
> sure that IRQF_ONESHOT is set so we're just oring it in 
> unconditionally.

So it is correct that IRQF_ONESHOT is also set in the driver which is
using regmap_add_irq_chip(), right?

-michael

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

* Re: [PATCH v3 06/16] irqchip: add sl28cpld interrupt controller support
  2020-04-27 18:01         ` Michael Walle
@ 2020-04-27 18:05           ` Mark Brown
  0 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2020-04-27 18:05 UTC (permalink / raw)
  To: Michael Walle
  Cc: Thomas Gleixner, Andy Shevchenko, linux-gpio, devicetree,
	linux-kernel, linux-hwmon, linux-pwm, linux-watchdog,
	linux-arm-kernel, Linus Walleij, Bartosz Golaszewski,
	Rob Herring, Jean Delvare, Guenter Roeck, Lee Jones,
	Thierry Reding, Uwe Kleine-König, Wim Van Sebroeck,
	Shawn Guo, Li Yang, Jason Cooper, Marc Zyngier,
	Greg Kroah-Hartman


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

On Mon, Apr 27, 2020 at 08:01:14PM +0200, Michael Walle wrote:
> Am 2020-04-27 19:44, schrieb Mark Brown:

> > Looking at the changelog there the "we can't be sure" bit is that
> > coccinelle couldn't follow the flags through from the caller to make
> > sure that IRQF_ONESHOT is set so we're just oring it in unconditionally.

> So it is correct that IRQF_ONESHOT is also set in the driver which is
> using regmap_add_irq_chip(), right?

It shouldn't break anything and my instinct is that it's better form.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH v3 06/16] irqchip: add sl28cpld interrupt controller support
  2020-04-27 17:40     ` Michael Walle
  2020-04-27 17:44       ` Mark Brown
@ 2020-04-27 19:00       ` Thomas Gleixner
  1 sibling, 0 replies; 60+ messages in thread
From: Thomas Gleixner @ 2020-04-27 19:00 UTC (permalink / raw)
  To: Michael Walle
  Cc: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel,
	Linus Walleij, Bartosz Golaszewski, Rob Herring, Jean Delvare,
	Guenter Roeck, Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Jason Cooper, Marc Zyngier,
	Mark Brown, Greg Kroah-Hartman

Michael,

Michael Walle <michael@walle.cc> writes:
> Am 2020-04-27 13:40, schrieb Thomas Gleixner:
>>> +
>>> +	ret = devm_regmap_add_irq_chip(&pdev->dev, irqchip->regmap, irq,
>>> +				       IRQF_SHARED | IRQF_ONESHOT, 0,
>> 
>> What's the point of IRQF_SHARED | IRQF_ONESHOT here?
>
> IRQF_SHARED because this interrupt is shared with all the blocks
> which can generate interrupts, i.e. the GPIO contollers.

Why are people still designing hardware with shared interrupts? Shared
interrupts are broken by design and that's well known for decades.

> IRQF_ONESHOT, because its is a threaded interrupt with no primary
> handler. But I just noticed, that regmap-irq will also set the
> IRQF_ONESHOT. But that the commit 09cadf6e088b ("regmap-irq:
> set IRQF_ONESHOT flag to ensure IRQ request") reads like it is
> just there to be sure. So I don't know if it should also be set
> here.

Ok. Wasn't aware of that magic threaded interrupt connection.

Thanks,

        tglx

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

* Re: [PATCH v3 02/16] mfd: mfd-core: Don't overwrite the dma_mask of the child device
  2020-04-23 17:45 ` [PATCH v3 02/16] mfd: mfd-core: Don't overwrite the dma_mask of the child device Michael Walle
@ 2020-04-28 12:45   ` Andy Shevchenko
  2020-04-28 13:06     ` Robin Murphy
  0 siblings, 1 reply; 60+ messages in thread
From: Andy Shevchenko @ 2020-04-28 12:45 UTC (permalink / raw)
  To: Michael Walle
  Cc: linux-gpio, devicetree, linux-kernel, linux-hwmon, linux-pwm,
	linux-watchdog, linux-arm-kernel, Linus Walleij,
	Bartosz Golaszewski, Rob Herring, Jean Delvare, Guenter Roeck,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman,
	Robin Murphy

On Thu, Apr 23, 2020 at 07:45:29PM +0200, Michael Walle wrote:
> Commit cdfee5623290 ("driver core: initialize a default DMA mask for
> platform device") initialize the DMA of a platform device. But if the
> parent doesn't have a dma_mask set, for example if it's an I2C device,
> the dma_mask of the child platform device will be set to zero again.
> Which leads to many "DMA mask not set" warnings, if the MFD cell has the
> of_compatible property set.

I'm wondering why parent doesn't have it.
I remember we have explicit patches in the past for buses such as PCI and AMBA
to set default DMA mask for all physical devices on the respective bus, of
course they can individually override it later.

So, this seems to me a paper over the real issue (absence of default DMA mask
where it's needed) and devices should explicitly define it if they disagree
with default.

If I'm wrong, you really need elaborate commit message much better.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v3 04/16] dt-bindings: mfd: Add bindings for sl28cpld
  2020-04-23 17:45 ` [PATCH v3 04/16] dt-bindings: mfd: Add bindings for sl28cpld Michael Walle
@ 2020-04-28 12:48   ` Andy Shevchenko
  2020-04-28 14:39     ` Michael Walle
  0 siblings, 1 reply; 60+ messages in thread
From: Andy Shevchenko @ 2020-04-28 12:48 UTC (permalink / raw)
  To: Michael Walle
  Cc: linux-gpio, devicetree, linux-kernel, linux-hwmon, linux-pwm,
	linux-watchdog, linux-arm-kernel, Linus Walleij,
	Bartosz Golaszewski, Rob Herring, Jean Delvare, Guenter Roeck,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman

On Thu, Apr 23, 2020 at 07:45:31PM +0200, Michael Walle wrote:
> This adds device tree bindings for the board management controller found
> on the Kontron SMARC-sAL28 board.

I think it should be independent patches (same way as you do for drivers).

>  .../bindings/gpio/kontron,sl28cpld-gpio.yaml  |  51 ++++++
>  .../hwmon/kontron,sl28cpld-hwmon.yaml         |  27 +++
>  .../bindings/mfd/kontron,sl28cpld.yaml        | 162 ++++++++++++++++++
>  .../bindings/pwm/kontron,sl28cpld-pwm.yaml    |  35 ++++
>  .../watchdog/kontron,sl28cpld-wdt.yaml        |  35 ++++

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v3 05/16] mfd: Add support for Kontron sl28cpld management controller
  2020-04-23 17:45 ` [PATCH v3 05/16] mfd: Add support for Kontron sl28cpld management controller Michael Walle
@ 2020-04-28 12:50   ` Andy Shevchenko
  2020-04-28 14:43     ` Michael Walle
  2020-05-11 21:13   ` Rob Herring
  1 sibling, 1 reply; 60+ messages in thread
From: Andy Shevchenko @ 2020-04-28 12:50 UTC (permalink / raw)
  To: Michael Walle
  Cc: linux-gpio, devicetree, linux-kernel, linux-hwmon, linux-pwm,
	linux-watchdog, linux-arm-kernel, Linus Walleij,
	Bartosz Golaszewski, Rob Herring, Jean Delvare, Guenter Roeck,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman

On Thu, Apr 23, 2020 at 07:45:32PM +0200, Michael Walle wrote:
> This patch adds core support for the board management controller found
> on the SMARC-sAL28 board. It consists of the following functions:
>  - watchdog
>  - GPIO controller
>  - PWM controller
>  - fan sensor
>  - interrupt controller

...

>  obj-$(CONFIG_MFD_STMFX) 	+= stmfx.o
>  
>  obj-$(CONFIG_SGI_MFD_IOC3)	+= ioc3.o
> +
> +obj-$(CONFIG_MFD_SL28CPLD)	+= sl28cpld.o

Perhaps keep an order?

...

> +	return devm_mfd_add_devices(dev, -1, sl28cpld_devs,

-1 has its own definition.

> +				    ARRAY_SIZE(sl28cpld_devs), NULL,
> +				    i2c->irq, NULL);
> +}

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v3 02/16] mfd: mfd-core: Don't overwrite the dma_mask of the child device
  2020-04-28 12:45   ` Andy Shevchenko
@ 2020-04-28 13:06     ` Robin Murphy
  2020-04-28 14:29       ` Andy Shevchenko
  0 siblings, 1 reply; 60+ messages in thread
From: Robin Murphy @ 2020-04-28 13:06 UTC (permalink / raw)
  To: Andy Shevchenko, Michael Walle
  Cc: linux-gpio, devicetree, linux-kernel, linux-hwmon, linux-pwm,
	linux-watchdog, linux-arm-kernel, Linus Walleij,
	Bartosz Golaszewski, Rob Herring, Jean Delvare, Guenter Roeck,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman

On 2020-04-28 1:45 pm, Andy Shevchenko wrote:
> On Thu, Apr 23, 2020 at 07:45:29PM +0200, Michael Walle wrote:
>> Commit cdfee5623290 ("driver core: initialize a default DMA mask for
>> platform device") initialize the DMA of a platform device. But if the
>> parent doesn't have a dma_mask set, for example if it's an I2C device,
>> the dma_mask of the child platform device will be set to zero again.
>> Which leads to many "DMA mask not set" warnings, if the MFD cell has the
>> of_compatible property set.
> 
> I'm wondering why parent doesn't have it.

Because the parent isn't on a DMA-capable bus, and thus really shouldn't 
have a valid DMA configuration ever.

> I remember we have explicit patches in the past for buses such as PCI and AMBA
> to set default DMA mask for all physical devices on the respective bus, of
> course they can individually override it later.
> 
> So, this seems to me a paper over the real issue (absence of default DMA mask
> where it's needed) and devices should explicitly define it if they disagree
> with default.
> 
> If I'm wrong, you really need elaborate commit message much better.

The problem here is that MFD children are created as platform devices 
(regardless of what their parent is) and assigned an of_node, at which 
point they look pretty much indistinguishable from SoC devices created 
by the of_platform code, that *do* have to be assumed to be DMA-capable 
to prevent ~90% of existing devicetrees from breaking.

Of course the real fundamental issue is the platform bus itself, but 
it's way too late to fix that :(

Robin.

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

* Re: [PATCH v3 02/16] mfd: mfd-core: Don't overwrite the dma_mask of the child device
  2020-04-28 13:06     ` Robin Murphy
@ 2020-04-28 14:29       ` Andy Shevchenko
  2020-04-28 14:49         ` Robin Murphy
  0 siblings, 1 reply; 60+ messages in thread
From: Andy Shevchenko @ 2020-04-28 14:29 UTC (permalink / raw)
  To: Robin Murphy
  Cc: Michael Walle, linux-gpio, devicetree, linux-kernel, linux-hwmon,
	linux-pwm, linux-watchdog, linux-arm-kernel, Linus Walleij,
	Bartosz Golaszewski, Rob Herring, Jean Delvare, Guenter Roeck,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman

On Tue, Apr 28, 2020 at 02:06:20PM +0100, Robin Murphy wrote:
> On 2020-04-28 1:45 pm, Andy Shevchenko wrote:
> > On Thu, Apr 23, 2020 at 07:45:29PM +0200, Michael Walle wrote:
> > > Commit cdfee5623290 ("driver core: initialize a default DMA mask for
> > > platform device") initialize the DMA of a platform device. But if the
> > > parent doesn't have a dma_mask set, for example if it's an I2C device,
> > > the dma_mask of the child platform device will be set to zero again.
> > > Which leads to many "DMA mask not set" warnings, if the MFD cell has the
> > > of_compatible property set.
> > 
> > I'm wondering why parent doesn't have it.
> 
> Because the parent isn't on a DMA-capable bus, and thus really shouldn't
> have a valid DMA configuration ever.

Then how come a child is DMA capable? MFD takes a physical device node as a
parent and creates one of several children with that device as a parent. DMA
mask is a property of the device which *does DMA*. Obviously a child is not
correct device for that.

Where am I mistaken?

> > I remember we have explicit patches in the past for buses such as PCI and AMBA
> > to set default DMA mask for all physical devices on the respective bus, of
> > course they can individually override it later.
> > 
> > So, this seems to me a paper over the real issue (absence of default DMA mask
> > where it's needed) and devices should explicitly define it if they disagree
> > with default.
> > 
> > If I'm wrong, you really need elaborate commit message much better.
> 
> The problem here is that MFD children are created as platform devices
> (regardless of what their parent is) and assigned an of_node, at which point
> they look pretty much indistinguishable from SoC devices created by the
> of_platform code, that *do* have to be assumed to be DMA-capable to prevent
> ~90% of existing devicetrees from breaking.
> 
> Of course the real fundamental issue is the platform bus itself, but it's
> way too late to fix that :(

I don't think it's an issue, rather in model you are describing. Or I miss
something not so obvious.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v3 04/16] dt-bindings: mfd: Add bindings for sl28cpld
  2020-04-28 12:48   ` Andy Shevchenko
@ 2020-04-28 14:39     ` Michael Walle
  2020-04-28 14:49       ` Andy Shevchenko
  0 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-04-28 14:39 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: linux-gpio, devicetree, linux-kernel, linux-hwmon, linux-pwm,
	linux-watchdog, linux-arm-kernel, Linus Walleij,
	Bartosz Golaszewski, Rob Herring, Jean Delvare, Guenter Roeck,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman

Am 2020-04-28 14:48, schrieb Andy Shevchenko:
> On Thu, Apr 23, 2020 at 07:45:31PM +0200, Michael Walle wrote:
>> This adds device tree bindings for the board management controller 
>> found
>> on the Kontron SMARC-sAL28 board.
> 
> I think it should be independent patches (same way as you do for 
> drivers).

It used to be several patches but Rob suggested to put it into one:
https://lore.kernel.org/linux-devicetree/20200330223535.GA31402@bogus/

-michael

> 
>>  .../bindings/gpio/kontron,sl28cpld-gpio.yaml  |  51 ++++++
>>  .../hwmon/kontron,sl28cpld-hwmon.yaml         |  27 +++
>>  .../bindings/mfd/kontron,sl28cpld.yaml        | 162 
>> ++++++++++++++++++
>>  .../bindings/pwm/kontron,sl28cpld-pwm.yaml    |  35 ++++
>>  .../watchdog/kontron,sl28cpld-wdt.yaml        |  35 ++++

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

* Re: [PATCH v3 05/16] mfd: Add support for Kontron sl28cpld management controller
  2020-04-28 12:50   ` Andy Shevchenko
@ 2020-04-28 14:43     ` Michael Walle
  2020-04-28 14:49       ` Andy Shevchenko
  0 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-04-28 14:43 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: linux-gpio, devicetree, linux-kernel, linux-hwmon, linux-pwm,
	linux-watchdog, linux-arm-kernel, Linus Walleij,
	Bartosz Golaszewski, Rob Herring, Jean Delvare, Guenter Roeck,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman

Am 2020-04-28 14:50, schrieb Andy Shevchenko:
> On Thu, Apr 23, 2020 at 07:45:32PM +0200, Michael Walle wrote:
>> This patch adds core support for the board management controller found
>> on the SMARC-sAL28 board. It consists of the following functions:
>>  - watchdog
>>  - GPIO controller
>>  - PWM controller
>>  - fan sensor
>>  - interrupt controller
> 
> ...
> 
>>  obj-$(CONFIG_MFD_STMFX) 	+= stmfx.o
>> 
>>  obj-$(CONFIG_SGI_MFD_IOC3)	+= ioc3.o
>> +
>> +obj-$(CONFIG_MFD_SL28CPLD)	+= sl28cpld.o
> 
> Perhaps keep an order?

I don't see any order in that makefile. Looked to me like every new
file was added at the end.

> 
> ...
> 
>> +	return devm_mfd_add_devices(dev, -1, sl28cpld_devs,
> 
> -1 has its own definition.

ok, I'll replace that by PLATFORM_DEVID_NONE.

Thanks,
-michael

> 
>> +				    ARRAY_SIZE(sl28cpld_devs), NULL,
>> +				    i2c->irq, NULL);
>> +}

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

* Re: [PATCH v3 04/16] dt-bindings: mfd: Add bindings for sl28cpld
  2020-04-28 14:39     ` Michael Walle
@ 2020-04-28 14:49       ` Andy Shevchenko
  0 siblings, 0 replies; 60+ messages in thread
From: Andy Shevchenko @ 2020-04-28 14:49 UTC (permalink / raw)
  To: Michael Walle
  Cc: linux-gpio, devicetree, linux-kernel, linux-hwmon, linux-pwm,
	linux-watchdog, linux-arm-kernel, Linus Walleij,
	Bartosz Golaszewski, Rob Herring, Jean Delvare, Guenter Roeck,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman

On Tue, Apr 28, 2020 at 04:39:44PM +0200, Michael Walle wrote:
> Am 2020-04-28 14:48, schrieb Andy Shevchenko:
> > On Thu, Apr 23, 2020 at 07:45:31PM +0200, Michael Walle wrote:
> > > This adds device tree bindings for the board management controller
> > > found
> > > on the Kontron SMARC-sAL28 board.
> > 
> > I think it should be independent patches (same way as you do for
> > drivers).
> 
> It used to be several patches but Rob suggested to put it into one:
> https://lore.kernel.org/linux-devicetree/20200330223535.GA31402@bogus/

Ah, okay.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v3 02/16] mfd: mfd-core: Don't overwrite the dma_mask of the child device
  2020-04-28 14:29       ` Andy Shevchenko
@ 2020-04-28 14:49         ` Robin Murphy
  2020-04-28 15:25           ` Mark Brown
  0 siblings, 1 reply; 60+ messages in thread
From: Robin Murphy @ 2020-04-28 14:49 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Michael Walle, linux-gpio, devicetree, linux-kernel, linux-hwmon,
	linux-pwm, linux-watchdog, linux-arm-kernel, Linus Walleij,
	Bartosz Golaszewski, Rob Herring, Jean Delvare, Guenter Roeck,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman

On 2020-04-28 3:29 pm, Andy Shevchenko wrote:
> On Tue, Apr 28, 2020 at 02:06:20PM +0100, Robin Murphy wrote:
>> On 2020-04-28 1:45 pm, Andy Shevchenko wrote:
>>> On Thu, Apr 23, 2020 at 07:45:29PM +0200, Michael Walle wrote:
>>>> Commit cdfee5623290 ("driver core: initialize a default DMA mask for
>>>> platform device") initialize the DMA of a platform device. But if the
>>>> parent doesn't have a dma_mask set, for example if it's an I2C device,
>>>> the dma_mask of the child platform device will be set to zero again.
>>>> Which leads to many "DMA mask not set" warnings, if the MFD cell has the
>>>> of_compatible property set.
>>>
>>> I'm wondering why parent doesn't have it.
>>
>> Because the parent isn't on a DMA-capable bus, and thus really shouldn't
>> have a valid DMA configuration ever.
> 
> Then how come a child is DMA capable?

Because it's a platform device, and thanks to decades of legacy we have 
to assume that any platform devices *is* DMA capable.

> MFD takes a physical device node as a
> parent and creates one of several children with that device as a parent. DMA
> mask is a property of the device which *does DMA*. Obviously a child is not
> correct device for that.
> 
> Where am I mistaken?

In theory you're not, however in practice the driver model doesn't 
really give us a nice way to express the necessary subtle distinctions 
between this and other similar-looking but fundamentally different 
parent-child relationships - if it did, we probably wouldn't need the 
whole MFD layer in the first place. The logical ideal would be to create 
the children on the same bus as the parent, but as it is doing that 
would likely lead to the I2C/SPI/whatever bus code assuming they are 
first-class devices and open up a whole new world of problems.

For better or worse, the platform bus is the dumping ground for random 
crap, so we just have to deal with all the abstraction breakage that 
leaks out of that.

Robin.

>>> I remember we have explicit patches in the past for buses such as PCI and AMBA
>>> to set default DMA mask for all physical devices on the respective bus, of
>>> course they can individually override it later.
>>>
>>> So, this seems to me a paper over the real issue (absence of default DMA mask
>>> where it's needed) and devices should explicitly define it if they disagree
>>> with default.
>>>
>>> If I'm wrong, you really need elaborate commit message much better.
>>
>> The problem here is that MFD children are created as platform devices
>> (regardless of what their parent is) and assigned an of_node, at which point
>> they look pretty much indistinguishable from SoC devices created by the
>> of_platform code, that *do* have to be assumed to be DMA-capable to prevent
>> ~90% of existing devicetrees from breaking.
>>
>> Of course the real fundamental issue is the platform bus itself, but it's
>> way too late to fix that :(
> 
> I don't think it's an issue, rather in model you are describing. Or I miss
> something not so obvious.
> 

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

* Re: [PATCH v3 05/16] mfd: Add support for Kontron sl28cpld management controller
  2020-04-28 14:43     ` Michael Walle
@ 2020-04-28 14:49       ` Andy Shevchenko
  2020-04-29  6:27         ` Lee Jones
  0 siblings, 1 reply; 60+ messages in thread
From: Andy Shevchenko @ 2020-04-28 14:49 UTC (permalink / raw)
  To: Michael Walle
  Cc: linux-gpio, devicetree, linux-kernel, linux-hwmon, linux-pwm,
	linux-watchdog, linux-arm-kernel, Linus Walleij,
	Bartosz Golaszewski, Rob Herring, Jean Delvare, Guenter Roeck,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman

On Tue, Apr 28, 2020 at 04:43:24PM +0200, Michael Walle wrote:
> Am 2020-04-28 14:50, schrieb Andy Shevchenko:
> > On Thu, Apr 23, 2020 at 07:45:32PM +0200, Michael Walle wrote:
> > > This patch adds core support for the board management controller found
> > > on the SMARC-sAL28 board. It consists of the following functions:
> > >  - watchdog
> > >  - GPIO controller
> > >  - PWM controller
> > >  - fan sensor
> > >  - interrupt controller
> > 
> > ...
> > 
> > >  obj-$(CONFIG_MFD_STMFX) 	+= stmfx.o
> > > 
> > >  obj-$(CONFIG_SGI_MFD_IOC3)	+= ioc3.o
> > > +
> > > +obj-$(CONFIG_MFD_SL28CPLD)	+= sl28cpld.o
> > 
> > Perhaps keep an order?
> 
> I don't see any order in that makefile. Looked to me like every new
> file was added at the end.

Okay, just didn't note from above context.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v3 02/16] mfd: mfd-core: Don't overwrite the dma_mask of the child device
  2020-04-28 14:49         ` Robin Murphy
@ 2020-04-28 15:25           ` Mark Brown
  2020-05-14 20:45             ` Michael Walle
  0 siblings, 1 reply; 60+ messages in thread
From: Mark Brown @ 2020-04-28 15:25 UTC (permalink / raw)
  To: Robin Murphy
  Cc: Andy Shevchenko, Michael Walle, linux-gpio, devicetree,
	linux-kernel, linux-hwmon, linux-pwm, linux-watchdog,
	linux-arm-kernel, Linus Walleij, Bartosz Golaszewski,
	Rob Herring, Jean Delvare, Guenter Roeck, Lee Jones,
	Thierry Reding, Uwe Kleine-König, Wim Van Sebroeck,
	Shawn Guo, Li Yang, Thomas Gleixner, Jason Cooper, Marc Zyngier,
	Greg Kroah-Hartman


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

On Tue, Apr 28, 2020 at 03:49:49PM +0100, Robin Murphy wrote:

> For better or worse, the platform bus is the dumping ground for random crap,
> so we just have to deal with all the abstraction breakage that leaks out of
> that.

The reason we're using the platform bus for this is that historically
people were creating buses which were essentially carbon copies of the
platform bus with the name changed and it was felt that rather than
duplicate code it was better to just use platform devices with no MMIO
ranges defined.  If there's some assumptions about DMA for platform
devices floating about somewhere it might be reasonable to revisit this
and create a non-DMA variant of platform devices since there is a
meaningful difference.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH v3 05/16] mfd: Add support for Kontron sl28cpld management controller
  2020-04-28 14:49       ` Andy Shevchenko
@ 2020-04-29  6:27         ` Lee Jones
  0 siblings, 0 replies; 60+ messages in thread
From: Lee Jones @ 2020-04-29  6:27 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Michael Walle, linux-gpio, devicetree, linux-kernel, linux-hwmon,
	linux-pwm, linux-watchdog, linux-arm-kernel, Linus Walleij,
	Bartosz Golaszewski, Rob Herring, Jean Delvare, Guenter Roeck,
	Thierry Reding, Uwe Kleine-König, Wim Van Sebroeck,
	Shawn Guo, Li Yang, Thomas Gleixner, Jason Cooper, Marc Zyngier,
	Mark Brown, Greg Kroah-Hartman

On Tue, 28 Apr 2020, Andy Shevchenko wrote:

> On Tue, Apr 28, 2020 at 04:43:24PM +0200, Michael Walle wrote:
> > Am 2020-04-28 14:50, schrieb Andy Shevchenko:
> > > On Thu, Apr 23, 2020 at 07:45:32PM +0200, Michael Walle wrote:
> > > > This patch adds core support for the board management controller found
> > > > on the SMARC-sAL28 board. It consists of the following functions:
> > > >  - watchdog
> > > >  - GPIO controller
> > > >  - PWM controller
> > > >  - fan sensor
> > > >  - interrupt controller
> > > 
> > > ...
> > > 
> > > >  obj-$(CONFIG_MFD_STMFX) 	+= stmfx.o
> > > > 
> > > >  obj-$(CONFIG_SGI_MFD_IOC3)	+= ioc3.o
> > > > +
> > > > +obj-$(CONFIG_MFD_SL28CPLD)	+= sl28cpld.o
> > > 
> > > Perhaps keep an order?
> > 
> > I don't see any order in that makefile. Looked to me like every new
> > file was added at the end.
> 
> Okay, just didn't note from above context.

Yes, this is historical.  I've been meaning to visit this for ~7 years!

-- 
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

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

* Re: [PATCH v3 03/16] mfd: mfd-core: match device tree node against reg property
  2020-04-23 17:45 ` [PATCH v3 03/16] mfd: mfd-core: match device tree node against reg property Michael Walle
@ 2020-04-29 22:18   ` Michael Walle
  2020-05-15 10:28     ` Lee Jones
  0 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-04-29 22:18 UTC (permalink / raw)
  To: Lee Jones
  Cc: Andy Shevchenko, Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Jean Delvare, Guenter Roeck, Thierry Reding,
	Uwe Kleine-König, Wim Van Sebroeck, Shawn Guo, Li Yang,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Mark Brown,
	Greg Kroah-Hartman, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel

Hi Lee,

Am 2020-04-23 19:45, schrieb Michael Walle:
> There might be multiple children with the device tree compatible, for
> example if a MFD has multiple instances of the same function. In this
> case only the first is matched and the other children get a wrong
> of_node reference.
> Add a new option to match also against the unit address of the child
> node. Additonally, a new helper OF_MFD_CELL_REG is added.


Do you think this is feasible? I guess this is the biggest uncertainty
for me at the moment in this patch series.

-michael

> 
> Signed-off-by: Michael Walle <michael@walle.cc>
> ---
>  drivers/mfd/mfd-core.c   | 29 ++++++++++++++++++++---------
>  include/linux/mfd/core.h | 26 ++++++++++++++++++++------
>  2 files changed, 40 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
> index e735565969b3..4ecb376338f7 100644
> --- a/drivers/mfd/mfd-core.c
> +++ b/drivers/mfd/mfd-core.c
> @@ -117,6 +117,7 @@ static int mfd_add_device(struct device *parent, 
> int id,
>  	struct device_node *np = NULL;
>  	int ret = -ENOMEM;
>  	int platform_id;
> +	u32 of_reg;
>  	int r;
> 
>  	if (id == PLATFORM_DEVID_AUTO)
> @@ -151,16 +152,26 @@ static int mfd_add_device(struct device *parent, 
> int id,
> 
>  	if (parent->of_node && cell->of_compatible) {
>  		for_each_child_of_node(parent->of_node, np) {
> -			if (of_device_is_compatible(np, cell->of_compatible)) {
> -				if (!of_device_is_available(np)) {
> -					/* Ignore disabled devices error free */
> -					ret = 0;
> -					goto fail_alias;
> -				}
> -				pdev->dev.of_node = np;
> -				pdev->dev.fwnode = &np->fwnode;
> -				break;
> +			if (!of_device_is_compatible(np, cell->of_compatible))
> +				continue;
> +
> +			/* also match the unit address if set */
> +			if (cell->of_reg & MFD_OF_REG_VALID) {
> +				if (of_property_read_u32(np, "reg", &of_reg))
> +					continue;
> +				if ((cell->of_reg & MFD_OF_REG_MASK) != of_reg)
> +					continue;
>  			}
> +
> +			if (!of_device_is_available(np)) {
> +				/* Ignore disabled devices error free */
> +				ret = 0;
> +				goto fail_alias;
> +			}
> +
> +			pdev->dev.of_node = np;
> +			pdev->dev.fwnode = &np->fwnode;
> +			break;
>  		}
>  	}
> 
> diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
> index d01d1299e49d..c2c0ad6b14f3 100644
> --- a/include/linux/mfd/core.h
> +++ b/include/linux/mfd/core.h
> @@ -13,8 +13,11 @@
>  #include <linux/platform_device.h>
> 
>  #define MFD_RES_SIZE(arr) (sizeof(arr) / sizeof(struct resource))
> +#define MFD_OF_REG_VALID	BIT(31)
> +#define MFD_OF_REG_MASK		GENMASK(30, 0)
> 
> -#define MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, 
> _match)\
> +#define MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat,	\
> +		     _of_reg, _match)					\
>  	{								\
>  		.name = (_name),					\
>  		.resources = (_res),					\
> @@ -22,24 +25,32 @@
>  		.platform_data = (_pdata),				\
>  		.pdata_size = (_pdsize),				\
>  		.of_compatible = (_compat),				\
> +		.of_reg = (_of_reg),					\
>  		.acpi_match = (_match),					\
>  		.id = (_id),						\
>  	}
> 
> +#define OF_MFD_CELL_REG(_name, _res, _pdata, _pdsize, _id, _compat,	\
> +			_of_reg)					\
> +	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat,	\
> +		     ((_of_reg) | MFD_OF_REG_VALID), NULL)		\
> +
>  #define OF_MFD_CELL(_name, _res, _pdata, _pdsize,_id, _compat)		\
> -	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, NULL)	\
> +	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat,	\
> +		     0, NULL)						\
> 
>  #define ACPI_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _match)	\
> -	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, _match)	\
> +	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, 0,	\
> +		     _match)						\
> 
>  #define MFD_CELL_BASIC(_name, _res, _pdata, _pdsize, _id)		\
> -	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, NULL)	\
> +	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, 0, NULL) \
> 
>  #define MFD_CELL_RES(_name, _res)					\
> -	MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, NULL)		\
> +	MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, 0, NULL)		\
> 
>  #define MFD_CELL_NAME(_name)						\
> -	MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, NULL)		\
> +	MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, 0, NULL)		\
> 
>  struct irq_domain;
>  struct property_entry;
> @@ -78,6 +89,9 @@ struct mfd_cell {
>  	 */
>  	const char		*of_compatible;
> 
> +	/* matching the reg property if set */
> +	unsigned int		of_reg;
> +
>  	/* Matches ACPI */
>  	const struct mfd_cell_acpi_match	*acpi_match;

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

* Re: [PATCH v3 08/16] pwm: add support for sl28cpld PWM controller
  2020-04-23 17:45 ` [PATCH v3 08/16] pwm: add support for sl28cpld PWM controller Michael Walle
@ 2020-05-11 20:45   ` Rob Herring
  0 siblings, 0 replies; 60+ messages in thread
From: Rob Herring @ 2020-05-11 20:45 UTC (permalink / raw)
  To: Michael Walle
  Cc: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel,
	Linus Walleij, Bartosz Golaszewski, Jean Delvare, Guenter Roeck,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman

On Thu, Apr 23, 2020 at 07:45:35PM +0200, Michael Walle wrote:
> This adds support for the PWM controller of the sl28cpld board
> management controller. This is part of a multi-function device driver.
> 
> Signed-off-by: Michael Walle <michael@walle.cc>
> ---
>  drivers/pwm/Kconfig        |  10 ++
>  drivers/pwm/Makefile       |   1 +
>  drivers/pwm/pwm-sl28cpld.c | 203 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 214 insertions(+)
>  create mode 100644 drivers/pwm/pwm-sl28cpld.c


> +static const struct of_device_id sl28cpld_pwm_of_match[] = {
> +	{ .compatible = "kontron,sl28cpld-pwm" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, sl28cpld_pwm_of_match);
> +
> +static const struct platform_device_id sl28cpld_pwm_id_table[] = {
> +	{"sl28cpld-gpio"},

copy-n-paste error?

> +	{},
> +};
> +MODULE_DEVICE_TABLE(platform, sl28cpld_pwm_id_table);
> +
> +static struct platform_driver sl28cpld_pwm_driver = {
> +	.probe = sl28cpld_pwm_probe,
> +	.remove	= sl28cpld_pwm_remove,
> +	.id_table = sl28cpld_pwm_id_table,
> +	.driver = {
> +		.name = KBUILD_MODNAME,
> +		.of_match_table = sl28cpld_pwm_of_match,
> +	},
> +};
> +module_platform_driver(sl28cpld_pwm_driver);
> +
> +MODULE_DESCRIPTION("sl28cpld PWM Driver");
> +MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
> +MODULE_LICENSE("GPL");
> -- 
> 2.20.1
> 

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

* Re: [PATCH v3 05/16] mfd: Add support for Kontron sl28cpld management controller
  2020-04-23 17:45 ` [PATCH v3 05/16] mfd: Add support for Kontron sl28cpld management controller Michael Walle
  2020-04-28 12:50   ` Andy Shevchenko
@ 2020-05-11 21:13   ` Rob Herring
  2020-05-11 21:44     ` Michael Walle
  1 sibling, 1 reply; 60+ messages in thread
From: Rob Herring @ 2020-05-11 21:13 UTC (permalink / raw)
  To: Michael Walle
  Cc: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel,
	Linus Walleij, Bartosz Golaszewski, Jean Delvare, Guenter Roeck,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman

On Thu, Apr 23, 2020 at 07:45:32PM +0200, Michael Walle wrote:
> This patch adds core support for the board management controller found
> on the SMARC-sAL28 board. It consists of the following functions:
>  - watchdog
>  - GPIO controller
>  - PWM controller
>  - fan sensor
>  - interrupt controller
> 
> At the moment, this controller is used on the Kontron SMARC-sAL28 board.
> 
> Please note that the MFD driver is defined as bool in the Kconfig
> because the next patch will add interrupt support.
> 
> Signed-off-by: Michael Walle <michael@walle.cc>
> ---
>  drivers/mfd/Kconfig    |  19 +++++
>  drivers/mfd/Makefile   |   2 +
>  drivers/mfd/sl28cpld.c | 153 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 174 insertions(+)
>  create mode 100644 drivers/mfd/sl28cpld.c
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 0a59249198d3..be0c8d93c526 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -2060,5 +2060,24 @@ config SGI_MFD_IOC3
>  	  If you have an SGI Origin, Octane, or a PCI IOC3 card,
>  	  then say Y. Otherwise say N.
>  
> +config MFD_SL28CPLD
> +	bool "Kontron sl28 core driver"
> +	depends on I2C=y
> +	depends on OF
> +	select REGMAP_I2C
> +	select MFD_CORE
> +	help
> +	  This option enables support for the board management controller
> +	  found on the Kontron sl28 CPLD. You have to select individual
> +	  functions, such as watchdog, GPIO, etc, under the corresponding menus
> +	  in order to enable them.
> +
> +	  Currently supported boards are:
> +
> +		Kontron SMARC-sAL28
> +
> +	  To compile this driver as a module, choose M here: the module will be
> +	  called sl28cpld.
> +
>  endmenu
>  endif
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index f935d10cbf0f..9bc38863b9c7 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -259,3 +259,5 @@ obj-$(CONFIG_MFD_ROHM_BD718XX)	+= rohm-bd718x7.o
>  obj-$(CONFIG_MFD_STMFX) 	+= stmfx.o
>  
>  obj-$(CONFIG_SGI_MFD_IOC3)	+= ioc3.o
> +
> +obj-$(CONFIG_MFD_SL28CPLD)	+= sl28cpld.o
> diff --git a/drivers/mfd/sl28cpld.c b/drivers/mfd/sl28cpld.c
> new file mode 100644
> index 000000000000..1e5860cc7ffc
> --- /dev/null
> +++ b/drivers/mfd/sl28cpld.c
> @@ -0,0 +1,153 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * MFD core for the sl28cpld.
> + *
> + * Copyright 2019 Kontron Europe GmbH
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/core.h>
> +#include <linux/module.h>
> +#include <linux/of_platform.h>
> +#include <linux/regmap.h>
> +
> +#define SL28CPLD_VERSION	0x03
> +#define SL28CPLD_WATCHDOG_BASE	0x04
> +#define SL28CPLD_HWMON_FAN_BASE	0x0b
> +#define SL28CPLD_PWM0_BASE	0x0c
> +#define SL28CPLD_PWM1_BASE	0x0e
> +#define SL28CPLD_GPIO0_BASE	0x10
> +#define SL28CPLD_GPIO1_BASE	0x15
> +#define SL28CPLD_GPO_BASE	0x1a
> +#define SL28CPLD_GPI_BASE	0x1b
> +#define SL28CPLD_INTC_BASE	0x1c

If you want to use 'reg' in the binding, these are the numbers you 
should be using rather than making up numbering!

However, I still don't think you need any child nodes. All the data in 
the DT binding is right here in the driver already. There's no advantage 
to putting child nodes in DT, because this driver still has to be 
updated if you add more nodes.

Rob

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

* Re: [PATCH v3 05/16] mfd: Add support for Kontron sl28cpld management controller
  2020-05-11 21:13   ` Rob Herring
@ 2020-05-11 21:44     ` Michael Walle
  2020-05-11 22:29       ` Michael Walle
  2020-05-12 21:59       ` Rob Herring
  0 siblings, 2 replies; 60+ messages in thread
From: Michael Walle @ 2020-05-11 21:44 UTC (permalink / raw)
  To: Rob Herring
  Cc: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel,
	Linus Walleij, Bartosz Golaszewski, Jean Delvare, Guenter Roeck,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman

Am 2020-05-11 23:13, schrieb Rob Herring:
> On Thu, Apr 23, 2020 at 07:45:32PM +0200, Michael Walle wrote:
>> This patch adds core support for the board management controller found
>> on the SMARC-sAL28 board. It consists of the following functions:
>>  - watchdog
>>  - GPIO controller
>>  - PWM controller
>>  - fan sensor
>>  - interrupt controller
>> 
>> At the moment, this controller is used on the Kontron SMARC-sAL28 
>> board.
>> 
>> Please note that the MFD driver is defined as bool in the Kconfig
>> because the next patch will add interrupt support.
>> 
>> Signed-off-by: Michael Walle <michael@walle.cc>
>> ---
>>  drivers/mfd/Kconfig    |  19 +++++
>>  drivers/mfd/Makefile   |   2 +
>>  drivers/mfd/sl28cpld.c | 153 
>> +++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 174 insertions(+)
>>  create mode 100644 drivers/mfd/sl28cpld.c
>> 
>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> index 0a59249198d3..be0c8d93c526 100644
>> --- a/drivers/mfd/Kconfig
>> +++ b/drivers/mfd/Kconfig
>> @@ -2060,5 +2060,24 @@ config SGI_MFD_IOC3
>>  	  If you have an SGI Origin, Octane, or a PCI IOC3 card,
>>  	  then say Y. Otherwise say N.
>> 
>> +config MFD_SL28CPLD
>> +	bool "Kontron sl28 core driver"
>> +	depends on I2C=y
>> +	depends on OF
>> +	select REGMAP_I2C
>> +	select MFD_CORE
>> +	help
>> +	  This option enables support for the board management controller
>> +	  found on the Kontron sl28 CPLD. You have to select individual
>> +	  functions, such as watchdog, GPIO, etc, under the corresponding 
>> menus
>> +	  in order to enable them.
>> +
>> +	  Currently supported boards are:
>> +
>> +		Kontron SMARC-sAL28
>> +
>> +	  To compile this driver as a module, choose M here: the module will 
>> be
>> +	  called sl28cpld.
>> +
>>  endmenu
>>  endif
>> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
>> index f935d10cbf0f..9bc38863b9c7 100644
>> --- a/drivers/mfd/Makefile
>> +++ b/drivers/mfd/Makefile
>> @@ -259,3 +259,5 @@ obj-$(CONFIG_MFD_ROHM_BD718XX)	+= rohm-bd718x7.o
>>  obj-$(CONFIG_MFD_STMFX) 	+= stmfx.o
>> 
>>  obj-$(CONFIG_SGI_MFD_IOC3)	+= ioc3.o
>> +
>> +obj-$(CONFIG_MFD_SL28CPLD)	+= sl28cpld.o
>> diff --git a/drivers/mfd/sl28cpld.c b/drivers/mfd/sl28cpld.c
>> new file mode 100644
>> index 000000000000..1e5860cc7ffc
>> --- /dev/null
>> +++ b/drivers/mfd/sl28cpld.c
>> @@ -0,0 +1,153 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * MFD core for the sl28cpld.
>> + *
>> + * Copyright 2019 Kontron Europe GmbH
>> + */
>> +
>> +#include <linux/i2c.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/kernel.h>
>> +#include <linux/mfd/core.h>
>> +#include <linux/module.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/regmap.h>
>> +
>> +#define SL28CPLD_VERSION	0x03
>> +#define SL28CPLD_WATCHDOG_BASE	0x04
>> +#define SL28CPLD_HWMON_FAN_BASE	0x0b
>> +#define SL28CPLD_PWM0_BASE	0x0c
>> +#define SL28CPLD_PWM1_BASE	0x0e
>> +#define SL28CPLD_GPIO0_BASE	0x10
>> +#define SL28CPLD_GPIO1_BASE	0x15
>> +#define SL28CPLD_GPO_BASE	0x1a
>> +#define SL28CPLD_GPI_BASE	0x1b
>> +#define SL28CPLD_INTC_BASE	0x1c
> 
> If you want to use 'reg' in the binding, these are the numbers you
> should be using rather than making up numbering!

My motivation is that I don't want to hardcode the internal addresses
of the management controller in the device tree. For example if they
will move around with a later update of the controller, so a driver can
be compatible with both the old and the new version. If they are in the
device tree, only one register layout is possible.

> However, I still don't think you need any child nodes. All the data in
> the DT binding is right here in the driver already. There's no 
> advantage
> to putting child nodes in DT, because this driver still has to be
> updated if you add more nodes.

But then any phandle will reference the mfd device. And for example 
there
are two different interrupt controllers, that is the INTC and the 
GPIO[01],
which will then be combined into one device tree node, right?

So the mfd node would be

cpld: sl28cpld@4a {
   interrupt-controller;
   #interrupt-cells = <2>;
   gpio-controller;
   #gpio-cells = <2>;
   [..]
};

and then depending on the mapping one could use:

interrupts-extended = <&cpld 0 FLAGS>; /* gpio0 line 0 */
interrupts-extended = <&cpld 8 FLAGS>; /* gpio1 line 0 */
interrupts-extended = <&cpld 12 FLAGS>; /* irq0 */

gpios = <&cpld 0> /* gpio0 line 0 */

But there is also offset 12, but then it is the GPI controller:

gpios = <&cpld 12> /* gpi line 0, nothing to do with irq0 */

I don't know if this is good practice, I guess you have to tell me. And
is it possible to combine any sub device into the mfd node in that way?

-michael

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

* Re: [PATCH v3 05/16] mfd: Add support for Kontron sl28cpld management controller
  2020-05-11 21:44     ` Michael Walle
@ 2020-05-11 22:29       ` Michael Walle
  2020-05-12 21:59       ` Rob Herring
  1 sibling, 0 replies; 60+ messages in thread
From: Michael Walle @ 2020-05-11 22:29 UTC (permalink / raw)
  To: Rob Herring
  Cc: Andy Shevchenko, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel,
	Linus Walleij, Bartosz Golaszewski, Jean Delvare, Guenter Roeck,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman

Am 2020-05-11 23:44, schrieb Michael Walle:
> Am 2020-05-11 23:13, schrieb Rob Herring:
>> On Thu, Apr 23, 2020 at 07:45:32PM +0200, Michael Walle wrote:
>>> This patch adds core support for the board management controller 
>>> found
>>> on the SMARC-sAL28 board. It consists of the following functions:
>>>  - watchdog
>>>  - GPIO controller
>>>  - PWM controller
>>>  - fan sensor
>>>  - interrupt controller
>>> 
>>> At the moment, this controller is used on the Kontron SMARC-sAL28 
>>> board.
>>> 
>>> Please note that the MFD driver is defined as bool in the Kconfig
>>> because the next patch will add interrupt support.
>>> 
>>> Signed-off-by: Michael Walle <michael@walle.cc>
>>> ---
>>>  drivers/mfd/Kconfig    |  19 +++++
>>>  drivers/mfd/Makefile   |   2 +
>>>  drivers/mfd/sl28cpld.c | 153 
>>> +++++++++++++++++++++++++++++++++++++++++
>>>  3 files changed, 174 insertions(+)
>>>  create mode 100644 drivers/mfd/sl28cpld.c
>>> 
>>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>>> index 0a59249198d3..be0c8d93c526 100644
>>> --- a/drivers/mfd/Kconfig
>>> +++ b/drivers/mfd/Kconfig
>>> @@ -2060,5 +2060,24 @@ config SGI_MFD_IOC3
>>>  	  If you have an SGI Origin, Octane, or a PCI IOC3 card,
>>>  	  then say Y. Otherwise say N.
>>> 
>>> +config MFD_SL28CPLD
>>> +	bool "Kontron sl28 core driver"
>>> +	depends on I2C=y
>>> +	depends on OF
>>> +	select REGMAP_I2C
>>> +	select MFD_CORE
>>> +	help
>>> +	  This option enables support for the board management controller
>>> +	  found on the Kontron sl28 CPLD. You have to select individual
>>> +	  functions, such as watchdog, GPIO, etc, under the corresponding 
>>> menus
>>> +	  in order to enable them.
>>> +
>>> +	  Currently supported boards are:
>>> +
>>> +		Kontron SMARC-sAL28
>>> +
>>> +	  To compile this driver as a module, choose M here: the module 
>>> will be
>>> +	  called sl28cpld.
>>> +
>>>  endmenu
>>>  endif
>>> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
>>> index f935d10cbf0f..9bc38863b9c7 100644
>>> --- a/drivers/mfd/Makefile
>>> +++ b/drivers/mfd/Makefile
>>> @@ -259,3 +259,5 @@ obj-$(CONFIG_MFD_ROHM_BD718XX)	+= rohm-bd718x7.o
>>>  obj-$(CONFIG_MFD_STMFX) 	+= stmfx.o
>>> 
>>>  obj-$(CONFIG_SGI_MFD_IOC3)	+= ioc3.o
>>> +
>>> +obj-$(CONFIG_MFD_SL28CPLD)	+= sl28cpld.o
>>> diff --git a/drivers/mfd/sl28cpld.c b/drivers/mfd/sl28cpld.c
>>> new file mode 100644
>>> index 000000000000..1e5860cc7ffc
>>> --- /dev/null
>>> +++ b/drivers/mfd/sl28cpld.c
>>> @@ -0,0 +1,153 @@
>>> +// SPDX-License-Identifier: GPL-2.0-only
>>> +/*
>>> + * MFD core for the sl28cpld.
>>> + *
>>> + * Copyright 2019 Kontron Europe GmbH
>>> + */
>>> +
>>> +#include <linux/i2c.h>
>>> +#include <linux/interrupt.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/mfd/core.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of_platform.h>
>>> +#include <linux/regmap.h>
>>> +
>>> +#define SL28CPLD_VERSION	0x03
>>> +#define SL28CPLD_WATCHDOG_BASE	0x04
>>> +#define SL28CPLD_HWMON_FAN_BASE	0x0b
>>> +#define SL28CPLD_PWM0_BASE	0x0c
>>> +#define SL28CPLD_PWM1_BASE	0x0e
>>> +#define SL28CPLD_GPIO0_BASE	0x10
>>> +#define SL28CPLD_GPIO1_BASE	0x15
>>> +#define SL28CPLD_GPO_BASE	0x1a
>>> +#define SL28CPLD_GPI_BASE	0x1b
>>> +#define SL28CPLD_INTC_BASE	0x1c
>> 
>> If you want to use 'reg' in the binding, these are the numbers you
>> should be using rather than making up numbering!
> 
> My motivation is that I don't want to hardcode the internal addresses
> of the management controller in the device tree. For example if they
> will move around with a later update of the controller, so a driver can
> be compatible with both the old and the new version. If they are in the
> device tree, only one register layout is possible.
> 
>> However, I still don't think you need any child nodes. All the data in
>> the DT binding is right here in the driver already. There's no 
>> advantage
>> to putting child nodes in DT, because this driver still has to be
>> updated if you add more nodes.
> 
> But then any phandle will reference the mfd device. And for example 
> there
> are two different interrupt controllers, that is the INTC and the 
> GPIO[01],
> which will then be combined into one device tree node, right?
> 
> So the mfd node would be
> 
> cpld: sl28cpld@4a {
>   interrupt-controller;
>   #interrupt-cells = <2>;
>   gpio-controller;
>   #gpio-cells = <2>;
>   [..]
> };
> 
> and then depending on the mapping one could use:
> 
> interrupts-extended = <&cpld 0 FLAGS>; /* gpio0 line 0 */
> interrupts-extended = <&cpld 8 FLAGS>; /* gpio1 line 0 */
> interrupts-extended = <&cpld 12 FLAGS>; /* irq0 */
> 
> gpios = <&cpld 0> /* gpio0 line 0 */
> 
> But there is also offset 12, but then it is the GPI controller:
> 
> gpios = <&cpld 12> /* gpi line 0, nothing to do with irq0 */
> 
> I don't know if this is good practice, I guess you have to tell me. And
> is it possible to combine any sub device into the mfd node in that way?

Oh I don't think that will work for the watchdog. If you just have one
watchdog it just looks odd.

cpld: sl28cpld@4a {
    interrupt-controller;
    #interrupt-cells = <2>;
    gpio-controller;
    #gpio-cells = <2>;
    timeout-sec = <10>; /* watchdog property */
};

And won't pass the dtbindings check because the nodename is not
"watchdog(@[0-9]+)?". But it really falls short if you want to have
two watchdogs with different properties.

-michael

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

* Re: [PATCH v3 10/16] gpio: add a reusable generic gpio_chip using regmap
  2020-04-23 17:45 ` [PATCH v3 10/16] gpio: add a reusable generic gpio_chip using regmap Michael Walle
@ 2020-05-12 12:48   ` Bartosz Golaszewski
  2020-05-12 14:41     ` Michael Walle
  0 siblings, 1 reply; 60+ messages in thread
From: Bartosz Golaszewski @ 2020-05-12 12:48 UTC (permalink / raw)
  To: Michael Walle
  Cc: Andy Shevchenko, linux-gpio, linux-devicetree, LKML, linux-hwmon,
	linux-pwm, LINUXWATCHDOG, arm-soc, Linus Walleij, Rob Herring,
	Jean Delvare, Guenter Roeck, Lee Jones, Thierry Reding,
	Uwe Kleine-König, Wim Van Sebroeck, Shawn Guo, Li Yang,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Mark Brown,
	Greg Kroah-Hartman

czw., 23 kwi 2020 o 19:46 Michael Walle <michael@walle.cc> napisał(a):
>
> There are quite a lot simple GPIO controller which are using regmap to
> access the hardware. This driver tries to be a base to unify existing
> code into one place. This won't cover everything but it should be a good
> starting point.
>
> It does not implement its own irq_chip because there is already a
> generic one for regmap based devices. Instead, the irq_chip will be
> instantiated in the parent driver and its irq domain will be associate
> to this driver.
>
> For now it consists of the usual registers, like set (and an optional
> clear) data register, an input register and direction registers.
> Out-of-the-box, it supports consecutive register mappings and mappings
> where the registers have gaps between them with a linear mapping between
> GPIO offset and bit position. For weirder mappings the user can register
> its own .xlate().
>
> Signed-off-by: Michael Walle <michael@walle.cc>
> ---

This looks good to me. Please see some nits below.

>  drivers/gpio/Kconfig        |   4 +
>  drivers/gpio/Makefile       |   1 +
>  drivers/gpio/gpio-regmap.c  | 343 ++++++++++++++++++++++++++++++++++++
>  include/linux/gpio-regmap.h |  69 ++++++++
>  4 files changed, 417 insertions(+)
>  create mode 100644 drivers/gpio/gpio-regmap.c
>  create mode 100644 include/linux/gpio-regmap.h
>
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index 8ef2179fb999..ae3a49a2e970 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -73,6 +73,10 @@ config GPIO_GENERIC
>         depends on HAS_IOMEM # Only for IOMEM drivers
>         tristate
>
> +config GPIO_REGMAP
> +       depends on REGMAP
> +       tristate
> +
>  # put drivers in the right section, in alphabetical order
>
>  # This symbol is selected by both I2C and SPI expanders
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index b2cfc21a97f3..93e139fdfa57 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -12,6 +12,7 @@ obj-$(CONFIG_GPIO_SYSFS)      += gpiolib-sysfs.o
>  obj-$(CONFIG_GPIO_ACPI)                += gpiolib-acpi.o
>
>  # Device drivers. Generally keep list sorted alphabetically
> +obj-$(CONFIG_GPIO_REGMAP)      += gpio-regmap.o
>  obj-$(CONFIG_GPIO_GENERIC)     += gpio-generic.o
>
>  # directly supported by gpio-generic
> diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
> new file mode 100644
> index 000000000000..04939c0a22f9
> --- /dev/null
> +++ b/drivers/gpio/gpio-regmap.c
> @@ -0,0 +1,343 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * regmap based generic GPIO driver
> + *
> + * Copyright 2019 Michael Walle <michael@walle.cc>
> + */
> +
> +#include <linux/gpio/driver.h>
> +#include <linux/gpio-regmap.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +
> +struct gpio_regmap {
> +       struct device *parent;
> +       struct regmap *regmap;
> +       struct gpio_chip gpio_chip;
> +
> +       int reg_stride;
> +       int ngpio_per_reg;
> +       unsigned int reg_dat_base;
> +       unsigned int reg_set_base;
> +       unsigned int reg_clr_base;
> +       unsigned int reg_dir_in_base;
> +       unsigned int reg_dir_out_base;
> +
> +       int (*reg_mask_xlate)(struct gpio_regmap *gpio, unsigned int base,
> +                             unsigned int offset, unsigned int *reg,
> +                             unsigned int *mask);
> +
> +       void *driver_data;
> +};
> +
> +static unsigned int gpio_regmap_addr(unsigned int addr)
> +{
> +       return (addr == GPIO_REGMAP_ADDR_ZERO) ? 0 : addr;
> +}
> +
> +/**
> + * gpio_regmap_simple_xlate() - translate base/offset to reg/mask
> + *
> + * Use a simple linear mapping to translate the offset to the bitmask.
> + */
> +static int gpio_regmap_simple_xlate(struct gpio_regmap *gpio,
> +                                   unsigned int base, unsigned int offset,
> +                                   unsigned int *reg, unsigned int *mask)
> +{
> +       unsigned int line = offset % gpio->ngpio_per_reg;
> +       unsigned int stride = offset / gpio->ngpio_per_reg;
> +
> +       *reg = base + stride * gpio->reg_stride;
> +       *mask = BIT(line);
> +
> +       return 0;
> +}
> +
> +static int gpio_regmap_get(struct gpio_chip *chip, unsigned int offset)
> +{
> +       struct gpio_regmap *gpio = gpiochip_get_data(chip);
> +       unsigned int base, val, reg, mask;
> +       int ret;
> +
> +       /* we might not have an output register if we are input only */
> +       if (gpio->reg_dat_base)
> +               base = gpio_regmap_addr(gpio->reg_dat_base);
> +       else
> +               base = gpio_regmap_addr(gpio->reg_set_base);
> +
> +       ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
> +       if (ret)
> +               return ret;
> +
> +       ret = regmap_read(gpio->regmap, reg, &val);
> +       if (ret)
> +               return ret;
> +
> +       return (val & mask) ? 1 : 0;
> +}
> +
> +static void gpio_regmap_set(struct gpio_chip *chip, unsigned int offset,
> +                           int val)
> +{
> +       struct gpio_regmap *gpio = gpiochip_get_data(chip);
> +       unsigned int base = gpio_regmap_addr(gpio->reg_set_base);
> +       unsigned int reg, mask;
> +
> +       gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
> +       if (val)
> +               regmap_update_bits(gpio->regmap, reg, mask, mask);
> +       else
> +               regmap_update_bits(gpio->regmap, reg, mask, 0);
> +}
> +
> +static void gpio_regmap_set_with_clear(struct gpio_chip *chip,
> +                                      unsigned int offset, int val)
> +{
> +       struct gpio_regmap *gpio = gpiochip_get_data(chip);
> +       unsigned int base, reg, mask;
> +
> +       if (val)
> +               base = gpio_regmap_addr(gpio->reg_set_base);
> +       else
> +               base = gpio_regmap_addr(gpio->reg_clr_base);
> +
> +       gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
> +       regmap_write(gpio->regmap, reg, mask);
> +}
> +
> +static int gpio_regmap_get_direction(struct gpio_chip *chip,
> +                                    unsigned int offset)
> +{
> +       struct gpio_regmap *gpio = gpiochip_get_data(chip);
> +       unsigned int base, val, reg, mask;
> +       int invert, ret;
> +
> +       if (gpio->reg_dir_out_base) {
> +               base = gpio_regmap_addr(gpio->reg_dir_out_base);
> +               invert = 0;
> +       } else if (gpio->reg_dir_in_base) {
> +               base = gpio_regmap_addr(gpio->reg_dir_in_base);
> +               invert = 1;
> +       } else {
> +               return GPIO_LINE_DIRECTION_IN;
> +       }
> +
> +       ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
> +       if (ret)
> +               return ret;
> +
> +       ret = regmap_read(gpio->regmap, reg, &val);
> +       if (ret)
> +               return ret;
> +
> +       if (!!(val & mask) ^ invert)
> +               return GPIO_LINE_DIRECTION_OUT;
> +       else
> +               return GPIO_LINE_DIRECTION_IN;
> +}
> +
> +static int gpio_regmap_set_direction(struct gpio_chip *chip,
> +                                    unsigned int offset, bool output)
> +{
> +       struct gpio_regmap *gpio = gpiochip_get_data(chip);
> +       unsigned int base, val, reg, mask;
> +       int invert, ret;
> +
> +       if (gpio->reg_dir_out_base) {
> +               base = gpio_regmap_addr(gpio->reg_dir_out_base);
> +               invert = 0;
> +       } else if (gpio->reg_dir_in_base) {
> +               base = gpio_regmap_addr(gpio->reg_dir_in_base);
> +               invert = 1;
> +       } else {
> +               return 0;
> +       }
> +
> +       ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
> +       if (ret)
> +               return ret;
> +
> +       if (!invert)
> +               val = (output) ? mask : 0;
> +       else
> +               val = (output) ? 0 : mask;
> +
> +       return regmap_update_bits(gpio->regmap, reg, mask, val);
> +}
> +
> +static int gpio_regmap_direction_input(struct gpio_chip *chip,
> +                                      unsigned int offset)
> +{
> +       return gpio_regmap_set_direction(chip, offset, false);
> +}
> +
> +static int gpio_regmap_direction_output(struct gpio_chip *chip,
> +                                       unsigned int offset, int value)
> +{
> +       gpio_regmap_set(chip, offset, value);
> +
> +       return gpio_regmap_set_direction(chip, offset, true);
> +}
> +
> +void gpio_regmap_set_drvdata(struct gpio_regmap *gpio, void *data)
> +{
> +       gpio->driver_data = data;
> +}
> +EXPORT_SYMBOL_GPL(gpio_regmap_set_drvdata);
> +
> +void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio)
> +{
> +       return gpio->driver_data;
> +}
> +EXPORT_SYMBOL_GPL(gpio_regmap_get_drvdata);
> +
> +/**
> + * gpio_regmap_register() - Register a generic regmap GPIO controller
> + *
> + * @gpio: gpio_regmap device to register
> + *
> + * Returns 0 on success or an errno on failure.
> + */
> +struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config)
> +{
> +       struct gpio_regmap *gpio;
> +       struct gpio_chip *chip;
> +       int ret;
> +
> +       if (!config->parent)
> +               return ERR_PTR(-EINVAL);
> +
> +       if (!config->ngpio)
> +               return ERR_PTR(-EINVAL);
> +
> +       /* we need at least one */
> +       if (!config->reg_dat_base && !config->reg_set_base)
> +               return ERR_PTR(-EINVAL);
> +
> +       /* we don't support having both registers simulaniously for now */
> +       if (config->reg_dir_out_base && config->reg_dir_in_base)
> +               return ERR_PTR(-EINVAL);
> +
> +       gpio = kzalloc(sizeof(*gpio), GFP_KERNEL);
> +       if (!gpio)
> +               return ERR_PTR(-ENOMEM);
> +
> +       gpio->parent = config->parent;
> +       gpio->regmap = config->regmap;
> +       gpio->ngpio_per_reg = config->ngpio_per_reg;
> +       gpio->reg_stride = config->reg_stride;
> +       gpio->reg_mask_xlate = config->reg_mask_xlate;
> +       gpio->reg_set_base = config->reg_set_base;
> +       gpio->reg_clr_base = config->reg_clr_base;
> +       gpio->reg_dir_in_base = config->reg_dir_in_base;
> +       gpio->reg_dir_out_base = config->reg_dir_out_base;
> +
> +       /* if not set, assume there is only one register */
> +       if (!gpio->ngpio_per_reg)
> +               gpio->ngpio_per_reg = config->ngpio;
> +
> +       /* if not set, assume they are consecutive */
> +       if (!gpio->reg_stride)
> +               gpio->reg_stride = 1;
> +
> +       if (!gpio->reg_mask_xlate)
> +               gpio->reg_mask_xlate = gpio_regmap_simple_xlate;
> +
> +       chip = &gpio->gpio_chip;
> +       chip->parent = config->parent;
> +       chip->base = -1;
> +       chip->ngpio = config->ngpio;
> +       chip->can_sleep = true;
> +
> +       if (!chip->label)
> +               chip->label = dev_name(config->parent);
> +       else
> +               chip->label = config->label;
> +
> +       chip->get = gpio_regmap_get;
> +       if (gpio->reg_set_base && gpio->reg_clr_base)
> +               chip->set = gpio_regmap_set_with_clear;
> +       else if (gpio->reg_set_base)
> +               chip->set = gpio_regmap_set;
> +
> +       if (gpio->reg_dir_in_base || gpio->reg_dir_out_base) {
> +               chip->get_direction = gpio_regmap_get_direction;
> +               chip->direction_input = gpio_regmap_direction_input;
> +               chip->direction_output = gpio_regmap_direction_output;
> +       }
> +
> +       ret = gpiochip_add_data(chip, gpio);
> +       if (ret < 0) {
> +               kfree(gpio);

Maybe add a second label at the end of the function?

> +               return ERR_PTR(ret);
> +       }
> +
> +       if (config->irq_domain) {
> +               ret = gpiochip_irqchip_add_domain(chip, config->irq_domain);
> +               if (ret < 0)
> +                       goto err;
> +       }
> +
> +       return gpio;
> +
> +err:
> +       gpiochip_remove(chip);
> +       kfree(gpio);
> +       return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(gpio_regmap_register);
> +
> +/**
> + * gpio_regmap_unregister() - Unregister a generic regmap GPIO controller
> + *
> + * @gpio: gpio_regmap device to unregister
> + */
> +void gpio_regmap_unregister(struct gpio_regmap *gpio)
> +{
> +       gpiochip_remove(&gpio->gpio_chip);
> +       kfree(gpio);
> +}
> +EXPORT_SYMBOL_GPL(gpio_regmap_unregister);
> +
> +static void devm_gpio_regmap_unregister(struct device *dev, void *res)
> +{
> +       gpio_regmap_unregister(*(struct gpio_regmap **)res);
> +}
> +
> +/**
> + * devm_gpio_regmap_register() - resource managed gpio_regmap_register()
> + *
> + * @dev: device that is registering this GPIO device
> + * @gpio: gpio_regmap device to register
> + *
> + * Managed gpio_regmap_register(). For generic regmap GPIO device registered by
> + * this function, gpio_regmap_unregister() is automatically called on driver
> + * detach. See gpio_regmap_register() for more information.
> + */
> +struct gpio_regmap *devm_gpio_regmap_register(struct device *dev,
> +                                             const struct gpio_regmap_config *config)
> +{
> +       struct gpio_regmap **ptr, *gpio;
> +
> +       ptr = devres_alloc(devm_gpio_regmap_unregister, sizeof(*ptr),
> +                          GFP_KERNEL);
> +       if (!ptr)
> +               return ERR_PTR(-ENOMEM);
> +
> +       gpio = gpio_regmap_register(config);
> +
> +       if (!IS_ERR(gpio)) {
> +               *ptr = gpio;
> +               devres_add(dev, ptr);
> +       } else {
> +               devres_free(ptr);
> +       }
> +
> +       return gpio;
> +}
> +EXPORT_SYMBOL_GPL(devm_gpio_regmap_register);
> +
> +MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
> +MODULE_DESCRIPTION("GPIO generic regmap driver core");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/gpio-regmap.h b/include/linux/gpio-regmap.h
> new file mode 100644
> index 000000000000..a868cbcde6e9
> --- /dev/null
> +++ b/include/linux/gpio-regmap.h
> @@ -0,0 +1,69 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +#ifndef _LINUX_GPIO_REGMAP_H
> +#define _LINUX_GPIO_REGMAP_H
> +
> +struct gpio_regmap;
> +
> +#define GPIO_REGMAP_ADDR_ZERO ((unsigned long)(-1))
> +#define GPIO_REGMAP_ADDR(addr) ((addr) ? : GPIO_REGMAP_ADDR_ZERO)
> +

What if the addr is actually 0? Maybe drop GPIO_REGMAP_ADDR and
require users to set unused registers to GPIO_REGMAP_ADDR_ZERO?

> +/**
> + * struct gpio_regmap_config - Description of a generic regmap gpio_chip.
> + *
> + * @parent:            The parent device
> + * @regmap:            The regmap used to access the registers
> + *                     given, the name of the device is used
> + * @label:             (Optional) Descriptive name for GPIO controller.
> + *                     If not given, the name of the device is used.
> + * @ngpio:             Number of GPIOs
> + * @reg_dat_base:      (Optional) (in) register base address
> + * @reg_set_base:      (Optional) set register base address
> + * @reg_clr_base:      (Optional) clear register base address
> + * @reg_dir_in_base:   (Optional) out setting register base address
> + * @reg_dir_out_base:  (Optional) in setting register base address

The two above are inverted I think? Also: why the limitation of only
supporting one at a time?

> + * @reg_stride:                (Optional) May be set if the registers (of the
> + *                     same type, dat, set, etc) are not consecutive.
> + * @ngpio_per_reg:     Number of GPIOs per register
> + * @irq_domain:                (Optional) IRQ domain if the controller is
> + *                     interrupt-capable
> + * @reg_mask_xlate:     (Optional) Translates base address and GPIO
> + *                     offset to a register/bitmask pair. If not
> + *                     given the default gpio_regmap_simple_xlate()
> + *                     is used.
> + *
> + * The reg_mask_xlate translates a given base address and GPIO offset to
> + * register and mask pair. The base address is one of the given reg_*_base.
> + *
> + * All base addresses may have the special value GPIO_REGMAP_ADDR_ZERO
> + * which forces the address to the value 0.
> + */
> +struct gpio_regmap_config {
> +       struct device *parent;
> +       struct regmap *regmap;
> +
> +       const char *label;
> +       int ngpio;
> +
> +       unsigned int reg_dat_base;
> +       unsigned int reg_set_base;
> +       unsigned int reg_clr_base;
> +       unsigned int reg_dir_in_base;
> +       unsigned int reg_dir_out_base;
> +       int reg_stride;
> +       int ngpio_per_reg;
> +       struct irq_domain *irq_domain;
> +
> +       int (*reg_mask_xlate)(struct gpio_regmap *gpio, unsigned int base,
> +                             unsigned int offset, unsigned int *reg,
> +                             unsigned int *mask);
> +};
> +
> +struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config);
> +void gpio_regmap_unregister(struct gpio_regmap *gpio);
> +struct gpio_regmap *devm_gpio_regmap_register(struct device *dev,
> +                                             const struct gpio_regmap_config *config);
> +void gpio_regmap_set_drvdata(struct gpio_regmap *gpio, void *data);
> +void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio);
> +
> +#endif /* _LINUX_GPIO_REGMAP_H */
> --
> 2.20.1
>

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

* Re: [PATCH v3 10/16] gpio: add a reusable generic gpio_chip using regmap
  2020-05-12 12:48   ` Bartosz Golaszewski
@ 2020-05-12 14:41     ` Michael Walle
  2020-05-25  9:05       ` Bartosz Golaszewski
  0 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-05-12 14:41 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Andy Shevchenko, linux-gpio, linux-devicetree, LKML, linux-hwmon,
	linux-pwm, LINUXWATCHDOG, arm-soc, Linus Walleij, Rob Herring,
	Jean Delvare, Guenter Roeck, Lee Jones, Thierry Reding,
	Uwe Kleine-König, Wim Van Sebroeck, Shawn Guo, Li Yang,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Mark Brown,
	Greg Kroah-Hartman

Am 2020-05-12 14:48, schrieb Bartosz Golaszewski:
> czw., 23 kwi 2020 o 19:46 Michael Walle <michael@walle.cc> napisał(a):
>> 
>> There are quite a lot simple GPIO controller which are using regmap to
>> access the hardware. This driver tries to be a base to unify existing
>> code into one place. This won't cover everything but it should be a 
>> good
>> starting point.
>> 
>> It does not implement its own irq_chip because there is already a
>> generic one for regmap based devices. Instead, the irq_chip will be
>> instantiated in the parent driver and its irq domain will be associate
>> to this driver.
>> 
>> For now it consists of the usual registers, like set (and an optional
>> clear) data register, an input register and direction registers.
>> Out-of-the-box, it supports consecutive register mappings and mappings
>> where the registers have gaps between them with a linear mapping 
>> between
>> GPIO offset and bit position. For weirder mappings the user can 
>> register
>> its own .xlate().
>> 
>> Signed-off-by: Michael Walle <michael@walle.cc>
>> ---
> 
> This looks good to me. Please see some nits below.
> 
>>  drivers/gpio/Kconfig        |   4 +
>>  drivers/gpio/Makefile       |   1 +
>>  drivers/gpio/gpio-regmap.c  | 343 
>> ++++++++++++++++++++++++++++++++++++
>>  include/linux/gpio-regmap.h |  69 ++++++++
>>  4 files changed, 417 insertions(+)
>>  create mode 100644 drivers/gpio/gpio-regmap.c
>>  create mode 100644 include/linux/gpio-regmap.h
>> 
>> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
>> index 8ef2179fb999..ae3a49a2e970 100644
>> --- a/drivers/gpio/Kconfig
>> +++ b/drivers/gpio/Kconfig
>> @@ -73,6 +73,10 @@ config GPIO_GENERIC
>>         depends on HAS_IOMEM # Only for IOMEM drivers
>>         tristate
>> 
>> +config GPIO_REGMAP
>> +       depends on REGMAP
>> +       tristate
>> +
>>  # put drivers in the right section, in alphabetical order
>> 
>>  # This symbol is selected by both I2C and SPI expanders
>> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
>> index b2cfc21a97f3..93e139fdfa57 100644
>> --- a/drivers/gpio/Makefile
>> +++ b/drivers/gpio/Makefile
>> @@ -12,6 +12,7 @@ obj-$(CONFIG_GPIO_SYSFS)      += gpiolib-sysfs.o
>>  obj-$(CONFIG_GPIO_ACPI)                += gpiolib-acpi.o
>> 
>>  # Device drivers. Generally keep list sorted alphabetically
>> +obj-$(CONFIG_GPIO_REGMAP)      += gpio-regmap.o
>>  obj-$(CONFIG_GPIO_GENERIC)     += gpio-generic.o
>> 
>>  # directly supported by gpio-generic
>> diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
>> new file mode 100644
>> index 000000000000..04939c0a22f9
>> --- /dev/null
>> +++ b/drivers/gpio/gpio-regmap.c
>> @@ -0,0 +1,343 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * regmap based generic GPIO driver
>> + *
>> + * Copyright 2019 Michael Walle <michael@walle.cc>
>> + */
>> +
>> +#include <linux/gpio/driver.h>
>> +#include <linux/gpio-regmap.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/regmap.h>
>> +
>> +struct gpio_regmap {
>> +       struct device *parent;
>> +       struct regmap *regmap;
>> +       struct gpio_chip gpio_chip;
>> +
>> +       int reg_stride;
>> +       int ngpio_per_reg;
>> +       unsigned int reg_dat_base;
>> +       unsigned int reg_set_base;
>> +       unsigned int reg_clr_base;
>> +       unsigned int reg_dir_in_base;
>> +       unsigned int reg_dir_out_base;
>> +
>> +       int (*reg_mask_xlate)(struct gpio_regmap *gpio, unsigned int 
>> base,
>> +                             unsigned int offset, unsigned int *reg,
>> +                             unsigned int *mask);
>> +
>> +       void *driver_data;
>> +};
>> +
>> +static unsigned int gpio_regmap_addr(unsigned int addr)
>> +{
>> +       return (addr == GPIO_REGMAP_ADDR_ZERO) ? 0 : addr;
>> +}
>> +
>> +/**
>> + * gpio_regmap_simple_xlate() - translate base/offset to reg/mask
>> + *
>> + * Use a simple linear mapping to translate the offset to the 
>> bitmask.
>> + */
>> +static int gpio_regmap_simple_xlate(struct gpio_regmap *gpio,
>> +                                   unsigned int base, unsigned int 
>> offset,
>> +                                   unsigned int *reg, unsigned int 
>> *mask)
>> +{
>> +       unsigned int line = offset % gpio->ngpio_per_reg;
>> +       unsigned int stride = offset / gpio->ngpio_per_reg;
>> +
>> +       *reg = base + stride * gpio->reg_stride;
>> +       *mask = BIT(line);
>> +
>> +       return 0;
>> +}
>> +
>> +static int gpio_regmap_get(struct gpio_chip *chip, unsigned int 
>> offset)
>> +{
>> +       struct gpio_regmap *gpio = gpiochip_get_data(chip);
>> +       unsigned int base, val, reg, mask;
>> +       int ret;
>> +
>> +       /* we might not have an output register if we are input only 
>> */
>> +       if (gpio->reg_dat_base)
>> +               base = gpio_regmap_addr(gpio->reg_dat_base);
>> +       else
>> +               base = gpio_regmap_addr(gpio->reg_set_base);
>> +
>> +       ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
>> +       if (ret)
>> +               return ret;
>> +
>> +       ret = regmap_read(gpio->regmap, reg, &val);
>> +       if (ret)
>> +               return ret;
>> +
>> +       return (val & mask) ? 1 : 0;
>> +}
>> +
>> +static void gpio_regmap_set(struct gpio_chip *chip, unsigned int 
>> offset,
>> +                           int val)
>> +{
>> +       struct gpio_regmap *gpio = gpiochip_get_data(chip);
>> +       unsigned int base = gpio_regmap_addr(gpio->reg_set_base);
>> +       unsigned int reg, mask;
>> +
>> +       gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
>> +       if (val)
>> +               regmap_update_bits(gpio->regmap, reg, mask, mask);
>> +       else
>> +               regmap_update_bits(gpio->regmap, reg, mask, 0);
>> +}
>> +
>> +static void gpio_regmap_set_with_clear(struct gpio_chip *chip,
>> +                                      unsigned int offset, int val)
>> +{
>> +       struct gpio_regmap *gpio = gpiochip_get_data(chip);
>> +       unsigned int base, reg, mask;
>> +
>> +       if (val)
>> +               base = gpio_regmap_addr(gpio->reg_set_base);
>> +       else
>> +               base = gpio_regmap_addr(gpio->reg_clr_base);
>> +
>> +       gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
>> +       regmap_write(gpio->regmap, reg, mask);
>> +}
>> +
>> +static int gpio_regmap_get_direction(struct gpio_chip *chip,
>> +                                    unsigned int offset)
>> +{
>> +       struct gpio_regmap *gpio = gpiochip_get_data(chip);
>> +       unsigned int base, val, reg, mask;
>> +       int invert, ret;
>> +
>> +       if (gpio->reg_dir_out_base) {
>> +               base = gpio_regmap_addr(gpio->reg_dir_out_base);
>> +               invert = 0;
>> +       } else if (gpio->reg_dir_in_base) {
>> +               base = gpio_regmap_addr(gpio->reg_dir_in_base);
>> +               invert = 1;
>> +       } else {
>> +               return GPIO_LINE_DIRECTION_IN;
>> +       }
>> +
>> +       ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
>> +       if (ret)
>> +               return ret;
>> +
>> +       ret = regmap_read(gpio->regmap, reg, &val);
>> +       if (ret)
>> +               return ret;
>> +
>> +       if (!!(val & mask) ^ invert)
>> +               return GPIO_LINE_DIRECTION_OUT;
>> +       else
>> +               return GPIO_LINE_DIRECTION_IN;
>> +}
>> +
>> +static int gpio_regmap_set_direction(struct gpio_chip *chip,
>> +                                    unsigned int offset, bool output)
>> +{
>> +       struct gpio_regmap *gpio = gpiochip_get_data(chip);
>> +       unsigned int base, val, reg, mask;
>> +       int invert, ret;
>> +
>> +       if (gpio->reg_dir_out_base) {
>> +               base = gpio_regmap_addr(gpio->reg_dir_out_base);
>> +               invert = 0;
>> +       } else if (gpio->reg_dir_in_base) {
>> +               base = gpio_regmap_addr(gpio->reg_dir_in_base);
>> +               invert = 1;
>> +       } else {
>> +               return 0;
>> +       }
>> +
>> +       ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
>> +       if (ret)
>> +               return ret;
>> +
>> +       if (!invert)
>> +               val = (output) ? mask : 0;
>> +       else
>> +               val = (output) ? 0 : mask;
>> +
>> +       return regmap_update_bits(gpio->regmap, reg, mask, val);
>> +}
>> +
>> +static int gpio_regmap_direction_input(struct gpio_chip *chip,
>> +                                      unsigned int offset)
>> +{
>> +       return gpio_regmap_set_direction(chip, offset, false);
>> +}
>> +
>> +static int gpio_regmap_direction_output(struct gpio_chip *chip,
>> +                                       unsigned int offset, int 
>> value)
>> +{
>> +       gpio_regmap_set(chip, offset, value);
>> +
>> +       return gpio_regmap_set_direction(chip, offset, true);
>> +}
>> +
>> +void gpio_regmap_set_drvdata(struct gpio_regmap *gpio, void *data)
>> +{
>> +       gpio->driver_data = data;
>> +}
>> +EXPORT_SYMBOL_GPL(gpio_regmap_set_drvdata);
>> +
>> +void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio)
>> +{
>> +       return gpio->driver_data;
>> +}
>> +EXPORT_SYMBOL_GPL(gpio_regmap_get_drvdata);
>> +
>> +/**
>> + * gpio_regmap_register() - Register a generic regmap GPIO controller
>> + *
>> + * @gpio: gpio_regmap device to register
>> + *
>> + * Returns 0 on success or an errno on failure.
>> + */
>> +struct gpio_regmap *gpio_regmap_register(const struct 
>> gpio_regmap_config *config)
>> +{
>> +       struct gpio_regmap *gpio;
>> +       struct gpio_chip *chip;
>> +       int ret;
>> +
>> +       if (!config->parent)
>> +               return ERR_PTR(-EINVAL);
>> +
>> +       if (!config->ngpio)
>> +               return ERR_PTR(-EINVAL);
>> +
>> +       /* we need at least one */
>> +       if (!config->reg_dat_base && !config->reg_set_base)
>> +               return ERR_PTR(-EINVAL);
>> +
>> +       /* we don't support having both registers simulaniously for 
>> now */
>> +       if (config->reg_dir_out_base && config->reg_dir_in_base)
>> +               return ERR_PTR(-EINVAL);
>> +
>> +       gpio = kzalloc(sizeof(*gpio), GFP_KERNEL);
>> +       if (!gpio)
>> +               return ERR_PTR(-ENOMEM);
>> +
>> +       gpio->parent = config->parent;
>> +       gpio->regmap = config->regmap;
>> +       gpio->ngpio_per_reg = config->ngpio_per_reg;
>> +       gpio->reg_stride = config->reg_stride;
>> +       gpio->reg_mask_xlate = config->reg_mask_xlate;
>> +       gpio->reg_set_base = config->reg_set_base;
>> +       gpio->reg_clr_base = config->reg_clr_base;
>> +       gpio->reg_dir_in_base = config->reg_dir_in_base;
>> +       gpio->reg_dir_out_base = config->reg_dir_out_base;
>> +
>> +       /* if not set, assume there is only one register */
>> +       if (!gpio->ngpio_per_reg)
>> +               gpio->ngpio_per_reg = config->ngpio;
>> +
>> +       /* if not set, assume they are consecutive */
>> +       if (!gpio->reg_stride)
>> +               gpio->reg_stride = 1;
>> +
>> +       if (!gpio->reg_mask_xlate)
>> +               gpio->reg_mask_xlate = gpio_regmap_simple_xlate;
>> +
>> +       chip = &gpio->gpio_chip;
>> +       chip->parent = config->parent;
>> +       chip->base = -1;
>> +       chip->ngpio = config->ngpio;
>> +       chip->can_sleep = true;
>> +
>> +       if (!chip->label)
>> +               chip->label = dev_name(config->parent);
>> +       else
>> +               chip->label = config->label;
>> +
>> +       chip->get = gpio_regmap_get;
>> +       if (gpio->reg_set_base && gpio->reg_clr_base)
>> +               chip->set = gpio_regmap_set_with_clear;
>> +       else if (gpio->reg_set_base)
>> +               chip->set = gpio_regmap_set;
>> +
>> +       if (gpio->reg_dir_in_base || gpio->reg_dir_out_base) {
>> +               chip->get_direction = gpio_regmap_get_direction;
>> +               chip->direction_input = gpio_regmap_direction_input;
>> +               chip->direction_output = gpio_regmap_direction_output;
>> +       }
>> +
>> +       ret = gpiochip_add_data(chip, gpio);
>> +       if (ret < 0) {
>> +               kfree(gpio);
> 
> Maybe add a second label at the end of the function?
sure

>> +               return ERR_PTR(ret);
>> +       }
>> +
>> +       if (config->irq_domain) {
>> +               ret = gpiochip_irqchip_add_domain(chip, 
>> config->irq_domain);
>> +               if (ret < 0)
>> +                       goto err;
>> +       }
>> +
>> +       return gpio;
>> +
>> +err:
>> +       gpiochip_remove(chip);
>> +       kfree(gpio);
>> +       return ERR_PTR(ret);
>> +}
>> +EXPORT_SYMBOL_GPL(gpio_regmap_register);
>> +
>> +/**
>> + * gpio_regmap_unregister() - Unregister a generic regmap GPIO 
>> controller
>> + *
>> + * @gpio: gpio_regmap device to unregister
>> + */
>> +void gpio_regmap_unregister(struct gpio_regmap *gpio)
>> +{
>> +       gpiochip_remove(&gpio->gpio_chip);
>> +       kfree(gpio);
>> +}
>> +EXPORT_SYMBOL_GPL(gpio_regmap_unregister);
>> +
>> +static void devm_gpio_regmap_unregister(struct device *dev, void 
>> *res)
>> +{
>> +       gpio_regmap_unregister(*(struct gpio_regmap **)res);
>> +}
>> +
>> +/**
>> + * devm_gpio_regmap_register() - resource managed 
>> gpio_regmap_register()
>> + *
>> + * @dev: device that is registering this GPIO device
>> + * @gpio: gpio_regmap device to register
>> + *
>> + * Managed gpio_regmap_register(). For generic regmap GPIO device 
>> registered by
>> + * this function, gpio_regmap_unregister() is automatically called on 
>> driver
>> + * detach. See gpio_regmap_register() for more information.
>> + */
>> +struct gpio_regmap *devm_gpio_regmap_register(struct device *dev,
>> +                                             const struct 
>> gpio_regmap_config *config)
>> +{
>> +       struct gpio_regmap **ptr, *gpio;
>> +
>> +       ptr = devres_alloc(devm_gpio_regmap_unregister, sizeof(*ptr),
>> +                          GFP_KERNEL);
>> +       if (!ptr)
>> +               return ERR_PTR(-ENOMEM);
>> +
>> +       gpio = gpio_regmap_register(config);
>> +
>> +       if (!IS_ERR(gpio)) {
>> +               *ptr = gpio;
>> +               devres_add(dev, ptr);
>> +       } else {
>> +               devres_free(ptr);
>> +       }
>> +
>> +       return gpio;
>> +}
>> +EXPORT_SYMBOL_GPL(devm_gpio_regmap_register);
>> +
>> +MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
>> +MODULE_DESCRIPTION("GPIO generic regmap driver core");
>> +MODULE_LICENSE("GPL");
>> diff --git a/include/linux/gpio-regmap.h b/include/linux/gpio-regmap.h
>> new file mode 100644
>> index 000000000000..a868cbcde6e9
>> --- /dev/null
>> +++ b/include/linux/gpio-regmap.h
>> @@ -0,0 +1,69 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +
>> +#ifndef _LINUX_GPIO_REGMAP_H
>> +#define _LINUX_GPIO_REGMAP_H
>> +
>> +struct gpio_regmap;
>> +
>> +#define GPIO_REGMAP_ADDR_ZERO ((unsigned long)(-1))
>> +#define GPIO_REGMAP_ADDR(addr) ((addr) ? : GPIO_REGMAP_ADDR_ZERO)
>> +
> 
> What if the addr is actually 0?

Then the driver has to set GPIO_REGMAP_ADDR_ZERO or use the convenience
macro GPIO_REGMAP_ADDR.

So you can have

   struct gpio_regmap_config config = { 0 };
   config.reg_dat_base = 0x10;
   config.reg_dir_out_base = 0x20;

or

   config.reg_dat_base = GPIO_REGMAP_ADDR_ZERO;

or if you can't be sure if the RHS value might be zero:

   config.reg_dat_base = GPIO_REGMAP_ADDR(reg);


> Maybe drop GPIO_REGMAP_ADDR and require users to set unused registers
> to GPIO_REGMAP_ADDR_ZERO?

Thats bad because:
  * you'd have to set plenty of unused base registers for a simple driver
  * if there will be additional properties in the future, you have to 
touch
    all other drivers, because they are initialized as 0 (ie. valid reg 
0).

>> +/**
>> + * struct gpio_regmap_config - Description of a generic regmap 
>> gpio_chip.
>> + *
>> + * @parent:            The parent device
>> + * @regmap:            The regmap used to access the registers
>> + *                     given, the name of the device is used
>> + * @label:             (Optional) Descriptive name for GPIO 
>> controller.
>> + *                     If not given, the name of the device is used.
>> + * @ngpio:             Number of GPIOs
>> + * @reg_dat_base:      (Optional) (in) register base address
>> + * @reg_set_base:      (Optional) set register base address
>> + * @reg_clr_base:      (Optional) clear register base address
>> + * @reg_dir_in_base:   (Optional) out setting register base address
>> + * @reg_dir_out_base:  (Optional) in setting register base address
> 
> The two above are inverted I think?
good catch.

> Also: why the limitation of only supporting one at a time?

they should be exclusive, either you have a register where you set the
output bits to one, or the input bits. Maybe this need a bit more 
context
above. in gpio-mmio.c you can set both and both are used in
set_direction(), but only one is read in get_direction().

That being said, I have no strong opinion wether they should be 
exclusive
or not, besides the symmetry of set_/get_direction().

-michael

> 
>> + * @reg_stride:                (Optional) May be set if the registers 
>> (of the
>> + *                     same type, dat, set, etc) are not consecutive.
>> + * @ngpio_per_reg:     Number of GPIOs per register
>> + * @irq_domain:                (Optional) IRQ domain if the 
>> controller is
>> + *                     interrupt-capable
>> + * @reg_mask_xlate:     (Optional) Translates base address and GPIO
>> + *                     offset to a register/bitmask pair. If not
>> + *                     given the default gpio_regmap_simple_xlate()
>> + *                     is used.
>> + *
>> + * The reg_mask_xlate translates a given base address and GPIO offset 
>> to
>> + * register and mask pair. The base address is one of the given 
>> reg_*_base.
>> + *
>> + * All base addresses may have the special value 
>> GPIO_REGMAP_ADDR_ZERO
>> + * which forces the address to the value 0.
>> + */
>> +struct gpio_regmap_config {
>> +       struct device *parent;
>> +       struct regmap *regmap;
>> +
>> +       const char *label;
>> +       int ngpio;
>> +
>> +       unsigned int reg_dat_base;
>> +       unsigned int reg_set_base;
>> +       unsigned int reg_clr_base;
>> +       unsigned int reg_dir_in_base;
>> +       unsigned int reg_dir_out_base;
>> +       int reg_stride;
>> +       int ngpio_per_reg;
>> +       struct irq_domain *irq_domain;
>> +
>> +       int (*reg_mask_xlate)(struct gpio_regmap *gpio, unsigned int 
>> base,
>> +                             unsigned int offset, unsigned int *reg,
>> +                             unsigned int *mask);
>> +};
>> +
>> +struct gpio_regmap *gpio_regmap_register(const struct 
>> gpio_regmap_config *config);
>> +void gpio_regmap_unregister(struct gpio_regmap *gpio);
>> +struct gpio_regmap *devm_gpio_regmap_register(struct device *dev,
>> +                                             const struct 
>> gpio_regmap_config *config);
>> +void gpio_regmap_set_drvdata(struct gpio_regmap *gpio, void *data);
>> +void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio);
>> +
>> +#endif /* _LINUX_GPIO_REGMAP_H */
>> --
>> 2.20.1
>> 

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

* Re: [PATCH v3 05/16] mfd: Add support for Kontron sl28cpld management controller
  2020-05-11 21:44     ` Michael Walle
  2020-05-11 22:29       ` Michael Walle
@ 2020-05-12 21:59       ` Rob Herring
  2020-05-13 22:15         ` Michael Walle
  1 sibling, 1 reply; 60+ messages in thread
From: Rob Herring @ 2020-05-12 21:59 UTC (permalink / raw)
  To: Michael Walle
  Cc: Andy Shevchenko, open list:GPIO SUBSYSTEM, devicetree,
	linux-kernel, Linux HWMON List, Linux PWM List, LINUX-WATCHDOG,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Linus Walleij, Bartosz Golaszewski, Jean Delvare, Guenter Roeck,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman

On Mon, May 11, 2020 at 4:45 PM Michael Walle <michael@walle.cc> wrote:
>
> Am 2020-05-11 23:13, schrieb Rob Herring:
> > On Thu, Apr 23, 2020 at 07:45:32PM +0200, Michael Walle wrote:
> >> This patch adds core support for the board management controller found
> >> on the SMARC-sAL28 board. It consists of the following functions:
> >>  - watchdog
> >>  - GPIO controller
> >>  - PWM controller
> >>  - fan sensor
> >>  - interrupt controller
> >>
> >> At the moment, this controller is used on the Kontron SMARC-sAL28
> >> board.
> >>
> >> Please note that the MFD driver is defined as bool in the Kconfig
> >> because the next patch will add interrupt support.
> >>
> >> Signed-off-by: Michael Walle <michael@walle.cc>
> >> ---
> >>  drivers/mfd/Kconfig    |  19 +++++
> >>  drivers/mfd/Makefile   |   2 +
> >>  drivers/mfd/sl28cpld.c | 153
> >> +++++++++++++++++++++++++++++++++++++++++
> >>  3 files changed, 174 insertions(+)
> >>  create mode 100644 drivers/mfd/sl28cpld.c
> >>
> >> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> >> index 0a59249198d3..be0c8d93c526 100644
> >> --- a/drivers/mfd/Kconfig
> >> +++ b/drivers/mfd/Kconfig
> >> @@ -2060,5 +2060,24 @@ config SGI_MFD_IOC3
> >>        If you have an SGI Origin, Octane, or a PCI IOC3 card,
> >>        then say Y. Otherwise say N.
> >>
> >> +config MFD_SL28CPLD
> >> +    bool "Kontron sl28 core driver"
> >> +    depends on I2C=y
> >> +    depends on OF
> >> +    select REGMAP_I2C
> >> +    select MFD_CORE
> >> +    help
> >> +      This option enables support for the board management controller
> >> +      found on the Kontron sl28 CPLD. You have to select individual
> >> +      functions, such as watchdog, GPIO, etc, under the corresponding
> >> menus
> >> +      in order to enable them.
> >> +
> >> +      Currently supported boards are:
> >> +
> >> +            Kontron SMARC-sAL28
> >> +
> >> +      To compile this driver as a module, choose M here: the module will
> >> be
> >> +      called sl28cpld.
> >> +
> >>  endmenu
> >>  endif
> >> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> >> index f935d10cbf0f..9bc38863b9c7 100644
> >> --- a/drivers/mfd/Makefile
> >> +++ b/drivers/mfd/Makefile
> >> @@ -259,3 +259,5 @@ obj-$(CONFIG_MFD_ROHM_BD718XX)   += rohm-bd718x7.o
> >>  obj-$(CONFIG_MFD_STMFX)     += stmfx.o
> >>
> >>  obj-$(CONFIG_SGI_MFD_IOC3)  += ioc3.o
> >> +
> >> +obj-$(CONFIG_MFD_SL28CPLD)  += sl28cpld.o
> >> diff --git a/drivers/mfd/sl28cpld.c b/drivers/mfd/sl28cpld.c
> >> new file mode 100644
> >> index 000000000000..1e5860cc7ffc
> >> --- /dev/null
> >> +++ b/drivers/mfd/sl28cpld.c
> >> @@ -0,0 +1,153 @@
> >> +// SPDX-License-Identifier: GPL-2.0-only
> >> +/*
> >> + * MFD core for the sl28cpld.
> >> + *
> >> + * Copyright 2019 Kontron Europe GmbH
> >> + */
> >> +
> >> +#include <linux/i2c.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/kernel.h>
> >> +#include <linux/mfd/core.h>
> >> +#include <linux/module.h>
> >> +#include <linux/of_platform.h>
> >> +#include <linux/regmap.h>
> >> +
> >> +#define SL28CPLD_VERSION    0x03
> >> +#define SL28CPLD_WATCHDOG_BASE      0x04
> >> +#define SL28CPLD_HWMON_FAN_BASE     0x0b
> >> +#define SL28CPLD_PWM0_BASE  0x0c
> >> +#define SL28CPLD_PWM1_BASE  0x0e
> >> +#define SL28CPLD_GPIO0_BASE 0x10
> >> +#define SL28CPLD_GPIO1_BASE 0x15
> >> +#define SL28CPLD_GPO_BASE   0x1a
> >> +#define SL28CPLD_GPI_BASE   0x1b
> >> +#define SL28CPLD_INTC_BASE  0x1c
> >
> > If you want to use 'reg' in the binding, these are the numbers you
> > should be using rather than making up numbering!
>
> My motivation is that I don't want to hardcode the internal addresses
> of the management controller in the device tree. For example if they
> will move around with a later update of the controller, so a driver can
> be compatible with both the old and the new version. If they are in the
> device tree, only one register layout is possible.

I don't understand, if the addresses change, then the above defines
have to change. So your driver is only compatible with 1 version. If
you change the CPLD, then that's a h/w change and your h/w description
(DT) should change. That can either be the compatible string changing
and updating the driver with new match data such as register offsets
or all the differences are in DT and there's no kernel change.

> > However, I still don't think you need any child nodes. All the data in
> > the DT binding is right here in the driver already. There's no
> > advantage
> > to putting child nodes in DT, because this driver still has to be
> > updated if you add more nodes.
>
> But then any phandle will reference the mfd device. And for example
> there
> are two different interrupt controllers, that is the INTC and the
> GPIO[01],
> which will then be combined into one device tree node, right?

You either have to add a cell for 'bank' or divide the 1st cell into a
bank and index. Both have been done before.

To go the other direction, AIUI you shouldn't need OF_MFD_CELL_REG
entries if you have the child devices in DT. Pick one way or the
other. It's ultimately a judgement call. For a one-off device, sub
devices in DT doesn't really buy you anything. If you have sub-blocks
showing up multiple devices, then sub devices makes sense. If there's
only 2-3 combinations, then it's a toss up.

Rob

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

* Re: [PATCH v3 05/16] mfd: Add support for Kontron sl28cpld management controller
  2020-05-12 21:59       ` Rob Herring
@ 2020-05-13 22:15         ` Michael Walle
  0 siblings, 0 replies; 60+ messages in thread
From: Michael Walle @ 2020-05-13 22:15 UTC (permalink / raw)
  To: Rob Herring
  Cc: Andy Shevchenko, open list:GPIO SUBSYSTEM, devicetree,
	linux-kernel, Linux HWMON List, Linux PWM List, LINUX-WATCHDOG,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Linus Walleij, Bartosz Golaszewski, Jean Delvare, Guenter Roeck,
	Lee Jones, Thierry Reding, Uwe Kleine-König,
	Wim Van Sebroeck, Shawn Guo, Li Yang, Thomas Gleixner,
	Jason Cooper, Marc Zyngier, Mark Brown, Greg Kroah-Hartman

Am 2020-05-12 23:59, schrieb Rob Herring:
> On Mon, May 11, 2020 at 4:45 PM Michael Walle <michael@walle.cc> wrote:
>> 
>> Am 2020-05-11 23:13, schrieb Rob Herring:
>> > On Thu, Apr 23, 2020 at 07:45:32PM +0200, Michael Walle wrote:
>> >> +#define SL28CPLD_VERSION    0x03
>> >> +#define SL28CPLD_WATCHDOG_BASE      0x04
>> >> +#define SL28CPLD_HWMON_FAN_BASE     0x0b
>> >> +#define SL28CPLD_PWM0_BASE  0x0c
>> >> +#define SL28CPLD_PWM1_BASE  0x0e
>> >> +#define SL28CPLD_GPIO0_BASE 0x10
>> >> +#define SL28CPLD_GPIO1_BASE 0x15
>> >> +#define SL28CPLD_GPO_BASE   0x1a
>> >> +#define SL28CPLD_GPI_BASE   0x1b
>> >> +#define SL28CPLD_INTC_BASE  0x1c
>> >
>> > If you want to use 'reg' in the binding, these are the numbers you
>> > should be using rather than making up numbering!
>> 
>> My motivation is that I don't want to hardcode the internal addresses
>> of the management controller in the device tree. For example if they
>> will move around with a later update of the controller, so a driver 
>> can
>> be compatible with both the old and the new version. If they are in 
>> the
>> device tree, only one register layout is possible.
> 
> I don't understand, if the addresses change, then the above defines
> have to change. So your driver is only compatible with 1 version. If
> you change the CPLD, then that's a h/w change and your h/w description
> (DT) should change. That can either be the compatible string changing
> and updating the driver with new match data such as register offsets
> or all the differences are in DT and there's no kernel change.

The CPLD and the board is designed in a way that it is possible to
update and/or change its function (or parts of it). It must not be
a hardware change, although I admit thats a bit of a grey area wether
you treat it as hardware or "firmware". Anyway, yes you'd have to
change the register offsets, but as this is code it might support
different register offsets. For example you could dynamically add
functionality, if there is a newer controller version while still
being compatible with older versions.

>> > However, I still don't think you need any child nodes. All the data in
>> > the DT binding is right here in the driver already. There's no
>> > advantage
>> > to putting child nodes in DT, because this driver still has to be
>> > updated if you add more nodes.
>> 
>> But then any phandle will reference the mfd device. And for example
>> there
>> are two different interrupt controllers, that is the INTC and the
>> GPIO[01],
>> which will then be combined into one device tree node, right?
> 
> You either have to add a cell for 'bank' or divide the 1st cell into a
> bank and index. Both have been done before.

But this won't work with watchdogs, correct? See
https://lore.kernel.org/linux-devicetree/7acbb6d9b2240b1856136fa35c1318bf@walle.cc/

> To go the other direction, AIUI you shouldn't need OF_MFD_CELL_REG
> entries if you have the child devices in DT.

This is a general problem IMHO. There are mfd drivers which have mfd
cells and a device tree node associated with each cell. But it just
works as long as there is only one sub device per unique compatible
string. So you cannot have multiple mfd cells with the same
compatible string.

That being said, I can try to reimplement it using
of_platform_populate() and its internal offset as its unit address.

> Pick one way or the
> other. It's ultimately a judgement call. For a one-off device, sub
> devices in DT doesn't really buy you anything. If you have sub-blocks
> showing up multiple devices, then sub devices makes sense. If there's
> only 2-3 combinations, then it's a toss up.

-michael

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

* Re: [PATCH v3 02/16] mfd: mfd-core: Don't overwrite the dma_mask of the child device
  2020-04-28 15:25           ` Mark Brown
@ 2020-05-14 20:45             ` Michael Walle
  0 siblings, 0 replies; 60+ messages in thread
From: Michael Walle @ 2020-05-14 20:45 UTC (permalink / raw)
  To: Mark Brown
  Cc: Robin Murphy, Andy Shevchenko, linux-gpio, devicetree,
	linux-kernel, linux-hwmon, linux-pwm, linux-watchdog,
	linux-arm-kernel, Linus Walleij, Bartosz Golaszewski,
	Rob Herring, Jean Delvare, Guenter Roeck, Lee Jones,
	Thierry Reding, Uwe Kleine-König, Wim Van Sebroeck,
	Shawn Guo, Li Yang, Thomas Gleixner, Jason Cooper, Marc Zyngier,
	Greg Kroah-Hartman

Am 2020-04-28 17:25, schrieb Mark Brown:
> On Tue, Apr 28, 2020 at 03:49:49PM +0100, Robin Murphy wrote:
> 
>> For better or worse, the platform bus is the dumping ground for random 
>> crap,
>> so we just have to deal with all the abstraction breakage that leaks 
>> out of
>> that.
> 
> The reason we're using the platform bus for this is that historically
> people were creating buses which were essentially carbon copies of the
> platform bus with the name changed and it was felt that rather than
> duplicate code it was better to just use platform devices with no MMIO
> ranges defined.  If there's some assumptions about DMA for platform
> devices floating about somewhere it might be reasonable to revisit this
> and create a non-DMA variant of platform devices since there is a
> meaningful difference.

Was there any conclusion? Should I keep or drop this patch in the next 
version
of this series?

-- 
-michael

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

* Re: [PATCH v3 03/16] mfd: mfd-core: match device tree node against reg property
  2020-04-29 22:18   ` Michael Walle
@ 2020-05-15 10:28     ` Lee Jones
  2020-05-25 17:36       ` Michael Walle
  0 siblings, 1 reply; 60+ messages in thread
From: Lee Jones @ 2020-05-15 10:28 UTC (permalink / raw)
  To: Michael Walle
  Cc: Andy Shevchenko, Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Jean Delvare, Guenter Roeck, Thierry Reding,
	Uwe Kleine-König, Wim Van Sebroeck, Shawn Guo, Li Yang,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Mark Brown,
	Greg Kroah-Hartman, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel

On Thu, 30 Apr 2020, Michael Walle wrote:

> Hi Lee,
> 
> Am 2020-04-23 19:45, schrieb Michael Walle:
> > There might be multiple children with the device tree compatible, for
> > example if a MFD has multiple instances of the same function. In this
> > case only the first is matched and the other children get a wrong
> > of_node reference.
> > Add a new option to match also against the unit address of the child
> > node. Additonally, a new helper OF_MFD_CELL_REG is added.
> 
> 
> Do you think this is feasible? I guess this is the biggest uncertainty
> for me at the moment in this patch series.

I think it sounds fine in principle.  So long as it doesn't change the
existing behaviour when of_reg isn't set.

> > Signed-off-by: Michael Walle <michael@walle.cc>
> > ---
> >  drivers/mfd/mfd-core.c   | 29 ++++++++++++++++++++---------
> >  include/linux/mfd/core.h | 26 ++++++++++++++++++++------
> >  2 files changed, 40 insertions(+), 15 deletions(-)
> > 
> > diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
> > index e735565969b3..4ecb376338f7 100644
> > --- a/drivers/mfd/mfd-core.c
> > +++ b/drivers/mfd/mfd-core.c
> > @@ -117,6 +117,7 @@ static int mfd_add_device(struct device *parent, int
> > id,
> >  	struct device_node *np = NULL;
> >  	int ret = -ENOMEM;
> >  	int platform_id;
> > +	u32 of_reg;
> >  	int r;
> > 
> >  	if (id == PLATFORM_DEVID_AUTO)
> > @@ -151,16 +152,26 @@ static int mfd_add_device(struct device *parent,
> > int id,
> > 
> >  	if (parent->of_node && cell->of_compatible) {
> >  		for_each_child_of_node(parent->of_node, np) {
> > -			if (of_device_is_compatible(np, cell->of_compatible)) {
> > -				if (!of_device_is_available(np)) {
> > -					/* Ignore disabled devices error free */
> > -					ret = 0;
> > -					goto fail_alias;
> > -				}
> > -				pdev->dev.of_node = np;
> > -				pdev->dev.fwnode = &np->fwnode;
> > -				break;
> > +			if (!of_device_is_compatible(np, cell->of_compatible))
> > +				continue;
> > +
> > +			/* also match the unit address if set */

Please use correct grammar in comments (leaving off the full-stop).

> > +			if (cell->of_reg & MFD_OF_REG_VALID) {
> > +				if (of_property_read_u32(np, "reg", &of_reg))
> > +					continue;
> > +				if ((cell->of_reg & MFD_OF_REG_MASK) != of_reg)
> > +					continue;
> >  			}
> > +
> > +			if (!of_device_is_available(np)) {
> > +				/* Ignore disabled devices error free */
> > +				ret = 0;
> > +				goto fail_alias;
> > +			}
> > +
> > +			pdev->dev.of_node = np;
> > +			pdev->dev.fwnode = &np->fwnode;
> > +			break;
> >  		}
> >  	}
> > 
> > diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
> > index d01d1299e49d..c2c0ad6b14f3 100644
> > --- a/include/linux/mfd/core.h
> > +++ b/include/linux/mfd/core.h
> > @@ -13,8 +13,11 @@
> >  #include <linux/platform_device.h>
> > 
> >  #define MFD_RES_SIZE(arr) (sizeof(arr) / sizeof(struct resource))
> > +#define MFD_OF_REG_VALID	BIT(31)

What about 64bit platforms?

> > +#define MFD_OF_REG_MASK		GENMASK(30, 0)
> > 
> > -#define MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat,
> > _match)\
> > +#define MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat,	\
> > +		     _of_reg, _match)					\
> >  	{								\
> >  		.name = (_name),					\
> >  		.resources = (_res),					\
> > @@ -22,24 +25,32 @@
> >  		.platform_data = (_pdata),				\
> >  		.pdata_size = (_pdsize),				\
> >  		.of_compatible = (_compat),				\
> > +		.of_reg = (_of_reg),					\
> >  		.acpi_match = (_match),					\
> >  		.id = (_id),						\
> >  	}
> > 
> > +#define OF_MFD_CELL_REG(_name, _res, _pdata, _pdsize, _id, _compat,	\
> > +			_of_reg)					\
> > +	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat,	\
> > +		     ((_of_reg) | MFD_OF_REG_VALID), NULL)		\
> > +
> >  #define OF_MFD_CELL(_name, _res, _pdata, _pdsize,_id, _compat)		\
> > -	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, NULL)	\
> > +	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat,	\
> > +		     0, NULL)						\
> > 
> >  #define ACPI_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _match)	\
> > -	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, _match)	\
> > +	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, 0,	\
> > +		     _match)						\
> > 
> >  #define MFD_CELL_BASIC(_name, _res, _pdata, _pdsize, _id)		\
> > -	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, NULL)	\
> > +	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, 0, NULL) \
> > 
> >  #define MFD_CELL_RES(_name, _res)					\
> > -	MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, NULL)		\
> > +	MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, 0, NULL)		\
> > 
> >  #define MFD_CELL_NAME(_name)						\
> > -	MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, NULL)		\
> > +	MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, 0, NULL)		\
> > 
> >  struct irq_domain;
> >  struct property_entry;
> > @@ -78,6 +89,9 @@ struct mfd_cell {
> >  	 */
> >  	const char		*of_compatible;
> > 
> > +	/* matching the reg property if set */

Proper grammar please.

"OF unit address for device matching"

> > +	unsigned int		of_reg;
> > +
> >  	/* Matches ACPI */
> >  	const struct mfd_cell_acpi_match	*acpi_match;

-- 
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

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

* Re: [PATCH v3 10/16] gpio: add a reusable generic gpio_chip using regmap
  2020-05-12 14:41     ` Michael Walle
@ 2020-05-25  9:05       ` Bartosz Golaszewski
  2020-05-25 10:20         ` Michael Walle
  0 siblings, 1 reply; 60+ messages in thread
From: Bartosz Golaszewski @ 2020-05-25  9:05 UTC (permalink / raw)
  To: Michael Walle
  Cc: Andy Shevchenko, linux-gpio, linux-devicetree, LKML, linux-hwmon,
	linux-pwm, LINUXWATCHDOG, arm-soc, Linus Walleij, Rob Herring,
	Jean Delvare, Guenter Roeck, Lee Jones, Thierry Reding,
	Uwe Kleine-König, Wim Van Sebroeck, Shawn Guo, Li Yang,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Mark Brown,
	Greg Kroah-Hartman

wt., 12 maj 2020 o 16:41 Michael Walle <michael@walle.cc> napisał(a):
>
> >> +
> >> +MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
> >> +MODULE_DESCRIPTION("GPIO generic regmap driver core");
> >> +MODULE_LICENSE("GPL");
> >> diff --git a/include/linux/gpio-regmap.h b/include/linux/gpio-regmap.h
> >> new file mode 100644
> >> index 000000000000..a868cbcde6e9
> >> --- /dev/null
> >> +++ b/include/linux/gpio-regmap.h
> >> @@ -0,0 +1,69 @@
> >> +/* SPDX-License-Identifier: GPL-2.0-only */
> >> +
> >> +#ifndef _LINUX_GPIO_REGMAP_H
> >> +#define _LINUX_GPIO_REGMAP_H
> >> +
> >> +struct gpio_regmap;
> >> +
> >> +#define GPIO_REGMAP_ADDR_ZERO ((unsigned long)(-1))
> >> +#define GPIO_REGMAP_ADDR(addr) ((addr) ? : GPIO_REGMAP_ADDR_ZERO)
> >> +
> >
> > What if the addr is actually 0?
>
> Then the driver has to set GPIO_REGMAP_ADDR_ZERO or use the convenience
> macro GPIO_REGMAP_ADDR.
>
> So you can have
>
>    struct gpio_regmap_config config = { 0 };
>    config.reg_dat_base = 0x10;
>    config.reg_dir_out_base = 0x20;
>
> or
>
>    config.reg_dat_base = GPIO_REGMAP_ADDR_ZERO;
>
> or if you can't be sure if the RHS value might be zero:
>
>    config.reg_dat_base = GPIO_REGMAP_ADDR(reg);
>
>
> > Maybe drop GPIO_REGMAP_ADDR and require users to set unused registers
> > to GPIO_REGMAP_ADDR_ZERO?
>
> Thats bad because:
>   * you'd have to set plenty of unused base registers for a simple driver
>   * if there will be additional properties in the future, you have to
> touch
>     all other drivers, because they are initialized as 0 (ie. valid reg
> 0).
>
> >> +/**
> >> + * struct gpio_regmap_config - Description of a generic regmap
> >> gpio_chip.
> >> + *
> >> + * @parent:            The parent device
> >> + * @regmap:            The regmap used to access the registers
> >> + *                     given, the name of the device is used
> >> + * @label:             (Optional) Descriptive name for GPIO
> >> controller.
> >> + *                     If not given, the name of the device is used.
> >> + * @ngpio:             Number of GPIOs
> >> + * @reg_dat_base:      (Optional) (in) register base address
> >> + * @reg_set_base:      (Optional) set register base address
> >> + * @reg_clr_base:      (Optional) clear register base address
> >> + * @reg_dir_in_base:   (Optional) out setting register base address
> >> + * @reg_dir_out_base:  (Optional) in setting register base address
> >
> > The two above are inverted I think?
> good catch.
>
> > Also: why the limitation of only supporting one at a time?
>
> they should be exclusive, either you have a register where you set the
> output bits to one, or the input bits. Maybe this need a bit more
> context
> above. in gpio-mmio.c you can set both and both are used in
> set_direction(), but only one is read in get_direction().
>
> That being said, I have no strong opinion wether they should be
> exclusive
> or not, besides the symmetry of set_/get_direction().
>
> -michael
>

Sorry for the late response, your comments make sense to me. Are you
going to submit a v4 before the v5.8 merge window?

Bart

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

* Re: [PATCH v3 10/16] gpio: add a reusable generic gpio_chip using regmap
  2020-05-25  9:05       ` Bartosz Golaszewski
@ 2020-05-25 10:20         ` Michael Walle
  2020-05-25 12:59           ` Linus Walleij
  0 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-05-25 10:20 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Andy Shevchenko, linux-gpio, linux-devicetree, LKML, linux-hwmon,
	linux-pwm, LINUXWATCHDOG, arm-soc, Linus Walleij, Rob Herring,
	Jean Delvare, Guenter Roeck, Lee Jones, Thierry Reding,
	Uwe Kleine-König, Wim Van Sebroeck, Shawn Guo, Li Yang,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Mark Brown,
	Greg Kroah-Hartman

Am 2020-05-25 11:05, schrieb Bartosz Golaszewski:
> wt., 12 maj 2020 o 16:41 Michael Walle <michael@walle.cc> napisał(a):
>> 
>> >> +
>> >> +MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
>> >> +MODULE_DESCRIPTION("GPIO generic regmap driver core");
>> >> +MODULE_LICENSE("GPL");
>> >> diff --git a/include/linux/gpio-regmap.h b/include/linux/gpio-regmap.h
>> >> new file mode 100644
>> >> index 000000000000..a868cbcde6e9
>> >> --- /dev/null
>> >> +++ b/include/linux/gpio-regmap.h
>> >> @@ -0,0 +1,69 @@
>> >> +/* SPDX-License-Identifier: GPL-2.0-only */
>> >> +
>> >> +#ifndef _LINUX_GPIO_REGMAP_H
>> >> +#define _LINUX_GPIO_REGMAP_H
>> >> +
>> >> +struct gpio_regmap;
>> >> +
>> >> +#define GPIO_REGMAP_ADDR_ZERO ((unsigned long)(-1))
>> >> +#define GPIO_REGMAP_ADDR(addr) ((addr) ? : GPIO_REGMAP_ADDR_ZERO)
>> >> +
>> >
>> > What if the addr is actually 0?
>> 
>> Then the driver has to set GPIO_REGMAP_ADDR_ZERO or use the 
>> convenience
>> macro GPIO_REGMAP_ADDR.
>> 
>> So you can have
>> 
>>    struct gpio_regmap_config config = { 0 };
>>    config.reg_dat_base = 0x10;
>>    config.reg_dir_out_base = 0x20;
>> 
>> or
>> 
>>    config.reg_dat_base = GPIO_REGMAP_ADDR_ZERO;
>> 
>> or if you can't be sure if the RHS value might be zero:
>> 
>>    config.reg_dat_base = GPIO_REGMAP_ADDR(reg);
>> 
>> 
>> > Maybe drop GPIO_REGMAP_ADDR and require users to set unused registers
>> > to GPIO_REGMAP_ADDR_ZERO?
>> 
>> Thats bad because:
>>   * you'd have to set plenty of unused base registers for a simple 
>> driver
>>   * if there will be additional properties in the future, you have to
>> touch
>>     all other drivers, because they are initialized as 0 (ie. valid 
>> reg
>> 0).
>> 
>> >> +/**
>> >> + * struct gpio_regmap_config - Description of a generic regmap
>> >> gpio_chip.
>> >> + *
>> >> + * @parent:            The parent device
>> >> + * @regmap:            The regmap used to access the registers
>> >> + *                     given, the name of the device is used
>> >> + * @label:             (Optional) Descriptive name for GPIO
>> >> controller.
>> >> + *                     If not given, the name of the device is used.
>> >> + * @ngpio:             Number of GPIOs
>> >> + * @reg_dat_base:      (Optional) (in) register base address
>> >> + * @reg_set_base:      (Optional) set register base address
>> >> + * @reg_clr_base:      (Optional) clear register base address
>> >> + * @reg_dir_in_base:   (Optional) out setting register base address
>> >> + * @reg_dir_out_base:  (Optional) in setting register base address
>> >
>> > The two above are inverted I think?
>> good catch.
>> 
>> > Also: why the limitation of only supporting one at a time?
>> 
>> they should be exclusive, either you have a register where you set the
>> output bits to one, or the input bits. Maybe this need a bit more
>> context
>> above. in gpio-mmio.c you can set both and both are used in
>> set_direction(), but only one is read in get_direction().
>> 
>> That being said, I have no strong opinion wether they should be
>> exclusive
>> or not, besides the symmetry of set_/get_direction().
>> 
>> -michael
>> 
> 
> Sorry for the late response, your comments make sense to me. Are you
> going to submit a v4 before the v5.8 merge window?

I'm currently stuck with how to handle the MFD part. Ie. Rob doesn't
seem to like the logicial device numbering - or at least there wasn't
an answer to that one anymore, see patch 5/16.

If you like I could submit this patch on its own. But then there
wouldn't be a user for it.

-michael

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

* Re: [PATCH v3 10/16] gpio: add a reusable generic gpio_chip using regmap
  2020-05-25 10:20         ` Michael Walle
@ 2020-05-25 12:59           ` Linus Walleij
  2020-05-25 13:25             ` Andy Shevchenko
  0 siblings, 1 reply; 60+ messages in thread
From: Linus Walleij @ 2020-05-25 12:59 UTC (permalink / raw)
  To: Michael Walle
  Cc: Bartosz Golaszewski, Andy Shevchenko, linux-gpio,
	linux-devicetree, LKML, linux-hwmon, linux-pwm, LINUXWATCHDOG,
	arm-soc, Rob Herring, Jean Delvare, Guenter Roeck, Lee Jones,
	Thierry Reding, Uwe Kleine-König, Wim Van Sebroeck,
	Shawn Guo, Li Yang, Thomas Gleixner, Jason Cooper, Marc Zyngier,
	Mark Brown, Greg Kroah-Hartman

On Mon, May 25, 2020 at 12:20 PM Michael Walle <michael@walle.cc> wrote:

> If you like I could submit this patch on its own. But then there
> wouldn't be a user for it.

I'm pretty much fine with that, we do merge code that has no
users if we anticipate they will be around the corner.

Yours,
Linus Walleij

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

* Re: [PATCH v3 10/16] gpio: add a reusable generic gpio_chip using regmap
  2020-05-25 12:59           ` Linus Walleij
@ 2020-05-25 13:25             ` Andy Shevchenko
  0 siblings, 0 replies; 60+ messages in thread
From: Andy Shevchenko @ 2020-05-25 13:25 UTC (permalink / raw)
  To: Linus Walleij, Pierre-louis Bossart
  Cc: Michael Walle, Bartosz Golaszewski, linux-gpio, linux-devicetree,
	LKML, linux-hwmon, linux-pwm, LINUXWATCHDOG, arm-soc,
	Rob Herring, Jean Delvare, Guenter Roeck, Lee Jones,
	Thierry Reding, Uwe Kleine-König, Wim Van Sebroeck,
	Shawn Guo, Li Yang, Thomas Gleixner, Jason Cooper, Marc Zyngier,
	Mark Brown, Greg Kroah-Hartman

On Mon, May 25, 2020 at 02:59:36PM +0200, Linus Walleij wrote:
> On Mon, May 25, 2020 at 12:20 PM Michael Walle <michael@walle.cc> wrote:
> 
> > If you like I could submit this patch on its own. But then there
> > wouldn't be a user for it.
> 
> I'm pretty much fine with that, we do merge code that has no
> users if we anticipate they will be around the corner.

I remember we discussed with Pierre to use it for his ASoC work.
Pierre, does it sound useful for you?

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v3 03/16] mfd: mfd-core: match device tree node against reg property
  2020-05-15 10:28     ` Lee Jones
@ 2020-05-25 17:36       ` Michael Walle
  2020-05-26  7:24         ` Lee Jones
  0 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-05-25 17:36 UTC (permalink / raw)
  To: Lee Jones
  Cc: Andy Shevchenko, Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Jean Delvare, Guenter Roeck, Thierry Reding,
	Uwe Kleine-König, Wim Van Sebroeck, Shawn Guo, Li Yang,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Mark Brown,
	Greg Kroah-Hartman, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel

Am 2020-05-15 12:28, schrieb Lee Jones:
> On Thu, 30 Apr 2020, Michael Walle wrote:
> 
>> Hi Lee,
>> 
>> Am 2020-04-23 19:45, schrieb Michael Walle:
>> > There might be multiple children with the device tree compatible, for
>> > example if a MFD has multiple instances of the same function. In this
>> > case only the first is matched and the other children get a wrong
>> > of_node reference.
>> > Add a new option to match also against the unit address of the child
>> > node. Additonally, a new helper OF_MFD_CELL_REG is added.
>> 
>> 
>> Do you think this is feasible? I guess this is the biggest uncertainty
>> for me at the moment in this patch series.
> 
> I think it sounds fine in principle.  So long as it doesn't change the
> existing behaviour when of_reg isn't set.
> 
>> > Signed-off-by: Michael Walle <michael@walle.cc>
>> > ---
>> >  drivers/mfd/mfd-core.c   | 29 ++++++++++++++++++++---------
>> >  include/linux/mfd/core.h | 26 ++++++++++++++++++++------
>> >  2 files changed, 40 insertions(+), 15 deletions(-)
>> >
>> > diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
>> > index e735565969b3..4ecb376338f7 100644
>> > --- a/drivers/mfd/mfd-core.c
>> > +++ b/drivers/mfd/mfd-core.c
>> > @@ -117,6 +117,7 @@ static int mfd_add_device(struct device *parent, int
>> > id,
>> >  	struct device_node *np = NULL;
>> >  	int ret = -ENOMEM;
>> >  	int platform_id;
>> > +	u32 of_reg;
>> >  	int r;
>> >
>> >  	if (id == PLATFORM_DEVID_AUTO)
>> > @@ -151,16 +152,26 @@ static int mfd_add_device(struct device *parent,
>> > int id,
>> >
>> >  	if (parent->of_node && cell->of_compatible) {
>> >  		for_each_child_of_node(parent->of_node, np) {
>> > -			if (of_device_is_compatible(np, cell->of_compatible)) {
>> > -				if (!of_device_is_available(np)) {
>> > -					/* Ignore disabled devices error free */
>> > -					ret = 0;
>> > -					goto fail_alias;
>> > -				}
>> > -				pdev->dev.of_node = np;
>> > -				pdev->dev.fwnode = &np->fwnode;
>> > -				break;
>> > +			if (!of_device_is_compatible(np, cell->of_compatible))
>> > +				continue;
>> > +
>> > +			/* also match the unit address if set */
> 
> Please use correct grammar in comments (leaving off the full-stop).
> 
>> > +			if (cell->of_reg & MFD_OF_REG_VALID) {
>> > +				if (of_property_read_u32(np, "reg", &of_reg))
>> > +					continue;
>> > +				if ((cell->of_reg & MFD_OF_REG_MASK) != of_reg)
>> > +					continue;
>> >  			}
>> > +
>> > +			if (!of_device_is_available(np)) {
>> > +				/* Ignore disabled devices error free */
>> > +				ret = 0;
>> > +				goto fail_alias;
>> > +			}
>> > +
>> > +			pdev->dev.of_node = np;
>> > +			pdev->dev.fwnode = &np->fwnode;
>> > +			break;
>> >  		}
>> >  	}
>> >
>> > diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
>> > index d01d1299e49d..c2c0ad6b14f3 100644
>> > --- a/include/linux/mfd/core.h
>> > +++ b/include/linux/mfd/core.h
>> > @@ -13,8 +13,11 @@
>> >  #include <linux/platform_device.h>
>> >
>> >  #define MFD_RES_SIZE(arr) (sizeof(arr) / sizeof(struct resource))
>> > +#define MFD_OF_REG_VALID	BIT(31)
> 
> What about 64bit platforms?

The idea was to have this as a logical number. I.e. for now you may only
have one subdevice per unique compatible string. In fact, if you have a
look at the ab8500.c, there are multiple "stericsson,ab8500-pwm"
subdevices. But there is only one DT node for all three of it. I guess
this works as long as you don't use phandles to reference the pwm node
in the device tree. Or you don't want to use device tree properties
per subdevice (for example the "timeout-sec" of a watchdog device).

So to circumvent this, I thought of having the unit-address (and thus
the "reg" property) to differentiate between multiple subdevices. Now
there is one special case for me: this board management controller
might be upgradable and it might change internally. Thus I came up
with that logical numbering of subdevices. Rob doesn't seem to be a
fan of that, though. Therefore, having bit 31 as a valid indicator
leaves you with 2^31 logical devices, which should be enough ;)

Rob proposed to have the internal offset as the unit-address. But
in that case I can also use devm_of_platform_populate() and don't
need the OF_MFD_CELL_REG; I'd just parse the reg offset in each
individual subdevice driver. But like I said, I wanted to keep the
internal offsets out of the device tree.

-michael

> 
>> > +#define MFD_OF_REG_MASK		GENMASK(30, 0)
>> >
>> > -#define MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat,
>> > _match)\
>> > +#define MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat,	\
>> > +		     _of_reg, _match)					\
>> >  	{								\
>> >  		.name = (_name),					\
>> >  		.resources = (_res),					\
>> > @@ -22,24 +25,32 @@
>> >  		.platform_data = (_pdata),				\
>> >  		.pdata_size = (_pdsize),				\
>> >  		.of_compatible = (_compat),				\
>> > +		.of_reg = (_of_reg),					\
>> >  		.acpi_match = (_match),					\
>> >  		.id = (_id),						\
>> >  	}
>> >
>> > +#define OF_MFD_CELL_REG(_name, _res, _pdata, _pdsize, _id, _compat,	\
>> > +			_of_reg)					\
>> > +	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat,	\
>> > +		     ((_of_reg) | MFD_OF_REG_VALID), NULL)		\
>> > +
>> >  #define OF_MFD_CELL(_name, _res, _pdata, _pdsize,_id, _compat)		\
>> > -	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, NULL)	\
>> > +	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat,	\
>> > +		     0, NULL)						\
>> >
>> >  #define ACPI_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _match)	\
>> > -	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, _match)	\
>> > +	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, 0,	\
>> > +		     _match)						\
>> >
>> >  #define MFD_CELL_BASIC(_name, _res, _pdata, _pdsize, _id)		\
>> > -	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, NULL)	\
>> > +	MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, 0, NULL) \
>> >
>> >  #define MFD_CELL_RES(_name, _res)					\
>> > -	MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, NULL)		\
>> > +	MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, 0, NULL)		\
>> >
>> >  #define MFD_CELL_NAME(_name)						\
>> > -	MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, NULL)		\
>> > +	MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, 0, NULL)		\
>> >
>> >  struct irq_domain;
>> >  struct property_entry;
>> > @@ -78,6 +89,9 @@ struct mfd_cell {
>> >  	 */
>> >  	const char		*of_compatible;
>> >
>> > +	/* matching the reg property if set */
> 
> Proper grammar please.
> 
> "OF unit address for device matching"
> 
>> > +	unsigned int		of_reg;
>> > +
>> >  	/* Matches ACPI */
>> >  	const struct mfd_cell_acpi_match	*acpi_match;

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

* Re: [PATCH v3 03/16] mfd: mfd-core: match device tree node against reg property
  2020-05-25 17:36       ` Michael Walle
@ 2020-05-26  7:24         ` Lee Jones
  2020-05-26 15:54           ` Michael Walle
  0 siblings, 1 reply; 60+ messages in thread
From: Lee Jones @ 2020-05-26  7:24 UTC (permalink / raw)
  To: Michael Walle
  Cc: Andy Shevchenko, Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Jean Delvare, Guenter Roeck, Thierry Reding,
	Uwe Kleine-König, Wim Van Sebroeck, Shawn Guo, Li Yang,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Mark Brown,
	Greg Kroah-Hartman, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel

On Mon, 25 May 2020, Michael Walle wrote:

> Am 2020-05-15 12:28, schrieb Lee Jones:
> > On Thu, 30 Apr 2020, Michael Walle wrote:
> > 
> > > Hi Lee,
> > > 
> > > Am 2020-04-23 19:45, schrieb Michael Walle:
> > > > There might be multiple children with the device tree compatible, for
> > > > example if a MFD has multiple instances of the same function. In this
> > > > case only the first is matched and the other children get a wrong
> > > > of_node reference.
> > > > Add a new option to match also against the unit address of the child
> > > > node. Additonally, a new helper OF_MFD_CELL_REG is added.
> > > 
> > > 
> > > Do you think this is feasible? I guess this is the biggest uncertainty
> > > for me at the moment in this patch series.
> > 
> > I think it sounds fine in principle.  So long as it doesn't change the
> > existing behaviour when of_reg isn't set.
> > 
> > > > Signed-off-by: Michael Walle <michael@walle.cc>
> > > > ---
> > > >  drivers/mfd/mfd-core.c   | 29 ++++++++++++++++++++---------
> > > >  include/linux/mfd/core.h | 26 ++++++++++++++++++++------
> > > >  2 files changed, 40 insertions(+), 15 deletions(-)

[...]

> > > > diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
> > > > index d01d1299e49d..c2c0ad6b14f3 100644
> > > > --- a/include/linux/mfd/core.h
> > > > +++ b/include/linux/mfd/core.h
> > > > @@ -13,8 +13,11 @@
> > > >  #include <linux/platform_device.h>
> > > >
> > > >  #define MFD_RES_SIZE(arr) (sizeof(arr) / sizeof(struct resource))
> > > > +#define MFD_OF_REG_VALID	BIT(31)
> > 
> > What about 64bit platforms?
> 
> The idea was to have this as a logical number. I.e. for now you may only
> have one subdevice per unique compatible string. In fact, if you have a
> look at the ab8500.c, there are multiple "stericsson,ab8500-pwm"
> subdevices. But there is only one DT node for all three of it. I guess
> this works as long as you don't use phandles to reference the pwm node
> in the device tree. Or you don't want to use device tree properties
> per subdevice (for example the "timeout-sec" of a watchdog device).
> 
> So to circumvent this, I thought of having the unit-address (and thus
> the "reg" property) to differentiate between multiple subdevices. Now
> there is one special case for me: this board management controller
> might be upgradable and it might change internally. Thus I came up
> with that logical numbering of subdevices. Rob doesn't seem to be a
> fan of that, though. Therefore, having bit 31 as a valid indicator
> leaves you with 2^31 logical devices, which should be enough ;)
> 
> Rob proposed to have the internal offset as the unit-address. But
> in that case I can also use devm_of_platform_populate() and don't
> need the OF_MFD_CELL_REG; I'd just parse the reg offset in each
> individual subdevice driver. But like I said, I wanted to keep the
> internal offsets out of the device tree.

Oh, I see what you're doing.

So you're adding an arbitrary ID to the device's reg property in DT?

How is this not a hack?

Why don't you use the full address for identification?

-- 
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

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

* Re: [PATCH v3 03/16] mfd: mfd-core: match device tree node against reg property
  2020-05-26  7:24         ` Lee Jones
@ 2020-05-26 15:54           ` Michael Walle
  2020-05-26 16:03             ` Andy Shevchenko
  0 siblings, 1 reply; 60+ messages in thread
From: Michael Walle @ 2020-05-26 15:54 UTC (permalink / raw)
  To: Lee Jones
  Cc: Andy Shevchenko, Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Jean Delvare, Guenter Roeck, Thierry Reding,
	Uwe Kleine-König, Wim Van Sebroeck, Shawn Guo, Li Yang,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Mark Brown,
	Greg Kroah-Hartman, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel

Am 2020-05-26 09:24, schrieb Lee Jones:
> On Mon, 25 May 2020, Michael Walle wrote:
> 
>> Am 2020-05-15 12:28, schrieb Lee Jones:
>> > On Thu, 30 Apr 2020, Michael Walle wrote:
>> >
>> > > Hi Lee,
>> > >
>> > > Am 2020-04-23 19:45, schrieb Michael Walle:
>> > > > There might be multiple children with the device tree compatible, for
>> > > > example if a MFD has multiple instances of the same function. In this
>> > > > case only the first is matched and the other children get a wrong
>> > > > of_node reference.
>> > > > Add a new option to match also against the unit address of the child
>> > > > node. Additonally, a new helper OF_MFD_CELL_REG is added.
>> > >
>> > >
>> > > Do you think this is feasible? I guess this is the biggest uncertainty
>> > > for me at the moment in this patch series.
>> >
>> > I think it sounds fine in principle.  So long as it doesn't change the
>> > existing behaviour when of_reg isn't set.
>> >
>> > > > Signed-off-by: Michael Walle <michael@walle.cc>
>> > > > ---
>> > > >  drivers/mfd/mfd-core.c   | 29 ++++++++++++++++++++---------
>> > > >  include/linux/mfd/core.h | 26 ++++++++++++++++++++------
>> > > >  2 files changed, 40 insertions(+), 15 deletions(-)
> 
> [...]
> 
>> > > > diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
>> > > > index d01d1299e49d..c2c0ad6b14f3 100644
>> > > > --- a/include/linux/mfd/core.h
>> > > > +++ b/include/linux/mfd/core.h
>> > > > @@ -13,8 +13,11 @@
>> > > >  #include <linux/platform_device.h>
>> > > >
>> > > >  #define MFD_RES_SIZE(arr) (sizeof(arr) / sizeof(struct resource))
>> > > > +#define MFD_OF_REG_VALID	BIT(31)
>> >
>> > What about 64bit platforms?
>> 
>> The idea was to have this as a logical number. I.e. for now you may 
>> only
>> have one subdevice per unique compatible string. In fact, if you have 
>> a
>> look at the ab8500.c, there are multiple "stericsson,ab8500-pwm"
>> subdevices. But there is only one DT node for all three of it. I guess
>> this works as long as you don't use phandles to reference the pwm node
>> in the device tree. Or you don't want to use device tree properties
>> per subdevice (for example the "timeout-sec" of a watchdog device).
>> 
>> So to circumvent this, I thought of having the unit-address (and thus
>> the "reg" property) to differentiate between multiple subdevices. Now
>> there is one special case for me: this board management controller
>> might be upgradable and it might change internally. Thus I came up
>> with that logical numbering of subdevices. Rob doesn't seem to be a
>> fan of that, though. Therefore, having bit 31 as a valid indicator
>> leaves you with 2^31 logical devices, which should be enough ;)
>> 
>> Rob proposed to have the internal offset as the unit-address. But
>> in that case I can also use devm_of_platform_populate() and don't
>> need the OF_MFD_CELL_REG; I'd just parse the reg offset in each
>> individual subdevice driver. But like I said, I wanted to keep the
>> internal offsets out of the device tree.
> 
> Oh, I see what you're doing.
> 
> So you're adding an arbitrary ID to the device's reg property in DT?

Yes.

> How is this not a hack?

Well IMHO this is not more or less a hack as the current of_node
handling of MFD devices, which happens to work only because there
is only one device per compatible string (or it doesn't really work,
like in the stericsson,ab8500-pwm case). The of_node is assigned
according to the compatible string, just like in my case, only that
I have two subdevices with the same compatible string.

> Why don't you use the full address for identification?

Like I said, in the long term I would like to have support for
different versions of the board management controller without having
to change the device tree and have device tree bindings for the
subdevices at the same time. But it seems, that this is not possible
and I guess I have to bite the bullet and may need to provide another
device tree if the controller might be updated.

-michael

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

* Re: [PATCH v3 03/16] mfd: mfd-core: match device tree node against reg property
  2020-05-26 15:54           ` Michael Walle
@ 2020-05-26 16:03             ` Andy Shevchenko
  2020-05-27  6:53               ` Lee Jones
  0 siblings, 1 reply; 60+ messages in thread
From: Andy Shevchenko @ 2020-05-26 16:03 UTC (permalink / raw)
  To: Michael Walle
  Cc: Lee Jones, Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Jean Delvare, Guenter Roeck, Thierry Reding,
	Uwe Kleine-König, Wim Van Sebroeck, Shawn Guo, Li Yang,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Mark Brown,
	Greg Kroah-Hartman, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel

On Tue, May 26, 2020 at 05:54:38PM +0200, Michael Walle wrote:
> Am 2020-05-26 09:24, schrieb Lee Jones:

...

> Like I said, in the long term I would like to have support for
> different versions of the board management controller

> without having to change the device tree and have device tree bindings for the
> subdevices at the same time.

But isn't device tree to describe *very specific platform* rather than *class
of platforms*?

> But it seems, that this is not possible
> and I guess I have to bite the bullet and may need to provide another
> device tree if the controller might be updated.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v3 03/16] mfd: mfd-core: match device tree node against reg property
  2020-05-26 16:03             ` Andy Shevchenko
@ 2020-05-27  6:53               ` Lee Jones
  0 siblings, 0 replies; 60+ messages in thread
From: Lee Jones @ 2020-05-27  6:53 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Michael Walle, Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Jean Delvare, Guenter Roeck, Thierry Reding,
	Uwe Kleine-König, Wim Van Sebroeck, Shawn Guo, Li Yang,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Mark Brown,
	Greg Kroah-Hartman, linux-gpio, devicetree, linux-kernel,
	linux-hwmon, linux-pwm, linux-watchdog, linux-arm-kernel

On Tue, 26 May 2020, Andy Shevchenko wrote:

> On Tue, May 26, 2020 at 05:54:38PM +0200, Michael Walle wrote:
> > Am 2020-05-26 09:24, schrieb Lee Jones:
> 
> ...
> 
> > Like I said, in the long term I would like to have support for
> > different versions of the board management controller
> 
> > without having to change the device tree and have device tree bindings for the
> > subdevices at the same time.
> 
> But isn't device tree to describe *very specific platform* rather than *class
> of platforms*?

Yes.  Device Tree describes the hardware.

If the hardware changes, so must the Device Tree.

-- 
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

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

end of thread, back to index

Thread overview: 60+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-23 17:45 [PATCH v3 00/16] Add support for Kontron sl28cpld Michael Walle
2020-04-23 17:45 ` [PATCH v3 01/16] include/linux/ioport.h: add helper to define REG resource constructs Michael Walle
2020-04-23 17:45 ` [PATCH v3 02/16] mfd: mfd-core: Don't overwrite the dma_mask of the child device Michael Walle
2020-04-28 12:45   ` Andy Shevchenko
2020-04-28 13:06     ` Robin Murphy
2020-04-28 14:29       ` Andy Shevchenko
2020-04-28 14:49         ` Robin Murphy
2020-04-28 15:25           ` Mark Brown
2020-05-14 20:45             ` Michael Walle
2020-04-23 17:45 ` [PATCH v3 03/16] mfd: mfd-core: match device tree node against reg property Michael Walle
2020-04-29 22:18   ` Michael Walle
2020-05-15 10:28     ` Lee Jones
2020-05-25 17:36       ` Michael Walle
2020-05-26  7:24         ` Lee Jones
2020-05-26 15:54           ` Michael Walle
2020-05-26 16:03             ` Andy Shevchenko
2020-05-27  6:53               ` Lee Jones
2020-04-23 17:45 ` [PATCH v3 04/16] dt-bindings: mfd: Add bindings for sl28cpld Michael Walle
2020-04-28 12:48   ` Andy Shevchenko
2020-04-28 14:39     ` Michael Walle
2020-04-28 14:49       ` Andy Shevchenko
2020-04-23 17:45 ` [PATCH v3 05/16] mfd: Add support for Kontron sl28cpld management controller Michael Walle
2020-04-28 12:50   ` Andy Shevchenko
2020-04-28 14:43     ` Michael Walle
2020-04-28 14:49       ` Andy Shevchenko
2020-04-29  6:27         ` Lee Jones
2020-05-11 21:13   ` Rob Herring
2020-05-11 21:44     ` Michael Walle
2020-05-11 22:29       ` Michael Walle
2020-05-12 21:59       ` Rob Herring
2020-05-13 22:15         ` Michael Walle
2020-04-23 17:45 ` [PATCH v3 06/16] irqchip: add sl28cpld interrupt controller support Michael Walle
2020-04-27 11:40   ` Thomas Gleixner
2020-04-27 17:40     ` Michael Walle
2020-04-27 17:44       ` Mark Brown
2020-04-27 18:01         ` Michael Walle
2020-04-27 18:05           ` Mark Brown
2020-04-27 19:00       ` Thomas Gleixner
2020-04-23 17:45 ` [PATCH v3 07/16] watchdog: add support for sl28cpld watchdog Michael Walle
2020-04-25 17:02   ` Guenter Roeck
2020-04-23 17:45 ` [PATCH v3 08/16] pwm: add support for sl28cpld PWM controller Michael Walle
2020-05-11 20:45   ` Rob Herring
2020-04-23 17:45 ` [PATCH v3 09/16] gpiolib: Introduce gpiochip_irqchip_add_domain() Michael Walle
2020-04-27 11:42   ` Thomas Gleixner
2020-04-27 17:49     ` Michael Walle
2020-04-23 17:45 ` [PATCH v3 10/16] gpio: add a reusable generic gpio_chip using regmap Michael Walle
2020-05-12 12:48   ` Bartosz Golaszewski
2020-05-12 14:41     ` Michael Walle
2020-05-25  9:05       ` Bartosz Golaszewski
2020-05-25 10:20         ` Michael Walle
2020-05-25 12:59           ` Linus Walleij
2020-05-25 13:25             ` Andy Shevchenko
2020-04-23 17:45 ` [PATCH v3 11/16] gpio: add support for the sl28cpld GPIO controller Michael Walle
2020-04-27 11:45   ` Thomas Gleixner
2020-04-27 17:58     ` Michael Walle
2020-04-23 17:45 ` [PATCH v3 12/16] hwmon: add support for the sl28cpld hardware monitoring controller Michael Walle
2020-04-23 17:45 ` [PATCH v3 13/16] arm64: dts: freescale: sl28: enable sl28cpld Michael Walle
2020-04-23 17:45 ` [PATCH v3 14/16] arm64: dts: freescale: sl28: map GPIOs to input events Michael Walle
2020-04-23 17:45 ` [PATCH v3 15/16] arm64: dts: freescale: sl28: enable LED support Michael Walle
2020-04-23 17:45 ` [PATCH v3 16/16] arm64: dts: freescale: sl28: enable fan support Michael Walle

Linux-Hwmon Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-hwmon/0 linux-hwmon/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-hwmon linux-hwmon/ https://lore.kernel.org/linux-hwmon \
		linux-hwmon@vger.kernel.org
	public-inbox-index linux-hwmon

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-hwmon


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git