]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
spi: add devm_spi_new_ancillary_device()
authorAntoniu Miclaus <antoniu.miclaus@analog.com>
Mon, 23 Feb 2026 16:21:01 +0000 (18:21 +0200)
committerMark Brown <broonie@kernel.org>
Tue, 24 Feb 2026 17:41:42 +0000 (17:41 +0000)
Add a devres-managed version of spi_new_ancillary_device() that
automatically unregisters the ancillary SPI device when the parent
device is removed.

This follows the same devm_add_action_or_reset() pattern used by the
other managed SPI functions (devm_spi_optimize_message,
devm_spi_register_controller, etc.) and eliminates the need for drivers
to open-code their own devm cleanup callbacks for ancillary devices.

Acked-by: Nuno Sá <nuno.sa@analog.com>
Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
Link: https://patch.msgid.link/20260223162110.156746-3-antoniu.miclaus@analog.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi.c
include/linux/spi/spi.h

index 8fbed4754de4e520ec21167254b9378f1c59e35b..26cc10aa75334e7fe6f9428fa1daf6927d9b205f 100644 (file)
@@ -2747,6 +2747,46 @@ err_out:
 }
 EXPORT_SYMBOL_GPL(spi_new_ancillary_device);
 
+static void devm_spi_unregister_device(void *spi)
+{
+       spi_unregister_device(spi);
+}
+
+/**
+ * devm_spi_new_ancillary_device() - Register managed 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 is the managed version of spi_new_ancillary_device(). The ancillary
+ * device will be unregistered automatically when the parent SPI device is
+ * unregistered.
+ *
+ * This may only be called from main SPI device's probe routine.
+ *
+ * Return: Pointer to new ancillary device on success; ERR_PTR on failure
+ */
+struct spi_device *devm_spi_new_ancillary_device(struct spi_device *spi,
+                                                u8 chip_select)
+{
+       struct spi_device *ancillary;
+       int ret;
+
+       ancillary = spi_new_ancillary_device(spi, chip_select);
+       if (IS_ERR(ancillary))
+               return ancillary;
+
+       ret = devm_add_action_or_reset(&spi->dev, devm_spi_unregister_device,
+                                      ancillary);
+       if (ret)
+               return ERR_PTR(ret);
+
+       return ancillary;
+}
+EXPORT_SYMBOL_GPL(devm_spi_new_ancillary_device);
+
 #ifdef CONFIG_ACPI
 struct acpi_spi_lookup {
        struct spi_controller   *ctlr;
index af7cfee7b8f60d7e022cb82e7fe2dbd3e37bf617..1c9aab627583c482e639083ad2c921ea6cd027fc 100644 (file)
@@ -387,6 +387,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
 }
 
 extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 chip_select);
+extern struct spi_device *devm_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) \