kernel: move patches to backported
authorHauke Mehrtens <hauke@hauke-m.de>
Thu, 1 Jan 2026 01:34:27 +0000 (02:34 +0100)
committerHauke Mehrtens <hauke@hauke-m.de>
Sun, 4 Jan 2026 15:41:29 +0000 (16:41 +0100)
These formally pending patches were merged into upstream Linux some time
ago. Move them to the backports folder and add the kernel version they
were added to the file name.

Link: https://github.com/openwrt/openwrt/pull/21366
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
24 files changed:
target/linux/generic/backport-6.12/152-v6.16-net-wireguard-add-nonstring-annotation-to-fix-build-with-GCC15.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/421-v6.16-next-spi-spi-qpic-snand-validate-user-chip-specific-ECC-properties.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/422-v6.19-mtd-spinand-esmt-add-support-for-F50L1G41LC.patch [deleted file]
target/linux/generic/backport-6.12/426-v6.17-mtd-nand-qpic-common-add-defines-for-ECC_MODE-values.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/427-v6.17-spi-spi-qpic-snand-add-support-for-8-bits-ECC-strength.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/429-01-v6.18-mtd-spinand-fix-direct-mapping-creation-sizes.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/429-02-v6.18-mtd-spinand-try-a-regular-dirmap-if-creating-a-di.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/429-03-v6.18-mtd-spinand-repeat-reading-in-regular-mode-if-con.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/434-v6.19-mtd-spinand-esmt-add-support-for-F50L1G41LC.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/435-v6.19-mtd-spinand-add-support-for-FudanMicro-FM25S01BI3.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/891-v6.14-dt-bindings-leds-Add-LED1202-LED-Controller.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/892-v6.14-leds-Add-LED1202-I2C-driver.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/893-v6.14-leds_st1202-Fix-NULL-pointer-access-error.patch [new file with mode: 0644]
target/linux/generic/pending-6.12/152-net-wireguard-add-nonstring-annotation-to-fix-build-with-GCC15.patch [deleted file]
target/linux/generic/pending-6.12/403-mtd-spinand-add-support-for-FudanMicro-FM25S01BI3.patch [deleted file]
target/linux/generic/pending-6.12/405-01-mtd-spinand-fix-direct-mapping-creation-sizes.patch [deleted file]
target/linux/generic/pending-6.12/405-02-mtd-spinand-try-a-regular-dirmap-if-creating-a-di.patch [deleted file]
target/linux/generic/pending-6.12/405-03-mtd-spinand-repeat-reading-in-regular-mode-if-con.patch [deleted file]
target/linux/generic/pending-6.12/416-09-next-spi-spi-qpic-snand-validate-user-chip-specific-ECC-properties.patch [deleted file]
target/linux/generic/pending-6.12/416-10-next-1-2-mtd-nand-qpic-common-add-defines-for-ECC_MODE-values.patch [deleted file]
target/linux/generic/pending-6.12/416-11-next-2-2-spi-spi-qpic-snand-add-support-for-8-bits-ECC-strength.patch [deleted file]
target/linux/generic/pending-6.12/891-dt-bindings-leds-Add-LED1202-LED-Controller.patch [deleted file]
target/linux/generic/pending-6.12/892-leds-Add-LED1202-I2C-driver.patch [deleted file]
target/linux/generic/pending-6.12/893-leds_st1202-Fix-NULL-pointer-access-error.patch [deleted file]

diff --git a/target/linux/generic/backport-6.12/152-v6.16-net-wireguard-add-nonstring-annotation-to-fix-build-with-GCC15.patch b/target/linux/generic/backport-6.12/152-v6.16-net-wireguard-add-nonstring-annotation-to-fix-build-with-GCC15.patch
new file mode 100644 (file)
index 0000000..1fdf2f1
--- /dev/null
@@ -0,0 +1,63 @@
+From 71e5da46e78c1cd24e2feed251a2845327447ad8 Mon Sep 17 00:00:00 2001
+From: Kees Cook <kees@kernel.org>
+Date: Wed, 21 May 2025 23:27:04 +0200
+Subject: wireguard: global: add __nonstring annotations for unterminated
+ strings
+
+When a character array without a terminating NUL character has a static
+initializer, GCC 15's -Wunterminated-string-initialization will only
+warn if the array lacks the "nonstring" attribute[1]. Mark the arrays
+with __nonstring to correctly identify the char array as "not a C string"
+and thereby eliminate the warning:
+
+../drivers/net/wireguard/cookie.c:29:56: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (9 chars into 8 available) [-Wunterminated-string-initialization]
+   29 | static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] = "mac1----";
+      |                                                        ^~~~~~~~~~
+../drivers/net/wireguard/cookie.c:30:58: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (9 chars into 8 available) [-Wunterminated-string-initialization]
+   30 | static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] = "cookie--";
+      |                                                          ^~~~~~~~~~
+../drivers/net/wireguard/noise.c:28:38: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (38 chars into 37 available) [-Wunterminated-string-initialization]
+   28 | static const u8 handshake_name[37] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s";
+      |                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../drivers/net/wireguard/noise.c:29:39: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (35 chars into 34 available) [-Wunterminated-string-initialization]
+   29 | static const u8 identifier_name[34] = "WireGuard v1 zx2c4 Jason@zx2c4.com";
+      |                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The arrays are always used with their fixed size, so use __nonstring.
+
+Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117178 [1]
+Signed-off-by: Kees Cook <kees@kernel.org>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Link: https://patch.msgid.link/20250521212707.1767879-3-Jason@zx2c4.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/wireguard/cookie.c | 4 ++--
+ drivers/net/wireguard/noise.c  | 4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/wireguard/cookie.c
++++ b/drivers/net/wireguard/cookie.c
+@@ -26,8 +26,8 @@ void wg_cookie_checker_init(struct cooki
+ }
+ enum { COOKIE_KEY_LABEL_LEN = 8 };
+-static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] = "mac1----";
+-static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] = "cookie--";
++static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] __nonstring = "mac1----";
++static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] __nonstring = "cookie--";
+ static void precompute_key(u8 key[NOISE_SYMMETRIC_KEY_LEN],
+                          const u8 pubkey[NOISE_PUBLIC_KEY_LEN],
+--- a/drivers/net/wireguard/noise.c
++++ b/drivers/net/wireguard/noise.c
+@@ -25,8 +25,8 @@
+  * <- e, ee, se, psk, {}
+  */
+-static const u8 handshake_name[37] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s";
+-static const u8 identifier_name[34] = "WireGuard v1 zx2c4 Jason@zx2c4.com";
++static const u8 handshake_name[37] __nonstring = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s";
++static const u8 identifier_name[34] __nonstring = "WireGuard v1 zx2c4 Jason@zx2c4.com";
+ static u8 handshake_init_hash[NOISE_HASH_LEN] __ro_after_init;
+ static u8 handshake_init_chaining_key[NOISE_HASH_LEN] __ro_after_init;
+ static atomic64_t keypair_counter = ATOMIC64_INIT(0);
diff --git a/target/linux/generic/backport-6.12/421-v6.16-next-spi-spi-qpic-snand-validate-user-chip-specific-ECC-properties.patch b/target/linux/generic/backport-6.12/421-v6.16-next-spi-spi-qpic-snand-validate-user-chip-specific-ECC-properties.patch
new file mode 100644 (file)
index 0000000..2f95156
--- /dev/null
@@ -0,0 +1,166 @@
+From 65cb56d49f6edea409600a3c61effc70ee5d43d8 Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <j4g8y7@gmail.com>
+Date: Thu, 1 May 2025 18:19:16 +0200
+Subject: spi: spi-qpic-snand: validate user/chip specific ECC properties
+
+The driver only supports 512 bytes ECC step size and 4 bit ECC strength
+at the moment, however it does not reject unsupported step/strength
+configurations. Due to this, whenever the driver is used with a flash
+chip which needs stronger ECC protection, the following warning is shown
+in the kernel log:
+
+  [    0.574648] spi-nand spi0.0: GigaDevice SPI NAND was found.
+  [    0.635748] spi-nand spi0.0: 256 MiB, block size: 128 KiB, page size: 2048, OOB size: 128
+  [    0.649079] nand: WARNING: (null): the ECC used on your system is too weak compared to the one required by the NAND chip
+
+Although the message indicates that something is wrong, but it often gets
+unnoticed, which can cause serious problems. For example when the user
+writes something into the flash chip despite the warning, the written data
+may won't be readable by the bootloader or by the boot ROM. In the worst
+case, when the attached SPI NAND chip is the boot device, the board may not
+be able to boot anymore.
+
+Also, it is not even possible to create a backup of the flash, because
+reading its content results in bogus data. For example, dumping the first
+page of the flash gives this:
+
+  # hexdump -C -n 2048 /dev/mtd0
+  00000000  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
+  *
+  00000040  0f 0f 0f 0f 0f 0f 0f 0d  0f 0f 0f 0f 0f 0f 0f 0f  |................|
+  00000050  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
+  *
+  000001c0  0f 0f 0f 0f ff 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
+  000001d0  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
+  *
+  00000200  0f 0f 0f 0f f5 5b ff ff  0f 0f 0f 0f 0f 0f 0f 0f  |.....[..........|
+  00000210  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
+  *
+  000002f0  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 1f 0f 0f  |................|
+  00000300  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
+  *
+  000003c0  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f ff 0f 0f 0f  |................|
+  000003d0  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
+  *
+  00000400  0f 0f 0f 0f 0f 0f 0f 0f  e9 74 c9 06 f5 5b ff ff  |.........t...[..|
+  00000410  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
+  *
+  000005d0  0f 0f 0f 0f ff 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
+  000005e0  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
+  *
+  00000600  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f c6 be 0f c3  |................|
+  00000610  e9 74 c9 06 f5 5b ff ff  0f 0f 0f 0f 0f 0f 0f 0f  |.t...[..........|
+  00000620  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
+  *
+  00000770  0f 0f 0f 0f 8f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
+  00000780  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
+  *
+  00000800
+  #
+
+Doing the same by using the downstream kernel results in different output:
+
+  # hexdump -C -n 2048 /dev/mtd0
+  00000000  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
+  *
+  00000800
+  #
+
+This patch adds some sanity checks to the code to prevent using the driver
+with unsupported ECC step/strength configurations. After the change, probing
+of the driver fails in such cases:
+
+  [    0.655038] spi-nand spi0.0: GigaDevice SPI NAND was found.
+  [    0.659159] spi-nand spi0.0: 256 MiB, block size: 128 KiB, page size: 2048, OOB size: 128
+  [    0.669138] qcom_snand 79b0000.spi: only 4 bits ECC strength is supported
+  [    0.677476] nand: No suitable ECC configuration
+  [    0.689909] spi-nand spi0.0: probe with driver spi-nand failed with error -95
+
+This helps to avoid the aforementioned hassles until support for 8 bit ECC
+strength gets implemented.
+
+Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
+Signed-off-by: Gabor Juhos <j4g8y7@gmail.com>
+Link: https://patch.msgid.link/20250501-qpic-snand-validate-ecc-v1-1-532776581a66@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ drivers/spi/spi-qpic-snand.c | 42 +++++++++++++++++++++++++++++++-----
+ 1 file changed, 37 insertions(+), 5 deletions(-)
+
+--- a/drivers/spi/spi-qpic-snand.c
++++ b/drivers/spi/spi-qpic-snand.c
+@@ -249,9 +249,11 @@ static const struct mtd_ooblayout_ops qc
+ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand)
+ {
+       struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
++      struct nand_ecc_props *reqs = &nand->ecc.requirements;
++      struct nand_ecc_props *user = &nand->ecc.user_conf;
+       struct nand_ecc_props *conf = &nand->ecc.ctx.conf;
+       struct mtd_info *mtd = nanddev_to_mtd(nand);
+-      int cwperpage, bad_block_byte;
++      int cwperpage, bad_block_byte, ret;
+       struct qpic_ecc *ecc_cfg;
+       cwperpage = mtd->writesize / NANDC_STEP_SIZE;
+@@ -260,11 +262,39 @@ static int qcom_spi_ecc_init_ctx_pipelin
+       ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL);
+       if (!ecc_cfg)
+               return -ENOMEM;
++
++      if (user->step_size && user->strength) {
++              ecc_cfg->step_size = user->step_size;
++              ecc_cfg->strength = user->strength;
++      } else if (reqs->step_size && reqs->strength) {
++              ecc_cfg->step_size = reqs->step_size;
++              ecc_cfg->strength = reqs->strength;
++      } else {
++              /* use defaults */
++              ecc_cfg->step_size = NANDC_STEP_SIZE;
++              ecc_cfg->strength = 4;
++      }
++
++      if (ecc_cfg->step_size != NANDC_STEP_SIZE) {
++              dev_err(snandc->dev,
++                      "only %u bytes ECC step size is supported\n",
++                      NANDC_STEP_SIZE);
++              ret = -EOPNOTSUPP;
++              goto err_free_ecc_cfg;
++      }
++
++      if (ecc_cfg->strength != 4) {
++              dev_err(snandc->dev,
++                      "only 4 bits ECC strength is supported\n");
++              ret = -EOPNOTSUPP;
++              goto err_free_ecc_cfg;
++      }
++
+       snandc->qspi->oob_buf = kmalloc(mtd->writesize + mtd->oobsize,
+                                       GFP_KERNEL);
+       if (!snandc->qspi->oob_buf) {
+-              kfree(ecc_cfg);
+-              return -ENOMEM;
++              ret = -ENOMEM;
++              goto err_free_ecc_cfg;
+       }
+       memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize);
+@@ -279,8 +309,6 @@ static int qcom_spi_ecc_init_ctx_pipelin
+       ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size;
+       ecc_cfg->steps = 4;
+-      ecc_cfg->strength = 4;
+-      ecc_cfg->step_size = 512;
+       ecc_cfg->cw_data = 516;
+       ecc_cfg->cw_size = ecc_cfg->cw_data + ecc_cfg->bytes;
+       bad_block_byte = mtd->writesize - ecc_cfg->cw_size * (cwperpage - 1) + 1;
+@@ -338,6 +366,10 @@ static int qcom_spi_ecc_init_ctx_pipelin
+               ecc_cfg->strength, ecc_cfg->step_size);
+       return 0;
++
++err_free_ecc_cfg:
++      kfree(ecc_cfg);
++      return ret;
+ }
+ static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand)
diff --git a/target/linux/generic/backport-6.12/422-v6.19-mtd-spinand-esmt-add-support-for-F50L1G41LC.patch b/target/linux/generic/backport-6.12/422-v6.19-mtd-spinand-esmt-add-support-for-F50L1G41LC.patch
deleted file mode 100644 (file)
index b65df4e..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-From b98994cb9bc24f5c7575c86650f96c384576fdfa Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Mon, 17 Nov 2025 02:54:19 +0000
-Subject: [PATCH] mtd: spinand: esmt: add support for F50L1G41LC
-
-This adds support for ESMT F50L1G41LC, which appears to be an updated
-version of the already supported F50L1G41LB.
-Add esmt_8c SPI_NAND manufacturer to account for the newly used vendor
-ID with support for the ESMT F50L1G41LC chip.
-
-Link: https://github.com/openwrt/openwrt/pull/15214#issuecomment-3514824435
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
-Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
----
- drivers/mtd/nand/spi/core.c |  1 +
- drivers/mtd/nand/spi/esmt.c | 24 ++++++++++++++++++++++++
- include/linux/mtd/spinand.h |  1 +
- 3 files changed, 26 insertions(+)
-
---- a/drivers/mtd/nand/spi/core.c
-+++ b/drivers/mtd/nand/spi/core.c
-@@ -1114,6 +1114,7 @@ static const struct nand_ops spinand_ops
- static const struct spinand_manufacturer *spinand_manufacturers[] = {
-       &alliancememory_spinand_manufacturer,
-       &ato_spinand_manufacturer,
-+      &esmt_8c_spinand_manufacturer,
-       &esmt_c8_spinand_manufacturer,
-       &fmsh_spinand_manufacturer,
-       &foresee_spinand_manufacturer,
---- a/drivers/mtd/nand/spi/esmt.c
-+++ b/drivers/mtd/nand/spi/esmt.c
-@@ -11,6 +11,7 @@
- /* ESMT uses GigaDevice 0xc8 JECDEC ID on some SPI NANDs */
- #define SPINAND_MFR_ESMT_C8                   0xc8
-+#define SPINAND_MFR_ESMT_8C                   0x8c
- static SPINAND_OP_VARIANTS(read_cache_variants,
-                          SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
-@@ -102,6 +103,19 @@ static const struct mtd_ooblayout_ops f5
-       .free = f50l1g41lb_ooblayout_free,
- };
-+
-+static const struct spinand_info esmt_8c_spinand_table[] = {
-+      SPINAND_INFO("F50L1G41LC",
-+                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x2C),
-+                   NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
-+                   NAND_ECCREQ(1, 512),
-+                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+                                            &write_cache_variants,
-+                                            &update_cache_variants),
-+                   0,
-+                   SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
-+};
-+
- static const struct spinand_info esmt_c8_spinand_table[] = {
-       SPINAND_INFO("F50L1G41LB",
-                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01, 0x7f,
-@@ -138,6 +152,14 @@ static const struct spinand_info esmt_c8
- static const struct spinand_manufacturer_ops esmt_spinand_manuf_ops = {
- };
-+const struct spinand_manufacturer esmt_8c_spinand_manufacturer = {
-+      .id = SPINAND_MFR_ESMT_8C,
-+      .name = "ESMT",
-+      .chips = esmt_8c_spinand_table,
-+      .nchips = ARRAY_SIZE(esmt_8c_spinand_table),
-+      .ops = &esmt_spinand_manuf_ops,
-+};
-+
- const struct spinand_manufacturer esmt_c8_spinand_manufacturer = {
-       .id = SPINAND_MFR_ESMT_C8,
-       .name = "ESMT",
---- a/include/linux/mtd/spinand.h
-+++ b/include/linux/mtd/spinand.h
-@@ -262,6 +262,7 @@ struct spinand_manufacturer {
- /* SPI NAND manufacturers */
- extern const struct spinand_manufacturer alliancememory_spinand_manufacturer;
- extern const struct spinand_manufacturer ato_spinand_manufacturer;
-+extern const struct spinand_manufacturer esmt_8c_spinand_manufacturer;
- extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
- extern const struct spinand_manufacturer fmsh_spinand_manufacturer;
- extern const struct spinand_manufacturer foresee_spinand_manufacturer;
diff --git a/target/linux/generic/backport-6.12/426-v6.17-mtd-nand-qpic-common-add-defines-for-ECC_MODE-values.patch b/target/linux/generic/backport-6.12/426-v6.17-mtd-nand-qpic-common-add-defines-for-ECC_MODE-values.patch
new file mode 100644 (file)
index 0000000..c232410
--- /dev/null
@@ -0,0 +1,74 @@
+From 0dc7e656ddd54c3267b7cc18c1ac8ec1297ed02f Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <j4g8y7@gmail.com>
+Date: Wed, 2 Jul 2025 14:35:23 +0200
+Subject: mtd: nand: qpic-common: add defines for ECC_MODE values
+
+Add defines for the values of the ECC_MODE field of the NAND_DEV0_ECC_CFG
+register and change both the 'qcom-nandc' and 'spi-qpic-snand' drivers to
+use those instead of magic numbers.
+
+No functional changes. This is in preparation for adding 8 bit ECC strength
+support for the 'spi-qpic-snand' driver.
+
+Reviewed-by: Md Sadre Alam <quic_mdalam@quicinc.com>
+Signed-off-by: Gabor Juhos <j4g8y7@gmail.com>
+Acked-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://patch.msgid.link/20250702-qpic-snand-8bit-ecc-v2-1-ae2c17a30bb7@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ drivers/mtd/nand/raw/qcom_nandc.c    | 6 +++---
+ drivers/spi/spi-qpic-snand.c         | 2 +-
+ include/linux/mtd/nand-qpic-common.h | 2 ++
+ 3 files changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/mtd/nand/raw/qcom_nandc.c
++++ b/drivers/mtd/nand/raw/qcom_nandc.c
+@@ -1379,7 +1379,7 @@ static int qcom_nand_attach_chip(struct
+       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+       int cwperpage, bad_block_byte, ret;
+       bool wide_bus;
+-      int ecc_mode = 1;
++      int ecc_mode = ECC_MODE_8BIT;
+       /* controller only supports 512 bytes data steps */
+       ecc->size = NANDC_STEP_SIZE;
+@@ -1400,7 +1400,7 @@ static int qcom_nand_attach_chip(struct
+       if (ecc->strength >= 8) {
+               /* 8 bit ECC defaults to BCH ECC on all platforms */
+               host->bch_enabled = true;
+-              ecc_mode = 1;
++              ecc_mode = ECC_MODE_8BIT;
+               if (wide_bus) {
+                       host->ecc_bytes_hw = 14;
+@@ -1420,7 +1420,7 @@ static int qcom_nand_attach_chip(struct
+               if (nandc->props->ecc_modes & ECC_BCH_4BIT) {
+                       /* BCH */
+                       host->bch_enabled = true;
+-                      ecc_mode = 0;
++                      ecc_mode = ECC_MODE_4BIT;
+                       if (wide_bus) {
+                               host->ecc_bytes_hw = 8;
+--- a/drivers/spi/spi-qpic-snand.c
++++ b/drivers/spi/spi-qpic-snand.c
+@@ -349,7 +349,7 @@ static int qcom_spi_ecc_init_ctx_pipelin
+                              FIELD_PREP(ECC_SW_RESET, 0) |
+                              FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) |
+                              FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
+-                             FIELD_PREP(ECC_MODE_MASK, 0) |
++                             FIELD_PREP(ECC_MODE_MASK, ECC_MODE_4BIT) |
+                              FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw);
+       ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS;
+--- a/include/linux/mtd/nand-qpic-common.h
++++ b/include/linux/mtd/nand-qpic-common.h
+@@ -101,6 +101,8 @@
+ #define       ECC_SW_RESET                    BIT(1)
+ #define       ECC_MODE                        4
+ #define       ECC_MODE_MASK                   GENMASK(5, 4)
++#define       ECC_MODE_4BIT                   0
++#define       ECC_MODE_8BIT                   1
+ #define       ECC_PARITY_SIZE_BYTES_BCH       8
+ #define       ECC_PARITY_SIZE_BYTES_BCH_MASK  GENMASK(12, 8)
+ #define       ECC_NUM_DATA_BYTES              16
diff --git a/target/linux/generic/backport-6.12/427-v6.17-spi-spi-qpic-snand-add-support-for-8-bits-ECC-strength.patch b/target/linux/generic/backport-6.12/427-v6.17-spi-spi-qpic-snand-add-support-for-8-bits-ECC-strength.patch
new file mode 100644 (file)
index 0000000..acf5d60
--- /dev/null
@@ -0,0 +1,66 @@
+From 913bf8d50cbd144c87e9660b591781179182ff59 Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <j4g8y7@gmail.com>
+Date: Wed, 2 Jul 2025 14:35:24 +0200
+Subject: spi: spi-qpic-snand: add support for 8 bits ECC strength
+
+Even though the hardware supports 8 bits ECC strength, but that is not
+handled in the driver yet. This change adds the missing bits in order
+to allow using the driver with chips which require 8 bits ECC strength.
+
+No functional changes intended with regard to the existing 4 bits ECC
+strength support.
+
+Tested on an IPQ9574 platform using a GigaDevice GD5F2GM7REYIG chip.
+
+Signed-off-by: Gabor Juhos <j4g8y7@gmail.com>
+Link: https://patch.msgid.link/20250702-qpic-snand-8bit-ecc-v2-2-ae2c17a30bb7@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ drivers/spi/spi-qpic-snand.c | 21 ++++++++++++++++-----
+ 1 file changed, 16 insertions(+), 5 deletions(-)
+
+--- a/drivers/spi/spi-qpic-snand.c
++++ b/drivers/spi/spi-qpic-snand.c
+@@ -283,9 +283,22 @@ static int qcom_spi_ecc_init_ctx_pipelin
+               goto err_free_ecc_cfg;
+       }
+-      if (ecc_cfg->strength != 4) {
++      switch (ecc_cfg->strength) {
++      case 4:
++              ecc_cfg->ecc_mode = ECC_MODE_4BIT;
++              ecc_cfg->ecc_bytes_hw = 7;
++              ecc_cfg->spare_bytes = 4;
++              break;
++
++      case 8:
++              ecc_cfg->ecc_mode = ECC_MODE_8BIT;
++              ecc_cfg->ecc_bytes_hw = 13;
++              ecc_cfg->spare_bytes = 2;
++              break;
++
++      default:
+               dev_err(snandc->dev,
+-                      "only 4 bits ECC strength is supported\n");
++                      "only 4 or 8 bits ECC strength is supported\n");
+               ret = -EOPNOTSUPP;
+               goto err_free_ecc_cfg;
+       }
+@@ -302,8 +315,6 @@ static int qcom_spi_ecc_init_ctx_pipelin
+       nand->ecc.ctx.priv = ecc_cfg;
+       snandc->qspi->mtd = mtd;
+-      ecc_cfg->ecc_bytes_hw = 7;
+-      ecc_cfg->spare_bytes = 4;
+       ecc_cfg->bbm_size = 1;
+       ecc_cfg->bch_enabled = true;
+       ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size;
+@@ -349,7 +360,7 @@ static int qcom_spi_ecc_init_ctx_pipelin
+                              FIELD_PREP(ECC_SW_RESET, 0) |
+                              FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) |
+                              FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
+-                             FIELD_PREP(ECC_MODE_MASK, ECC_MODE_4BIT) |
++                             FIELD_PREP(ECC_MODE_MASK, ecc_cfg->ecc_mode) |
+                              FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw);
+       ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS;
diff --git a/target/linux/generic/backport-6.12/429-01-v6.18-mtd-spinand-fix-direct-mapping-creation-sizes.patch b/target/linux/generic/backport-6.12/429-01-v6.18-mtd-spinand-fix-direct-mapping-creation-sizes.patch
new file mode 100644 (file)
index 0000000..994e06e
--- /dev/null
@@ -0,0 +1,63 @@
+From e4a0cf9f1d90e6888e5373da3314f761024f6c97 Mon Sep 17 00:00:00 2001
+From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
+Date: Thu, 18 Sep 2025 00:53:59 +0300
+Subject: mtd: spinand: fix direct mapping creation sizes
+
+Continuous mode is only supported for data reads, thus writing
+requires only single flash page mapping.
+
+Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+---
+ drivers/mtd/nand/spi/core.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -1028,18 +1028,13 @@ static int spinand_create_dirmap(struct
+                                unsigned int plane)
+ {
+       struct nand_device *nand = spinand_to_nand(spinand);
+-      struct spi_mem_dirmap_info info = {
+-              .length = nanddev_page_size(nand) +
+-                        nanddev_per_page_oobsize(nand),
+-      };
++      struct spi_mem_dirmap_info info = { 0 };
+       struct spi_mem_dirmap_desc *desc;
+-      if (spinand->cont_read_possible)
+-              info.length = nanddev_eraseblock_size(nand);
+-
+       /* The plane number is passed in MSB just above the column address */
+       info.offset = plane << fls(nand->memorg.pagesize);
++      info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand);
+       info.op_tmpl = *spinand->op_templates.update_cache;
+       desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
+                                         spinand->spimem, &info);
+@@ -1048,6 +1043,8 @@ static int spinand_create_dirmap(struct
+       spinand->dirmaps[plane].wdesc = desc;
++      if (spinand->cont_read_possible)
++              info.length = nanddev_eraseblock_size(nand);
+       info.op_tmpl = *spinand->op_templates.read_cache;
+       desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
+                                         spinand->spimem, &info);
+@@ -1063,6 +1060,7 @@ static int spinand_create_dirmap(struct
+               return 0;
+       }
++      info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand);
+       info.op_tmpl = *spinand->op_templates.update_cache;
+       info.op_tmpl.data.ecc = true;
+       desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
+@@ -1072,6 +1070,8 @@ static int spinand_create_dirmap(struct
+       spinand->dirmaps[plane].wdesc_ecc = desc;
++      if (spinand->cont_read_possible)
++              info.length = nanddev_eraseblock_size(nand);
+       info.op_tmpl = *spinand->op_templates.read_cache;
+       info.op_tmpl.data.ecc = true;
+       desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
diff --git a/target/linux/generic/backport-6.12/429-02-v6.18-mtd-spinand-try-a-regular-dirmap-if-creating-a-di.patch b/target/linux/generic/backport-6.12/429-02-v6.18-mtd-spinand-try-a-regular-dirmap-if-creating-a-di.patch
new file mode 100644 (file)
index 0000000..005c0aa
--- /dev/null
@@ -0,0 +1,98 @@
+From 004f8ea0d9917398aabff7388b3bf62a84a4088b Mon Sep 17 00:00:00 2001
+From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
+Date: Thu, 18 Sep 2025 00:54:00 +0300
+Subject: mtd: spinand: try a regular dirmap if creating a dirmap for
+ continuous reading fails
+
+Continuous reading may result in multiple flash pages reading in one
+operation. Typically only one flash page has read/written (a little bit
+more than 2-4 Kb), but continuous reading requires the spi controller
+to read up to 512 Kb in one operation without toggling CS in beetween.
+
+Roughly speaking spi controllers can be divided on 2 categories:
+ * spi controllers without dirmap acceleration support
+ * spi controllers with dirmap acceleration support
+
+Firt of them will have issues with continuous reading if restriction on
+the transfer length is implemented in the adjust_op_size() handler.
+Second group often supports acceleration of single page only reading.
+Thus enabling of continuous reading can break flash reading.
+
+This patch tries to create dirmap for continuous reading first and
+fallback to regular reading if spi controller refuses to create it.
+
+Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+---
+ drivers/mtd/nand/spi/core.c | 43 ++++++++++++++++++++++++++++++-------
+ 1 file changed, 35 insertions(+), 8 deletions(-)
+
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -1024,6 +1024,39 @@ static int spinand_mtd_block_isreserved(
+       return ret;
+ }
++static struct spi_mem_dirmap_desc *spinand_create_rdesc(
++                                      struct spinand_device *spinand,
++                                      struct spi_mem_dirmap_info *info)
++{
++      struct nand_device *nand = spinand_to_nand(spinand);
++      struct spi_mem_dirmap_desc *desc = NULL;
++
++      if (spinand->cont_read_possible) {
++              /*
++               * spi controller may return an error if info->length is
++               * too large
++               */
++              info->length = nanddev_eraseblock_size(nand);
++              desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
++                                                spinand->spimem, info);
++      }
++
++      if (IS_ERR_OR_NULL(desc)) {
++              /*
++               * continuous reading is not supported by flash or
++               * its spi controller, use regular reading
++               */
++              spinand->cont_read_possible = false;
++
++              info->length = nanddev_page_size(nand) +
++                             nanddev_per_page_oobsize(nand);
++              desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
++                                                spinand->spimem, info);
++      }
++
++      return desc;
++}
++
+ static int spinand_create_dirmap(struct spinand_device *spinand,
+                                unsigned int plane)
+ {
+@@ -1043,11 +1076,8 @@ static int spinand_create_dirmap(struct
+       spinand->dirmaps[plane].wdesc = desc;
+-      if (spinand->cont_read_possible)
+-              info.length = nanddev_eraseblock_size(nand);
+       info.op_tmpl = *spinand->op_templates.read_cache;
+-      desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
+-                                        spinand->spimem, &info);
++      desc = spinand_create_rdesc(spinand, &info);
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
+@@ -1070,12 +1100,9 @@ static int spinand_create_dirmap(struct
+       spinand->dirmaps[plane].wdesc_ecc = desc;
+-      if (spinand->cont_read_possible)
+-              info.length = nanddev_eraseblock_size(nand);
+       info.op_tmpl = *spinand->op_templates.read_cache;
+       info.op_tmpl.data.ecc = true;
+-      desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
+-                                        spinand->spimem, &info);
++      desc = spinand_create_rdesc(spinand, &info);
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
diff --git a/target/linux/generic/backport-6.12/429-03-v6.18-mtd-spinand-repeat-reading-in-regular-mode-if-con.patch b/target/linux/generic/backport-6.12/429-03-v6.18-mtd-spinand-repeat-reading-in-regular-mode-if-con.patch
new file mode 100644 (file)
index 0000000..af53d20
--- /dev/null
@@ -0,0 +1,64 @@
+From 010dc7f2dd6a0078ade3f88f627ed5fbf45ceb94 Mon Sep 17 00:00:00 2001
+From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
+Date: Thu, 18 Sep 2025 00:54:01 +0300
+Subject: mtd: spinand: repeat reading in regular mode if continuous reading
+ fails
+
+Continuous reading may result in multiple flash pages reading in one
+operation. Unfortunately, not all spinand controllers support such
+large reading. They will read less data. Unfortunately, the operation
+can't be continued.
+
+In this case:
+ * disable continuous reading on this (not good enough) spi controller
+ * repeat reading in regular mode.
+
+Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+---
+ drivers/mtd/nand/spi/core.c | 25 +++++++++++++++++++++----
+ 1 file changed, 21 insertions(+), 4 deletions(-)
+
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -427,8 +427,16 @@ static int spinand_read_from_cache_op(st
+                * Dirmap accesses are allowed to toggle the CS.
+                * Toggling the CS during a continuous read is forbidden.
+                */
+-              if (nbytes && req->continuous)
+-                      return -EIO;
++              if (nbytes && req->continuous) {
++                      /*
++                       * Spi controller with broken support of continuous
++                       * reading was detected. Disable future use of
++                       * continuous reading and return -EAGAIN to retry
++                       * reading within regular mode.
++                       */
++                      spinand->cont_read_possible = false;
++                      return -EAGAIN;
++              }
+       }
+       if (req->datalen)
+@@ -841,10 +849,19 @@ static int spinand_mtd_read(struct mtd_i
+       old_stats = mtd->ecc_stats;
+-      if (spinand_use_cont_read(mtd, from, ops))
++      if (spinand_use_cont_read(mtd, from, ops)) {
+               ret = spinand_mtd_continuous_page_read(mtd, from, ops, &max_bitflips);
+-      else
++              if (ret == -EAGAIN && !spinand->cont_read_possible) {
++                      /*
++                       * Spi controller with broken support of continuous
++                       * reading was detected (see spinand_read_from_cache_op()),
++                       * repeat reading in regular mode.
++                       */
++                      ret = spinand_mtd_regular_page_read(mtd, from, ops, &max_bitflips);
++              }
++      } else {
+               ret = spinand_mtd_regular_page_read(mtd, from, ops, &max_bitflips);
++      }
+       if (ops->stats) {
+               ops->stats->uncorrectable_errors +=
diff --git a/target/linux/generic/backport-6.12/434-v6.19-mtd-spinand-esmt-add-support-for-F50L1G41LC.patch b/target/linux/generic/backport-6.12/434-v6.19-mtd-spinand-esmt-add-support-for-F50L1G41LC.patch
new file mode 100644 (file)
index 0000000..8350f14
--- /dev/null
@@ -0,0 +1,84 @@
+From b98994cb9bc24f5c7575c86650f96c384576fdfa Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 17 Nov 2025 02:54:19 +0000
+Subject: [PATCH] mtd: spinand: esmt: add support for F50L1G41LC
+
+This adds support for ESMT F50L1G41LC, which appears to be an updated
+version of the already supported F50L1G41LB.
+Add esmt_8c SPI_NAND manufacturer to account for the newly used vendor
+ID with support for the ESMT F50L1G41LC chip.
+
+Link: https://github.com/openwrt/openwrt/pull/15214#issuecomment-3514824435
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+---
+ drivers/mtd/nand/spi/core.c |  1 +
+ drivers/mtd/nand/spi/esmt.c | 24 ++++++++++++++++++++++++
+ include/linux/mtd/spinand.h |  1 +
+ 3 files changed, 26 insertions(+)
+
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -1158,6 +1158,7 @@ static const struct nand_ops spinand_ops
+ static const struct spinand_manufacturer *spinand_manufacturers[] = {
+       &alliancememory_spinand_manufacturer,
+       &ato_spinand_manufacturer,
++      &esmt_8c_spinand_manufacturer,
+       &esmt_c8_spinand_manufacturer,
+       &fmsh_spinand_manufacturer,
+       &foresee_spinand_manufacturer,
+--- a/drivers/mtd/nand/spi/esmt.c
++++ b/drivers/mtd/nand/spi/esmt.c
+@@ -11,6 +11,7 @@
+ /* ESMT uses GigaDevice 0xc8 JECDEC ID on some SPI NANDs */
+ #define SPINAND_MFR_ESMT_C8                   0xc8
++#define SPINAND_MFR_ESMT_8C                   0x8c
+ static SPINAND_OP_VARIANTS(read_cache_variants,
+                          SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+@@ -102,6 +103,19 @@ static const struct mtd_ooblayout_ops f5
+       .free = f50l1g41lb_ooblayout_free,
+ };
++
++static const struct spinand_info esmt_8c_spinand_table[] = {
++      SPINAND_INFO("F50L1G41LC",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x2C),
++                   NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
++                   NAND_ECCREQ(1, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
++};
++
+ static const struct spinand_info esmt_c8_spinand_table[] = {
+       SPINAND_INFO("F50L1G41LB",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01, 0x7f,
+@@ -138,6 +152,14 @@ static const struct spinand_info esmt_c8
+ static const struct spinand_manufacturer_ops esmt_spinand_manuf_ops = {
+ };
++const struct spinand_manufacturer esmt_8c_spinand_manufacturer = {
++      .id = SPINAND_MFR_ESMT_8C,
++      .name = "ESMT",
++      .chips = esmt_8c_spinand_table,
++      .nchips = ARRAY_SIZE(esmt_8c_spinand_table),
++      .ops = &esmt_spinand_manuf_ops,
++};
++
+ const struct spinand_manufacturer esmt_c8_spinand_manufacturer = {
+       .id = SPINAND_MFR_ESMT_C8,
+       .name = "ESMT",
+--- a/include/linux/mtd/spinand.h
++++ b/include/linux/mtd/spinand.h
+@@ -262,6 +262,7 @@ struct spinand_manufacturer {
+ /* SPI NAND manufacturers */
+ extern const struct spinand_manufacturer alliancememory_spinand_manufacturer;
+ extern const struct spinand_manufacturer ato_spinand_manufacturer;
++extern const struct spinand_manufacturer esmt_8c_spinand_manufacturer;
+ extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
+ extern const struct spinand_manufacturer fmsh_spinand_manufacturer;
+ extern const struct spinand_manufacturer foresee_spinand_manufacturer;
diff --git a/target/linux/generic/backport-6.12/435-v6.19-mtd-spinand-add-support-for-FudanMicro-FM25S01BI3.patch b/target/linux/generic/backport-6.12/435-v6.19-mtd-spinand-add-support-for-FudanMicro-FM25S01BI3.patch
new file mode 100644 (file)
index 0000000..7355efe
--- /dev/null
@@ -0,0 +1,115 @@
+From f6dffe2a9ed1bdcee1879e2728310fb1e08602cf Mon Sep 17 00:00:00 2001
+From: Mikhail Zhilkin <csharper2005@gmail.com>
+Date: Thu, 27 Nov 2025 22:59:00 +0300
+Subject: mtd: spinand: add support for FudanMicro FM25S01BI3
+
+Add support for FudanMicro FM25S01BI3 SPI NAND.
+
+Link: https://www.fmsh.com/nvm/FM25S01BI3_ds_eng.pdf
+
+Signed-off-by: Mikhail Zhilkin <csharper2005@gmail.com>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+---
+ drivers/mtd/nand/spi/fmsh.c | 72 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 72 insertions(+)
+
+--- a/drivers/mtd/nand/spi/fmsh.c
++++ b/drivers/mtd/nand/spi/fmsh.c
+@@ -9,6 +9,13 @@
+ #include <linux/kernel.h>
+ #include <linux/mtd/spinand.h>
++#define FM25S01BI3_STATUS_ECC_MASK            (7 << 4)
++      #define FM25S01BI3_STATUS_ECC_NO_BITFLIPS       (0 << 4)
++      #define FM25S01BI3_STATUS_ECC_1_3_BITFLIPS      (1 << 4)
++      #define FM25S01BI3_STATUS_ECC_UNCOR_ERROR       (2 << 4)
++      #define FM25S01BI3_STATUS_ECC_4_6_BITFLIPS      (3 << 4)
++      #define FM25S01BI3_STATUS_ECC_7_8_BITFLIPS      (5 << 4)
++
+ #define SPINAND_MFR_FMSH              0xA1
+ static SPINAND_OP_VARIANTS(read_cache_variants,
+@@ -45,11 +52,66 @@ static int fm25s01a_ooblayout_free(struc
+       return 0;
+ }
++static int fm25s01bi3_ecc_get_status(struct spinand_device *spinand,
++                                   u8 status)
++{
++      switch (status & FM25S01BI3_STATUS_ECC_MASK) {
++      case FM25S01BI3_STATUS_ECC_NO_BITFLIPS:
++              return 0;
++
++      case FM25S01BI3_STATUS_ECC_UNCOR_ERROR:
++              return -EBADMSG;
++
++      case FM25S01BI3_STATUS_ECC_1_3_BITFLIPS:
++              return 3;
++
++      case FM25S01BI3_STATUS_ECC_4_6_BITFLIPS:
++              return 6;
++
++      case FM25S01BI3_STATUS_ECC_7_8_BITFLIPS:
++              return 8;
++
++      default:
++              break;
++      }
++
++      return -EINVAL;
++}
++
++static int fm25s01bi3_ooblayout_ecc(struct mtd_info *mtd, int section,
++                                  struct mtd_oob_region *region)
++{
++      if (section)
++              return -ERANGE;
++
++      region->offset = 64;
++      region->length = 64;
++
++      return 0;
++}
++
++static int fm25s01bi3_ooblayout_free(struct mtd_info *mtd, int section,
++                                   struct mtd_oob_region *region)
++{
++      if (section > 3)
++              return -ERANGE;
++
++      region->offset = (16 * section) + 4;
++      region->length = 12;
++
++      return 0;
++}
++
+ static const struct mtd_ooblayout_ops fm25s01a_ooblayout = {
+       .ecc = fm25s01a_ooblayout_ecc,
+       .free = fm25s01a_ooblayout_free,
+ };
++static const struct mtd_ooblayout_ops fm25s01bi3_ooblayout = {
++      .ecc = fm25s01bi3_ooblayout_ecc,
++      .free = fm25s01bi3_ooblayout_free,
++};
++
+ static const struct spinand_info fmsh_spinand_table[] = {
+       SPINAND_INFO("FM25S01A",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4),
+@@ -60,6 +122,16 @@ static const struct spinand_info fmsh_sp
+                                             &update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)),
++      SPINAND_INFO("FM25S01BI3",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xd4),
++                   NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&fm25s01bi3_ooblayout,
++                                    fm25s01bi3_ecc_get_status)),
+ };
+ static const struct spinand_manufacturer_ops fmsh_spinand_manuf_ops = {
diff --git a/target/linux/generic/backport-6.12/891-v6.14-dt-bindings-leds-Add-LED1202-LED-Controller.patch b/target/linux/generic/backport-6.12/891-v6.14-dt-bindings-leds-Add-LED1202-LED-Controller.patch
new file mode 100644 (file)
index 0000000..9901d13
--- /dev/null
@@ -0,0 +1,160 @@
+From 599b92fd0efa8b7c43e7f58c9dd0f7951f7cbf09 Mon Sep 17 00:00:00 2001
+From: Vicentiu Galanopulo <vicentiu.galanopulo@remote-tech.co.uk>
+Date: Wed, 18 Dec 2024 18:33:58 +0000
+Subject: dt-bindings: leds: Add LED1202 LED Controller
+
+The LED1202 is a 12-channel low quiescent current LED driver with:
+  * Supply range from 2.6 V to 5 V
+  * 20 mA current capability per channel
+  * 1.8 V compatible I2C control interface
+  * 8-bit analog dimming individual control
+  * 12-bit local PWM resolution
+  * 8 programmable patterns
+
+If the led node is present in the controller then the channel is
+set to active.
+
+Signed-off-by: Vicentiu Galanopulo <vicentiu.galanopulo@remote-tech.co.uk>
+Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://lore.kernel.org/r/20241218183401.41687-3-vicentiu.galanopulo@remote-tech.co.uk
+Signed-off-by: Lee Jones <lee@kernel.org>
+---
+ .../devicetree/bindings/leds/st,led1202.yaml  | 132 ++++++++++++++++++
+ 1 file changed, 132 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/leds/st,led1202.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/leds/st,led1202.yaml
+@@ -0,0 +1,132 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/leds/st,led1202.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: ST LED1202 LED controllers
++
++maintainers:
++  - Vicentiu Galanopulo <vicentiu.galanopulo@remote-tech.co.uk>
++
++description: |
++  The LED1202 is a 12-channel low quiescent current LED controller
++  programmable via I2C; The output current can be adjusted separately
++  for each channel by 8-bit analog and 12-bit digital dimming control.
++  Datasheet available at
++  https://www.st.com/en/power-management/led1202.html
++
++properties:
++  compatible:
++    const: st,led1202
++
++  reg:
++    maxItems: 1
++
++  "#address-cells":
++    const: 1
++
++  "#size-cells":
++    const: 0
++
++patternProperties:
++  "^led@[0-9a-f]$":
++    type: object
++    $ref: common.yaml#
++    unevaluatedProperties: false
++
++    properties:
++      reg:
++        minimum: 0
++        maximum: 11
++
++    required:
++      - reg
++
++required:
++  - compatible
++  - reg
++  - "#address-cells"
++  - "#size-cells"
++
++additionalProperties: false
++
++examples:
++  - |
++    #include <dt-bindings/leds/common.h>
++
++    i2c {
++        #address-cells = <1>;
++        #size-cells = <0>;
++
++        led-controller@58 {
++            compatible = "st,led1202";
++            reg = <0x58>;
++            #address-cells = <1>;
++            #size-cells = <0>;
++
++            led@0 {
++                reg = <0x0>;
++                function = LED_FUNCTION_STATUS;
++                color = <LED_COLOR_ID_RED>;
++                function-enumerator = <1>;
++            };
++
++            led@1 {
++                reg = <0x1>;
++                function = LED_FUNCTION_STATUS;
++                color = <LED_COLOR_ID_GREEN>;
++                function-enumerator = <2>;
++            };
++
++            led@2 {
++                reg = <0x2>;
++                function = LED_FUNCTION_STATUS;
++                color = <LED_COLOR_ID_BLUE>;
++                function-enumerator = <3>;
++            };
++
++            led@3 {
++                reg = <0x3>;
++                function = LED_FUNCTION_STATUS;
++                color = <LED_COLOR_ID_RED>;
++                function-enumerator = <4>;
++            };
++
++            led@4 {
++                reg = <0x4>;
++                function = LED_FUNCTION_STATUS;
++                color = <LED_COLOR_ID_GREEN>;
++                function-enumerator = <5>;
++            };
++
++            led@5 {
++                reg = <0x5>;
++                function = LED_FUNCTION_STATUS;
++                color = <LED_COLOR_ID_BLUE>;
++                function-enumerator = <6>;
++            };
++
++            led@6 {
++                reg = <0x6>;
++                function = LED_FUNCTION_STATUS;
++                color = <LED_COLOR_ID_RED>;
++                function-enumerator = <7>;
++            };
++
++            led@7 {
++                reg = <0x7>;
++                function = LED_FUNCTION_STATUS;
++                color = <LED_COLOR_ID_GREEN>;
++                function-enumerator = <8>;
++            };
++
++            led@8 {
++                reg = <0x8>;
++                function = LED_FUNCTION_STATUS;
++                color = <LED_COLOR_ID_BLUE>;
++                function-enumerator = <9>;
++            };
++        };
++    };
++...
diff --git a/target/linux/generic/backport-6.12/892-v6.14-leds-Add-LED1202-I2C-driver.patch b/target/linux/generic/backport-6.12/892-v6.14-leds-Add-LED1202-I2C-driver.patch
new file mode 100644 (file)
index 0000000..ee2ea07
--- /dev/null
@@ -0,0 +1,475 @@
+From 939757aafeb9c266dda37657ee5f7a73ffd35ae2 Mon Sep 17 00:00:00 2001
+From: Vicentiu Galanopulo <vicentiu.galanopulo@remote-tech.co.uk>
+Date: Wed, 18 Dec 2024 18:33:59 +0000
+Subject: leds: Add LED1202 I2C driver
+
+The output current can be adjusted separately for each channel by 8-bit
+analog (current sink input) and 12-bit digital (PWM) dimming control. The
+LED1202 implements 12 low-side current generators with independent dimming
+control.
+Internal volatile memory allows the user to store up to 8 different patterns,
+each pattern is a particular output configuration in terms of PWM
+duty-cycle (on 4096 steps). Analog dimming (on 256 steps) is per channel but
+common to all patterns. Each device tree LED node will have a corresponding
+entry in /sys/class/leds with the label name. The brightness property
+corresponds to the per channel analog dimming, while the patterns[1-8] to the
+PWM dimming control.
+
+Signed-off-by: Vicentiu Galanopulo <vicentiu.galanopulo@remote-tech.co.uk>
+Link: https://lore.kernel.org/r/20241218183401.41687-4-vicentiu.galanopulo@remote-tech.co.uk
+Signed-off-by: Lee Jones <lee@kernel.org>
+---
+ drivers/leds/Kconfig       |  10 +
+ drivers/leds/Makefile      |   1 +
+ drivers/leds/leds-st1202.c | 416 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 427 insertions(+)
+ create mode 100644 drivers/leds/leds-st1202.c
+
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -931,6 +931,16 @@ config LEDS_LM36274
+         Say Y to enable the LM36274 LED driver for TI LMU devices.
+         This supports the LED device LM36274.
++config LEDS_ST1202
++      tristate "LED Support for STMicroelectronics LED1202 I2C chips"
++      depends on LEDS_CLASS
++      depends on I2C
++      depends on OF
++      select LEDS_TRIGGERS
++      help
++        Say Y to enable support for LEDs connected to LED1202
++        LED driver chips accessed via the I2C bus.
++
+ config LEDS_TPS6105X
+       tristate "LED support for TI TPS6105X"
+       depends on LEDS_CLASS
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -81,6 +81,7 @@ obj-$(CONFIG_LEDS_POWERNV)           += leds-powe
+ obj-$(CONFIG_LEDS_PWM)                        += leds-pwm.o
+ obj-$(CONFIG_LEDS_REGULATOR)          += leds-regulator.o
+ obj-$(CONFIG_LEDS_SC27XX_BLTC)                += leds-sc27xx-bltc.o
++obj-$(CONFIG_LEDS_ST1202)             += leds-st1202.o
+ obj-$(CONFIG_LEDS_SUN50I_A100)                += leds-sun50i-a100.o
+ obj-$(CONFIG_LEDS_SUNFIRE)            += leds-sunfire.o
+ obj-$(CONFIG_LEDS_SYSCON)             += leds-syscon.o
+--- /dev/null
++++ b/drivers/leds/leds-st1202.c
+@@ -0,0 +1,416 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * LED driver for STMicroelectronics LED1202 chip
++ *
++ * Copyright (C) 2024 Remote-Tech Ltd. UK
++ */
++
++#include <linux/cleanup.h>
++#include <linux/ctype.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/gpio.h>
++#include <linux/i2c.h>
++#include <linux/leds.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++
++#define ST1202_CHAN_DISABLE_ALL            0x00
++#define ST1202_CHAN_ENABLE_HIGH            0x03
++#define ST1202_CHAN_ENABLE_LOW             0x02
++#define ST1202_CONFIG_REG                  0x04
++/* PATS: Pattern sequence feature enable */
++#define ST1202_CONFIG_REG_PATS             BIT(7)
++/* PATSR: Pattern sequence runs (self-clear when sequence is finished) */
++#define ST1202_CONFIG_REG_PATSR            BIT(6)
++#define ST1202_CONFIG_REG_SHFT             BIT(3)
++#define ST1202_DEV_ENABLE                  0x01
++#define ST1202_DEV_ENABLE_ON               BIT(0)
++#define ST1202_DEV_ENABLE_RESET            BIT(7)
++#define ST1202_DEVICE_ID                   0x00
++#define ST1202_ILED_REG0                   0x09
++#define ST1202_MAX_LEDS                    12
++#define ST1202_MAX_PATTERNS                8
++#define ST1202_MILLIS_PATTERN_DUR_MAX      5660
++#define ST1202_MILLIS_PATTERN_DUR_MIN      22
++#define ST1202_PATTERN_DUR                 0x16
++#define ST1202_PATTERN_PWM                 0x1E
++#define ST1202_PATTERN_REP                 0x15
++
++struct st1202_led {
++      struct fwnode_handle *fwnode;
++      struct led_classdev led_cdev;
++      struct st1202_chip *chip;
++      bool is_active;
++      int led_num;
++};
++
++struct st1202_chip {
++      struct i2c_client *client;
++      struct mutex lock;
++      struct st1202_led leds[ST1202_MAX_LEDS];
++};
++
++static struct st1202_led *cdev_to_st1202_led(struct led_classdev *cdev)
++{
++      return container_of(cdev, struct st1202_led, led_cdev);
++}
++
++static int st1202_read_reg(struct st1202_chip *chip, int reg, uint8_t *val)
++{
++      struct device *dev = &chip->client->dev;
++      int ret;
++
++      ret = i2c_smbus_read_byte_data(chip->client, reg);
++      if (ret < 0) {
++              dev_err(dev, "Failed to read register [0x%x]: %d\n", reg, ret);
++              return ret;
++      }
++
++      *val = (uint8_t)ret;
++      return 0;
++}
++
++static int st1202_write_reg(struct st1202_chip *chip, int reg, uint8_t val)
++{
++      struct device *dev = &chip->client->dev;
++      int ret;
++
++      ret = i2c_smbus_write_byte_data(chip->client, reg, val);
++      if (ret != 0)
++              dev_err(dev, "Failed to write %d to register [0x%x]: %d\n", val, reg, ret);
++
++      return ret;
++}
++
++static uint8_t st1202_prescalar_to_miliseconds(unsigned int value)
++{
++      return value / ST1202_MILLIS_PATTERN_DUR_MIN - 1;
++}
++
++static int st1202_pwm_pattern_write(struct st1202_chip *chip, int led_num,
++                              int pattern, unsigned int value)
++{
++      u8 value_l, value_h;
++      int ret;
++
++      value_l = (u8)value;
++      value_h = (u8)(value >> 8);
++
++      /*
++       *  Datasheet: Register address low = 1Eh + 2*(xh) + 18h*(yh),
++       *  where x is the channel number (led number) in hexadecimal (x = 00h .. 0Bh)
++       *  and y is the pattern number in hexadecimal (y = 00h .. 07h)
++       */
++      ret = st1202_write_reg(chip, (ST1202_PATTERN_PWM + (led_num * 2) + 0x18 * pattern),
++                              value_l);
++      if (ret != 0)
++              return ret;
++
++      /*
++       * Datasheet: Register address high = 1Eh + 01h + 2(xh) +18h*(yh),
++       * where x is the channel number in hexadecimal (x = 00h .. 0Bh)
++       * and y is the pattern number in hexadecimal (y = 00h .. 07h)
++       */
++      ret = st1202_write_reg(chip, (ST1202_PATTERN_PWM + 0x1 + (led_num * 2) + 0x18 * pattern),
++                              value_h);
++      if (ret != 0)
++              return ret;
++
++      return 0;
++}
++
++static int st1202_duration_pattern_write(struct st1202_chip *chip, int pattern,
++                                      unsigned int value)
++{
++      return st1202_write_reg(chip, (ST1202_PATTERN_DUR + pattern),
++                              st1202_prescalar_to_miliseconds(value));
++}
++
++static void st1202_brightness_set(struct led_classdev *led_cdev,
++                              enum led_brightness value)
++{
++      struct st1202_led *led = cdev_to_st1202_led(led_cdev);
++      struct st1202_chip *chip = led->chip;
++
++      guard(mutex)(&chip->lock);
++
++      st1202_write_reg(chip, ST1202_ILED_REG0 + led->led_num, value);
++}
++
++static enum led_brightness st1202_brightness_get(struct led_classdev *led_cdev)
++{
++      struct st1202_led *led = cdev_to_st1202_led(led_cdev);
++      struct st1202_chip *chip = led->chip;
++      u8 value = 0;
++
++      guard(mutex)(&chip->lock);
++
++      st1202_read_reg(chip, ST1202_ILED_REG0 + led->led_num, &value);
++
++      return value;
++}
++
++static int st1202_channel_set(struct st1202_chip *chip, int led_num, bool active)
++{
++      u8 chan_low, chan_high;
++      int ret;
++
++      guard(mutex)(&chip->lock);
++
++      if (led_num <= 7) {
++              ret = st1202_read_reg(chip, ST1202_CHAN_ENABLE_LOW, &chan_low);
++              if (ret < 0)
++                      return ret;
++
++              chan_low = active ? chan_low | BIT(led_num) : chan_low & ~BIT(led_num);
++
++              ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_LOW, chan_low);
++              if (ret < 0)
++                      return ret;
++
++      } else {
++              ret = st1202_read_reg(chip, ST1202_CHAN_ENABLE_HIGH, &chan_high);
++              if (ret < 0)
++                      return ret;
++
++              chan_high = active ? chan_high | (BIT(led_num) >> 8) :
++                                      chan_high & ~(BIT(led_num) >> 8);
++
++              ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_HIGH, chan_high);
++              if (ret < 0)
++                      return ret;
++      }
++
++      return 0;
++}
++
++static int st1202_led_set(struct led_classdev *ldev, enum led_brightness value)
++{
++      struct st1202_led *led = cdev_to_st1202_led(ldev);
++      struct st1202_chip *chip = led->chip;
++
++      return st1202_channel_set(chip, led->led_num, value == LED_OFF ? false : true);
++}
++
++static int st1202_led_pattern_clear(struct led_classdev *ldev)
++{
++      struct st1202_led *led = cdev_to_st1202_led(ldev);
++      struct st1202_chip *chip = led->chip;
++      int ret;
++
++      guard(mutex)(&chip->lock);
++
++      for (int patt = 0; patt < ST1202_MAX_PATTERNS; patt++) {
++              ret = st1202_pwm_pattern_write(chip, led->led_num, patt, LED_OFF);
++              if (ret != 0)
++                      return ret;
++
++              ret = st1202_duration_pattern_write(chip, patt, ST1202_MILLIS_PATTERN_DUR_MIN);
++              if (ret != 0)
++                      return ret;
++      }
++
++      return 0;
++}
++
++static int st1202_led_pattern_set(struct led_classdev *ldev,
++                              struct led_pattern *pattern,
++                              u32 len, int repeat)
++{
++      struct st1202_led *led = cdev_to_st1202_led(ldev);
++      struct st1202_chip *chip = led->chip;
++      int ret;
++
++      if (len > ST1202_MAX_PATTERNS)
++              return -EINVAL;
++
++      guard(mutex)(&chip->lock);
++
++      for (int patt = 0; patt < len; patt++) {
++              if (pattern[patt].delta_t < ST1202_MILLIS_PATTERN_DUR_MIN ||
++                              pattern[patt].delta_t > ST1202_MILLIS_PATTERN_DUR_MAX)
++                      return -EINVAL;
++
++              ret = st1202_pwm_pattern_write(chip, led->led_num, patt, pattern[patt].brightness);
++              if (ret != 0)
++                      return ret;
++
++              ret = st1202_duration_pattern_write(chip, patt, pattern[patt].delta_t);
++              if (ret != 0)
++                      return ret;
++      }
++
++      ret = st1202_write_reg(chip, ST1202_PATTERN_REP, repeat);
++      if (ret != 0)
++              return ret;
++
++      ret = st1202_write_reg(chip, ST1202_CONFIG_REG, (ST1202_CONFIG_REG_PATSR |
++                                                      ST1202_CONFIG_REG_PATS | ST1202_CONFIG_REG_SHFT));
++      if (ret != 0)
++              return ret;
++
++      return 0;
++}
++
++static int st1202_dt_init(struct st1202_chip *chip)
++{
++      struct device *dev = &chip->client->dev;
++      struct st1202_led *led;
++      int err, reg;
++
++      for_each_available_child_of_node_scoped(dev_of_node(dev), child) {
++              struct led_init_data init_data = {};
++
++              err = of_property_read_u32(child, "reg", &reg);
++              if (err)
++                      return dev_err_probe(dev, err, "Invalid register\n");
++
++              led = &chip->leds[reg];
++              led->is_active = true;
++              led->fwnode = of_fwnode_handle(child);
++
++              led->led_cdev.max_brightness = U8_MAX;
++              led->led_cdev.brightness_set_blocking = st1202_led_set;
++              led->led_cdev.pattern_set = st1202_led_pattern_set;
++              led->led_cdev.pattern_clear = st1202_led_pattern_clear;
++              led->led_cdev.default_trigger = "pattern";
++
++              init_data.fwnode = led->fwnode;
++              init_data.devicename = "st1202";
++              init_data.default_label = ":";
++
++              err = devm_led_classdev_register_ext(dev, &led->led_cdev, &init_data);
++              if (err < 0)
++                      return dev_err_probe(dev, err, "Failed to register LED class device\n");
++
++              led->led_cdev.brightness_set = st1202_brightness_set;
++              led->led_cdev.brightness_get = st1202_brightness_get;
++      }
++
++      return 0;
++}
++
++static int st1202_setup(struct st1202_chip *chip)
++{
++      int ret;
++
++      guard(mutex)(&chip->lock);
++
++      /*
++       * Once the supply voltage is applied, the LED1202 executes some internal checks,
++       * afterwords it stops the oscillator and puts the internal LDO in quiescent mode.
++       * To start the device, EN bit must be set inside the “Device Enable” register at
++       * address 01h. As soon as EN is set, the LED1202 loads the adjustment parameters
++       * from the internal non-volatile memory and performs an auto-calibration procedure
++       * in order to increase the output current precision.
++       * Such initialization lasts about 6.5 ms.
++       */
++
++      /* Reset the chip during setup */
++      ret = st1202_write_reg(chip, ST1202_DEV_ENABLE, ST1202_DEV_ENABLE_RESET);
++      if (ret < 0)
++              return ret;
++
++      /* Enable phase-shift delay feature */
++      ret = st1202_write_reg(chip, ST1202_CONFIG_REG, ST1202_CONFIG_REG_SHFT);
++      if (ret < 0)
++              return ret;
++
++      /* Enable the device */
++      ret = st1202_write_reg(chip, ST1202_DEV_ENABLE, ST1202_DEV_ENABLE_ON);
++      if (ret < 0)
++              return ret;
++
++      /* Duration of initialization */
++      usleep_range(6500, 10000);
++
++      /* Deactivate all LEDS (channels) and activate only the ones found in Device Tree */
++      ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_LOW, ST1202_CHAN_DISABLE_ALL);
++      if (ret < 0)
++              return ret;
++
++      ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_HIGH, ST1202_CHAN_DISABLE_ALL);
++      if (ret < 0)
++              return ret;
++
++      ret = st1202_write_reg(chip, ST1202_CONFIG_REG,
++                              ST1202_CONFIG_REG_PATS | ST1202_CONFIG_REG_PATSR);
++      if (ret < 0)
++              return ret;
++
++      return 0;
++}
++
++static int st1202_probe(struct i2c_client *client)
++{
++      struct st1202_chip *chip;
++      struct st1202_led *led;
++      int ret;
++
++      if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
++              return dev_err_probe(&client->dev, -EIO, "SMBUS Byte Data not Supported\n");
++
++      chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
++      if (!chip)
++              return -ENOMEM;
++
++      devm_mutex_init(&client->dev, &chip->lock);
++      chip->client = client;
++
++      ret = st1202_dt_init(chip);
++      if (ret < 0)
++              return ret;
++
++      ret = st1202_setup(chip);
++      if (ret < 0)
++              return ret;
++
++      for (int i = 0; i < ST1202_MAX_LEDS; i++) {
++              led = &chip->leds[i];
++              led->chip = chip;
++              led->led_num = i;
++
++              if (!led->is_active)
++                      continue;
++
++              ret = st1202_channel_set(led->chip, led->led_num, true);
++              if (ret < 0)
++                      return dev_err_probe(&client->dev, ret,
++                                      "Failed to activate LED channel\n");
++
++              ret = st1202_led_pattern_clear(&led->led_cdev);
++              if (ret < 0)
++                      return dev_err_probe(&client->dev, ret,
++                                      "Failed to clear LED pattern\n");
++      }
++
++      return 0;
++}
++
++static const struct i2c_device_id st1202_id[] = {
++      { "st1202-i2c" },
++      { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(i2c, st1202_id);
++
++static const struct of_device_id st1202_dt_ids[] = {
++      { .compatible = "st,led1202" },
++      { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, st1202_dt_ids);
++
++static struct i2c_driver st1202_driver = {
++      .driver = {
++              .name = "leds-st1202",
++              .of_match_table = of_match_ptr(st1202_dt_ids),
++      },
++      .probe = st1202_probe,
++      .id_table = st1202_id,
++};
++module_i2c_driver(st1202_driver);
++
++MODULE_AUTHOR("Remote Tech LTD");
++MODULE_DESCRIPTION("STMicroelectronics LED1202 : 12-channel constant current LED driver");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/generic/backport-6.12/893-v6.14-leds_st1202-Fix-NULL-pointer-access-error.patch b/target/linux/generic/backport-6.12/893-v6.14-leds_st1202-Fix-NULL-pointer-access-error.patch
new file mode 100644 (file)
index 0000000..39d8ddb
--- /dev/null
@@ -0,0 +1,73 @@
+From c72e455b89f216b43cd0dbb518036ec4c98f5c46 Mon Sep 17 00:00:00 2001
+From: Manuel Fombuena <fombuena@outlook.com>
+Date: Tue, 25 Feb 2025 22:01:02 +0000
+Subject: leds: leds-st1202: Fix NULL pointer access on race condition
+
+st1202_dt_init() calls devm_led_classdev_register_ext() before the
+internal data structures are properly set up, so the LEDs become visible
+to user space while being partially initialized, leading to a window
+where trying to access them causes a NULL pointer access.
+
+Move devm_led_classdev_register_ext() from DT initialization
+to the end of the probe function when DT and hardware are fully
+initialized and ready to interact with user space.
+
+Fixes: 259230378c65 ("leds: Add LED1202 I2C driver")
+Signed-off-by: Manuel Fombuena <fombuena@outlook.com>
+Link: https://lore.kernel.org/r/CWLP123MB54732771AC0CE5491B3C84DCC5C32@CWLP123MB5473.GBRP123.PROD.OUTLOOK.COM
+Signed-off-by: Lee Jones <lee@kernel.org>
+---
+ drivers/leds/leds-st1202.c | 21 ++++++++++-----------
+ 1 file changed, 10 insertions(+), 11 deletions(-)
+
+--- a/drivers/leds/leds-st1202.c
++++ b/drivers/leds/leds-st1202.c
+@@ -261,8 +261,6 @@ static int st1202_dt_init(struct st1202_
+       int err, reg;
+       for_each_available_child_of_node_scoped(dev_of_node(dev), child) {
+-              struct led_init_data init_data = {};
+-
+               err = of_property_read_u32(child, "reg", &reg);
+               if (err)
+                       return dev_err_probe(dev, err, "Invalid register\n");
+@@ -276,15 +274,6 @@ static int st1202_dt_init(struct st1202_
+               led->led_cdev.pattern_set = st1202_led_pattern_set;
+               led->led_cdev.pattern_clear = st1202_led_pattern_clear;
+               led->led_cdev.default_trigger = "pattern";
+-
+-              init_data.fwnode = led->fwnode;
+-              init_data.devicename = "st1202";
+-              init_data.default_label = ":";
+-
+-              err = devm_led_classdev_register_ext(dev, &led->led_cdev, &init_data);
+-              if (err < 0)
+-                      return dev_err_probe(dev, err, "Failed to register LED class device\n");
+-
+               led->led_cdev.brightness_set = st1202_brightness_set;
+               led->led_cdev.brightness_get = st1202_brightness_get;
+       }
+@@ -368,6 +357,7 @@ static int st1202_probe(struct i2c_clien
+               return ret;
+       for (int i = 0; i < ST1202_MAX_LEDS; i++) {
++              struct led_init_data init_data = {};
+               led = &chip->leds[i];
+               led->chip = chip;
+               led->led_num = i;
+@@ -384,6 +374,15 @@ static int st1202_probe(struct i2c_clien
+               if (ret < 0)
+                       return dev_err_probe(&client->dev, ret,
+                                       "Failed to clear LED pattern\n");
++
++              init_data.fwnode = led->fwnode;
++              init_data.devicename = "st1202";
++              init_data.default_label = ":";
++
++              ret = devm_led_classdev_register_ext(&client->dev, &led->led_cdev, &init_data);
++              if (ret < 0)
++                      return dev_err_probe(&client->dev, ret,
++                                      "Failed to register LED class device\n");
+       }
+       return 0;
diff --git a/target/linux/generic/pending-6.12/152-net-wireguard-add-nonstring-annotation-to-fix-build-with-GCC15.patch b/target/linux/generic/pending-6.12/152-net-wireguard-add-nonstring-annotation-to-fix-build-with-GCC15.patch
deleted file mode 100644 (file)
index 1fdf2f1..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-From 71e5da46e78c1cd24e2feed251a2845327447ad8 Mon Sep 17 00:00:00 2001
-From: Kees Cook <kees@kernel.org>
-Date: Wed, 21 May 2025 23:27:04 +0200
-Subject: wireguard: global: add __nonstring annotations for unterminated
- strings
-
-When a character array without a terminating NUL character has a static
-initializer, GCC 15's -Wunterminated-string-initialization will only
-warn if the array lacks the "nonstring" attribute[1]. Mark the arrays
-with __nonstring to correctly identify the char array as "not a C string"
-and thereby eliminate the warning:
-
-../drivers/net/wireguard/cookie.c:29:56: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (9 chars into 8 available) [-Wunterminated-string-initialization]
-   29 | static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] = "mac1----";
-      |                                                        ^~~~~~~~~~
-../drivers/net/wireguard/cookie.c:30:58: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (9 chars into 8 available) [-Wunterminated-string-initialization]
-   30 | static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] = "cookie--";
-      |                                                          ^~~~~~~~~~
-../drivers/net/wireguard/noise.c:28:38: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (38 chars into 37 available) [-Wunterminated-string-initialization]
-   28 | static const u8 handshake_name[37] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s";
-      |                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-../drivers/net/wireguard/noise.c:29:39: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (35 chars into 34 available) [-Wunterminated-string-initialization]
-   29 | static const u8 identifier_name[34] = "WireGuard v1 zx2c4 Jason@zx2c4.com";
-      |                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The arrays are always used with their fixed size, so use __nonstring.
-
-Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117178 [1]
-Signed-off-by: Kees Cook <kees@kernel.org>
-Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-Link: https://patch.msgid.link/20250521212707.1767879-3-Jason@zx2c4.com
-Signed-off-by: Paolo Abeni <pabeni@redhat.com>
----
- drivers/net/wireguard/cookie.c | 4 ++--
- drivers/net/wireguard/noise.c  | 4 ++--
- 2 files changed, 4 insertions(+), 4 deletions(-)
-
---- a/drivers/net/wireguard/cookie.c
-+++ b/drivers/net/wireguard/cookie.c
-@@ -26,8 +26,8 @@ void wg_cookie_checker_init(struct cooki
- }
- enum { COOKIE_KEY_LABEL_LEN = 8 };
--static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] = "mac1----";
--static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] = "cookie--";
-+static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] __nonstring = "mac1----";
-+static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] __nonstring = "cookie--";
- static void precompute_key(u8 key[NOISE_SYMMETRIC_KEY_LEN],
-                          const u8 pubkey[NOISE_PUBLIC_KEY_LEN],
---- a/drivers/net/wireguard/noise.c
-+++ b/drivers/net/wireguard/noise.c
-@@ -25,8 +25,8 @@
-  * <- e, ee, se, psk, {}
-  */
--static const u8 handshake_name[37] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s";
--static const u8 identifier_name[34] = "WireGuard v1 zx2c4 Jason@zx2c4.com";
-+static const u8 handshake_name[37] __nonstring = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s";
-+static const u8 identifier_name[34] __nonstring = "WireGuard v1 zx2c4 Jason@zx2c4.com";
- static u8 handshake_init_hash[NOISE_HASH_LEN] __ro_after_init;
- static u8 handshake_init_chaining_key[NOISE_HASH_LEN] __ro_after_init;
- static atomic64_t keypair_counter = ATOMIC64_INIT(0);
diff --git a/target/linux/generic/pending-6.12/403-mtd-spinand-add-support-for-FudanMicro-FM25S01BI3.patch b/target/linux/generic/pending-6.12/403-mtd-spinand-add-support-for-FudanMicro-FM25S01BI3.patch
deleted file mode 100644 (file)
index 7355efe..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-From f6dffe2a9ed1bdcee1879e2728310fb1e08602cf Mon Sep 17 00:00:00 2001
-From: Mikhail Zhilkin <csharper2005@gmail.com>
-Date: Thu, 27 Nov 2025 22:59:00 +0300
-Subject: mtd: spinand: add support for FudanMicro FM25S01BI3
-
-Add support for FudanMicro FM25S01BI3 SPI NAND.
-
-Link: https://www.fmsh.com/nvm/FM25S01BI3_ds_eng.pdf
-
-Signed-off-by: Mikhail Zhilkin <csharper2005@gmail.com>
-Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
----
- drivers/mtd/nand/spi/fmsh.c | 72 +++++++++++++++++++++++++++++++++++++
- 1 file changed, 72 insertions(+)
-
---- a/drivers/mtd/nand/spi/fmsh.c
-+++ b/drivers/mtd/nand/spi/fmsh.c
-@@ -9,6 +9,13 @@
- #include <linux/kernel.h>
- #include <linux/mtd/spinand.h>
-+#define FM25S01BI3_STATUS_ECC_MASK            (7 << 4)
-+      #define FM25S01BI3_STATUS_ECC_NO_BITFLIPS       (0 << 4)
-+      #define FM25S01BI3_STATUS_ECC_1_3_BITFLIPS      (1 << 4)
-+      #define FM25S01BI3_STATUS_ECC_UNCOR_ERROR       (2 << 4)
-+      #define FM25S01BI3_STATUS_ECC_4_6_BITFLIPS      (3 << 4)
-+      #define FM25S01BI3_STATUS_ECC_7_8_BITFLIPS      (5 << 4)
-+
- #define SPINAND_MFR_FMSH              0xA1
- static SPINAND_OP_VARIANTS(read_cache_variants,
-@@ -45,11 +52,66 @@ static int fm25s01a_ooblayout_free(struc
-       return 0;
- }
-+static int fm25s01bi3_ecc_get_status(struct spinand_device *spinand,
-+                                   u8 status)
-+{
-+      switch (status & FM25S01BI3_STATUS_ECC_MASK) {
-+      case FM25S01BI3_STATUS_ECC_NO_BITFLIPS:
-+              return 0;
-+
-+      case FM25S01BI3_STATUS_ECC_UNCOR_ERROR:
-+              return -EBADMSG;
-+
-+      case FM25S01BI3_STATUS_ECC_1_3_BITFLIPS:
-+              return 3;
-+
-+      case FM25S01BI3_STATUS_ECC_4_6_BITFLIPS:
-+              return 6;
-+
-+      case FM25S01BI3_STATUS_ECC_7_8_BITFLIPS:
-+              return 8;
-+
-+      default:
-+              break;
-+      }
-+
-+      return -EINVAL;
-+}
-+
-+static int fm25s01bi3_ooblayout_ecc(struct mtd_info *mtd, int section,
-+                                  struct mtd_oob_region *region)
-+{
-+      if (section)
-+              return -ERANGE;
-+
-+      region->offset = 64;
-+      region->length = 64;
-+
-+      return 0;
-+}
-+
-+static int fm25s01bi3_ooblayout_free(struct mtd_info *mtd, int section,
-+                                   struct mtd_oob_region *region)
-+{
-+      if (section > 3)
-+              return -ERANGE;
-+
-+      region->offset = (16 * section) + 4;
-+      region->length = 12;
-+
-+      return 0;
-+}
-+
- static const struct mtd_ooblayout_ops fm25s01a_ooblayout = {
-       .ecc = fm25s01a_ooblayout_ecc,
-       .free = fm25s01a_ooblayout_free,
- };
-+static const struct mtd_ooblayout_ops fm25s01bi3_ooblayout = {
-+      .ecc = fm25s01bi3_ooblayout_ecc,
-+      .free = fm25s01bi3_ooblayout_free,
-+};
-+
- static const struct spinand_info fmsh_spinand_table[] = {
-       SPINAND_INFO("FM25S01A",
-                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4),
-@@ -60,6 +122,16 @@ static const struct spinand_info fmsh_sp
-                                             &update_cache_variants),
-                    0,
-                    SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)),
-+      SPINAND_INFO("FM25S01BI3",
-+                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xd4),
-+                   NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
-+                   NAND_ECCREQ(8, 512),
-+                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+                                            &write_cache_variants,
-+                                            &update_cache_variants),
-+                   SPINAND_HAS_QE_BIT,
-+                   SPINAND_ECCINFO(&fm25s01bi3_ooblayout,
-+                                    fm25s01bi3_ecc_get_status)),
- };
- static const struct spinand_manufacturer_ops fmsh_spinand_manuf_ops = {
diff --git a/target/linux/generic/pending-6.12/405-01-mtd-spinand-fix-direct-mapping-creation-sizes.patch b/target/linux/generic/pending-6.12/405-01-mtd-spinand-fix-direct-mapping-creation-sizes.patch
deleted file mode 100644 (file)
index 994e06e..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-From e4a0cf9f1d90e6888e5373da3314f761024f6c97 Mon Sep 17 00:00:00 2001
-From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
-Date: Thu, 18 Sep 2025 00:53:59 +0300
-Subject: mtd: spinand: fix direct mapping creation sizes
-
-Continuous mode is only supported for data reads, thus writing
-requires only single flash page mapping.
-
-Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
-Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
----
- drivers/mtd/nand/spi/core.c | 14 +++++++-------
- 1 file changed, 7 insertions(+), 7 deletions(-)
-
---- a/drivers/mtd/nand/spi/core.c
-+++ b/drivers/mtd/nand/spi/core.c
-@@ -1028,18 +1028,13 @@ static int spinand_create_dirmap(struct
-                                unsigned int plane)
- {
-       struct nand_device *nand = spinand_to_nand(spinand);
--      struct spi_mem_dirmap_info info = {
--              .length = nanddev_page_size(nand) +
--                        nanddev_per_page_oobsize(nand),
--      };
-+      struct spi_mem_dirmap_info info = { 0 };
-       struct spi_mem_dirmap_desc *desc;
--      if (spinand->cont_read_possible)
--              info.length = nanddev_eraseblock_size(nand);
--
-       /* The plane number is passed in MSB just above the column address */
-       info.offset = plane << fls(nand->memorg.pagesize);
-+      info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand);
-       info.op_tmpl = *spinand->op_templates.update_cache;
-       desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
-                                         spinand->spimem, &info);
-@@ -1048,6 +1043,8 @@ static int spinand_create_dirmap(struct
-       spinand->dirmaps[plane].wdesc = desc;
-+      if (spinand->cont_read_possible)
-+              info.length = nanddev_eraseblock_size(nand);
-       info.op_tmpl = *spinand->op_templates.read_cache;
-       desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
-                                         spinand->spimem, &info);
-@@ -1063,6 +1060,7 @@ static int spinand_create_dirmap(struct
-               return 0;
-       }
-+      info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand);
-       info.op_tmpl = *spinand->op_templates.update_cache;
-       info.op_tmpl.data.ecc = true;
-       desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
-@@ -1072,6 +1070,8 @@ static int spinand_create_dirmap(struct
-       spinand->dirmaps[plane].wdesc_ecc = desc;
-+      if (spinand->cont_read_possible)
-+              info.length = nanddev_eraseblock_size(nand);
-       info.op_tmpl = *spinand->op_templates.read_cache;
-       info.op_tmpl.data.ecc = true;
-       desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
diff --git a/target/linux/generic/pending-6.12/405-02-mtd-spinand-try-a-regular-dirmap-if-creating-a-di.patch b/target/linux/generic/pending-6.12/405-02-mtd-spinand-try-a-regular-dirmap-if-creating-a-di.patch
deleted file mode 100644 (file)
index 005c0aa..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-From 004f8ea0d9917398aabff7388b3bf62a84a4088b Mon Sep 17 00:00:00 2001
-From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
-Date: Thu, 18 Sep 2025 00:54:00 +0300
-Subject: mtd: spinand: try a regular dirmap if creating a dirmap for
- continuous reading fails
-
-Continuous reading may result in multiple flash pages reading in one
-operation. Typically only one flash page has read/written (a little bit
-more than 2-4 Kb), but continuous reading requires the spi controller
-to read up to 512 Kb in one operation without toggling CS in beetween.
-
-Roughly speaking spi controllers can be divided on 2 categories:
- * spi controllers without dirmap acceleration support
- * spi controllers with dirmap acceleration support
-
-Firt of them will have issues with continuous reading if restriction on
-the transfer length is implemented in the adjust_op_size() handler.
-Second group often supports acceleration of single page only reading.
-Thus enabling of continuous reading can break flash reading.
-
-This patch tries to create dirmap for continuous reading first and
-fallback to regular reading if spi controller refuses to create it.
-
-Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
-Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
----
- drivers/mtd/nand/spi/core.c | 43 ++++++++++++++++++++++++++++++-------
- 1 file changed, 35 insertions(+), 8 deletions(-)
-
---- a/drivers/mtd/nand/spi/core.c
-+++ b/drivers/mtd/nand/spi/core.c
-@@ -1024,6 +1024,39 @@ static int spinand_mtd_block_isreserved(
-       return ret;
- }
-+static struct spi_mem_dirmap_desc *spinand_create_rdesc(
-+                                      struct spinand_device *spinand,
-+                                      struct spi_mem_dirmap_info *info)
-+{
-+      struct nand_device *nand = spinand_to_nand(spinand);
-+      struct spi_mem_dirmap_desc *desc = NULL;
-+
-+      if (spinand->cont_read_possible) {
-+              /*
-+               * spi controller may return an error if info->length is
-+               * too large
-+               */
-+              info->length = nanddev_eraseblock_size(nand);
-+              desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
-+                                                spinand->spimem, info);
-+      }
-+
-+      if (IS_ERR_OR_NULL(desc)) {
-+              /*
-+               * continuous reading is not supported by flash or
-+               * its spi controller, use regular reading
-+               */
-+              spinand->cont_read_possible = false;
-+
-+              info->length = nanddev_page_size(nand) +
-+                             nanddev_per_page_oobsize(nand);
-+              desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
-+                                                spinand->spimem, info);
-+      }
-+
-+      return desc;
-+}
-+
- static int spinand_create_dirmap(struct spinand_device *spinand,
-                                unsigned int plane)
- {
-@@ -1043,11 +1076,8 @@ static int spinand_create_dirmap(struct
-       spinand->dirmaps[plane].wdesc = desc;
--      if (spinand->cont_read_possible)
--              info.length = nanddev_eraseblock_size(nand);
-       info.op_tmpl = *spinand->op_templates.read_cache;
--      desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
--                                        spinand->spimem, &info);
-+      desc = spinand_create_rdesc(spinand, &info);
-       if (IS_ERR(desc))
-               return PTR_ERR(desc);
-@@ -1070,12 +1100,9 @@ static int spinand_create_dirmap(struct
-       spinand->dirmaps[plane].wdesc_ecc = desc;
--      if (spinand->cont_read_possible)
--              info.length = nanddev_eraseblock_size(nand);
-       info.op_tmpl = *spinand->op_templates.read_cache;
-       info.op_tmpl.data.ecc = true;
--      desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
--                                        spinand->spimem, &info);
-+      desc = spinand_create_rdesc(spinand, &info);
-       if (IS_ERR(desc))
-               return PTR_ERR(desc);
diff --git a/target/linux/generic/pending-6.12/405-03-mtd-spinand-repeat-reading-in-regular-mode-if-con.patch b/target/linux/generic/pending-6.12/405-03-mtd-spinand-repeat-reading-in-regular-mode-if-con.patch
deleted file mode 100644 (file)
index af53d20..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-From 010dc7f2dd6a0078ade3f88f627ed5fbf45ceb94 Mon Sep 17 00:00:00 2001
-From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
-Date: Thu, 18 Sep 2025 00:54:01 +0300
-Subject: mtd: spinand: repeat reading in regular mode if continuous reading
- fails
-
-Continuous reading may result in multiple flash pages reading in one
-operation. Unfortunately, not all spinand controllers support such
-large reading. They will read less data. Unfortunately, the operation
-can't be continued.
-
-In this case:
- * disable continuous reading on this (not good enough) spi controller
- * repeat reading in regular mode.
-
-Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
-Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
----
- drivers/mtd/nand/spi/core.c | 25 +++++++++++++++++++++----
- 1 file changed, 21 insertions(+), 4 deletions(-)
-
---- a/drivers/mtd/nand/spi/core.c
-+++ b/drivers/mtd/nand/spi/core.c
-@@ -427,8 +427,16 @@ static int spinand_read_from_cache_op(st
-                * Dirmap accesses are allowed to toggle the CS.
-                * Toggling the CS during a continuous read is forbidden.
-                */
--              if (nbytes && req->continuous)
--                      return -EIO;
-+              if (nbytes && req->continuous) {
-+                      /*
-+                       * Spi controller with broken support of continuous
-+                       * reading was detected. Disable future use of
-+                       * continuous reading and return -EAGAIN to retry
-+                       * reading within regular mode.
-+                       */
-+                      spinand->cont_read_possible = false;
-+                      return -EAGAIN;
-+              }
-       }
-       if (req->datalen)
-@@ -841,10 +849,19 @@ static int spinand_mtd_read(struct mtd_i
-       old_stats = mtd->ecc_stats;
--      if (spinand_use_cont_read(mtd, from, ops))
-+      if (spinand_use_cont_read(mtd, from, ops)) {
-               ret = spinand_mtd_continuous_page_read(mtd, from, ops, &max_bitflips);
--      else
-+              if (ret == -EAGAIN && !spinand->cont_read_possible) {
-+                      /*
-+                       * Spi controller with broken support of continuous
-+                       * reading was detected (see spinand_read_from_cache_op()),
-+                       * repeat reading in regular mode.
-+                       */
-+                      ret = spinand_mtd_regular_page_read(mtd, from, ops, &max_bitflips);
-+              }
-+      } else {
-               ret = spinand_mtd_regular_page_read(mtd, from, ops, &max_bitflips);
-+      }
-       if (ops->stats) {
-               ops->stats->uncorrectable_errors +=
diff --git a/target/linux/generic/pending-6.12/416-09-next-spi-spi-qpic-snand-validate-user-chip-specific-ECC-properties.patch b/target/linux/generic/pending-6.12/416-09-next-spi-spi-qpic-snand-validate-user-chip-specific-ECC-properties.patch
deleted file mode 100644 (file)
index 2f95156..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-From 65cb56d49f6edea409600a3c61effc70ee5d43d8 Mon Sep 17 00:00:00 2001
-From: Gabor Juhos <j4g8y7@gmail.com>
-Date: Thu, 1 May 2025 18:19:16 +0200
-Subject: spi: spi-qpic-snand: validate user/chip specific ECC properties
-
-The driver only supports 512 bytes ECC step size and 4 bit ECC strength
-at the moment, however it does not reject unsupported step/strength
-configurations. Due to this, whenever the driver is used with a flash
-chip which needs stronger ECC protection, the following warning is shown
-in the kernel log:
-
-  [    0.574648] spi-nand spi0.0: GigaDevice SPI NAND was found.
-  [    0.635748] spi-nand spi0.0: 256 MiB, block size: 128 KiB, page size: 2048, OOB size: 128
-  [    0.649079] nand: WARNING: (null): the ECC used on your system is too weak compared to the one required by the NAND chip
-
-Although the message indicates that something is wrong, but it often gets
-unnoticed, which can cause serious problems. For example when the user
-writes something into the flash chip despite the warning, the written data
-may won't be readable by the bootloader or by the boot ROM. In the worst
-case, when the attached SPI NAND chip is the boot device, the board may not
-be able to boot anymore.
-
-Also, it is not even possible to create a backup of the flash, because
-reading its content results in bogus data. For example, dumping the first
-page of the flash gives this:
-
-  # hexdump -C -n 2048 /dev/mtd0
-  00000000  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
-  *
-  00000040  0f 0f 0f 0f 0f 0f 0f 0d  0f 0f 0f 0f 0f 0f 0f 0f  |................|
-  00000050  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
-  *
-  000001c0  0f 0f 0f 0f ff 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
-  000001d0  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
-  *
-  00000200  0f 0f 0f 0f f5 5b ff ff  0f 0f 0f 0f 0f 0f 0f 0f  |.....[..........|
-  00000210  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
-  *
-  000002f0  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 1f 0f 0f  |................|
-  00000300  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
-  *
-  000003c0  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f ff 0f 0f 0f  |................|
-  000003d0  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
-  *
-  00000400  0f 0f 0f 0f 0f 0f 0f 0f  e9 74 c9 06 f5 5b ff ff  |.........t...[..|
-  00000410  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
-  *
-  000005d0  0f 0f 0f 0f ff 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
-  000005e0  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
-  *
-  00000600  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f c6 be 0f c3  |................|
-  00000610  e9 74 c9 06 f5 5b ff ff  0f 0f 0f 0f 0f 0f 0f 0f  |.t...[..........|
-  00000620  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
-  *
-  00000770  0f 0f 0f 0f 8f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
-  00000780  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
-  *
-  00000800
-  #
-
-Doing the same by using the downstream kernel results in different output:
-
-  # hexdump -C -n 2048 /dev/mtd0
-  00000000  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
-  *
-  00000800
-  #
-
-This patch adds some sanity checks to the code to prevent using the driver
-with unsupported ECC step/strength configurations. After the change, probing
-of the driver fails in such cases:
-
-  [    0.655038] spi-nand spi0.0: GigaDevice SPI NAND was found.
-  [    0.659159] spi-nand spi0.0: 256 MiB, block size: 128 KiB, page size: 2048, OOB size: 128
-  [    0.669138] qcom_snand 79b0000.spi: only 4 bits ECC strength is supported
-  [    0.677476] nand: No suitable ECC configuration
-  [    0.689909] spi-nand spi0.0: probe with driver spi-nand failed with error -95
-
-This helps to avoid the aforementioned hassles until support for 8 bit ECC
-strength gets implemented.
-
-Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
-Signed-off-by: Gabor Juhos <j4g8y7@gmail.com>
-Link: https://patch.msgid.link/20250501-qpic-snand-validate-ecc-v1-1-532776581a66@gmail.com
-Signed-off-by: Mark Brown <broonie@kernel.org>
----
- drivers/spi/spi-qpic-snand.c | 42 +++++++++++++++++++++++++++++++-----
- 1 file changed, 37 insertions(+), 5 deletions(-)
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -249,9 +249,11 @@ static const struct mtd_ooblayout_ops qc
- static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand)
- {
-       struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
-+      struct nand_ecc_props *reqs = &nand->ecc.requirements;
-+      struct nand_ecc_props *user = &nand->ecc.user_conf;
-       struct nand_ecc_props *conf = &nand->ecc.ctx.conf;
-       struct mtd_info *mtd = nanddev_to_mtd(nand);
--      int cwperpage, bad_block_byte;
-+      int cwperpage, bad_block_byte, ret;
-       struct qpic_ecc *ecc_cfg;
-       cwperpage = mtd->writesize / NANDC_STEP_SIZE;
-@@ -260,11 +262,39 @@ static int qcom_spi_ecc_init_ctx_pipelin
-       ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL);
-       if (!ecc_cfg)
-               return -ENOMEM;
-+
-+      if (user->step_size && user->strength) {
-+              ecc_cfg->step_size = user->step_size;
-+              ecc_cfg->strength = user->strength;
-+      } else if (reqs->step_size && reqs->strength) {
-+              ecc_cfg->step_size = reqs->step_size;
-+              ecc_cfg->strength = reqs->strength;
-+      } else {
-+              /* use defaults */
-+              ecc_cfg->step_size = NANDC_STEP_SIZE;
-+              ecc_cfg->strength = 4;
-+      }
-+
-+      if (ecc_cfg->step_size != NANDC_STEP_SIZE) {
-+              dev_err(snandc->dev,
-+                      "only %u bytes ECC step size is supported\n",
-+                      NANDC_STEP_SIZE);
-+              ret = -EOPNOTSUPP;
-+              goto err_free_ecc_cfg;
-+      }
-+
-+      if (ecc_cfg->strength != 4) {
-+              dev_err(snandc->dev,
-+                      "only 4 bits ECC strength is supported\n");
-+              ret = -EOPNOTSUPP;
-+              goto err_free_ecc_cfg;
-+      }
-+
-       snandc->qspi->oob_buf = kmalloc(mtd->writesize + mtd->oobsize,
-                                       GFP_KERNEL);
-       if (!snandc->qspi->oob_buf) {
--              kfree(ecc_cfg);
--              return -ENOMEM;
-+              ret = -ENOMEM;
-+              goto err_free_ecc_cfg;
-       }
-       memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize);
-@@ -279,8 +309,6 @@ static int qcom_spi_ecc_init_ctx_pipelin
-       ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size;
-       ecc_cfg->steps = 4;
--      ecc_cfg->strength = 4;
--      ecc_cfg->step_size = 512;
-       ecc_cfg->cw_data = 516;
-       ecc_cfg->cw_size = ecc_cfg->cw_data + ecc_cfg->bytes;
-       bad_block_byte = mtd->writesize - ecc_cfg->cw_size * (cwperpage - 1) + 1;
-@@ -338,6 +366,10 @@ static int qcom_spi_ecc_init_ctx_pipelin
-               ecc_cfg->strength, ecc_cfg->step_size);
-       return 0;
-+
-+err_free_ecc_cfg:
-+      kfree(ecc_cfg);
-+      return ret;
- }
- static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand)
diff --git a/target/linux/generic/pending-6.12/416-10-next-1-2-mtd-nand-qpic-common-add-defines-for-ECC_MODE-values.patch b/target/linux/generic/pending-6.12/416-10-next-1-2-mtd-nand-qpic-common-add-defines-for-ECC_MODE-values.patch
deleted file mode 100644 (file)
index c232410..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-From 0dc7e656ddd54c3267b7cc18c1ac8ec1297ed02f Mon Sep 17 00:00:00 2001
-From: Gabor Juhos <j4g8y7@gmail.com>
-Date: Wed, 2 Jul 2025 14:35:23 +0200
-Subject: mtd: nand: qpic-common: add defines for ECC_MODE values
-
-Add defines for the values of the ECC_MODE field of the NAND_DEV0_ECC_CFG
-register and change both the 'qcom-nandc' and 'spi-qpic-snand' drivers to
-use those instead of magic numbers.
-
-No functional changes. This is in preparation for adding 8 bit ECC strength
-support for the 'spi-qpic-snand' driver.
-
-Reviewed-by: Md Sadre Alam <quic_mdalam@quicinc.com>
-Signed-off-by: Gabor Juhos <j4g8y7@gmail.com>
-Acked-by: Miquel Raynal <miquel.raynal@bootlin.com>
-Link: https://patch.msgid.link/20250702-qpic-snand-8bit-ecc-v2-1-ae2c17a30bb7@gmail.com
-Signed-off-by: Mark Brown <broonie@kernel.org>
----
- drivers/mtd/nand/raw/qcom_nandc.c    | 6 +++---
- drivers/spi/spi-qpic-snand.c         | 2 +-
- include/linux/mtd/nand-qpic-common.h | 2 ++
- 3 files changed, 6 insertions(+), 4 deletions(-)
-
---- a/drivers/mtd/nand/raw/qcom_nandc.c
-+++ b/drivers/mtd/nand/raw/qcom_nandc.c
-@@ -1379,7 +1379,7 @@ static int qcom_nand_attach_chip(struct
-       struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-       int cwperpage, bad_block_byte, ret;
-       bool wide_bus;
--      int ecc_mode = 1;
-+      int ecc_mode = ECC_MODE_8BIT;
-       /* controller only supports 512 bytes data steps */
-       ecc->size = NANDC_STEP_SIZE;
-@@ -1400,7 +1400,7 @@ static int qcom_nand_attach_chip(struct
-       if (ecc->strength >= 8) {
-               /* 8 bit ECC defaults to BCH ECC on all platforms */
-               host->bch_enabled = true;
--              ecc_mode = 1;
-+              ecc_mode = ECC_MODE_8BIT;
-               if (wide_bus) {
-                       host->ecc_bytes_hw = 14;
-@@ -1420,7 +1420,7 @@ static int qcom_nand_attach_chip(struct
-               if (nandc->props->ecc_modes & ECC_BCH_4BIT) {
-                       /* BCH */
-                       host->bch_enabled = true;
--                      ecc_mode = 0;
-+                      ecc_mode = ECC_MODE_4BIT;
-                       if (wide_bus) {
-                               host->ecc_bytes_hw = 8;
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -349,7 +349,7 @@ static int qcom_spi_ecc_init_ctx_pipelin
-                              FIELD_PREP(ECC_SW_RESET, 0) |
-                              FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) |
-                              FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
--                             FIELD_PREP(ECC_MODE_MASK, 0) |
-+                             FIELD_PREP(ECC_MODE_MASK, ECC_MODE_4BIT) |
-                              FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw);
-       ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS;
---- a/include/linux/mtd/nand-qpic-common.h
-+++ b/include/linux/mtd/nand-qpic-common.h
-@@ -101,6 +101,8 @@
- #define       ECC_SW_RESET                    BIT(1)
- #define       ECC_MODE                        4
- #define       ECC_MODE_MASK                   GENMASK(5, 4)
-+#define       ECC_MODE_4BIT                   0
-+#define       ECC_MODE_8BIT                   1
- #define       ECC_PARITY_SIZE_BYTES_BCH       8
- #define       ECC_PARITY_SIZE_BYTES_BCH_MASK  GENMASK(12, 8)
- #define       ECC_NUM_DATA_BYTES              16
diff --git a/target/linux/generic/pending-6.12/416-11-next-2-2-spi-spi-qpic-snand-add-support-for-8-bits-ECC-strength.patch b/target/linux/generic/pending-6.12/416-11-next-2-2-spi-spi-qpic-snand-add-support-for-8-bits-ECC-strength.patch
deleted file mode 100644 (file)
index acf5d60..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-From 913bf8d50cbd144c87e9660b591781179182ff59 Mon Sep 17 00:00:00 2001
-From: Gabor Juhos <j4g8y7@gmail.com>
-Date: Wed, 2 Jul 2025 14:35:24 +0200
-Subject: spi: spi-qpic-snand: add support for 8 bits ECC strength
-
-Even though the hardware supports 8 bits ECC strength, but that is not
-handled in the driver yet. This change adds the missing bits in order
-to allow using the driver with chips which require 8 bits ECC strength.
-
-No functional changes intended with regard to the existing 4 bits ECC
-strength support.
-
-Tested on an IPQ9574 platform using a GigaDevice GD5F2GM7REYIG chip.
-
-Signed-off-by: Gabor Juhos <j4g8y7@gmail.com>
-Link: https://patch.msgid.link/20250702-qpic-snand-8bit-ecc-v2-2-ae2c17a30bb7@gmail.com
-Signed-off-by: Mark Brown <broonie@kernel.org>
----
- drivers/spi/spi-qpic-snand.c | 21 ++++++++++++++++-----
- 1 file changed, 16 insertions(+), 5 deletions(-)
-
---- a/drivers/spi/spi-qpic-snand.c
-+++ b/drivers/spi/spi-qpic-snand.c
-@@ -283,9 +283,22 @@ static int qcom_spi_ecc_init_ctx_pipelin
-               goto err_free_ecc_cfg;
-       }
--      if (ecc_cfg->strength != 4) {
-+      switch (ecc_cfg->strength) {
-+      case 4:
-+              ecc_cfg->ecc_mode = ECC_MODE_4BIT;
-+              ecc_cfg->ecc_bytes_hw = 7;
-+              ecc_cfg->spare_bytes = 4;
-+              break;
-+
-+      case 8:
-+              ecc_cfg->ecc_mode = ECC_MODE_8BIT;
-+              ecc_cfg->ecc_bytes_hw = 13;
-+              ecc_cfg->spare_bytes = 2;
-+              break;
-+
-+      default:
-               dev_err(snandc->dev,
--                      "only 4 bits ECC strength is supported\n");
-+                      "only 4 or 8 bits ECC strength is supported\n");
-               ret = -EOPNOTSUPP;
-               goto err_free_ecc_cfg;
-       }
-@@ -302,8 +315,6 @@ static int qcom_spi_ecc_init_ctx_pipelin
-       nand->ecc.ctx.priv = ecc_cfg;
-       snandc->qspi->mtd = mtd;
--      ecc_cfg->ecc_bytes_hw = 7;
--      ecc_cfg->spare_bytes = 4;
-       ecc_cfg->bbm_size = 1;
-       ecc_cfg->bch_enabled = true;
-       ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size;
-@@ -349,7 +360,7 @@ static int qcom_spi_ecc_init_ctx_pipelin
-                              FIELD_PREP(ECC_SW_RESET, 0) |
-                              FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) |
-                              FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
--                             FIELD_PREP(ECC_MODE_MASK, ECC_MODE_4BIT) |
-+                             FIELD_PREP(ECC_MODE_MASK, ecc_cfg->ecc_mode) |
-                              FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw);
-       ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS;
diff --git a/target/linux/generic/pending-6.12/891-dt-bindings-leds-Add-LED1202-LED-Controller.patch b/target/linux/generic/pending-6.12/891-dt-bindings-leds-Add-LED1202-LED-Controller.patch
deleted file mode 100644 (file)
index 9901d13..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-From 599b92fd0efa8b7c43e7f58c9dd0f7951f7cbf09 Mon Sep 17 00:00:00 2001
-From: Vicentiu Galanopulo <vicentiu.galanopulo@remote-tech.co.uk>
-Date: Wed, 18 Dec 2024 18:33:58 +0000
-Subject: dt-bindings: leds: Add LED1202 LED Controller
-
-The LED1202 is a 12-channel low quiescent current LED driver with:
-  * Supply range from 2.6 V to 5 V
-  * 20 mA current capability per channel
-  * 1.8 V compatible I2C control interface
-  * 8-bit analog dimming individual control
-  * 12-bit local PWM resolution
-  * 8 programmable patterns
-
-If the led node is present in the controller then the channel is
-set to active.
-
-Signed-off-by: Vicentiu Galanopulo <vicentiu.galanopulo@remote-tech.co.uk>
-Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
-Link: https://lore.kernel.org/r/20241218183401.41687-3-vicentiu.galanopulo@remote-tech.co.uk
-Signed-off-by: Lee Jones <lee@kernel.org>
----
- .../devicetree/bindings/leds/st,led1202.yaml  | 132 ++++++++++++++++++
- 1 file changed, 132 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/leds/st,led1202.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/leds/st,led1202.yaml
-@@ -0,0 +1,132 @@
-+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/leds/st,led1202.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: ST LED1202 LED controllers
-+
-+maintainers:
-+  - Vicentiu Galanopulo <vicentiu.galanopulo@remote-tech.co.uk>
-+
-+description: |
-+  The LED1202 is a 12-channel low quiescent current LED controller
-+  programmable via I2C; The output current can be adjusted separately
-+  for each channel by 8-bit analog and 12-bit digital dimming control.
-+  Datasheet available at
-+  https://www.st.com/en/power-management/led1202.html
-+
-+properties:
-+  compatible:
-+    const: st,led1202
-+
-+  reg:
-+    maxItems: 1
-+
-+  "#address-cells":
-+    const: 1
-+
-+  "#size-cells":
-+    const: 0
-+
-+patternProperties:
-+  "^led@[0-9a-f]$":
-+    type: object
-+    $ref: common.yaml#
-+    unevaluatedProperties: false
-+
-+    properties:
-+      reg:
-+        minimum: 0
-+        maximum: 11
-+
-+    required:
-+      - reg
-+
-+required:
-+  - compatible
-+  - reg
-+  - "#address-cells"
-+  - "#size-cells"
-+
-+additionalProperties: false
-+
-+examples:
-+  - |
-+    #include <dt-bindings/leds/common.h>
-+
-+    i2c {
-+        #address-cells = <1>;
-+        #size-cells = <0>;
-+
-+        led-controller@58 {
-+            compatible = "st,led1202";
-+            reg = <0x58>;
-+            #address-cells = <1>;
-+            #size-cells = <0>;
-+
-+            led@0 {
-+                reg = <0x0>;
-+                function = LED_FUNCTION_STATUS;
-+                color = <LED_COLOR_ID_RED>;
-+                function-enumerator = <1>;
-+            };
-+
-+            led@1 {
-+                reg = <0x1>;
-+                function = LED_FUNCTION_STATUS;
-+                color = <LED_COLOR_ID_GREEN>;
-+                function-enumerator = <2>;
-+            };
-+
-+            led@2 {
-+                reg = <0x2>;
-+                function = LED_FUNCTION_STATUS;
-+                color = <LED_COLOR_ID_BLUE>;
-+                function-enumerator = <3>;
-+            };
-+
-+            led@3 {
-+                reg = <0x3>;
-+                function = LED_FUNCTION_STATUS;
-+                color = <LED_COLOR_ID_RED>;
-+                function-enumerator = <4>;
-+            };
-+
-+            led@4 {
-+                reg = <0x4>;
-+                function = LED_FUNCTION_STATUS;
-+                color = <LED_COLOR_ID_GREEN>;
-+                function-enumerator = <5>;
-+            };
-+
-+            led@5 {
-+                reg = <0x5>;
-+                function = LED_FUNCTION_STATUS;
-+                color = <LED_COLOR_ID_BLUE>;
-+                function-enumerator = <6>;
-+            };
-+
-+            led@6 {
-+                reg = <0x6>;
-+                function = LED_FUNCTION_STATUS;
-+                color = <LED_COLOR_ID_RED>;
-+                function-enumerator = <7>;
-+            };
-+
-+            led@7 {
-+                reg = <0x7>;
-+                function = LED_FUNCTION_STATUS;
-+                color = <LED_COLOR_ID_GREEN>;
-+                function-enumerator = <8>;
-+            };
-+
-+            led@8 {
-+                reg = <0x8>;
-+                function = LED_FUNCTION_STATUS;
-+                color = <LED_COLOR_ID_BLUE>;
-+                function-enumerator = <9>;
-+            };
-+        };
-+    };
-+...
diff --git a/target/linux/generic/pending-6.12/892-leds-Add-LED1202-I2C-driver.patch b/target/linux/generic/pending-6.12/892-leds-Add-LED1202-I2C-driver.patch
deleted file mode 100644 (file)
index ee2ea07..0000000
+++ /dev/null
@@ -1,475 +0,0 @@
-From 939757aafeb9c266dda37657ee5f7a73ffd35ae2 Mon Sep 17 00:00:00 2001
-From: Vicentiu Galanopulo <vicentiu.galanopulo@remote-tech.co.uk>
-Date: Wed, 18 Dec 2024 18:33:59 +0000
-Subject: leds: Add LED1202 I2C driver
-
-The output current can be adjusted separately for each channel by 8-bit
-analog (current sink input) and 12-bit digital (PWM) dimming control. The
-LED1202 implements 12 low-side current generators with independent dimming
-control.
-Internal volatile memory allows the user to store up to 8 different patterns,
-each pattern is a particular output configuration in terms of PWM
-duty-cycle (on 4096 steps). Analog dimming (on 256 steps) is per channel but
-common to all patterns. Each device tree LED node will have a corresponding
-entry in /sys/class/leds with the label name. The brightness property
-corresponds to the per channel analog dimming, while the patterns[1-8] to the
-PWM dimming control.
-
-Signed-off-by: Vicentiu Galanopulo <vicentiu.galanopulo@remote-tech.co.uk>
-Link: https://lore.kernel.org/r/20241218183401.41687-4-vicentiu.galanopulo@remote-tech.co.uk
-Signed-off-by: Lee Jones <lee@kernel.org>
----
- drivers/leds/Kconfig       |  10 +
- drivers/leds/Makefile      |   1 +
- drivers/leds/leds-st1202.c | 416 +++++++++++++++++++++++++++++++++++++
- 3 files changed, 427 insertions(+)
- create mode 100644 drivers/leds/leds-st1202.c
-
---- a/drivers/leds/Kconfig
-+++ b/drivers/leds/Kconfig
-@@ -931,6 +931,16 @@ config LEDS_LM36274
-         Say Y to enable the LM36274 LED driver for TI LMU devices.
-         This supports the LED device LM36274.
-+config LEDS_ST1202
-+      tristate "LED Support for STMicroelectronics LED1202 I2C chips"
-+      depends on LEDS_CLASS
-+      depends on I2C
-+      depends on OF
-+      select LEDS_TRIGGERS
-+      help
-+        Say Y to enable support for LEDs connected to LED1202
-+        LED driver chips accessed via the I2C bus.
-+
- config LEDS_TPS6105X
-       tristate "LED support for TI TPS6105X"
-       depends on LEDS_CLASS
---- a/drivers/leds/Makefile
-+++ b/drivers/leds/Makefile
-@@ -81,6 +81,7 @@ obj-$(CONFIG_LEDS_POWERNV)           += leds-powe
- obj-$(CONFIG_LEDS_PWM)                        += leds-pwm.o
- obj-$(CONFIG_LEDS_REGULATOR)          += leds-regulator.o
- obj-$(CONFIG_LEDS_SC27XX_BLTC)                += leds-sc27xx-bltc.o
-+obj-$(CONFIG_LEDS_ST1202)             += leds-st1202.o
- obj-$(CONFIG_LEDS_SUN50I_A100)                += leds-sun50i-a100.o
- obj-$(CONFIG_LEDS_SUNFIRE)            += leds-sunfire.o
- obj-$(CONFIG_LEDS_SYSCON)             += leds-syscon.o
---- /dev/null
-+++ b/drivers/leds/leds-st1202.c
-@@ -0,0 +1,416 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ * LED driver for STMicroelectronics LED1202 chip
-+ *
-+ * Copyright (C) 2024 Remote-Tech Ltd. UK
-+ */
-+
-+#include <linux/cleanup.h>
-+#include <linux/ctype.h>
-+#include <linux/delay.h>
-+#include <linux/err.h>
-+#include <linux/gpio.h>
-+#include <linux/i2c.h>
-+#include <linux/leds.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/string.h>
-+
-+#define ST1202_CHAN_DISABLE_ALL            0x00
-+#define ST1202_CHAN_ENABLE_HIGH            0x03
-+#define ST1202_CHAN_ENABLE_LOW             0x02
-+#define ST1202_CONFIG_REG                  0x04
-+/* PATS: Pattern sequence feature enable */
-+#define ST1202_CONFIG_REG_PATS             BIT(7)
-+/* PATSR: Pattern sequence runs (self-clear when sequence is finished) */
-+#define ST1202_CONFIG_REG_PATSR            BIT(6)
-+#define ST1202_CONFIG_REG_SHFT             BIT(3)
-+#define ST1202_DEV_ENABLE                  0x01
-+#define ST1202_DEV_ENABLE_ON               BIT(0)
-+#define ST1202_DEV_ENABLE_RESET            BIT(7)
-+#define ST1202_DEVICE_ID                   0x00
-+#define ST1202_ILED_REG0                   0x09
-+#define ST1202_MAX_LEDS                    12
-+#define ST1202_MAX_PATTERNS                8
-+#define ST1202_MILLIS_PATTERN_DUR_MAX      5660
-+#define ST1202_MILLIS_PATTERN_DUR_MIN      22
-+#define ST1202_PATTERN_DUR                 0x16
-+#define ST1202_PATTERN_PWM                 0x1E
-+#define ST1202_PATTERN_REP                 0x15
-+
-+struct st1202_led {
-+      struct fwnode_handle *fwnode;
-+      struct led_classdev led_cdev;
-+      struct st1202_chip *chip;
-+      bool is_active;
-+      int led_num;
-+};
-+
-+struct st1202_chip {
-+      struct i2c_client *client;
-+      struct mutex lock;
-+      struct st1202_led leds[ST1202_MAX_LEDS];
-+};
-+
-+static struct st1202_led *cdev_to_st1202_led(struct led_classdev *cdev)
-+{
-+      return container_of(cdev, struct st1202_led, led_cdev);
-+}
-+
-+static int st1202_read_reg(struct st1202_chip *chip, int reg, uint8_t *val)
-+{
-+      struct device *dev = &chip->client->dev;
-+      int ret;
-+
-+      ret = i2c_smbus_read_byte_data(chip->client, reg);
-+      if (ret < 0) {
-+              dev_err(dev, "Failed to read register [0x%x]: %d\n", reg, ret);
-+              return ret;
-+      }
-+
-+      *val = (uint8_t)ret;
-+      return 0;
-+}
-+
-+static int st1202_write_reg(struct st1202_chip *chip, int reg, uint8_t val)
-+{
-+      struct device *dev = &chip->client->dev;
-+      int ret;
-+
-+      ret = i2c_smbus_write_byte_data(chip->client, reg, val);
-+      if (ret != 0)
-+              dev_err(dev, "Failed to write %d to register [0x%x]: %d\n", val, reg, ret);
-+
-+      return ret;
-+}
-+
-+static uint8_t st1202_prescalar_to_miliseconds(unsigned int value)
-+{
-+      return value / ST1202_MILLIS_PATTERN_DUR_MIN - 1;
-+}
-+
-+static int st1202_pwm_pattern_write(struct st1202_chip *chip, int led_num,
-+                              int pattern, unsigned int value)
-+{
-+      u8 value_l, value_h;
-+      int ret;
-+
-+      value_l = (u8)value;
-+      value_h = (u8)(value >> 8);
-+
-+      /*
-+       *  Datasheet: Register address low = 1Eh + 2*(xh) + 18h*(yh),
-+       *  where x is the channel number (led number) in hexadecimal (x = 00h .. 0Bh)
-+       *  and y is the pattern number in hexadecimal (y = 00h .. 07h)
-+       */
-+      ret = st1202_write_reg(chip, (ST1202_PATTERN_PWM + (led_num * 2) + 0x18 * pattern),
-+                              value_l);
-+      if (ret != 0)
-+              return ret;
-+
-+      /*
-+       * Datasheet: Register address high = 1Eh + 01h + 2(xh) +18h*(yh),
-+       * where x is the channel number in hexadecimal (x = 00h .. 0Bh)
-+       * and y is the pattern number in hexadecimal (y = 00h .. 07h)
-+       */
-+      ret = st1202_write_reg(chip, (ST1202_PATTERN_PWM + 0x1 + (led_num * 2) + 0x18 * pattern),
-+                              value_h);
-+      if (ret != 0)
-+              return ret;
-+
-+      return 0;
-+}
-+
-+static int st1202_duration_pattern_write(struct st1202_chip *chip, int pattern,
-+                                      unsigned int value)
-+{
-+      return st1202_write_reg(chip, (ST1202_PATTERN_DUR + pattern),
-+                              st1202_prescalar_to_miliseconds(value));
-+}
-+
-+static void st1202_brightness_set(struct led_classdev *led_cdev,
-+                              enum led_brightness value)
-+{
-+      struct st1202_led *led = cdev_to_st1202_led(led_cdev);
-+      struct st1202_chip *chip = led->chip;
-+
-+      guard(mutex)(&chip->lock);
-+
-+      st1202_write_reg(chip, ST1202_ILED_REG0 + led->led_num, value);
-+}
-+
-+static enum led_brightness st1202_brightness_get(struct led_classdev *led_cdev)
-+{
-+      struct st1202_led *led = cdev_to_st1202_led(led_cdev);
-+      struct st1202_chip *chip = led->chip;
-+      u8 value = 0;
-+
-+      guard(mutex)(&chip->lock);
-+
-+      st1202_read_reg(chip, ST1202_ILED_REG0 + led->led_num, &value);
-+
-+      return value;
-+}
-+
-+static int st1202_channel_set(struct st1202_chip *chip, int led_num, bool active)
-+{
-+      u8 chan_low, chan_high;
-+      int ret;
-+
-+      guard(mutex)(&chip->lock);
-+
-+      if (led_num <= 7) {
-+              ret = st1202_read_reg(chip, ST1202_CHAN_ENABLE_LOW, &chan_low);
-+              if (ret < 0)
-+                      return ret;
-+
-+              chan_low = active ? chan_low | BIT(led_num) : chan_low & ~BIT(led_num);
-+
-+              ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_LOW, chan_low);
-+              if (ret < 0)
-+                      return ret;
-+
-+      } else {
-+              ret = st1202_read_reg(chip, ST1202_CHAN_ENABLE_HIGH, &chan_high);
-+              if (ret < 0)
-+                      return ret;
-+
-+              chan_high = active ? chan_high | (BIT(led_num) >> 8) :
-+                                      chan_high & ~(BIT(led_num) >> 8);
-+
-+              ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_HIGH, chan_high);
-+              if (ret < 0)
-+                      return ret;
-+      }
-+
-+      return 0;
-+}
-+
-+static int st1202_led_set(struct led_classdev *ldev, enum led_brightness value)
-+{
-+      struct st1202_led *led = cdev_to_st1202_led(ldev);
-+      struct st1202_chip *chip = led->chip;
-+
-+      return st1202_channel_set(chip, led->led_num, value == LED_OFF ? false : true);
-+}
-+
-+static int st1202_led_pattern_clear(struct led_classdev *ldev)
-+{
-+      struct st1202_led *led = cdev_to_st1202_led(ldev);
-+      struct st1202_chip *chip = led->chip;
-+      int ret;
-+
-+      guard(mutex)(&chip->lock);
-+
-+      for (int patt = 0; patt < ST1202_MAX_PATTERNS; patt++) {
-+              ret = st1202_pwm_pattern_write(chip, led->led_num, patt, LED_OFF);
-+              if (ret != 0)
-+                      return ret;
-+
-+              ret = st1202_duration_pattern_write(chip, patt, ST1202_MILLIS_PATTERN_DUR_MIN);
-+              if (ret != 0)
-+                      return ret;
-+      }
-+
-+      return 0;
-+}
-+
-+static int st1202_led_pattern_set(struct led_classdev *ldev,
-+                              struct led_pattern *pattern,
-+                              u32 len, int repeat)
-+{
-+      struct st1202_led *led = cdev_to_st1202_led(ldev);
-+      struct st1202_chip *chip = led->chip;
-+      int ret;
-+
-+      if (len > ST1202_MAX_PATTERNS)
-+              return -EINVAL;
-+
-+      guard(mutex)(&chip->lock);
-+
-+      for (int patt = 0; patt < len; patt++) {
-+              if (pattern[patt].delta_t < ST1202_MILLIS_PATTERN_DUR_MIN ||
-+                              pattern[patt].delta_t > ST1202_MILLIS_PATTERN_DUR_MAX)
-+                      return -EINVAL;
-+
-+              ret = st1202_pwm_pattern_write(chip, led->led_num, patt, pattern[patt].brightness);
-+              if (ret != 0)
-+                      return ret;
-+
-+              ret = st1202_duration_pattern_write(chip, patt, pattern[patt].delta_t);
-+              if (ret != 0)
-+                      return ret;
-+      }
-+
-+      ret = st1202_write_reg(chip, ST1202_PATTERN_REP, repeat);
-+      if (ret != 0)
-+              return ret;
-+
-+      ret = st1202_write_reg(chip, ST1202_CONFIG_REG, (ST1202_CONFIG_REG_PATSR |
-+                                                      ST1202_CONFIG_REG_PATS | ST1202_CONFIG_REG_SHFT));
-+      if (ret != 0)
-+              return ret;
-+
-+      return 0;
-+}
-+
-+static int st1202_dt_init(struct st1202_chip *chip)
-+{
-+      struct device *dev = &chip->client->dev;
-+      struct st1202_led *led;
-+      int err, reg;
-+
-+      for_each_available_child_of_node_scoped(dev_of_node(dev), child) {
-+              struct led_init_data init_data = {};
-+
-+              err = of_property_read_u32(child, "reg", &reg);
-+              if (err)
-+                      return dev_err_probe(dev, err, "Invalid register\n");
-+
-+              led = &chip->leds[reg];
-+              led->is_active = true;
-+              led->fwnode = of_fwnode_handle(child);
-+
-+              led->led_cdev.max_brightness = U8_MAX;
-+              led->led_cdev.brightness_set_blocking = st1202_led_set;
-+              led->led_cdev.pattern_set = st1202_led_pattern_set;
-+              led->led_cdev.pattern_clear = st1202_led_pattern_clear;
-+              led->led_cdev.default_trigger = "pattern";
-+
-+              init_data.fwnode = led->fwnode;
-+              init_data.devicename = "st1202";
-+              init_data.default_label = ":";
-+
-+              err = devm_led_classdev_register_ext(dev, &led->led_cdev, &init_data);
-+              if (err < 0)
-+                      return dev_err_probe(dev, err, "Failed to register LED class device\n");
-+
-+              led->led_cdev.brightness_set = st1202_brightness_set;
-+              led->led_cdev.brightness_get = st1202_brightness_get;
-+      }
-+
-+      return 0;
-+}
-+
-+static int st1202_setup(struct st1202_chip *chip)
-+{
-+      int ret;
-+
-+      guard(mutex)(&chip->lock);
-+
-+      /*
-+       * Once the supply voltage is applied, the LED1202 executes some internal checks,
-+       * afterwords it stops the oscillator and puts the internal LDO in quiescent mode.
-+       * To start the device, EN bit must be set inside the “Device Enable” register at
-+       * address 01h. As soon as EN is set, the LED1202 loads the adjustment parameters
-+       * from the internal non-volatile memory and performs an auto-calibration procedure
-+       * in order to increase the output current precision.
-+       * Such initialization lasts about 6.5 ms.
-+       */
-+
-+      /* Reset the chip during setup */
-+      ret = st1202_write_reg(chip, ST1202_DEV_ENABLE, ST1202_DEV_ENABLE_RESET);
-+      if (ret < 0)
-+              return ret;
-+
-+      /* Enable phase-shift delay feature */
-+      ret = st1202_write_reg(chip, ST1202_CONFIG_REG, ST1202_CONFIG_REG_SHFT);
-+      if (ret < 0)
-+              return ret;
-+
-+      /* Enable the device */
-+      ret = st1202_write_reg(chip, ST1202_DEV_ENABLE, ST1202_DEV_ENABLE_ON);
-+      if (ret < 0)
-+              return ret;
-+
-+      /* Duration of initialization */
-+      usleep_range(6500, 10000);
-+
-+      /* Deactivate all LEDS (channels) and activate only the ones found in Device Tree */
-+      ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_LOW, ST1202_CHAN_DISABLE_ALL);
-+      if (ret < 0)
-+              return ret;
-+
-+      ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_HIGH, ST1202_CHAN_DISABLE_ALL);
-+      if (ret < 0)
-+              return ret;
-+
-+      ret = st1202_write_reg(chip, ST1202_CONFIG_REG,
-+                              ST1202_CONFIG_REG_PATS | ST1202_CONFIG_REG_PATSR);
-+      if (ret < 0)
-+              return ret;
-+
-+      return 0;
-+}
-+
-+static int st1202_probe(struct i2c_client *client)
-+{
-+      struct st1202_chip *chip;
-+      struct st1202_led *led;
-+      int ret;
-+
-+      if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+              return dev_err_probe(&client->dev, -EIO, "SMBUS Byte Data not Supported\n");
-+
-+      chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
-+      if (!chip)
-+              return -ENOMEM;
-+
-+      devm_mutex_init(&client->dev, &chip->lock);
-+      chip->client = client;
-+
-+      ret = st1202_dt_init(chip);
-+      if (ret < 0)
-+              return ret;
-+
-+      ret = st1202_setup(chip);
-+      if (ret < 0)
-+              return ret;
-+
-+      for (int i = 0; i < ST1202_MAX_LEDS; i++) {
-+              led = &chip->leds[i];
-+              led->chip = chip;
-+              led->led_num = i;
-+
-+              if (!led->is_active)
-+                      continue;
-+
-+              ret = st1202_channel_set(led->chip, led->led_num, true);
-+              if (ret < 0)
-+                      return dev_err_probe(&client->dev, ret,
-+                                      "Failed to activate LED channel\n");
-+
-+              ret = st1202_led_pattern_clear(&led->led_cdev);
-+              if (ret < 0)
-+                      return dev_err_probe(&client->dev, ret,
-+                                      "Failed to clear LED pattern\n");
-+      }
-+
-+      return 0;
-+}
-+
-+static const struct i2c_device_id st1202_id[] = {
-+      { "st1202-i2c" },
-+      { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(i2c, st1202_id);
-+
-+static const struct of_device_id st1202_dt_ids[] = {
-+      { .compatible = "st,led1202" },
-+      { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, st1202_dt_ids);
-+
-+static struct i2c_driver st1202_driver = {
-+      .driver = {
-+              .name = "leds-st1202",
-+              .of_match_table = of_match_ptr(st1202_dt_ids),
-+      },
-+      .probe = st1202_probe,
-+      .id_table = st1202_id,
-+};
-+module_i2c_driver(st1202_driver);
-+
-+MODULE_AUTHOR("Remote Tech LTD");
-+MODULE_DESCRIPTION("STMicroelectronics LED1202 : 12-channel constant current LED driver");
-+MODULE_LICENSE("GPL");
diff --git a/target/linux/generic/pending-6.12/893-leds_st1202-Fix-NULL-pointer-access-error.patch b/target/linux/generic/pending-6.12/893-leds_st1202-Fix-NULL-pointer-access-error.patch
deleted file mode 100644 (file)
index 39d8ddb..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-From c72e455b89f216b43cd0dbb518036ec4c98f5c46 Mon Sep 17 00:00:00 2001
-From: Manuel Fombuena <fombuena@outlook.com>
-Date: Tue, 25 Feb 2025 22:01:02 +0000
-Subject: leds: leds-st1202: Fix NULL pointer access on race condition
-
-st1202_dt_init() calls devm_led_classdev_register_ext() before the
-internal data structures are properly set up, so the LEDs become visible
-to user space while being partially initialized, leading to a window
-where trying to access them causes a NULL pointer access.
-
-Move devm_led_classdev_register_ext() from DT initialization
-to the end of the probe function when DT and hardware are fully
-initialized and ready to interact with user space.
-
-Fixes: 259230378c65 ("leds: Add LED1202 I2C driver")
-Signed-off-by: Manuel Fombuena <fombuena@outlook.com>
-Link: https://lore.kernel.org/r/CWLP123MB54732771AC0CE5491B3C84DCC5C32@CWLP123MB5473.GBRP123.PROD.OUTLOOK.COM
-Signed-off-by: Lee Jones <lee@kernel.org>
----
- drivers/leds/leds-st1202.c | 21 ++++++++++-----------
- 1 file changed, 10 insertions(+), 11 deletions(-)
-
---- a/drivers/leds/leds-st1202.c
-+++ b/drivers/leds/leds-st1202.c
-@@ -261,8 +261,6 @@ static int st1202_dt_init(struct st1202_
-       int err, reg;
-       for_each_available_child_of_node_scoped(dev_of_node(dev), child) {
--              struct led_init_data init_data = {};
--
-               err = of_property_read_u32(child, "reg", &reg);
-               if (err)
-                       return dev_err_probe(dev, err, "Invalid register\n");
-@@ -276,15 +274,6 @@ static int st1202_dt_init(struct st1202_
-               led->led_cdev.pattern_set = st1202_led_pattern_set;
-               led->led_cdev.pattern_clear = st1202_led_pattern_clear;
-               led->led_cdev.default_trigger = "pattern";
--
--              init_data.fwnode = led->fwnode;
--              init_data.devicename = "st1202";
--              init_data.default_label = ":";
--
--              err = devm_led_classdev_register_ext(dev, &led->led_cdev, &init_data);
--              if (err < 0)
--                      return dev_err_probe(dev, err, "Failed to register LED class device\n");
--
-               led->led_cdev.brightness_set = st1202_brightness_set;
-               led->led_cdev.brightness_get = st1202_brightness_get;
-       }
-@@ -368,6 +357,7 @@ static int st1202_probe(struct i2c_clien
-               return ret;
-       for (int i = 0; i < ST1202_MAX_LEDS; i++) {
-+              struct led_init_data init_data = {};
-               led = &chip->leds[i];
-               led->chip = chip;
-               led->led_num = i;
-@@ -384,6 +374,15 @@ static int st1202_probe(struct i2c_clien
-               if (ret < 0)
-                       return dev_err_probe(&client->dev, ret,
-                                       "Failed to clear LED pattern\n");
-+
-+              init_data.fwnode = led->fwnode;
-+              init_data.devicename = "st1202";
-+              init_data.default_label = ":";
-+
-+              ret = devm_led_classdev_register_ext(&client->dev, &led->led_cdev, &init_data);
-+              if (ret < 0)
-+                      return dev_err_probe(&client->dev, ret,
-+                                      "Failed to register LED class device\n");
-       }
-       return 0;