All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv4 0/6] GE Healthcare PPD firmware upgrade driver for ACHC
@ 2021-06-09 15:12 Sebastian Reichel
  2021-06-09 15:12 ` [PATCHv4 1/6] spi: add ancillary device support Sebastian Reichel
                   ` (6 more replies)
  0 siblings, 7 replies; 16+ messages in thread
From: Sebastian Reichel @ 2021-06-09 15:12 UTC (permalink / raw)
  To: Mark Brown, Rob Herring
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Shawn Guo, Sascha Hauer,
	Fabio Estevam, Ian Ray, linux-kernel, linux-spi, devicetree,
	kernel, Sebastian Reichel

Hi,

The PPD has a secondary processor (NXP Kinetis K20), which can be
programmed from the main system. It is connected to the main processor
by having it's EzPort interface connected to the SPI bus. Currently
both (normal and EzPort) interfaces are simply exposed to userspace.
This does not work for the EzPort, since EzPort usage requires a device
reset. The proper solution is to do the flashing from kernel space
with properly timed toggling of EzPort chip-select and reset line. In
PATCHv2 it was suggested, that this should happen via an SPI ancillary
device, so this is how it has been implemented now.

Changes since PATCHv3:
 * https://lore.kernel.org/lkml/20210528113346.37137-1-sebastian.reichel@collabora.com/
 * Add Rob's Acked-by to 2nd patch
 * use GPL-2-only instead of GPL-2+
 * use %zu for printing a size_t
 * use driver's .dev_groups to register sysfs group
 * Add sysfs property documentation
 * split EzPort and ACHC drivers into separate patches
 * drop minItems/maxItems from achc binding, which seems to fix the problems
   reported by dt_binding_check. The information of two items being required
   is implied by the explicit item list.
 * drop spidev functionality for the main SPI interface. The current firmware
   communicates via UART and adding spidev support is complex. If future firmware
   releases start using it, spidev support for the main interface can be added
   later.

Changes since PATCHv2:
 * https://lore.kernel.org/lkml/20180327135259.30890-1-sebastian.reichel@collabora.co.uk/
 * add SPI core support for ancillary devices
 * modify ACHC binding to make use of ancillary device
 * rewrite driver to use ancillary device
 * rebased to 5.13-rc1

Changes since PATCHv1:
 * https://lore.kernel.org/lkml/20180320172201.2065-1-sebastian.reichel@collabora.co.uk/
 * split DT binding update into its own patch
 * add sysfs attribute documentation
 * fix problem reported by kbuild test robot

-- Sebastian

Sebastian Reichel (6):
  spi: add ancillary device support
  spi: dt-bindings: support devices with multiple chipselects
  dt-bindings: misc: ge-achc: Convert to DT schema format
  ARM: dts: imx53-ppd: Fix ACHC entry
  misc: nxp-ezport: introduce EzPort support
  misc: gehc-achc: new driver

 .../ABI/testing/sysfs-driver-ge-achc          |   9 +
 .../devicetree/bindings/misc/ge-achc.txt      |  26 -
 .../devicetree/bindings/misc/ge-achc.yaml     |  65 +++
 .../bindings/spi/spi-controller.yaml          |   7 +-
 arch/arm/boot/dts/imx53-ppd.dts               |  23 +-
 drivers/misc/Kconfig                          |  15 +
 drivers/misc/Makefile                         |   2 +
 drivers/misc/gehc-achc.c                      | 136 +++++
 drivers/misc/nxp-ezport.c                     | 476 ++++++++++++++++++
 drivers/spi/spi.c                             | 139 +++--
 drivers/spi/spidev.c                          |   1 -
 include/linux/platform_data/nxp-ezport.h      |   9 +
 include/linux/spi/spi.h                       |   2 +
 13 files changed, 839 insertions(+), 71 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-driver-ge-achc
 delete mode 100644 Documentation/devicetree/bindings/misc/ge-achc.txt
 create mode 100644 Documentation/devicetree/bindings/misc/ge-achc.yaml
 create mode 100644 drivers/misc/gehc-achc.c
 create mode 100644 drivers/misc/nxp-ezport.c
 create mode 100644 include/linux/platform_data/nxp-ezport.h

-- 
2.30.2


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

* [PATCHv4 1/6] spi: add ancillary device support
  2021-06-09 15:12 [PATCHv4 0/6] GE Healthcare PPD firmware upgrade driver for ACHC Sebastian Reichel
@ 2021-06-09 15:12 ` Sebastian Reichel
  2021-06-11  9:06   ` Greg Kroah-Hartman
                     ` (2 more replies)
  2021-06-09 15:12 ` [PATCHv4 2/6] spi: dt-bindings: support devices with multiple chipselects Sebastian Reichel
                   ` (5 subsequent siblings)
  6 siblings, 3 replies; 16+ messages in thread
From: Sebastian Reichel @ 2021-06-09 15:12 UTC (permalink / raw)
  To: Mark Brown, Rob Herring
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Shawn Guo, Sascha Hauer,
	Fabio Estevam, Ian Ray, linux-kernel, linux-spi, devicetree,
	kernel, Sebastian Reichel

Introduce support for ancillary devices, similar to existing
implementation for I2C. This is useful for devices having
multiple chip-selects, for example some microcontrollers
provide a normal SPI interface and a flashing SPI interface.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/spi/spi.c       | 139 +++++++++++++++++++++++++++++++---------
 include/linux/spi/spi.h |   2 +
 2 files changed, 109 insertions(+), 32 deletions(-)

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index ba425b9c7700..7fdf224262b1 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -558,49 +558,23 @@ static int spi_dev_check(struct device *dev, void *data)
 	return 0;
 }
 
-/**
- * spi_add_device - Add spi_device allocated with spi_alloc_device
- * @spi: spi_device to register
- *
- * Companion function to spi_alloc_device.  Devices allocated with
- * spi_alloc_device can be added onto the spi bus with this function.
- *
- * Return: 0 on success; negative errno on failure
- */
-int spi_add_device(struct spi_device *spi)
+static int __spi_add_device(struct spi_device *spi)
 {
 	struct spi_controller *ctlr = spi->controller;
 	struct device *dev = ctlr->dev.parent;
 	int status;
 
-	/* Chipselects are numbered 0..max; validate. */
-	if (spi->chip_select >= ctlr->num_chipselect) {
-		dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
-			ctlr->num_chipselect);
-		return -EINVAL;
-	}
-
-	/* Set the bus ID string */
-	spi_dev_set_name(spi);
-
-	/* We need to make sure there's no other device with this
-	 * chipselect **BEFORE** we call setup(), else we'll trash
-	 * its configuration.  Lock against concurrent add() calls.
-	 */
-	mutex_lock(&spi_add_lock);
-
 	status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
 	if (status) {
 		dev_err(dev, "chipselect %d already in use\n",
 				spi->chip_select);
-		goto done;
+		return status;
 	}
 
 	/* Controller may unregister concurrently */
 	if (IS_ENABLED(CONFIG_SPI_DYNAMIC) &&
 	    !device_is_registered(&ctlr->dev)) {
-		status = -ENODEV;
-		goto done;
+		return -ENODEV;
 	}
 
 	/* Descriptors take precedence */
@@ -617,7 +591,7 @@ int spi_add_device(struct spi_device *spi)
 	if (status < 0) {
 		dev_err(dev, "can't setup %s, status %d\n",
 				dev_name(&spi->dev), status);
-		goto done;
+		return status;
 	}
 
 	/* Device may be bound to an active driver when this returns */
@@ -628,12 +602,64 @@ int spi_add_device(struct spi_device *spi)
 	else
 		dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));
 
-done:
+	return status;
+}
+
+/**
+ * spi_add_device - Add spi_device allocated with spi_alloc_device
+ * @spi: spi_device to register
+ *
+ * Companion function to spi_alloc_device.  Devices allocated with
+ * spi_alloc_device can be added onto the spi bus with this function.
+ *
+ * Return: 0 on success; negative errno on failure
+ */
+int spi_add_device(struct spi_device *spi)
+{
+	struct spi_controller *ctlr = spi->controller;
+	struct device *dev = ctlr->dev.parent;
+	int status;
+
+	/* Chipselects are numbered 0..max; validate. */
+	if (spi->chip_select >= ctlr->num_chipselect) {
+		dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
+			ctlr->num_chipselect);
+		return -EINVAL;
+	}
+
+	/* Set the bus ID string */
+	spi_dev_set_name(spi);
+
+	/* We need to make sure there's no other device with this
+	 * chipselect **BEFORE** we call setup(), else we'll trash
+	 * its configuration.  Lock against concurrent add() calls.
+	 */
+	mutex_lock(&spi_add_lock);
+	status = __spi_add_device(spi);
 	mutex_unlock(&spi_add_lock);
 	return status;
 }
 EXPORT_SYMBOL_GPL(spi_add_device);
 
+static int spi_add_device_locked(struct spi_device *spi)
+{
+	struct spi_controller *ctlr = spi->controller;
+	struct device *dev = ctlr->dev.parent;
+
+	/* Chipselects are numbered 0..max; validate. */
+	if (spi->chip_select >= ctlr->num_chipselect) {
+		dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
+			ctlr->num_chipselect);
+		return -EINVAL;
+	}
+
+	/* Set the bus ID string */
+	spi_dev_set_name(spi);
+
+	WARN_ON(!mutex_is_locked(&spi_add_lock));
+	return __spi_add_device(spi);
+}
+
 /**
  * spi_new_device - instantiate one new SPI device
  * @ctlr: Controller to which device is connected
@@ -1993,7 +2019,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
 	}
 
 	/* Device address */
-	rc = of_property_read_u32(nc, "reg", &value);
+	rc = of_property_read_u32_index(nc, "reg", 0, &value);
 	if (rc) {
 		dev_err(&ctlr->dev, "%pOF has no valid 'reg' property (%d)\n",
 			nc, rc);
@@ -2084,6 +2110,55 @@ static void of_register_spi_devices(struct spi_controller *ctlr)
 static void of_register_spi_devices(struct spi_controller *ctlr) { }
 #endif
 
+/**
+ * spi_new_ancillary_device() - Register ancillary SPI device
+ * @spi:         Pointer to the main SPI device registering the ancillary device
+ * @chip_select: Chip Select of the ancillary device
+ *
+ * Register an ancillary SPI device; for example some chips have a chip-select
+ * for normal device usage and another one for setup/firmware upload.
+ *
+ * This may only be called from main SPI device's probe routine.
+ *
+ * Return: 0 on success; negative errno on failure
+ */
+struct spi_device *spi_new_ancillary_device(struct spi_device *spi,
+					     u8 chip_select)
+{
+	struct spi_device *ancillary;
+	int rc = 0;
+
+	/* Alloc an spi_device */
+	ancillary = spi_alloc_device(spi->controller);
+	if (!ancillary) {
+		rc = -ENOMEM;
+		goto err_out;
+	}
+
+	strlcpy(ancillary->modalias, "dummy", sizeof(ancillary->modalias));
+
+	/* Use provided chip-select for ancillary device */
+	ancillary->chip_select = chip_select;
+
+	/* Take over SPI mode/speed from SPI main device */
+	ancillary->max_speed_hz = spi->max_speed_hz;
+	ancillary->mode = ancillary->mode;
+
+	/* Register the new device */
+	rc = spi_add_device_locked(ancillary);
+	if (rc) {
+		dev_err(&spi->dev, "failed to register ancillary device\n");
+		goto err_out;
+	}
+
+	return ancillary;
+
+err_out:
+	spi_dev_put(ancillary);
+	return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(spi_new_ancillary_device);
+
 #ifdef CONFIG_ACPI
 struct acpi_spi_lookup {
 	struct spi_controller 	*ctlr;
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 360a3bc767ca..1949230ccd3a 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -299,6 +299,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
 		driver_unregister(&sdrv->driver);
 }
 
+extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 chip_select);
+
 /* use a define to avoid include chaining to get THIS_MODULE */
 #define spi_register_driver(driver) \
 	__spi_register_driver(THIS_MODULE, driver)
-- 
2.30.2


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

* [PATCHv4 2/6] spi: dt-bindings: support devices with multiple chipselects
  2021-06-09 15:12 [PATCHv4 0/6] GE Healthcare PPD firmware upgrade driver for ACHC Sebastian Reichel
  2021-06-09 15:12 ` [PATCHv4 1/6] spi: add ancillary device support Sebastian Reichel
@ 2021-06-09 15:12 ` Sebastian Reichel
  2021-06-09 15:12 ` [PATCHv4 3/6] dt-bindings: misc: ge-achc: Convert to DT schema format Sebastian Reichel
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 16+ messages in thread
From: Sebastian Reichel @ 2021-06-09 15:12 UTC (permalink / raw)
  To: Mark Brown, Rob Herring
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Shawn Guo, Sascha Hauer,
	Fabio Estevam, Ian Ray, linux-kernel, linux-spi, devicetree,
	kernel, Sebastian Reichel, Rob Herring

Add binding support for devices, that have more than one
chip select. A typical example are SPI connected microcontroller,
that can also be programmed over SPI like NXP Kinetis or
chips with a configuration and a data chip select, such as
Microchip's MRF89XA transceiver.

Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 Documentation/devicetree/bindings/spi/spi-controller.yaml | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/spi/spi-controller.yaml b/Documentation/devicetree/bindings/spi/spi-controller.yaml
index 0477396e4945..faef4f6f55b8 100644
--- a/Documentation/devicetree/bindings/spi/spi-controller.yaml
+++ b/Documentation/devicetree/bindings/spi/spi-controller.yaml
@@ -114,8 +114,11 @@ patternProperties:
           Compatible of the SPI device.
 
       reg:
-        minimum: 0
-        maximum: 256
+        minItems: 1
+        maxItems: 256
+        items:
+          minimum: 0
+          maximum: 256
         description:
           Chip select used by the device.
 
-- 
2.30.2


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

* [PATCHv4 3/6] dt-bindings: misc: ge-achc: Convert to DT schema format
  2021-06-09 15:12 [PATCHv4 0/6] GE Healthcare PPD firmware upgrade driver for ACHC Sebastian Reichel
  2021-06-09 15:12 ` [PATCHv4 1/6] spi: add ancillary device support Sebastian Reichel
  2021-06-09 15:12 ` [PATCHv4 2/6] spi: dt-bindings: support devices with multiple chipselects Sebastian Reichel
@ 2021-06-09 15:12 ` Sebastian Reichel
  2021-06-10 16:41   ` Rob Herring
  2021-06-09 15:12 ` [PATCHv4 4/6] ARM: dts: imx53-ppd: Fix ACHC entry Sebastian Reichel
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 16+ messages in thread
From: Sebastian Reichel @ 2021-06-09 15:12 UTC (permalink / raw)
  To: Mark Brown, Rob Herring
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Shawn Guo, Sascha Hauer,
	Fabio Estevam, Ian Ray, linux-kernel, linux-spi, devicetree,
	kernel, Sebastian Reichel

Convert the binding to DT schema format. Also update the binding
to fix shortcomings

 * Add "nxp,kinetis-k20" fallback compatible
 * add programming SPI interface and reset GPIO
 * add main clock
 * add voltage supplies
 * drop spi-max-frequency from required properties,
   driver will setup max. frequency

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 .../devicetree/bindings/misc/ge-achc.txt      | 26 --------
 .../devicetree/bindings/misc/ge-achc.yaml     | 65 +++++++++++++++++++
 2 files changed, 65 insertions(+), 26 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/misc/ge-achc.txt
 create mode 100644 Documentation/devicetree/bindings/misc/ge-achc.yaml

diff --git a/Documentation/devicetree/bindings/misc/ge-achc.txt b/Documentation/devicetree/bindings/misc/ge-achc.txt
deleted file mode 100644
index 77df94d7a32f..000000000000
--- a/Documentation/devicetree/bindings/misc/ge-achc.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-* GE Healthcare USB Management Controller
-
-A device which handles data aquisition from compatible USB based peripherals.
-SPI is used for device management.
-
-Note: This device does not expose the peripherals as USB devices.
-
-Required properties:
-
-- compatible : Should be "ge,achc"
-
-Required SPI properties:
-
-- reg : Should be address of the device chip select within
-  the controller.
-
-- spi-max-frequency : Maximum SPI clocking speed of device in Hz, should be
-  1MHz for the GE ACHC.
-
-Example:
-
-spidev0: spi@0 {
-	compatible = "ge,achc";
-	reg = <0>;
-	spi-max-frequency = <1000000>;
-};
diff --git a/Documentation/devicetree/bindings/misc/ge-achc.yaml b/Documentation/devicetree/bindings/misc/ge-achc.yaml
new file mode 100644
index 000000000000..ff07aa62ed57
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/ge-achc.yaml
@@ -0,0 +1,65 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+# Copyright (C) 2021 GE Inc.
+# Copyright (C) 2021 Collabora Ltd.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/misc/ge-achc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: GE Healthcare USB Management Controller
+
+description: |
+  A device which handles data acquisition from compatible USB based peripherals.
+  SPI is used for device management.
+
+  Note: This device does not expose the peripherals as USB devices.
+
+maintainers:
+  - Sebastian Reichel <sre@kernel.org>
+
+properties:
+  compatible:
+    items:
+      - const: ge,achc
+      - const: nxp,kinetis-k20
+
+  clocks:
+    maxItems: 1
+
+  vdd-supply:
+    description: Digital power supply regulator on VDD pin
+
+  vdda-supply:
+    description: Analog power supply regulator on VDDA pin
+
+  reg:
+    items:
+      - description: Control interface
+      - description: Firmware programming interface
+
+  reset-gpios:
+    description: GPIO used for hardware reset.
+    maxItems: 1
+
+required:
+  - compatible
+  - clocks
+  - reg
+  - reset-gpios
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        spi@1 {
+            compatible = "ge,achc", "nxp,kinetis-k20";
+            reg = <1>, <0>;
+            clocks = <&achc_24M>;
+            reset-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
+        };
+    };
-- 
2.30.2


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

* [PATCHv4 4/6] ARM: dts: imx53-ppd: Fix ACHC entry
  2021-06-09 15:12 [PATCHv4 0/6] GE Healthcare PPD firmware upgrade driver for ACHC Sebastian Reichel
                   ` (2 preceding siblings ...)
  2021-06-09 15:12 ` [PATCHv4 3/6] dt-bindings: misc: ge-achc: Convert to DT schema format Sebastian Reichel
@ 2021-06-09 15:12 ` Sebastian Reichel
  2021-06-09 15:12 ` [PATCHv4 5/6] misc: nxp-ezport: introduce EzPort support Sebastian Reichel
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 16+ messages in thread
From: Sebastian Reichel @ 2021-06-09 15:12 UTC (permalink / raw)
  To: Mark Brown, Rob Herring
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Shawn Guo, Sascha Hauer,
	Fabio Estevam, Ian Ray, linux-kernel, linux-spi, devicetree,
	kernel, Sebastian Reichel

PPD has only one ACHC device, which effectively is a Kinetis
microcontroller. It has one SPI interface used for normal
communication. Additionally it's possible to flash the device
firmware using NXP's EzPort protocol by correctly driving a
second chip select pin and the device reset pin.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 arch/arm/boot/dts/imx53-ppd.dts | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/arch/arm/boot/dts/imx53-ppd.dts b/arch/arm/boot/dts/imx53-ppd.dts
index be040b6a02fa..1f3ee60fb102 100644
--- a/arch/arm/boot/dts/imx53-ppd.dts
+++ b/arch/arm/boot/dts/imx53-ppd.dts
@@ -70,6 +70,12 @@ cko2_11M: sgtl-clock-cko2 {
 		clock-frequency = <11289600>;
 	};
 
+	achc_24M: achc-clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <24000000>;
+	};
+
 	sgtlsound: sound {
 		compatible = "fsl,imx53-cpuvo-sgtl5000",
 			     "fsl,imx-audio-sgtl5000";
@@ -314,16 +320,13 @@ &gpio4 11 GPIO_ACTIVE_LOW
 		    &gpio4 12 GPIO_ACTIVE_LOW>;
 	status = "okay";
 
-	spidev0: spi@0 {
-		compatible = "ge,achc";
-		reg = <0>;
-		spi-max-frequency = <1000000>;
-	};
-
-	spidev1: spi@1 {
-		compatible = "ge,achc";
-		reg = <1>;
-		spi-max-frequency = <1000000>;
+	spidev0: spi@1 {
+		compatible = "ge,achc", "nxp,kinetis-k20";
+		reg = <1>, <0>;
+		vdd-supply = <&reg_3v3>;
+		vdda-supply = <&reg_3v3>;
+		clocks = <&achc_24M>;
+		reset-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
 	};
 
 	gpioxra0: gpio@2 {
-- 
2.30.2


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

* [PATCHv4 5/6] misc: nxp-ezport: introduce EzPort support
  2021-06-09 15:12 [PATCHv4 0/6] GE Healthcare PPD firmware upgrade driver for ACHC Sebastian Reichel
                   ` (3 preceding siblings ...)
  2021-06-09 15:12 ` [PATCHv4 4/6] ARM: dts: imx53-ppd: Fix ACHC entry Sebastian Reichel
@ 2021-06-09 15:12 ` Sebastian Reichel
  2021-06-11  9:05   ` Greg Kroah-Hartman
  2021-06-09 15:12 ` [PATCHv4 6/6] misc: gehc-achc: new driver Sebastian Reichel
  2021-06-22 15:14 ` (subset) [PATCHv4 0/6] GE Healthcare PPD firmware upgrade driver for ACHC Mark Brown
  6 siblings, 1 reply; 16+ messages in thread
From: Sebastian Reichel @ 2021-06-09 15:12 UTC (permalink / raw)
  To: Mark Brown, Rob Herring
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Shawn Guo, Sascha Hauer,
	Fabio Estevam, Ian Ray, linux-kernel, linux-spi, devicetree,
	kernel, Sebastian Reichel

Add new EzPort support code, which can be used to do
firmware updates of Kinetis coprocessors. The driver
is not usable on its own and thus not user selectable.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/misc/Kconfig                     |   3 +
 drivers/misc/Makefile                    |   1 +
 drivers/misc/nxp-ezport.c                | 476 +++++++++++++++++++++++
 include/linux/platform_data/nxp-ezport.h |   9 +
 4 files changed, 489 insertions(+)
 create mode 100644 drivers/misc/nxp-ezport.c
 create mode 100644 include/linux/platform_data/nxp-ezport.h

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index f4fb5c52b863..392c091891a1 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -208,6 +208,9 @@ config CS5535_CLOCK_EVENT_SRC
 	  MFGPTs have a better resolution and max interval than the
 	  generic PIT, and are suitable for use as high-res timers.
 
+config NXP_EZPORT
+	tristate
+
 config HP_ILO
 	tristate "Channel interface driver for the HP iLO processor"
 	depends on PCI
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index e92a56d4442f..a85e763b9b33 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_KGDB_TESTS)	+= kgdbts.o
 obj-$(CONFIG_SGI_XP)		+= sgi-xp/
 obj-$(CONFIG_SGI_GRU)		+= sgi-gru/
 obj-$(CONFIG_CS5535_MFGPT)	+= cs5535-mfgpt.o
+obj-$(CONFIG_NXP_EZPORT)	+= nxp-ezport.o
 obj-$(CONFIG_HP_ILO)		+= hpilo.o
 obj-$(CONFIG_APDS9802ALS)	+= apds9802als.o
 obj-$(CONFIG_ISL29003)		+= isl29003.o
diff --git a/drivers/misc/nxp-ezport.c b/drivers/misc/nxp-ezport.c
new file mode 100644
index 000000000000..2fcdf135387b
--- /dev/null
+++ b/drivers/misc/nxp-ezport.c
@@ -0,0 +1,476 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * This library implements NXP's EzPort protocol used to
+ * flash the firmware of Kinetis microcontrollers, such
+ * as https://www.nxp.com/part/MK20FN1M0VMD12 and is
+ * intended to be used as ancillary SPI device.
+ *
+ * Copyright (C) 2018-2021 Collabora
+ * Copyright (C) 2018-2021 GE Healthcare
+ */
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_data/nxp-ezport.h>
+
+#define EZPORT_RESET_DELAY_MS	100
+#define EZPORT_STARTUP_DELAY_MS	200
+#define EZPORT_WRITE_WAIT_MS	10
+#define EZPORT_TRANSFER_SIZE	2048
+
+#define EZPORT_CMD_SP		0x02 /* flash section program */
+#define EZPORT_CMD_RDSR		0x05 /* read status register */
+#define EZPORT_CMD_WREN		0x06 /* write enable */
+#define EZPORT_CMD_FAST_READ	0x0b /* flash read data at high speed */
+#define EZPORT_CMD_RESET	0xb9 /* reset chip */
+#define EZPORT_CMD_BE		0xc7 /* bulk erase */
+#define EZPORT_CMD_SE		0xd8 /* sector erase */
+
+#define EZPORT_SECTOR_SIZE	4096
+#define EZPORT_SECTOR_MASK	(EZPORT_SECTOR_SIZE - 1)
+
+#define EZPORT_STATUS_WIP	BIT(0) /* write in progress */
+#define EZPORT_STATUS_WEN	BIT(1) /* write enable */
+#define EZPORT_STATUS_BEDIS	BIT(2) /* bulk erase disable */
+#define EZPORT_STATUS_FLEXRAM	BIT(3) /* FlexRAM mode */
+#define EZPORT_STATUS_WEF	BIT(6) /* write error flag */
+#define EZPORT_STATUS_FS	BIT(7) /* flash security */
+
+/**
+ * ezport_reset - reset ezport device
+ * @reset: the gpio connected to the device reset pin
+ *
+ * Context: can sleep
+ */
+void ezport_reset(struct gpio_desc *reset)
+{
+	gpiod_set_value(reset, 1);
+	msleep(EZPORT_RESET_DELAY_MS);
+	gpiod_set_value(reset, 0);
+	msleep(EZPORT_STARTUP_DELAY_MS);
+}
+EXPORT_SYMBOL_GPL(ezport_reset);
+
+static int ezport_start_programming(struct spi_device *spi, struct gpio_desc *reset)
+{
+	struct spi_message msg;
+	struct spi_transfer assert_cs = {
+		.cs_change   = 1,
+	};
+	struct spi_transfer release_cs = { };
+	int ret;
+
+	spi_bus_lock(spi->master);
+
+	/* assert chip select */
+	spi_message_init(&msg);
+	spi_message_add_tail(&assert_cs, &msg);
+	ret = spi_sync_locked(spi, &msg);
+	if (ret)
+		goto fail;
+
+	msleep(EZPORT_STARTUP_DELAY_MS);
+
+	/* reset with asserted chip select to switch into programming mode */
+	ezport_reset(reset);
+
+	/* release chip select */
+	spi_message_init(&msg);
+	spi_message_add_tail(&release_cs, &msg);
+	ret = spi_sync_locked(spi, &msg);
+
+fail:
+	spi_bus_unlock(spi->master);
+	return ret;
+}
+
+static void ezport_stop_programming(struct spi_device *spi, struct gpio_desc *reset)
+{
+	/* reset without asserted chip select to return into normal mode */
+	spi_bus_lock(spi->master);
+	ezport_reset(reset);
+	spi_bus_unlock(spi->master);
+}
+
+static int ezport_get_status_register(struct spi_device *spi)
+{
+	int ret;
+
+	ret = spi_w8r8(spi, EZPORT_CMD_RDSR);
+	if (ret < 0)
+		return ret;
+	if (ret == 0xff) {
+		dev_err(&spi->dev, "Invalid EzPort status, EzPort is not functional!\n");
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int ezport_soft_reset(struct spi_device *spi)
+{
+	u8 cmd = EZPORT_CMD_RESET;
+	int ret;
+
+	ret = spi_write(spi, &cmd, 1);
+	if (ret < 0)
+		return ret;
+
+	msleep(EZPORT_STARTUP_DELAY_MS);
+
+	return 0;
+}
+
+static int ezport_send_simple(struct spi_device *spi, u8 cmd)
+{
+	int ret;
+
+	ret = spi_write(spi, &cmd, 1);
+	if (ret < 0)
+		return ret;
+
+	return ezport_get_status_register(spi);
+}
+
+static int ezport_wait_write(struct spi_device *spi, u32 retries)
+{
+	int ret;
+	u32 i;
+
+	for (i = 0; i < retries; i++) {
+		ret = ezport_get_status_register(spi);
+		if (ret > 0 && !(ret & EZPORT_STATUS_WIP))
+			break;
+		msleep(EZPORT_WRITE_WAIT_MS);
+	}
+
+	return ret;
+}
+
+static int ezport_write_enable(struct spi_device *spi)
+{
+	int ret = 0, retries = 3;
+
+	for (retries = 0; retries < 3; retries++) {
+		ret = ezport_send_simple(spi, EZPORT_CMD_WREN);
+		if (ret > 0 && ret & EZPORT_STATUS_WEN)
+			break;
+	}
+
+	if (!(ret & EZPORT_STATUS_WEN)) {
+		dev_err(&spi->dev, "EzPort write enable timed out\n");
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+static int ezport_bulk_erase(struct spi_device *spi)
+{
+	int ret;
+	static const u8 cmd = EZPORT_CMD_BE;
+
+	dev_dbg(&spi->dev, "EzPort bulk erase...\n");
+
+	ret = ezport_write_enable(spi);
+	if (ret < 0)
+		return ret;
+
+	ret = spi_write(spi, &cmd, 1);
+	if (ret < 0)
+		return ret;
+
+	ret = ezport_wait_write(spi, 1000);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int ezport_section_erase(struct spi_device *spi, u32 address)
+{
+	u8 query[] = {EZPORT_CMD_SE, (address >> 16) & 0xff, (address >> 8) & 0xff, address & 0xff};
+	int ret;
+
+	dev_dbg(&spi->dev, "Ezport section erase @ 0x%06x...\n", address);
+
+	if (address & EZPORT_SECTOR_MASK)
+		return -EINVAL;
+
+	ret = ezport_write_enable(spi);
+	if (ret < 0)
+		return ret;
+
+	ret = spi_write(spi, query, sizeof(query));
+	if (ret < 0)
+		return ret;
+
+	return ezport_wait_write(spi, 200);
+}
+
+static int ezport_flash_transfer(struct spi_device *spi, u32 address,
+				 const u8 *payload, size_t payload_size)
+{
+	struct spi_transfer xfers[2] = {};
+	u8 *command;
+	int ret;
+
+	dev_dbg(&spi->dev, "EzPort write %zu bytes @ 0x%06x...\n", payload_size, address);
+
+	command = kmalloc(4, GFP_KERNEL | GFP_DMA);
+	if (!command)
+		return -ENOMEM;
+
+	command[0] = EZPORT_CMD_SP;
+	command[1] = address >> 16;
+	command[2] = address >> 8;
+	command[3] = address >> 0;
+
+	xfers[0].tx_buf = command;
+	xfers[0].len = 4;
+
+	xfers[1].tx_buf = payload;
+	xfers[1].len = payload_size;
+
+	ret = spi_sync_transfer(spi, xfers, 2);
+	kfree(command);
+	if (ret < 0)
+		return ret;
+
+	return ezport_wait_write(spi, 40);
+}
+
+static int ezport_flash_compare(struct spi_device *spi, u32 address,
+				const u8 *payload, size_t payload_size)
+{
+	struct spi_transfer xfers[2] = {};
+	u8 *buffer;
+	int ret;
+
+	buffer = kmalloc(payload_size + 4, GFP_KERNEL | GFP_DMA);
+	if (!buffer)
+		return -ENOMEM;
+
+	buffer[0] = EZPORT_CMD_FAST_READ;
+	buffer[1] = address >> 16;
+	buffer[2] = address >> 8;
+	buffer[3] = address >> 0;
+
+	xfers[0].tx_buf = buffer;
+	xfers[0].len = 4;
+
+	xfers[1].rx_buf = buffer + 4;
+	xfers[1].len = payload_size;
+
+	ret = spi_sync_transfer(spi, xfers, 2);
+	if (ret)
+		goto err;
+
+	ret = memcmp(payload, buffer + 4, payload_size);
+	if (ret) {
+		ret = -EBADMSG;
+		dev_dbg(&spi->dev, "Verfication failure @ %06x", address);
+		print_hex_dump_bytes("fw:  ", DUMP_PREFIX_OFFSET, payload, payload_size);
+		print_hex_dump_bytes("dev: ", DUMP_PREFIX_OFFSET, buffer + 4, payload_size);
+	}
+
+err:
+	kfree(buffer);
+	return ret;
+}
+
+static int ezport_firmware_compare_data(struct spi_device *spi,
+					const u8 *data, size_t size)
+{
+	int ret;
+	u32 address = 0;
+	u32 transfer_size;
+
+	dev_dbg(&spi->dev, "EzPort compare data with %zu bytes...\n", size);
+
+	ret = ezport_get_status_register(spi);
+	if (ret < 0)
+		return ret;
+
+	if (ret & EZPORT_STATUS_FS) {
+		dev_info(&spi->dev, "Device is in secure mode (status=0x%02x)!\n", ret);
+		dev_info(&spi->dev, "FW verification is not possible\n");
+		return -EACCES;
+	}
+
+	while (size - address > 0) {
+		transfer_size = min((u32) EZPORT_TRANSFER_SIZE, size - address);
+
+		ret = ezport_flash_compare(spi, address, data+address, transfer_size);
+		if (ret)
+			return ret;
+
+		address += transfer_size;
+	}
+
+	return 0;
+}
+
+static int ezport_firmware_flash_data(struct spi_device *spi,
+				      const u8 *data, size_t size)
+{
+	int ret;
+	u32 address = 0;
+	u32 transfer_size;
+
+	dev_dbg(&spi->dev, "EzPort flash data with %zu bytes...\n", size);
+
+	ret = ezport_get_status_register(spi);
+	if (ret < 0)
+		return ret;
+
+	if (ret & EZPORT_STATUS_FS) {
+		ret = ezport_bulk_erase(spi);
+		if (ret < 0)
+			return ret;
+		if (ret & EZPORT_STATUS_FS)
+			return -EINVAL;
+	}
+
+	while (size - address > 0) {
+		if (!(address & EZPORT_SECTOR_MASK)) {
+			ret = ezport_section_erase(spi, address);
+			if (ret < 0)
+				return ret;
+			if (ret & EZPORT_STATUS_WIP || ret & EZPORT_STATUS_WEF)
+				return -EIO;
+		}
+
+		transfer_size = min((u32) EZPORT_TRANSFER_SIZE, size - address);
+
+		ret = ezport_flash_transfer(spi, address,
+					    data+address, transfer_size);
+		if (ret < 0)
+			return ret;
+		else if (ret & EZPORT_STATUS_WIP)
+			return -ETIMEDOUT;
+		else if (ret & EZPORT_STATUS_WEF)
+			return -EIO;
+
+		address += transfer_size;
+	}
+
+	ret = ezport_soft_reset(spi);
+	if (ret < 0)
+		dev_warn(&spi->dev, "EzPort reset failed!\n");
+
+	dev_dbg(&spi->dev, "EzPort verify flashed data...\n");
+	ret = ezport_firmware_compare_data(spi, data, size);
+
+	/* allow missing FW verfication in secure mode */
+	if (ret == -EACCES)
+		ret = 0;
+
+	if (ret < 0)
+		dev_err(&spi->dev, "Failed to verify flashed data: %d\n", ret);
+
+	return ret;
+}
+
+static int ezport_firmware_load(struct spi_device *spi, const char *fwname)
+{
+	const struct firmware *fw;
+	int ret;
+
+	ret = request_firmware(&fw, fwname, &spi->dev);
+	if (ret) {
+		dev_err(&spi->dev, "Could not get firmware: %d\n", ret);
+		return ret;
+	}
+
+	ret = ezport_firmware_flash_data(spi, fw->data, fw->size);
+
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int ezport_firmware_verify(struct spi_device *spi, const char *fwname)
+{
+	const struct firmware *fw;
+	int ret;
+
+	ret = request_firmware(&fw, fwname, &spi->dev);
+	if (ret) {
+		dev_err(&spi->dev, "Could not get firmware: %d\n", ret);
+		return ret;
+	}
+
+	ret = ezport_firmware_compare_data(spi, fw->data, fw->size);
+
+	release_firmware(fw);
+
+	return ret;
+}
+
+/**
+ * ezport_flash - flash device firmware
+ * @spi: SPI device for NXP EzPort interface
+ * @reset: the gpio connected to the device reset pin
+ * @fwname: filename of the firmware that should be flashed
+ *
+ * Context: can sleep
+ *
+ * Return: 0 on success; negative errno on failure
+ */
+int ezport_flash(struct spi_device *spi, struct gpio_desc *reset, const char *fwname)
+{
+	int ret;
+
+	ret = ezport_start_programming(spi, reset);
+	if (ret)
+		return ret;
+
+	ret = ezport_firmware_load(spi, fwname);
+
+	ezport_stop_programming(spi, reset);
+
+	if (ret)
+		dev_err(&spi->dev, "Failed to flash firmware: %d\n", ret);
+	else
+		dev_dbg(&spi->dev, "Finished FW flashing!\n");
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ezport_flash);
+
+/**
+ * ezport_verify - verify device firmware
+ * @spi: SPI device for NXP EzPort interface
+ * @reset: the gpio connected to the device reset pin
+ * @fwname: filename of the firmware that should be compared
+ *
+ * Context: can sleep
+ *
+ * Return: 0 on success; negative errno on failure
+ */
+int ezport_verify(struct spi_device *spi, struct gpio_desc *reset, const char *fwname)
+{
+	int ret;
+
+	ret = ezport_start_programming(spi, reset);
+	if (ret)
+		return ret;
+
+	ret = ezport_firmware_verify(spi, fwname);
+
+	ezport_stop_programming(spi, reset);
+
+	if (ret)
+		dev_err(&spi->dev, "Failed to verify firmware: %d\n", ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ezport_verify);
+
+MODULE_DESCRIPTION("NXP EzPort protocol support");
+MODULE_AUTHOR("Sebastian Reichel <sebastian.reichel@collabora.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/platform_data/nxp-ezport.h b/include/linux/platform_data/nxp-ezport.h
new file mode 100644
index 000000000000..b0a2af9c1285
--- /dev/null
+++ b/include/linux/platform_data/nxp-ezport.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef __NXP_EZPORT_H
+#define __NXP_EZPORT_H
+
+extern void ezport_reset(struct gpio_desc *reset);
+extern int ezport_flash(struct spi_device *spi, struct gpio_desc *reset, const char *fwname);
+extern int ezport_verify(struct spi_device *spi, struct gpio_desc *reset, const char *fwname);
+
+#endif
-- 
2.30.2


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

* [PATCHv4 6/6] misc: gehc-achc: new driver
  2021-06-09 15:12 [PATCHv4 0/6] GE Healthcare PPD firmware upgrade driver for ACHC Sebastian Reichel
                   ` (4 preceding siblings ...)
  2021-06-09 15:12 ` [PATCHv4 5/6] misc: nxp-ezport: introduce EzPort support Sebastian Reichel
@ 2021-06-09 15:12 ` Sebastian Reichel
  2021-06-11  9:02   ` Greg Kroah-Hartman
  2021-06-22 15:14 ` (subset) [PATCHv4 0/6] GE Healthcare PPD firmware upgrade driver for ACHC Mark Brown
  6 siblings, 1 reply; 16+ messages in thread
From: Sebastian Reichel @ 2021-06-09 15:12 UTC (permalink / raw)
  To: Mark Brown, Rob Herring
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Shawn Guo, Sascha Hauer,
	Fabio Estevam, Ian Ray, linux-kernel, linux-spi, devicetree,
	kernel, Sebastian Reichel

General Electric Healthcare's PPD has a secondary processor from
NXP's Kinetis K20 series. That device has two SPI chip selects:

The main interface's behaviour depends on the loaded firmware
and is currently unused.

The secondary interface can be used to update the firmware using
EzPort protocol. This is implemented by this driver using the
kernel's firmware API. It's not done during probe time, since
the device has non-volatile memory and flashing lasts almost 3
minutes.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 .../ABI/testing/sysfs-driver-ge-achc          |   9 ++
 drivers/misc/Kconfig                          |  12 ++
 drivers/misc/Makefile                         |   1 +
 drivers/misc/gehc-achc.c                      | 136 ++++++++++++++++++
 drivers/spi/spidev.c                          |   1 -
 5 files changed, 158 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/ABI/testing/sysfs-driver-ge-achc
 create mode 100644 drivers/misc/gehc-achc.c

diff --git a/Documentation/ABI/testing/sysfs-driver-ge-achc b/Documentation/ABI/testing/sysfs-driver-ge-achc
new file mode 100644
index 000000000000..3ca71a1b4836
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-ge-achc
@@ -0,0 +1,9 @@
+What:		/sys/bus/spi/drivers/gehc-achc/<dev>/update_firmware
+Date:		June 2021
+Contact:	linux-kernel@vger.kernel.org
+Description:	Write 1 to this file to trigger a firmware update.
+
+What:		/sys/bus/spi/drivers/gehc-achc/<dev>/reset
+Date:		June 2021
+Contact:	linux-kernel@vger.kernel.org
+Description:	Write 1 to this file to trigger a device reset.
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 392c091891a1..a286f0775f2e 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -211,6 +211,18 @@ config CS5535_CLOCK_EVENT_SRC
 config NXP_EZPORT
 	tristate
 
+config GEHC_ACHC
+	tristate "GEHC ACHC support"
+	depends on SPI && SYSFS && SPI_SPIDEV
+	select FW_LOADER
+	select NXP_EZPORT
+	help
+	  Support for GE ACHC microcontroller, that is part of the GE
+	  PPD device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gehc-achc.
+
 config HP_ILO
 	tristate "Channel interface driver for the HP iLO processor"
 	depends on PCI
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index a85e763b9b33..b7bad5a16c8f 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_SGI_XP)		+= sgi-xp/
 obj-$(CONFIG_SGI_GRU)		+= sgi-gru/
 obj-$(CONFIG_CS5535_MFGPT)	+= cs5535-mfgpt.o
 obj-$(CONFIG_NXP_EZPORT)	+= nxp-ezport.o
+obj-$(CONFIG_GEHC_ACHC)		+= gehc-achc.o
 obj-$(CONFIG_HP_ILO)		+= hpilo.o
 obj-$(CONFIG_APDS9802ALS)	+= apds9802als.o
 obj-$(CONFIG_ISL29003)		+= isl29003.o
diff --git a/drivers/misc/gehc-achc.c b/drivers/misc/gehc-achc.c
new file mode 100644
index 000000000000..5868ac99a3f6
--- /dev/null
+++ b/drivers/misc/gehc-achc.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * datasheet: https://www.nxp.com/docs/en/data-sheet/K20P144M120SF3.pdf
+ *
+ * Copyright (C) 2018-2021 Collabora
+ * Copyright (C) 2018-2021 GE Healthcare
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/of.h>
+#include <linux/platform_data/nxp-ezport.h>
+
+#define ACHC_MAX_FREQ 300000
+
+struct achc_data {
+	struct spi_device *main;
+	struct spi_device *ezport;
+	struct gpio_desc *reset;
+
+	struct mutex device_lock; /* avoid concurrent device access */
+};
+
+static ssize_t update_firmware_store(struct device *dev, struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct achc_data *achc = dev_get_drvdata(dev);
+	int ret;
+
+	if (!count)
+		return -EINVAL;
+
+	mutex_lock(&achc->device_lock);
+	ret = ezport_flash(achc->ezport, achc->reset, "achc.bin");
+	mutex_unlock(&achc->device_lock);
+
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+static DEVICE_ATTR_WO(update_firmware);
+
+static ssize_t reset_store(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct achc_data *achc = dev_get_drvdata(dev);
+
+	if (!count)
+		return -EINVAL;
+
+	mutex_lock(&achc->device_lock);
+	ezport_reset(achc->reset);
+	mutex_unlock(&achc->device_lock);
+
+	return count;
+}
+static DEVICE_ATTR_WO(reset);
+
+static struct attribute *gehc_achc_attrs[] = {
+	&dev_attr_update_firmware.attr,
+	&dev_attr_reset.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(gehc_achc);
+
+static void unregister_ezport(void *data)
+{
+	struct spi_device *ezport = data;
+
+	spi_unregister_device(ezport);
+}
+
+static int gehc_achc_probe(struct spi_device *spi)
+{
+	struct achc_data *achc;
+	int ezport_reg, ret;
+
+	spi->max_speed_hz = ACHC_MAX_FREQ;
+	spi->bits_per_word = 8;
+	spi->mode = SPI_MODE_0;
+
+	achc = devm_kzalloc(&spi->dev, sizeof(*achc), GFP_KERNEL);
+	if (!achc)
+		return -ENOMEM;
+	spi_set_drvdata(spi, achc);
+	achc->main = spi;
+
+	mutex_init(&achc->device_lock);
+
+	ret = of_property_read_u32_index(spi->dev.of_node, "reg", 1, &ezport_reg);
+	if (ret)
+		return dev_err_probe(&spi->dev, ret, "missing second reg entry!\n");
+
+	achc->ezport = spi_new_ancillary_device(spi, ezport_reg);
+	if (IS_ERR(achc->ezport))
+		return PTR_ERR(achc->ezport);
+
+	ret = devm_add_action_or_reset(&spi->dev, unregister_ezport, achc->ezport);
+	if (ret)
+		return ret;
+
+	achc->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(achc->reset))
+		return dev_err_probe(&spi->dev, PTR_ERR(achc->reset), "Could not get reset gpio\n");
+
+	return 0;
+}
+
+static const struct spi_device_id gehc_achc_id[] = {
+	{ "ge,achc", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, gehc_achc_id);
+
+static const struct of_device_id gehc_achc_of_match[] = {
+	{ .compatible = "ge,achc" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, gehc_achc_of_match);
+
+static struct spi_driver gehc_achc_spi_driver = {
+	.driver = {
+		.name	= "gehc-achc",
+		.of_match_table = gehc_achc_of_match,
+		.dev_groups = gehc_achc_groups,
+	},
+	.probe		= gehc_achc_probe,
+	.id_table	= gehc_achc_id,
+};
+module_spi_driver(gehc_achc_spi_driver);
+
+MODULE_DESCRIPTION("GEHC ACHC driver");
+MODULE_AUTHOR("Sebastian Reichel <sebastian.reichel@collabora.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index f56e0e975a46..d0d9dbbbdec1 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -677,7 +677,6 @@ static struct class *spidev_class;
 static const struct of_device_id spidev_dt_ids[] = {
 	{ .compatible = "rohm,dh2228fv" },
 	{ .compatible = "lineartechnology,ltc2488" },
-	{ .compatible = "ge,achc" },
 	{ .compatible = "semtech,sx1301" },
 	{ .compatible = "lwn,bk4" },
 	{ .compatible = "dh,dhcom-board" },
-- 
2.30.2


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

* Re: [PATCHv4 3/6] dt-bindings: misc: ge-achc: Convert to DT schema format
  2021-06-09 15:12 ` [PATCHv4 3/6] dt-bindings: misc: ge-achc: Convert to DT schema format Sebastian Reichel
@ 2021-06-10 16:41   ` Rob Herring
  0 siblings, 0 replies; 16+ messages in thread
From: Rob Herring @ 2021-06-10 16:41 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Greg Kroah-Hartman, Sascha Hauer, kernel, Mark Brown, devicetree,
	linux-kernel, Rob Herring, Shawn Guo, Arnd Bergmann,
	Fabio Estevam, linux-spi, Ian Ray

On Wed, 09 Jun 2021 17:12:32 +0200, Sebastian Reichel wrote:
> Convert the binding to DT schema format. Also update the binding
> to fix shortcomings
> 
>  * Add "nxp,kinetis-k20" fallback compatible
>  * add programming SPI interface and reset GPIO
>  * add main clock
>  * add voltage supplies
>  * drop spi-max-frequency from required properties,
>    driver will setup max. frequency
> 
> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
> ---
>  .../devicetree/bindings/misc/ge-achc.txt      | 26 --------
>  .../devicetree/bindings/misc/ge-achc.yaml     | 65 +++++++++++++++++++
>  2 files changed, 65 insertions(+), 26 deletions(-)
>  delete mode 100644 Documentation/devicetree/bindings/misc/ge-achc.txt
>  create mode 100644 Documentation/devicetree/bindings/misc/ge-achc.yaml
> 

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

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

* Re: [PATCHv4 6/6] misc: gehc-achc: new driver
  2021-06-09 15:12 ` [PATCHv4 6/6] misc: gehc-achc: new driver Sebastian Reichel
@ 2021-06-11  9:02   ` Greg Kroah-Hartman
  0 siblings, 0 replies; 16+ messages in thread
From: Greg Kroah-Hartman @ 2021-06-11  9:02 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Mark Brown, Rob Herring, Arnd Bergmann, Shawn Guo, Sascha Hauer,
	Fabio Estevam, Ian Ray, linux-kernel, linux-spi, devicetree,
	kernel

On Wed, Jun 09, 2021 at 05:12:35PM +0200, Sebastian Reichel wrote:
> General Electric Healthcare's PPD has a secondary processor from
> NXP's Kinetis K20 series. That device has two SPI chip selects:
> 
> The main interface's behaviour depends on the loaded firmware
> and is currently unused.
> 
> The secondary interface can be used to update the firmware using
> EzPort protocol. This is implemented by this driver using the
> kernel's firmware API. It's not done during probe time, since
> the device has non-volatile memory and flashing lasts almost 3
> minutes.
> 
> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
> ---
>  .../ABI/testing/sysfs-driver-ge-achc          |   9 ++
>  drivers/misc/Kconfig                          |  12 ++
>  drivers/misc/Makefile                         |   1 +
>  drivers/misc/gehc-achc.c                      | 136 ++++++++++++++++++
>  drivers/spi/spidev.c                          |   1 -
>  5 files changed, 158 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/ABI/testing/sysfs-driver-ge-achc
>  create mode 100644 drivers/misc/gehc-achc.c
> 
> diff --git a/Documentation/ABI/testing/sysfs-driver-ge-achc b/Documentation/ABI/testing/sysfs-driver-ge-achc
> new file mode 100644
> index 000000000000..3ca71a1b4836
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-driver-ge-achc
> @@ -0,0 +1,9 @@
> +What:		/sys/bus/spi/drivers/gehc-achc/<dev>/update_firmware

Shouldn't the path be through the bus and not through the driver portion
of sysfs?

> +Date:		June 2021
> +Contact:	linux-kernel@vger.kernel.org

If you are not willing to put your name on this, I'm not willing to take
this :(

> +Description:	Write 1 to this file to trigger a firmware update.

What exactly does this mean?  What will be "triggered" and what will
happen?

And it is not what the kernel code does, it will take any write to this
file, not just "1" so something is wrong here.

> +
> +What:		/sys/bus/spi/drivers/gehc-achc/<dev>/reset
> +Date:		June 2021
> +Contact:	linux-kernel@vger.kernel.org

Again, real name for a contact for obvious reasons.

> +Description:	Write 1 to this file to trigger a device reset.

Also does not match the code :(


> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index 392c091891a1..a286f0775f2e 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -211,6 +211,18 @@ config CS5535_CLOCK_EVENT_SRC
>  config NXP_EZPORT
>  	tristate
>  
> +config GEHC_ACHC
> +	tristate "GEHC ACHC support"
> +	depends on SPI && SYSFS && SPI_SPIDEV
> +	select FW_LOADER
> +	select NXP_EZPORT
> +	help
> +	  Support for GE ACHC microcontroller, that is part of the GE
> +	  PPD device.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called gehc-achc.
> +
>  config HP_ILO
>  	tristate "Channel interface driver for the HP iLO processor"
>  	depends on PCI
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index a85e763b9b33..b7bad5a16c8f 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -25,6 +25,7 @@ obj-$(CONFIG_SGI_XP)		+= sgi-xp/
>  obj-$(CONFIG_SGI_GRU)		+= sgi-gru/
>  obj-$(CONFIG_CS5535_MFGPT)	+= cs5535-mfgpt.o
>  obj-$(CONFIG_NXP_EZPORT)	+= nxp-ezport.o
> +obj-$(CONFIG_GEHC_ACHC)		+= gehc-achc.o
>  obj-$(CONFIG_HP_ILO)		+= hpilo.o
>  obj-$(CONFIG_APDS9802ALS)	+= apds9802als.o
>  obj-$(CONFIG_ISL29003)		+= isl29003.o
> diff --git a/drivers/misc/gehc-achc.c b/drivers/misc/gehc-achc.c
> new file mode 100644
> index 000000000000..5868ac99a3f6
> --- /dev/null
> +++ b/drivers/misc/gehc-achc.c
> @@ -0,0 +1,136 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * datasheet: https://www.nxp.com/docs/en/data-sheet/K20P144M120SF3.pdf
> + *
> + * Copyright (C) 2018-2021 Collabora
> + * Copyright (C) 2018-2021 GE Healthcare
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/spi/spi.h>
> +#include <linux/of.h>
> +#include <linux/platform_data/nxp-ezport.h>
> +
> +#define ACHC_MAX_FREQ 300000

What is the units here?

> +
> +struct achc_data {
> +	struct spi_device *main;
> +	struct spi_device *ezport;
> +	struct gpio_desc *reset;
> +
> +	struct mutex device_lock; /* avoid concurrent device access */
> +};
> +
> +static ssize_t update_firmware_store(struct device *dev, struct device_attribute *attr,
> +				     const char *buf, size_t count)
> +{
> +	struct achc_data *achc = dev_get_drvdata(dev);
> +	int ret;
> +
> +	if (!count)
> +		return -EINVAL;

So just a non-empty string works?  As said above, that's not what you
documented :(

> +
> +	mutex_lock(&achc->device_lock);
> +	ret = ezport_flash(achc->ezport, achc->reset, "achc.bin");
> +	mutex_unlock(&achc->device_lock);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	return count;
> +}
> +static DEVICE_ATTR_WO(update_firmware);
> +
> +static ssize_t reset_store(struct device *dev, struct device_attribute *attr,
> +			   const char *buf, size_t count)
> +{
> +	struct achc_data *achc = dev_get_drvdata(dev);
> +
> +	if (!count)
> +		return -EINVAL;

Same here as above.


thanks,

greg k-h

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

* Re: [PATCHv4 5/6] misc: nxp-ezport: introduce EzPort support
  2021-06-09 15:12 ` [PATCHv4 5/6] misc: nxp-ezport: introduce EzPort support Sebastian Reichel
@ 2021-06-11  9:05   ` Greg Kroah-Hartman
  2021-06-11  9:45     ` Greg Kroah-Hartman
  0 siblings, 1 reply; 16+ messages in thread
From: Greg Kroah-Hartman @ 2021-06-11  9:05 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Mark Brown, Rob Herring, Arnd Bergmann, Shawn Guo, Sascha Hauer,
	Fabio Estevam, Ian Ray, linux-kernel, linux-spi, devicetree,
	kernel

On Wed, Jun 09, 2021 at 05:12:34PM +0200, Sebastian Reichel wrote:
> Add new EzPort support code, which can be used to do
> firmware updates of Kinetis coprocessors. The driver
> is not usable on its own and thus not user selectable.
> 
> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>


Why is this a separate module if only 1 driver needs this?  Why not keep
it together until you have a second user?

And this module is not able to be unloaded ever?  Why not?

> +int ezport_flash(struct spi_device *spi, struct gpio_desc *reset, const char *fwname)
> +{
> +	int ret;
> +
> +	ret = ezport_start_programming(spi, reset);
> +	if (ret)
> +		return ret;
> +
> +	ret = ezport_firmware_load(spi, fwname);
> +
> +	ezport_stop_programming(spi, reset);
> +
> +	if (ret)
> +		dev_err(&spi->dev, "Failed to flash firmware: %d\n", ret);

%pe perhaps instead of %d?



> +	else
> +		dev_dbg(&spi->dev, "Finished FW flashing!\n");
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(ezport_flash);
> +
> +/**
> + * ezport_verify - verify device firmware
> + * @spi: SPI device for NXP EzPort interface
> + * @reset: the gpio connected to the device reset pin
> + * @fwname: filename of the firmware that should be compared
> + *
> + * Context: can sleep
> + *
> + * Return: 0 on success; negative errno on failure
> + */
> +int ezport_verify(struct spi_device *spi, struct gpio_desc *reset, const char *fwname)
> +{
> +	int ret;
> +
> +	ret = ezport_start_programming(spi, reset);
> +	if (ret)
> +		return ret;
> +
> +	ret = ezport_firmware_verify(spi, fwname);
> +
> +	ezport_stop_programming(spi, reset);
> +
> +	if (ret)
> +		dev_err(&spi->dev, "Failed to verify firmware: %d\n", ret);

Same here, %pe?


> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(ezport_verify);
> +
> +MODULE_DESCRIPTION("NXP EzPort protocol support");
> +MODULE_AUTHOR("Sebastian Reichel <sebastian.reichel@collabora.com>");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/platform_data/nxp-ezport.h b/include/linux/platform_data/nxp-ezport.h
> new file mode 100644
> index 000000000000..b0a2af9c1285
> --- /dev/null
> +++ b/include/linux/platform_data/nxp-ezport.h
> @@ -0,0 +1,9 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */

This license does NOT match up with the .c file's license.  Why?

thanks,

greg k-h

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

* Re: [PATCHv4 1/6] spi: add ancillary device support
  2021-06-09 15:12 ` [PATCHv4 1/6] spi: add ancillary device support Sebastian Reichel
@ 2021-06-11  9:06   ` Greg Kroah-Hartman
  2021-06-11 17:22     ` Sebastian Reichel
  2021-06-13 14:18   ` Andy Shevchenko
  2021-06-17 12:51   ` Mark Brown
  2 siblings, 1 reply; 16+ messages in thread
From: Greg Kroah-Hartman @ 2021-06-11  9:06 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Mark Brown, Rob Herring, Arnd Bergmann, Shawn Guo, Sascha Hauer,
	Fabio Estevam, Ian Ray, linux-kernel, linux-spi, devicetree,
	kernel

On Wed, Jun 09, 2021 at 05:12:30PM +0200, Sebastian Reichel wrote:
> Introduce support for ancillary devices, similar to existing
> implementation for I2C. This is useful for devices having
> multiple chip-selects, for example some microcontrollers
> provide a normal SPI interface and a flashing SPI interface.
> 
> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
> ---
>  drivers/spi/spi.c       | 139 +++++++++++++++++++++++++++++++---------
>  include/linux/spi/spi.h |   2 +
>  2 files changed, 109 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> index ba425b9c7700..7fdf224262b1 100644
> --- a/drivers/spi/spi.c
> +++ b/drivers/spi/spi.c
> @@ -558,49 +558,23 @@ static int spi_dev_check(struct device *dev, void *data)
>  	return 0;
>  }
>  
> -/**
> - * spi_add_device - Add spi_device allocated with spi_alloc_device
> - * @spi: spi_device to register
> - *
> - * Companion function to spi_alloc_device.  Devices allocated with
> - * spi_alloc_device can be added onto the spi bus with this function.
> - *
> - * Return: 0 on success; negative errno on failure
> - */
> -int spi_add_device(struct spi_device *spi)
> +static int __spi_add_device(struct spi_device *spi)
>  {
>  	struct spi_controller *ctlr = spi->controller;
>  	struct device *dev = ctlr->dev.parent;
>  	int status;
>  
> -	/* Chipselects are numbered 0..max; validate. */
> -	if (spi->chip_select >= ctlr->num_chipselect) {
> -		dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
> -			ctlr->num_chipselect);
> -		return -EINVAL;
> -	}
> -
> -	/* Set the bus ID string */
> -	spi_dev_set_name(spi);
> -
> -	/* We need to make sure there's no other device with this
> -	 * chipselect **BEFORE** we call setup(), else we'll trash
> -	 * its configuration.  Lock against concurrent add() calls.
> -	 */
> -	mutex_lock(&spi_add_lock);
> -
>  	status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
>  	if (status) {
>  		dev_err(dev, "chipselect %d already in use\n",
>  				spi->chip_select);
> -		goto done;
> +		return status;
>  	}
>  
>  	/* Controller may unregister concurrently */
>  	if (IS_ENABLED(CONFIG_SPI_DYNAMIC) &&
>  	    !device_is_registered(&ctlr->dev)) {
> -		status = -ENODEV;
> -		goto done;
> +		return -ENODEV;
>  	}
>  
>  	/* Descriptors take precedence */
> @@ -617,7 +591,7 @@ int spi_add_device(struct spi_device *spi)
>  	if (status < 0) {
>  		dev_err(dev, "can't setup %s, status %d\n",
>  				dev_name(&spi->dev), status);
> -		goto done;
> +		return status;
>  	}
>  
>  	/* Device may be bound to an active driver when this returns */
> @@ -628,12 +602,64 @@ int spi_add_device(struct spi_device *spi)
>  	else
>  		dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));
>  
> -done:
> +	return status;
> +}
> +
> +/**
> + * spi_add_device - Add spi_device allocated with spi_alloc_device
> + * @spi: spi_device to register
> + *
> + * Companion function to spi_alloc_device.  Devices allocated with
> + * spi_alloc_device can be added onto the spi bus with this function.
> + *
> + * Return: 0 on success; negative errno on failure
> + */
> +int spi_add_device(struct spi_device *spi)
> +{
> +	struct spi_controller *ctlr = spi->controller;
> +	struct device *dev = ctlr->dev.parent;
> +	int status;
> +
> +	/* Chipselects are numbered 0..max; validate. */
> +	if (spi->chip_select >= ctlr->num_chipselect) {
> +		dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
> +			ctlr->num_chipselect);
> +		return -EINVAL;
> +	}
> +
> +	/* Set the bus ID string */
> +	spi_dev_set_name(spi);
> +
> +	/* We need to make sure there's no other device with this
> +	 * chipselect **BEFORE** we call setup(), else we'll trash
> +	 * its configuration.  Lock against concurrent add() calls.
> +	 */
> +	mutex_lock(&spi_add_lock);
> +	status = __spi_add_device(spi);
>  	mutex_unlock(&spi_add_lock);
>  	return status;
>  }
>  EXPORT_SYMBOL_GPL(spi_add_device);
>  
> +static int spi_add_device_locked(struct spi_device *spi)
> +{
> +	struct spi_controller *ctlr = spi->controller;
> +	struct device *dev = ctlr->dev.parent;
> +
> +	/* Chipselects are numbered 0..max; validate. */
> +	if (spi->chip_select >= ctlr->num_chipselect) {
> +		dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
> +			ctlr->num_chipselect);
> +		return -EINVAL;
> +	}
> +
> +	/* Set the bus ID string */
> +	spi_dev_set_name(spi);
> +
> +	WARN_ON(!mutex_is_locked(&spi_add_lock));

So you just rebooted a machine that has panic-on-warn set.  Not nice.

If this really can happen, test for it and recover, do not reboot
devices.

If this really can never happen, why are you testing for it?

thanks,

greg k-h

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

* Re: [PATCHv4 5/6] misc: nxp-ezport: introduce EzPort support
  2021-06-11  9:05   ` Greg Kroah-Hartman
@ 2021-06-11  9:45     ` Greg Kroah-Hartman
  0 siblings, 0 replies; 16+ messages in thread
From: Greg Kroah-Hartman @ 2021-06-11  9:45 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Mark Brown, Rob Herring, Arnd Bergmann, Shawn Guo, Sascha Hauer,
	Fabio Estevam, Ian Ray, linux-kernel, linux-spi, devicetree,
	kernel

On Fri, Jun 11, 2021 at 11:05:59AM +0200, Greg Kroah-Hartman wrote:
> On Wed, Jun 09, 2021 at 05:12:34PM +0200, Sebastian Reichel wrote:
> > Add new EzPort support code, which can be used to do
> > firmware updates of Kinetis coprocessors. The driver
> > is not usable on its own and thus not user selectable.
> > 
> > Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
> 
> 
> Why is this a separate module if only 1 driver needs this?  Why not keep
> it together until you have a second user?
> 
> And this module is not able to be unloaded ever?  Why not?
> 
> > +int ezport_flash(struct spi_device *spi, struct gpio_desc *reset, const char *fwname)
> > +{
> > +	int ret;
> > +
> > +	ret = ezport_start_programming(spi, reset);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = ezport_firmware_load(spi, fwname);
> > +
> > +	ezport_stop_programming(spi, reset);
> > +
> > +	if (ret)
> > +		dev_err(&spi->dev, "Failed to flash firmware: %d\n", ret);
> 
> %pe perhaps instead of %d?

Oops, nope, my fault, that's not a pointer.

greg k-h

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

* Re: [PATCHv4 1/6] spi: add ancillary device support
  2021-06-11  9:06   ` Greg Kroah-Hartman
@ 2021-06-11 17:22     ` Sebastian Reichel
  0 siblings, 0 replies; 16+ messages in thread
From: Sebastian Reichel @ 2021-06-11 17:22 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Mark Brown, Rob Herring, Arnd Bergmann, Shawn Guo, Sascha Hauer,
	Fabio Estevam, Ian Ray, linux-kernel, linux-spi, devicetree,
	kernel

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

Hi Greg,

On Fri, Jun 11, 2021 at 11:06:53AM +0200, Greg Kroah-Hartman wrote:
> On Wed, Jun 09, 2021 at 05:12:30PM +0200, Sebastian Reichel wrote:
> > Introduce support for ancillary devices, similar to existing
> > implementation for I2C. This is useful for devices having
> > multiple chip-selects, for example some microcontrollers
> > provide a normal SPI interface and a flashing SPI interface.
> > 
> > Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
> > ---
> > [...]
> > +static int spi_add_device_locked(struct spi_device *spi)
> > +{
> > +	struct spi_controller *ctlr = spi->controller;
> > +	struct device *dev = ctlr->dev.parent;
> > +
> > +	/* Chipselects are numbered 0..max; validate. */
> > +	if (spi->chip_select >= ctlr->num_chipselect) {
> > +		dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
> > +			ctlr->num_chipselect);
> > +		return -EINVAL;
> > +	}
> > +
> > +	/* Set the bus ID string */
> > +	spi_dev_set_name(spi);
> > +
> > +	WARN_ON(!mutex_is_locked(&spi_add_lock));
> 
> So you just rebooted a machine that has panic-on-warn set.  Not
> nice.
> 
> If this really can happen, test for it and recover, do not reboot
> devices.
> 
> If this really can never happen, why are you testing for it?

This is reached when ancillary device is not registered in
the main SPI device's probe routine, which would be a driver
bug. The gehc-achc driver calls it in the right place, so
this is not reached with this patchset, but the function to
register ancillary devices is generic and is expected to be
also used by others.

-- Sebastian

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

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

* Re: [PATCHv4 1/6] spi: add ancillary device support
  2021-06-09 15:12 ` [PATCHv4 1/6] spi: add ancillary device support Sebastian Reichel
  2021-06-11  9:06   ` Greg Kroah-Hartman
@ 2021-06-13 14:18   ` Andy Shevchenko
  2021-06-17 12:51   ` Mark Brown
  2 siblings, 0 replies; 16+ messages in thread
From: Andy Shevchenko @ 2021-06-13 14:18 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Mark Brown, Rob Herring, Arnd Bergmann, Greg Kroah-Hartman,
	Shawn Guo, Sascha Hauer, Fabio Estevam, Ian Ray,
	Linux Kernel Mailing List, linux-spi, devicetree,
	Collabora Kernel ML

On Wed, Jun 9, 2021 at 7:07 PM Sebastian Reichel
<sebastian.reichel@collabora.com> wrote:
>
> Introduce support for ancillary devices, similar to existing
> implementation for I2C. This is useful for devices having
> multiple chip-selects, for example some microcontrollers
> provide a normal SPI interface and a flashing SPI interface.

...

> @@ -1993,7 +2019,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
>         }
>
>         /* Device address */
> -       rc = of_property_read_u32(nc, "reg", &value);
> +       rc = of_property_read_u32_index(nc, "reg", 0, &value);
>         if (rc) {
>                 dev_err(&ctlr->dev, "%pOF has no valid 'reg' property (%d)\n",
>                         nc, rc);

Unrelated change.

-- 
With Best Regards,
Andy Shevchenko

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

* Re: [PATCHv4 1/6] spi: add ancillary device support
  2021-06-09 15:12 ` [PATCHv4 1/6] spi: add ancillary device support Sebastian Reichel
  2021-06-11  9:06   ` Greg Kroah-Hartman
  2021-06-13 14:18   ` Andy Shevchenko
@ 2021-06-17 12:51   ` Mark Brown
  2 siblings, 0 replies; 16+ messages in thread
From: Mark Brown @ 2021-06-17 12:51 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Rob Herring, Arnd Bergmann, Greg Kroah-Hartman, Shawn Guo,
	Sascha Hauer, Fabio Estevam, Ian Ray, linux-kernel, linux-spi,
	devicetree, kernel

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

On Wed, Jun 09, 2021 at 05:12:30PM +0200, Sebastian Reichel wrote:
> Introduce support for ancillary devices, similar to existing
> implementation for I2C. This is useful for devices having
> multiple chip-selects, for example some microcontrollers
> provide a normal SPI interface and a flashing SPI interface.

This doesn't apply against current code, please check and resend.

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

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

* Re: (subset) [PATCHv4 0/6] GE Healthcare PPD firmware upgrade driver for ACHC
  2021-06-09 15:12 [PATCHv4 0/6] GE Healthcare PPD firmware upgrade driver for ACHC Sebastian Reichel
                   ` (5 preceding siblings ...)
  2021-06-09 15:12 ` [PATCHv4 6/6] misc: gehc-achc: new driver Sebastian Reichel
@ 2021-06-22 15:14 ` Mark Brown
  6 siblings, 0 replies; 16+ messages in thread
From: Mark Brown @ 2021-06-22 15:14 UTC (permalink / raw)
  To: Sebastian Reichel, Rob Herring
  Cc: Mark Brown, Greg Kroah-Hartman, Sascha Hauer, Arnd Bergmann,
	Fabio Estevam, Shawn Guo, devicetree, linux-kernel, kernel,
	Ian Ray, linux-spi

On Wed, 9 Jun 2021 17:12:29 +0200, Sebastian Reichel wrote:
> The PPD has a secondary processor (NXP Kinetis K20), which can be
> programmed from the main system. It is connected to the main processor
> by having it's EzPort interface connected to the SPI bus. Currently
> both (normal and EzPort) interfaces are simply exposed to userspace.
> This does not work for the EzPort, since EzPort usage requires a device
> reset. The proper solution is to do the flashing from kernel space
> with properly timed toggling of EzPort chip-select and reset line. In
> PATCHv2 it was suggested, that this should happen via an SPI ancillary
> device, so this is how it has been implemented now.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/6] spi: add ancillary device support
      commit: 0c79378c01999bd60057c475f163ec807c24891f
[2/6] spi: dt-bindings: support devices with multiple chipselects
      commit: d90609a4b72dbfe42da2a55f3078c35e669948e0

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

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

end of thread, other threads:[~2021-06-22 15:14 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-09 15:12 [PATCHv4 0/6] GE Healthcare PPD firmware upgrade driver for ACHC Sebastian Reichel
2021-06-09 15:12 ` [PATCHv4 1/6] spi: add ancillary device support Sebastian Reichel
2021-06-11  9:06   ` Greg Kroah-Hartman
2021-06-11 17:22     ` Sebastian Reichel
2021-06-13 14:18   ` Andy Shevchenko
2021-06-17 12:51   ` Mark Brown
2021-06-09 15:12 ` [PATCHv4 2/6] spi: dt-bindings: support devices with multiple chipselects Sebastian Reichel
2021-06-09 15:12 ` [PATCHv4 3/6] dt-bindings: misc: ge-achc: Convert to DT schema format Sebastian Reichel
2021-06-10 16:41   ` Rob Herring
2021-06-09 15:12 ` [PATCHv4 4/6] ARM: dts: imx53-ppd: Fix ACHC entry Sebastian Reichel
2021-06-09 15:12 ` [PATCHv4 5/6] misc: nxp-ezport: introduce EzPort support Sebastian Reichel
2021-06-11  9:05   ` Greg Kroah-Hartman
2021-06-11  9:45     ` Greg Kroah-Hartman
2021-06-09 15:12 ` [PATCHv4 6/6] misc: gehc-achc: new driver Sebastian Reichel
2021-06-11  9:02   ` Greg Kroah-Hartman
2021-06-22 15:14 ` (subset) [PATCHv4 0/6] GE Healthcare PPD firmware upgrade driver for ACHC Mark Brown

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.